/* * R_BuildLightmap */ static void R_BuildLightmap( int w, int h, qboolean deluxe, const qbyte *data, qbyte *dest, int blockWidth ) { int x, y; qbyte *rgba; int bits = mapConfig.pow2MapOvrbr; if( !data || (r_fullbright->integer && !deluxe) ) { int val = deluxe ? 127 : 255; for( y = 0; y < h; y++, dest ) memset( dest + y * blockWidth, val, w * LIGHTMAP_BYTES * sizeof( *dest ) ); return; } if( deluxe || ( !bits && !r_lighting_grayscale->integer ) ) { int wB = w * LIGHTMAP_BYTES; for( y = 0, rgba = dest; y < h; y++, data += wB, rgba += blockWidth ) { memcpy( rgba, data, wB ); } } else { float scaled[3]; float intensity = (1 << bits) / 255.0f; for( y = 0; y < h; y++ ) { for( x = 0, rgba = dest + y * blockWidth; x < w; x++, data += LIGHTMAP_BYTES, rgba += LIGHTMAP_BYTES ) { vec3_t normalized; scaled[0] = (float)( (int)data[0] ) * intensity; scaled[1] = (float)( (int)data[1] ) * intensity; scaled[2] = (float)( (int)data[2] ) * intensity; ColorNormalize( scaled, normalized ); // monochrome lighting: convert to grayscale if( r_lighting_grayscale->integer ) { vec_t grey = ColorGrayscale( normalized ); normalized[0] = normalized[1] = normalized[2] = bound( 0, grey, 1 ); } rgba[0] = ( qbyte )( normalized[0] * 255 ); rgba[1] = ( qbyte )( normalized[1] * 255 ); rgba[2] = ( qbyte )( normalized[2] * 255 ); } } } }
/** @note Defaults should match those of ufo2map, or lighting will be inconsistent between world and models */ static void SP_worldspawn (const localEntityParse_t* entData) { /* maximum level */ cl.mapMaxLevel = entData->maxLevel; if (GAME_IsMultiplayer()) { if (cl_teamnum->integer > entData->maxMultiplayerTeams || cl_teamnum->integer <= TEAM_CIVILIAN) { Com_Printf("The selected team is not usable. " "The map doesn't support %i teams but only %i teams\n", cl_teamnum->integer, entData->maxMultiplayerTeams); Cvar_SetValue("cl_teamnum", TEAM_DEFAULT); Com_Printf("Set teamnum to %i\n", cl_teamnum->integer); } } /** @todo - make sun position/color vary based on local time at location? */ const int dayLightmap = CL_GetConfigStringInteger(CS_LIGHTMAP); /** @note Some vectors have exra elements to comply with mathlib and/or OpenGL conventions, but handled as shorter ones */ vec3_t sunAngles; vec4_t sunColor; vec_t sunIntensity; if (dayLightmap) { /* set defaults for daylight */ Vector4Set(refdef.ambientColor, 0.26, 0.26, 0.26, 1.0); sunIntensity = 280; VectorSet(sunAngles, -75, 100, 0); Vector4Set(sunColor, 0.90, 0.75, 0.65, 1.0); /* override defaults with data from worldspawn entity, if any */ if (VectorNotEmpty(entData->ambientDayColor)) VectorCopy(entData->ambientDayColor, refdef.ambientColor); if (entData->dayLight) sunIntensity = entData->dayLight; if (Vector2NotEmpty(entData->daySunAngles)) Vector2Copy(entData->daySunAngles, sunAngles); if (VectorNotEmpty(entData->daySunColor)) VectorCopy(entData->daySunColor, sunColor); Vector4Set(refdef.sunSpecularColor, 1.0, 1.0, 0.9, 1); } else { /* set defaults for night light */ Vector4Set(refdef.ambientColor, 0.16, 0.16, 0.17, 1.0); sunIntensity = 15; VectorSet(sunAngles, -80, 220, 0); Vector4Set(sunColor, 0.25, 0.25, 0.35, 1.0); /* override defaults with data from worldspawn entity, if any */ if (VectorNotEmpty(entData->ambientNightColor)) VectorCopy(entData->ambientNightColor, refdef.ambientColor); if (entData->nightLight) sunIntensity = entData->nightLight; if (Vector2NotEmpty(entData->nightSunAngles)) Vector2Copy(entData->nightSunAngles, sunAngles); if (VectorNotEmpty(entData->nightSunColor)) VectorCopy(entData->nightSunColor, sunColor); Vector4Set(refdef.sunSpecularColor, 0.5, 0.5, 0.7, 1); } ColorNormalize(sunColor, sunColor); VectorScale(sunColor, sunIntensity/255.0, sunColor); Vector4Copy(sunColor, refdef.sunDiffuseColor); /* clamp ambient for models */ Vector4Copy(refdef.ambientColor, refdef.modelAmbientColor); for (int i = 0; i < 3; i++) if (refdef.modelAmbientColor[i] < MIN_AMBIENT_COMPONENT) refdef.modelAmbientColor[i] = MIN_AMBIENT_COMPONENT; /* scale it into a reasonable range, the clamp above ensures this will work */ while (VectorSum(refdef.modelAmbientColor) < MIN_AMBIENT_SUM) VectorScale(refdef.modelAmbientColor, 1.25, refdef.modelAmbientColor); AngleVectors(sunAngles, refdef.sunVector, nullptr, nullptr); refdef.sunVector[3] = 0.0; /* to use as directional light source in OpenGL */ /** @todo Parse fog from worldspawn config */ refdef.weather = WEATHER_NONE; refdef.fogColor[3] = 1.0; VectorSet(refdef.fogColor, 0.75, 0.75, 0.75); }
void MakePatchForFace( int fn, winding_t *w ){ dface_t *f; float area; patch_t *patch; dplane_t *pl; int i; vec3_t color; dleaf_t *leaf; f = &dfaces[fn]; area = WindingArea( w ); totalarea += area; patch = &patches[num_patches]; if ( num_patches == MAX_PATCHES ) { Error( "num_patches == MAX_PATCHES" ); } patch->next = face_patches[fn]; face_patches[fn] = patch; patch->winding = w; if ( f->side ) { patch->plane = &backplanes[f->planenum]; } else{ patch->plane = &dplanes[f->planenum]; } if ( face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) { // origin offset faces must create new planes if ( numplanes + fakeplanes >= MAX_MAP_PLANES ) { Error( "numplanes + fakeplanes >= MAX_MAP_PLANES" ); } pl = &dplanes[numplanes + fakeplanes]; fakeplanes++; *pl = *( patch->plane ); pl->dist += DotProduct( face_offset[fn], pl->normal ); patch->plane = pl; } WindingCenter( w, patch->origin ); VectorAdd( patch->origin, patch->plane->normal, patch->origin ); leaf = Rad_PointInLeaf( patch->origin ); patch->cluster = leaf->cluster; if ( patch->cluster == -1 ) { Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n" ); } patch->area = area; if ( patch->area <= 1 ) { patch->area = 1; } patch->sky = IsSky( f ); VectorCopy( texture_reflectivity[f->texinfo], patch->reflectivity ); // non-bmodel patches can emit light if ( fn < dmodels[0].numfaces ) { BaseLightForFace( f, patch->baselight ); ColorNormalize( patch->reflectivity, color ); for ( i = 0 ; i < 3 ; i++ ) patch->baselight[i] *= color[i]; VectorCopy( patch->baselight, patch->totallight ); } num_patches++; }
/* ====================== CalcTextureReflectivity_Quake2 ====================== */ void CalcTextureReflectivity_Quake2( void ){ int i; int j, k, texels; int color[3]; int texel; byte *palette; char path[1024]; float r, scale; miptex_t *mt; sprintf( path, "%spics/colormap.pcx", gamedir ); // get the game palette Load256Image( path, NULL, &palette, NULL, NULL ); // allways set index 0 even if no textures texture_reflectivity[0][0] = 0.5; texture_reflectivity[0][1] = 0.5; texture_reflectivity[0][2] = 0.5; for ( i = 0 ; i < numtexinfo ; i++ ) { // see if an earlier texinfo allready got the value for ( j = 0 ; j < i ; j++ ) { if ( !strcmp( texinfo[i].texture, texinfo[j].texture ) ) { VectorCopy( texture_reflectivity[j], texture_reflectivity[i] ); break; } } if ( j != i ) { continue; } // load the wal file sprintf( path, "%stextures/%s.wal", gamedir, texinfo[i].texture ); if ( TryLoadFile( path, (void **)&mt ) == -1 ) { Sys_Printf( "Couldn't load %s\n", path ); texture_reflectivity[i][0] = 0.5; texture_reflectivity[i][1] = 0.5; texture_reflectivity[i][2] = 0.5; continue; } texels = LittleLong( mt->width ) * LittleLong( mt->height ); color[0] = color[1] = color[2] = 0; for ( j = 0 ; j < texels ; j++ ) { texel = ( (byte *)mt )[LittleLong( mt->offsets[0] ) + j]; for ( k = 0 ; k < 3 ; k++ ) color[k] += palette[texel * 3 + k]; } for ( j = 0 ; j < 3 ; j++ ) { r = color[j] / texels / 255.0; texture_reflectivity[i][j] = r; } // scale the reflectivity up, because the textures are // so dim scale = ColorNormalize( texture_reflectivity[i], texture_reflectivity[i] ); if ( scale < 0.5 ) { scale *= 2; VectorScale( texture_reflectivity[i], scale, texture_reflectivity[i] ); } #if 0 texture_reflectivity[i][0] = 0.5; texture_reflectivity[i][1] = 0.5; texture_reflectivity[i][2] = 0.5; #endif } }
/** * @brief Create lights out of patches and entity lights * @sa LightWorld * @sa BuildPatch */ void BuildLights (void) { int i; light_t* l; /* surfaces */ for (i = 0; i < MAX_MAP_FACES; i++) { /* iterate subdivided patches */ for(const patch_t* p = face_patches[i]; p; p = p->next) { if (VectorEmpty(p->light)) continue; numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); VectorCopy(p->origin, l->origin); l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; l->type = emit_surface; l->intensity = ColorNormalize(p->light, l->color); l->intensity *= p->area * config.surface_scale; } } /* entities (skip the world) */ for (i = 1; i < num_entities; i++) { float intensity; const char* color; const char* target; const entity_t* e = &entities[i]; const char* name = ValueForKey(e, "classname"); if (!Q_strstart(name, "light")) continue; /* remove those lights that are only for the night version */ if (config.compile_for_day) { const int spawnflags = atoi(ValueForKey(e, "spawnflags")); if (!(spawnflags & 1)) /* day */ continue; } numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); GetVectorForKey(e, "origin", l->origin); /* link in */ l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; intensity = FloatForKey(e, "light"); if (!intensity) intensity = 300.0; color = ValueForKey(e, "_color"); if (color && color[0] != '\0'){ if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3) Sys_Error("Invalid _color entity property given: %s", color); ColorNormalize(l->color, l->color); } else VectorSet(l->color, 1.0, 1.0, 1.0); l->intensity = intensity * config.entity_scale; l->type = emit_point; target = ValueForKey(e, "target"); if (target[0] != '\0' || Q_streq(name, "light_spot")) { l->type = emit_spotlight; l->stopdot = FloatForKey(e, "_cone"); if (!l->stopdot) l->stopdot = 10; l->stopdot = cos(l->stopdot * torad); if (target[0] != '\0') { /* point towards target */ entity_t* e2 = FindTargetEntity(target); if (!e2) Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n", (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target); else { vec3_t dest; GetVectorForKey(e2, "origin", dest); VectorSubtract(dest, l->origin, l->normal); VectorNormalize(l->normal); } } else { /* point down angle */ const float angle = FloatForKey(e, "angle"); if (angle == ANGLE_UP) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = 1.0; } else if (angle == ANGLE_DOWN) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = -1.0; } else { l->normal[2] = 0; l->normal[0] = cos(angle * torad); l->normal[1] = sin(angle * torad); } } } } /* handle worldspawn light settings */ { const entity_t* e = &entities[0]; const char* ambient, *light, *angles, *color; float f; int i; if (config.compile_for_day) { ambient = ValueForKey(e, "ambient_day"); light = ValueForKey(e, "light_day"); angles = ValueForKey(e, "angles_day"); color = ValueForKey(e, "color_day"); } else { ambient = ValueForKey(e, "ambient_night"); light = ValueForKey(e, "light_night"); angles = ValueForKey(e, "angles_night"); color = ValueForKey(e, "color_night"); } if (light[0] != '\0') sun_intensity = atoi(light); if (angles[0] != '\0') { VectorClear(sun_angles); if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2) Sys_Error("wrong angles values given: '%s'", angles); AngleVectors(sun_angles, sun_normal, nullptr, nullptr); } if (color[0] != '\0') { GetVectorFromString(color, sun_color); ColorNormalize(sun_color, sun_color); } if (ambient[0] != '\0') GetVectorFromString(ambient, sun_ambient_color); /* optionally pull brightness from worldspawn */ f = FloatForKey(e, "brightness"); if (f > 0.0) config.brightness = f; /* saturation as well */ f = FloatForKey(e, "saturation"); if (f > 0.0) config.saturation = f; else Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f); f = FloatForKey(e, "contrast"); if (f > 0.0) config.contrast = f; else Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f); /* lightmap resolution downscale (e.g. 4 = 1 << 4) */ i = atoi(ValueForKey(e, "quant")); if (i >= 1 && i <= 6) config.lightquant = i; else Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i); } Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n", sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]); Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night")); }