Пример #1
0
/*
 * R_LoadBspLights
 *
 * 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(void) {
	const char *ents;
	char class_name[128];
	vec3_t org, tmp, color;
	float radius;
	boolean_t entity, light;
	r_bsp_surface_t *surf;
	r_bsp_light_t *l;
	int i;

	R_ResolveBspLightParameters();

	// iterate the world surfaces for surface lights
	surf = r_load_model->surfaces;

	for (i = 0; i < r_load_model->num_surfaces; i++, surf++) {
		vec3_t color = { 0.0, 0.0, 0.0 };
		float scale = 1.0;

		// light-emitting surfaces are of course lights
		if ((surf->texinfo->flags & SURF_LIGHT) && surf->texinfo->value) {
			VectorCopy(surf->color, color);
			scale = BSP_LIGHT_SURFACE_RADIUS_SCALE;
		}

		// and so are sky surfaces, if sun light was specified
		else if ((surf->texinfo->flags & SURF_SKY) && r_locals.sun_light) {
			VectorCopy(r_locals.sun_color, color);
			scale = BSP_LIGHT_SURFACE_SKY_RADIUS_SCALE;
		}

		if (!VectorCompare(color, vec3_origin)) {
			VectorMA(surf->center, 1.0, surf->normal, org);

			VectorSubtract(surf->maxs, surf->mins, tmp);
			radius = VectorLength(tmp) * scale;

			R_AddBspLight(org, radius, color);
		}
	}

	// parse the entity string for point lights
	ents = Cm_EntityString();

	VectorClear(org);

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

	memset(class_name, 0, sizeof(class_name));
	entity = 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

				radius *= BSP_LIGHT_POINT_RADIUS_SCALE;

				R_AddBspLight(org, radius, color);

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

				light = false;
			}
		}

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

			c = ParseToken(&ents);
			strncpy(class_name, c, sizeof(class_name) - 1);

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

			continue;
		}

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

		if (!strcmp(c, "light")) {
			radius = atof(ParseToken(&ents));
			continue;
		}

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

	l = r_load_model->bsp_lights;
	for (i = 0; i < r_load_model->num_bsp_lights; i++, l++) {
		float max = 0.0;
		int j;

		for (j = 0; j < 3; j++) {
			if (l->color[j] > max)
				max = l->color[j];
		}

		if (max > BSP_LIGHT_COLOR_COMPONENT_MAX) {
			VectorScale(l->color, BSP_LIGHT_COLOR_COMPONENT_MAX / max, l->color);
		}
	}

	Com_Debug("Loaded %d bsp lights\n", r_load_model->num_bsp_lights);
}
Пример #2
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);
}