예제 #1
0
/**
 * @brief Initializes the elements pool, which is allocated based on the
 * geometry of the current level.
 */
void R_InitElements(r_bsp_model_t *bsp) {

	memset(&r_element_state, 0, sizeof(r_element_state));

	r_bsp_surfaces_t *surfs = &r_element_state.surfs;

	surfs->count += bsp->sorted_surfaces->blend.count;
	surfs->count += bsp->sorted_surfaces->blend_warp.count;

	surfs->surfaces = Mem_LinkMalloc(surfs->count * sizeof(r_bsp_surface_t **), bsp);

	r_element_state.size = MIN_ELEMENTS + r_element_state.surfs.count;
	r_element_state.elements = Mem_LinkMalloc(r_element_state.size * sizeof(r_element_t), bsp);
}
예제 #2
0
/**
 * @brief Uploads sorted lightmaps from start to (end - 1) and
 * puts them in the new maps sized to width/height
 */
static void R_UploadPackedLightmaps(uint32_t width, uint32_t height, r_bsp_model_t *bsp, GSList *start, GSList *end) {

	// edge case, no blocks left
	if (!width || !height || !start) {
		return;
	}

	// allocate the image
	r_image_t *lightmap = R_AllocLightmap(width, height);
	r_image_t *deluxemap = R_AllocDeluxemap(width, height);
	r_image_t *stainmap = NULL;

	if (r_stainmap->integer) {
		stainmap = R_AllocStainmap(width, height);
	}

	// temp buffers
	byte *sample_buffer = Mem_Malloc(width * height * 3);
	byte *direction_buffer = Mem_Malloc(width * height * 3);

	do {
		r_bsp_surface_t *surf = (r_bsp_surface_t *) start->data;

		const size_t stride = width * 3;
		const size_t lightmap_offset = (surf->lightmap_t *width + surf->lightmap_s) * 3;

		byte *sout = sample_buffer + lightmap_offset;
		byte *dout = direction_buffer + lightmap_offset;

		if (surf->lightmap_input) {
			byte *stout = NULL;

			if (r_stainmap->integer) {
				surf->stainmap = stainmap;
				stout = surf->stainmap_buffer = Mem_LinkMalloc(surf->lightmap_size[0] * surf->lightmap_size[1] * 3, bsp);
			}

			R_BuildLightmap(bsp, surf, surf->lightmap_input, sout, dout, stout, stride);
		} else {
			R_BuildDefaultLightmap(bsp, surf, sout, dout, stride);
		}

		surf->lightmap = lightmap;
		surf->deluxemap = deluxemap;

		start = start->next;
	} while (start != end);

	// upload!
	R_UploadImage(lightmap, GL_RGB, sample_buffer);
	R_UploadImage(deluxemap, GL_RGB, direction_buffer);

	// copy to the stainmap
	if (r_stainmap->integer) {
		R_UploadImage(stainmap, GL_RGB, sample_buffer);
	}

	Mem_Free(sample_buffer);
	Mem_Free(direction_buffer);
}
예제 #3
0
/**
 * @brief Allocates an initializes the flare for the specified surface, if one
 * should be applied. The flare is linked to the provided BSP model and will
 * be freed automatically.
 */
void R_CreateBspSurfaceFlare(r_bsp_model_t *bsp, r_bsp_surface_t *surf) {
	vec3_t span;

	const r_material_t *m = surf->texinfo->material;

	if (!(m->flags & STAGE_FLARE)) { // surface is not flared
		return;
	}

	surf->flare = Mem_LinkMalloc(sizeof(*surf->flare), bsp);

	// move the flare away from the surface, into the level
	VectorMA(surf->center, 2, surf->normal, surf->flare->particle.org);

	// calculate the flare radius based on surface size
	VectorSubtract(surf->maxs, surf->mins, span);
	surf->flare->radius = VectorLength(span);

	const r_stage_t *s = m->stages; // resolve the flare stage
	while (s) {
		if (s->cm->flags & STAGE_FLARE) {
			break;
		}
		s = s->next;
	}

	if (!s) {
		return;
	}

	// resolve flare color
	if (s->cm->flags & STAGE_COLOR) {
		VectorCopy(s->cm->color, surf->flare->particle.color);
	} else {
		VectorCopy(surf->texinfo->material->diffuse->color, surf->flare->particle.color);
	}

	// and scaled radius
	if (s->cm->flags & (STAGE_SCALE_S | STAGE_SCALE_T)) {
		surf->flare->radius *= (s->cm->scale.s ? s->cm->scale.s : s->cm->scale.t);
	}

	// and image
	surf->flare->particle.type = PARTICLE_FLARE;
	surf->flare->particle.image = s->image;
	surf->flare->particle.blend = GL_ONE;
}
예제 #4
0
/**
 * @brief Adds the specified static light source after first ensuring that it
 * can not be merged with any known sources.
 */
