/* * 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); }
/** * @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); }