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