static void R_AddBspLight(r_bsp_model_t *bsp, vec3_t origin, vec3_t color, vec_t radius) {

	if (radius <= 0.0) {
		Com_Debug(DEBUG_RENDERER, "Bad radius: %f\n", radius);
		return;
	}

	if (r_lighting->value) { // scale by r_lighting->value, if enabled
		radius *= r_lighting->value;
	}

	r_bsp_light_t *bl = NULL;
	GSList *e = r_bsp_light_state.lights;
	while (e) {
		vec3_t delta;

		bl = (r_bsp_light_t *) e->data;
		VectorSubtract(origin, bl->light.origin, delta);

		if (VectorLength(delta) <= BSP_LIGHT_MERGE_THRESHOLD) { // merge them
			break;
		}

		bl = NULL;
		e = e->next;
	}

	if (!bl) { // or allocate a new one
		bl = Mem_LinkMalloc(sizeof(*bl), bsp);
		r_bsp_light_state.lights = g_slist_prepend(r_bsp_light_state.lights, bl);

		VectorCopy(origin, bl->light.origin);
		bl->leaf = R_LeafForPoint(bl->light.origin, bsp);
	}

	bl->count++;
	bl->light.radius = ((bl->light.radius * (bl->count - 1)) + radius) / bl->count;

	VectorMix(bl->light.color, color, 1.0 / bl->count, bl->light.color);

	bl->debug.type = PARTICLE_CORONA;
	bl->debug.color[3] = 1.0;
	bl->debug.blend = GL_ONE;
}
예제 #5
0
/**
 * @brief Parse the entity string and resolve all static light sources. Sources which
 * are very close to each other are merged. Their colors are blended according
 * to their light value (intensity).
 */
void R_LoadBspLights(r_bsp_model_t *bsp) {
	vec3_t origin, color;
	vec_t radius;

	memset(&r_bsp_light_state, 0, sizeof(r_bsp_light_state));

	const r_bsp_light_state_t *s = &r_bsp_light_state;

	R_ResolveBspLightParameters();

	// iterate the world surfaces for surface lights
	const r_bsp_surface_t *surf = bsp->surfaces;

	for (uint16_t i = 0; i < bsp->num_surfaces; i++, surf++) {

		// light-emitting surfaces are of course lights
		if ((surf->texinfo->flags & SURF_LIGHT) && surf->texinfo->value) {
			VectorMA(surf->center, 1.0, surf->normal, origin);

			radius = sqrt(surf->texinfo->light * sqrt(surf->area) * BSP_LIGHT_SURFACE_RADIUS_SCALE);

			R_AddBspLight(bsp, origin, surf->texinfo->emissive, radius * s->brightness);
		}
	}
	
	// parse the entity string for point lights
	const char *ents = Cm_EntityString();

	VectorClear(origin);

	radius = BSP_LIGHT_POINT_DEFAULT_RADIUS * s->brightness;
	VectorSet(color, 1.0, 1.0, 1.0);

	char class_name[MAX_QPATH];
	_Bool entity = false, light = false;

	while (true) {

		const char *c = ParseToken(&ents);

		if (!strlen(c)) {
			break;
		}

		if (*c == '{') {
			entity = true;
		}

		if (!entity) { // skip any whitespace between ents
			continue;
		}

		if (*c == '}') {
			entity = false;

			if (light) { // add it
				R_AddBspLight(bsp, origin, color, radius * BSP_LIGHT_POINT_RADIUS_SCALE);

				radius = BSP_LIGHT_POINT_DEFAULT_RADIUS;
				VectorSet(color, 1.0, 1.0, 1.0);

				light = false;
			}
		}

		if (!g_strcmp0(c, "classname")) {

			c = ParseToken(&ents);
			g_strlcpy(class_name, c, sizeof(class_name));

			if (!strncmp(c, "light", 5)) { // light, light_spot, etc..
				light = true;
			}

			continue;
		}

		if (!g_strcmp0(c, "origin")) {
			sscanf(ParseToken(&ents), "%f %f %f", &origin[0], &origin[1], &origin[2]);
			continue;
		}

		if (!g_strcmp0(c, "light")) {
			radius = atof(ParseToken(&ents)) * s->brightness;
			continue;
		}

		if (!g_strcmp0(c, "_color")) {
			sscanf(ParseToken(&ents), "%f %f %f", &color[0], &color[1], &color[2]);
			ColorFilter(color, color, s->brightness, s->saturation, s->contrast);
			continue;
		}
	}

	// allocate the lights array and copy them in
	bsp->num_bsp_lights = g_slist_length(r_bsp_light_state.lights);
	bsp->bsp_lights = Mem_LinkMalloc(sizeof(r_bsp_light_t) * bsp->num_bsp_lights, bsp);

	GSList *e = r_bsp_light_state.lights;
	r_bsp_light_t *bl = bsp->bsp_lights;
	while (e) {
		*bl++ = *((r_bsp_light_t *) e->data);
		e = e->next;
	}

	// reset state
	g_slist_free_full(r_bsp_light_state.lights, Mem_Free);
	r_bsp_light_state.lights = NULL;

	Com_Debug(DEBUG_RENDERER, "Loaded %d bsp lights\n", bsp->num_bsp_lights);
}