00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "lighting.h"
00026 #include "bsp.h"
00027
00028 #define sun_angles config.sun_angles[config.compile_for_day]
00029 #define sun_normal config.sun_normal[config.compile_for_day]
00030 #define sun_color config.sun_color[config.compile_for_day]
00031 #define sun_intensity config.sun_intensity[config.compile_for_day]
00032 #define sun_ambient_color config.sun_ambient_color[config.compile_for_day]
00033
00034 vec3_t face_offset[MAX_MAP_FACES];
00037 typedef struct {
00038 vec_t facedist;
00039 vec3_t facenormal;
00040
00041 int numsurfpt;
00042 vec3_t *surfpt;
00043
00044 vec3_t modelorg;
00046 vec3_t texorg;
00047 vec3_t worldtotex[2];
00048 vec3_t textoworld[2];
00050 int texmins[2], texsize[2];
00051 dBspSurface_t *face;
00052 } lightinfo_t;
00053
00055 typedef struct extents_s {
00056 vec3_t mins, maxs;
00057 vec3_t center;
00058 vec2_t stmins, stmaxs;
00059 } extents_t;
00060
00061 static extents_t face_extents[MAX_MAP_FACES];
00062
00068 static void BuildFaceExtents (void)
00069 {
00070 int k;
00071
00072 for (k = 0; k < curTile->numfaces; k++) {
00073 const dBspSurface_t *s = &curTile->faces[k];
00074 const dBspTexinfo_t *tex = &curTile->texinfo[s->texinfo];
00075
00076 float *mins = face_extents[s - curTile->faces].mins;
00077 float *maxs = face_extents[s - curTile->faces].maxs;
00078
00079 float *center = face_extents[s - curTile->faces].center;
00080
00081 float *stmins = face_extents[s - curTile->faces].stmins;
00082 float *stmaxs = face_extents[s - curTile->faces].stmaxs;
00083 int i;
00084
00085 VectorSet(mins, 999999, 999999, 999999);
00086 VectorSet(maxs, -999999, -999999, -999999);
00087
00088 stmins[0] = stmins[1] = 999999;
00089 stmaxs[0] = stmaxs[1] = -999999;
00090
00091 for (i = 0; i < s->numedges; i++) {
00092 const int e = curTile->surfedges[s->firstedge + i];
00093 const dBspVertex_t *v;
00094 int j;
00095
00096 if (e >= 0)
00097 v = curTile->vertexes + curTile->edges[e].v[0];
00098 else
00099 v = curTile->vertexes + curTile->edges[-e].v[1];
00100
00101 for (j = 0; j < 3; j++) {
00102 if (v->point[j] > maxs[j])
00103 maxs[j] = v->point[j];
00104 if (v->point[j] < mins[j])
00105 mins[j] = v->point[j];
00106 }
00107
00108 for (j = 0; j < 2; j++) {
00109 const float val = DotProduct(v->point, tex->vecs[j]) + tex->vecs[j][3];
00110 if (val < stmins[j])
00111 stmins[j] = val;
00112 if (val > stmaxs[j])
00113 stmaxs[j] = val;
00114 }
00115 }
00116
00117 for (i = 0; i < 3; i++)
00118 center[i] = (mins[i] + maxs[i]) / 2.0f;
00119 }
00120 }
00121
00125 static void CalcLightinfoExtents (lightinfo_t *l)
00126 {
00127 const dBspSurface_t *s;
00128 float *stmins, *stmaxs;
00129 vec2_t lm_mins, lm_maxs;
00130 int i;
00131
00132 s = l->face;
00133
00134 stmins = face_extents[s - curTile->faces].stmins;
00135 stmaxs = face_extents[s - curTile->faces].stmaxs;
00136
00137 for (i = 0; i < 2; i++) {
00138 lm_mins[i] = floor(stmins[i] / (1 << config.lightquant));
00139 lm_maxs[i] = ceil(stmaxs[i] / (1 << config.lightquant));
00140
00141 l->texmins[i] = lm_mins[i];
00142 l->texsize[i] = lm_maxs[i] - lm_mins[i];
00143 }
00144
00145 if (l->texsize[0] * l->texsize[1] > MAX_MAP_LIGHTMAP)
00146 Sys_Error("Surface too large to light (%dx%d)", l->texsize[0], l->texsize[1]);
00147 }
00148
00152 static void CalcLightinfoVectors (lightinfo_t *l)
00153 {
00154 const dBspTexinfo_t *tex;
00155 int i;
00156 vec3_t texnormal;
00157 vec_t distscale, dist;
00158
00159 tex = &curTile->texinfo[l->face->texinfo];
00160
00161
00162 for (i = 0; i < 2; i++)
00163 VectorCopy(tex->vecs[i], l->worldtotex[i]);
00164
00165
00166
00167 texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2]
00168 - tex->vecs[1][2] * tex->vecs[0][1];
00169 texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0]
00170 - tex->vecs[1][0] * tex->vecs[0][2];
00171 texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1]
00172 - tex->vecs[1][1] * tex->vecs[0][0];
00173 VectorNormalize(texnormal);
00174
00175
00176 distscale = DotProduct(texnormal, l->facenormal);
00177 if (!distscale) {
00178 Verb_Printf(VERB_EXTRA, "WARNING: Texture axis perpendicular to face\n");
00179 distscale = 1.0;
00180 }
00181 if (distscale < 0.0) {
00182 distscale = -distscale;
00183 VectorSubtract(vec3_origin, texnormal, texnormal);
00184 }
00185
00186
00187
00188 distscale = 1.0 / distscale;
00189
00190 for (i = 0; i < 2; i++) {
00191 const vec_t len = VectorLength(l->worldtotex[i]);
00192 const vec_t distance = DotProduct(l->worldtotex[i], l->facenormal) * distscale;
00193 VectorMA(l->worldtotex[i], -distance, texnormal, l->textoworld[i]);
00194 VectorScale(l->textoworld[i], (1.0f / len) * (1.0f / len), l->textoworld[i]);
00195 }
00196
00197
00198 for (i = 0; i < 3; i++)
00199 l->texorg[i] =
00200 -tex->vecs[0][3] * l->textoworld[0][i] -
00201 tex->vecs[1][3] * l->textoworld[1][i];
00202
00203
00204 dist = DotProduct(l->texorg, l->facenormal) - l->facedist - 1;
00205 dist *= distscale;
00206 VectorMA(l->texorg, -dist, texnormal, l->texorg);
00207
00208
00209 VectorAdd(l->texorg, l->modelorg, l->texorg);
00210
00211
00212 l->numsurfpt = (l->texsize[0] + 1) * (l->texsize[1] + 1);
00213 l->surfpt = Mem_Alloc(l->numsurfpt * sizeof(vec3_t));
00214 if (!l->surfpt)
00215 Sys_Error("Surface too large to light ("UFO_SIZE_T")", l->numsurfpt * sizeof(*l->surfpt));
00216 }
00217
00222 static void CalcPoints (lightinfo_t *l, float sofs, float tofs)
00223 {
00224 int s, t, j;
00225 int w, h, step;
00226 vec_t starts, startt;
00227 vec_t *surf;
00228
00229
00230
00231
00232 surf = l->surfpt[0];
00233
00234 h = l->texsize[1] + 1;
00235 w = l->texsize[0] + 1;
00236
00237 step = 1 << config.lightquant;
00238 starts = l->texmins[0] * step;
00239 startt = l->texmins[1] * step;
00240
00241 for (t = 0; t < h; t++) {
00242 for (s = 0; s < w; s++, surf += 3) {
00243 const vec_t us = starts + (s + sofs) * step;
00244 const vec_t ut = startt + (t + tofs) * step;
00245
00246
00247 for (j = 0; j < 3; j++)
00248 surf[j] = l->texorg[j] + l->textoworld[0][j] * us +
00249 l->textoworld[1][j] * ut;
00250 }
00251 }
00252 }
00253
00255 typedef struct facelight_s {
00256 int numsamples;
00257 float *origins;
00258 float *samples;
00259 float *directions;
00260 } facelight_t;
00261
00262 static facelight_t facelight[LIGHTMAP_MAX][MAX_MAP_FACES];
00263
00265 typedef enum {
00266 emit_surface,
00267 emit_point,
00268 emit_spotlight
00269 } emittype_t;
00270
00272 typedef struct light_s {
00273 struct light_s *next;
00274 emittype_t type;
00276 float intensity;
00277 vec3_t origin;
00278 vec3_t color;
00279 vec3_t normal;
00280 float stopdot;
00281 } light_t;
00282
00283 static light_t *lights[LIGHTMAP_MAX];
00284 static int numlights[LIGHTMAP_MAX];
00285
00290 void BuildLights (void)
00291 {
00292 int i;
00293 light_t *l;
00294
00295
00296 for (i = 0; i < MAX_MAP_FACES; i++) {
00297 const patch_t *p = face_patches[i];
00298 while (p) {
00299 if (VectorCompare(p->light, vec3_origin))
00300 continue;
00301
00302 numlights[config.compile_for_day]++;
00303 l = Mem_Alloc(sizeof(*l));
00304
00305 VectorCopy(p->origin, l->origin);
00306
00307 l->next = lights[config.compile_for_day];
00308 lights[config.compile_for_day] = l;
00309
00310 l->type = emit_surface;
00311
00312 l->intensity = ColorNormalize(p->light, l->color);
00313 l->intensity *= p->area * config.surface_scale;
00314
00315 p = p->next;
00316 }
00317 }
00318
00319
00320 for (i = 1; i < num_entities; i++) {
00321 float intensity;
00322 const char *color;
00323 const char *target;
00324 const entity_t *e = &entities[i];
00325 const char *name = ValueForKey(e, "classname");
00326 if (strncmp(name, "light", 5))
00327 continue;
00328
00329
00330 if (config.compile_for_day) {
00331 const int spawnflags = atoi(ValueForKey(e, "spawnflags"));
00332 if (!(spawnflags & 1))
00333 continue;
00334 }
00335
00336 numlights[config.compile_for_day]++;
00337 l = Mem_Alloc(sizeof(*l));
00338
00339 GetVectorForKey(e, "origin", l->origin);
00340
00341
00342 l->next = lights[config.compile_for_day];
00343 lights[config.compile_for_day] = l;
00344
00345 intensity = FloatForKey(e, "light");
00346 if (!intensity)
00347 intensity = 300.0;
00348 color = ValueForKey(e, "_color");
00349 if (color && color[0] != '\0'){
00350 sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]);
00351 ColorNormalize(l->color, l->color);
00352 } else
00353 l->color[0] = l->color[1] = l->color[2] = 1.0;
00354 l->intensity = intensity * config.entity_scale;
00355 l->type = emit_point;
00356
00357 target = ValueForKey(e, "target");
00358 if (target[0] != '\0' || !strcmp(name, "light_spot")) {
00359 l->type = emit_spotlight;
00360 l->stopdot = FloatForKey(e, "_cone");
00361 if (!l->stopdot)
00362 l->stopdot = 10;
00363 l->stopdot = cos(l->stopdot * torad);
00364 if (target[0] != '\0') {
00365 entity_t *e2 = FindTargetEntity(target);
00366 if (!e2)
00367 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",
00368 (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target);
00369 else {
00370 vec3_t dest;
00371 GetVectorForKey(e2, "origin", dest);
00372 VectorSubtract(dest, l->origin, l->normal);
00373 VectorNormalize(l->normal);
00374 }
00375 } else {
00376 const float angle = FloatForKey(e, "angle");
00377 if (angle == ANGLE_UP) {
00378 l->normal[0] = l->normal[1] = 0.0;
00379 l->normal[2] = 1.0;
00380 } else if (angle == ANGLE_DOWN) {
00381 l->normal[0] = l->normal[1] = 0.0;
00382 l->normal[2] = -1.0;
00383 } else {
00384 l->normal[2] = 0;
00385 l->normal[0] = cos(angle * torad);
00386 l->normal[1] = sin(angle * torad);
00387 }
00388 }
00389 }
00390 }
00391
00392
00393 {
00394 const entity_t *e = &entities[0];
00395 const char *ambient, *light, *angles, *color;
00396 float f;
00397 int i;
00398
00399 if (config.compile_for_day) {
00400 ambient = ValueForKey(e, "ambient_day");
00401 light = ValueForKey(e, "light_day");
00402 angles = ValueForKey(e, "angles_day");
00403 color = ValueForKey(e, "color_day");
00404 } else {
00405 ambient = ValueForKey(e, "ambient_night");
00406 light = ValueForKey(e, "light_night");
00407 angles = ValueForKey(e, "angles_night");
00408 color = ValueForKey(e, "color_night");
00409 }
00410
00411 if (light[0] != '\0')
00412 sun_intensity = atoi(light);
00413
00414 if (angles[0] != '\0') {
00415 VectorClear(sun_angles);
00416 sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]);
00417 AngleVectors(sun_angles, sun_normal, NULL, NULL);
00418 }
00419
00420 if (color[0] != '\0') {
00421 GetVectorFromString(color, sun_color);
00422 ColorNormalize(sun_color, sun_color);
00423 }
00424
00425 if (ambient[0] != '\0')
00426 GetVectorFromString(ambient, sun_ambient_color);
00427
00428
00429 f = FloatForKey(e, "brightness");
00430 if (f > 0.0)
00431 config.brightness = f;
00432
00433
00434 f = FloatForKey(e, "saturation");
00435 if (f > 0.0)
00436 config.saturation = f;
00437 else
00438 Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f);
00439
00440 f = FloatForKey(e, "contrast");
00441 if (f > 0.0)
00442 config.contrast = f;
00443 else
00444 Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f);
00445
00446
00447 i = atoi(ValueForKey(e, "quant"));
00448 if (i >= 1 && i <= 6)
00449 config.lightquant = i;
00450 else
00451 Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i);
00452 }
00453
00454 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",
00455 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]);
00456 Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night"));
00457 }
00458
00467 static qboolean TR_TestLineSingleTile (const vec3_t start, const vec3_t stop, int *headhint)
00468 {
00469 int i;
00470 static int shared_lastthead = 0;
00471 int lastthead = *headhint;
00472
00473 if (!lastthead) {
00474 lastthead = shared_lastthead;
00475 *headhint = lastthead;
00476 }
00477
00478 assert(mapTiles.numTiles == 1);
00479
00480
00481
00482
00483 if (curTile->theadlevel[lastthead] <= LEVEL_LASTLIGHTBLOCKING
00484 && TR_TestLine_r(curTile, curTile->thead[lastthead], start, stop))
00485 return qtrue;
00486
00487 for (i = 0; i < curTile->numtheads; i++) {
00488 const int level = curTile->theadlevel[i];
00489 if (i == lastthead)
00490 continue;
00491 if (level > LEVEL_LASTLIGHTBLOCKING)
00492 continue;
00493 if (TR_TestLine_r(curTile, curTile->thead[i], start, stop)) {
00494 shared_lastthead = *headhint = i;
00495 return qtrue;
00496 }
00497 }
00498 return qfalse;
00499 }
00500
00504 static void GatherSampleSunlight (const vec3_t pos, const vec3_t normal, float *sample, float *direction, float scale, int *headhint)
00505 {
00506 vec3_t delta;
00507 float dot, light;
00508
00509 if (!sun_intensity)
00510 return;
00511
00512 dot = DotProduct(sun_normal, normal);
00513 if (dot <= 0.001)
00514 return;
00515
00516
00517
00518 VectorMA(pos, 8192, sun_normal, delta);
00519
00520 if (TR_TestLineSingleTile(pos, delta, headhint))
00521 return;
00522
00523 light = sun_intensity * dot * scale;
00524
00525
00526 VectorMA(sample, light, sun_color, sample);
00527
00528
00529 VectorMix(normal, sun_normal, light / sun_intensity, delta);
00530 VectorMA(direction, light * scale, delta, direction);
00531 }
00532
00533
00541 static void GatherSampleLight (vec3_t pos, const vec3_t normal, float *sample, float *direction, float scale, int *headhints)
00542 {
00543 light_t *l;
00544 vec3_t delta;
00545 float dot, dot2;
00546 float dist;
00547 int *headhint;
00548
00549 for (l = lights[config.compile_for_day], headhint = headhints; l; l = l->next, headhint++) {
00550 float light = 0.0;
00551
00552
00553
00554 VectorSubtract(l->origin, pos, delta);
00555 dist = VectorNormalize(delta);
00556
00557 dot = DotProduct(delta, normal);
00558 if (dot <= 0.001)
00559 continue;
00560
00561 switch (l->type) {
00562 case emit_point:
00563
00564 light = (l->intensity - dist) * dot;
00565 break;
00566
00567 case emit_surface:
00568
00569 light = (l->intensity / (dist * dist)) * dot;
00570 break;
00571
00572 case emit_spotlight:
00573
00574 dot2 = -DotProduct(delta, l->normal);
00575 if (dot2 > l->stopdot) {
00576
00577 light = (l->intensity - dist) * dot;
00578 } else {
00579
00580 light = (l->intensity * 0.5 - dist) * dot;
00581 }
00582 break;
00583 default:
00584 Sys_Error("Bad l->type");
00585 }
00586
00587 if (light <= 0.5)
00588 continue;
00589
00590 if (TR_TestLineSingleTile(pos, l->origin, headhint))
00591 continue;
00592
00593
00594 VectorMA(sample, light * scale, l->color, sample);
00595
00596
00597 VectorMix(normal, delta, 2.0 * light / l->intensity, delta);
00598 VectorMA(direction, light * scale, delta, direction);
00599 }
00600
00601
00602 GatherSampleSunlight(pos, normal, sample, direction, scale, headhint);
00603 }
00604
00605 #define SAMPLE_NUDGE 0.25
00606
00611 static inline void NudgeSamplePosition (const vec3_t in, const vec3_t normal, const vec3_t center, vec3_t out)
00612 {
00613 vec3_t dir;
00614
00615 VectorCopy(in, out);
00616
00617
00618 VectorSubtract(out, center, dir);
00619 VectorNormalize(dir);
00620
00621 VectorMA(out, SAMPLE_NUDGE, dir, out);
00622 VectorMA(out, SAMPLE_NUDGE, normal, out);
00623 }
00624
00625 #define MAX_VERT_FACES 256
00626
00633 static void FacesWithVert (int vert, int *faces, int *nfaces)
00634 {
00635 int i, j, k;
00636
00637 k = 0;
00638 for (i = 0; i < curTile->numfaces; i++) {
00639 const dBspSurface_t *face = &curTile->faces[i];
00640
00641 if (!(curTile->texinfo[face->texinfo].surfaceFlags & SURF_PHONG))
00642 continue;
00643
00644 for (j = 0; j < face->numedges; j++) {
00645 const int e = curTile->surfedges[face->firstedge + j];
00646 const int v = e >= 0 ? curTile->edges[e].v[0] : curTile->edges[-e].v[1];
00647
00648
00649 if (v == vert) {
00650 faces[k++] = i;
00651 if (k == MAX_VERT_FACES)
00652 Sys_Error("MAX_VERT_FACES");
00653 break;
00654 }
00655 }
00656 }
00657 *nfaces = k;
00658 }
00659
00665 void BuildVertexNormals (void)
00666 {
00667 int vert_faces[MAX_VERT_FACES];
00668 int num_vert_faces;
00669 vec3_t norm, delta;
00670 float scale;
00671 int i, j;
00672
00673 BuildFaceExtents();
00674
00675 for (i = 0; i < curTile->numvertexes; i++) {
00676 VectorClear(curTile->normals[i].normal);
00677
00678 FacesWithVert(i, vert_faces, &num_vert_faces);
00679 if (!num_vert_faces)
00680 continue;
00681
00682 for (j = 0; j < num_vert_faces; j++) {
00683 const dBspSurface_t *face = &curTile->faces[vert_faces[j]];
00684 const dBspPlane_t *plane = &curTile->planes[face->planenum];
00685
00686
00687 VectorSubtract(face_extents[vert_faces[j]].maxs, face_extents[vert_faces[j]].mins, delta);
00688 scale = VectorLength(delta);
00689
00690 if (face->side)
00691 VectorScale(plane->normal, -scale, norm);
00692 else
00693 VectorScale(plane->normal, scale, norm);
00694
00695 VectorAdd(curTile->normals[i].normal, norm, curTile->normals[i].normal);
00696 }
00697 VectorNormalize(curTile->normals[i].normal);
00698 }
00699 }
00700
00701
00706 static void SampleNormal (const lightinfo_t *l, const vec3_t pos, vec3_t normal)
00707 {
00708 vec3_t temp;
00709 float dist[MAX_VERT_FACES];
00710 float nearest;
00711 int i, v, nearv;
00712
00713 nearest = 9999.0;
00714 nearv = 0;
00715
00716
00717 for (i = 0; i < l->face->numedges; i++) {
00718 const int e = curTile->surfedges[l->face->firstedge + i];
00719 if (e >= 0)
00720 v = curTile->edges[e].v[0];
00721 else
00722 v = curTile->edges[-e].v[1];
00723
00724 VectorSubtract(pos, curTile->vertexes[v].point, temp);
00725 dist[i] = VectorLength(temp);
00726 if (dist[i] < nearest) {
00727 nearest = dist[i];
00728 nearv = v;
00729 }
00730 }
00731 VectorCopy(curTile->normals[nearv].normal, normal);
00732 }
00733
00734
00735 #define MAX_SAMPLES 5
00736 static const float sampleofs[MAX_SAMPLES][2] = {
00737 {0.0, 0.0}, {-0.125, -0.125}, {0.125, -0.125}, {0.125, 0.125}, {-0.125, 0.125}
00738 };
00739
00744 void BuildFacelights (unsigned int facenum)
00745 {
00746 dBspSurface_t *face;
00747 dBspPlane_t *plane;
00748 dBspTexinfo_t *tex;
00749 float *center;
00750 float *sdir, *tdir;
00751 vec3_t normal, binormal;
00752 vec4_t tangent;
00753 lightinfo_t l[MAX_SAMPLES];
00754 float scale;
00755 int i, j, numsamples;
00756 facelight_t *fl;
00757 int *headhints;
00758
00759 if (facenum >= MAX_MAP_FACES) {
00760 Com_Printf("MAX_MAP_FACES hit\n");
00761 return;
00762 }
00763
00764 face = &curTile->faces[facenum];
00765 plane = &curTile->planes[face->planenum];
00766 tex = &curTile->texinfo[face->texinfo];
00767
00768 if (tex->surfaceFlags & SURF_WARP)
00769 return;
00770
00771 sdir = tex->vecs[0];
00772 tdir = tex->vecs[1];
00773
00774
00775 if (config.extrasamples)
00776 numsamples = MAX_SAMPLES;
00777 else
00778 numsamples = 1;
00779
00780 memset(l, 0, sizeof(l));
00781
00782 scale = 1.0 / numsamples;
00783
00784 for (i = 0; i < numsamples; i++) {
00785 l[i].face = face;
00786 l[i].facedist = plane->dist;
00787 VectorCopy(plane->normal, l[i].facenormal);
00788
00789 if (face->side) {
00790 VectorNegate(l[i].facenormal, l[i].facenormal);
00791 l[i].facedist = -l[i].facedist;
00792 }
00793
00794
00795 VectorCopy(face_offset[facenum], l[i].modelorg);
00796
00797
00798 CalcLightinfoExtents(&l[i]);
00799
00800
00801 CalcLightinfoVectors(&l[i]);
00802
00803
00804 CalcPoints(&l[i], sampleofs[i][0], sampleofs[i][1]);
00805 }
00806
00807 fl = &facelight[config.compile_for_day][facenum];
00808 fl->numsamples = l[0].numsurfpt;
00809
00810 fl->origins = Mem_Alloc(fl->numsamples * sizeof(vec3_t));
00811 memcpy(fl->origins, l[0].surfpt, fl->numsamples * sizeof(vec3_t));
00812 fl->samples = Mem_Alloc(fl->numsamples * sizeof(vec3_t));
00813 fl->directions = Mem_Alloc(fl->numsamples * sizeof(vec3_t));
00814
00815 center = face_extents[facenum].center;
00816
00817
00818 headhints = Mem_Alloc((numlights[config.compile_for_day] + 1) * sizeof(int));
00819
00820
00821 for (i = 0; i < fl->numsamples; i++) {
00822 float *sample = fl->samples + i * 3;
00823 float *direction = fl->directions + i * 3;
00824
00825 for (j = 0; j < numsamples; j++) {
00826 vec3_t pos;
00827
00828 if (tex->surfaceFlags & SURF_PHONG)
00829
00830 SampleNormal(&l[0], l[j].surfpt[i], normal);
00831 else
00832
00833 VectorCopy(l[0].facenormal, normal);
00834
00835 NudgeSamplePosition(l[j].surfpt[i], normal, center, pos);
00836
00837 GatherSampleLight(pos, normal, sample, direction, scale, headhints);
00838 }
00839 if (!VectorCompare(direction, vec3_origin)) {
00840 vec3_t dir;
00841
00842
00843 VectorNormalize(direction);
00844
00845
00846 TangentVectors(normal, sdir, tdir, tangent, binormal);
00847
00848 dir[0] = DotProduct(direction, tangent);
00849 dir[1] = DotProduct(direction, binormal);
00850 dir[2] = DotProduct(direction, normal);
00851
00852 VectorCopy(dir, direction);
00853 }
00854 }
00855
00856
00857 Mem_Free(headhints);
00858
00859 for (i = 0; i < l[0].numsurfpt; i++) {
00860 float *direction = fl->directions + i * 3;
00861 if (VectorCompare(direction, vec3_origin))
00862 VectorSet(direction, 0.0, 0.0, 1.0);
00863 }
00864
00865
00866 for (i = 0; i < numsamples; i++)
00867 Mem_Free(l[i].surfpt);
00868 }
00869
00870 static void WriteTGA24 (const char *filename, const byte * data, int width, int height, int offset)
00871 {
00872 int i, c;
00873 byte *buffer;
00874 qFILE file;
00875
00876
00877 buffer = Mem_Alloc(width * height * 3 + 18);
00878 memset(buffer, 0, 18);
00879 buffer[2] = 2;
00880 buffer[12] = width & 255;
00881 buffer[13] = width >> 8;
00882 buffer[14] = height & 255;
00883 buffer[15] = height >> 8;
00884 buffer[16] = 24;
00885
00886
00887 c = (width * height * 3) + 18;
00888 for (i = 18; i < c; i += 6) {
00889 buffer[i] = data[i - 18 + offset + 2];
00890 buffer[i + 1] = data[i - 18 + offset + 1];
00891 buffer[i + 2] = data[i - 18 + offset + 0];
00892 }
00893
00894
00895 if (FS_OpenFile(filename, &file, FILE_WRITE) > 0)
00896 Sys_Error("Unable to open %s for writing", filename);
00897
00898 FS_Write(buffer, c, &file);
00899
00900
00901 FS_CloseFile(&file);
00902 Mem_Free(buffer);
00903 }
00904
00912 static void CalcTextureSize (const dBspSurface_t *s, vec2_t texsize, int scale)
00913 {
00914 const float *stmins = face_extents[s - curTile->faces].stmins;
00915 const float *stmaxs = face_extents[s - curTile->faces].stmaxs;
00916 int i;
00917
00918 for (i = 0; i < 2; i++) {
00919 const float mins = floor(stmins[i] / scale);
00920 const float maxs = ceil(stmaxs[i] / scale);
00921
00922 texsize[i] = maxs - mins;
00923 }
00924 }
00925
00932 static void ExportLightmap (const char *path, const char *name, qboolean day)
00933 {
00934 int i;
00935 const int lightmapIndex = day ? 1 : 0;
00936 const byte *bspLightBytes = curTile->lightdata[lightmapIndex];
00937 const byte quant = *bspLightBytes;
00938 const int scale = 1 << quant;
00939
00940 for (i = 0; i < curTile->numfaces; i++) {
00941 const dBspSurface_t *face = &curTile->faces[i];
00942 const byte *lightmap = bspLightBytes + face->lightofs[lightmapIndex];
00943 vec2_t texSize;
00944
00945 CalcTextureSize(face, texSize, scale);
00946
00947
00948 if (texSize[0] && texSize[1]) {
00949 char filename[MAX_QPATH];
00950 Com_sprintf(filename, sizeof(filename), "%s/%s_lightmap_%04d%c.tga", path, name, i, day ? 'd' : 'n');
00951 Com_Printf("Writing %s (%.0fx%.0f)\n", filename, texSize[0], texSize[1]);
00952 WriteTGA24(filename, lightmap, texSize[0], texSize[1], 0);
00953 Com_sprintf(filename, sizeof(filename), "%s/%s_direction_%04d%c.tga", path, name, i, day ? 'd' : 'n');
00954 Com_Printf("Writing %s (%.0fx%.0f)\n", filename, texSize[0], texSize[1]);
00955 WriteTGA24(filename, lightmap, texSize[0], texSize[1], 3);
00956 }
00957 }
00958 }
00959
00965 void ExportLightmaps (const char *bspFileName)
00966 {
00967 char path[MAX_QPATH], lightmapName[MAX_QPATH];
00968 const char *fileName = Com_SkipPath(bspFileName);
00969
00970 Com_FilePath(bspFileName, path);
00971 Com_StripExtension(fileName, lightmapName, sizeof(lightmapName));
00972
00973
00974 Com_Printf("--- ExportLightmaps ---\n");
00975
00976 BuildFaceExtents();
00977
00978 ExportLightmap(path, lightmapName, qtrue);
00979 ExportLightmap(path, lightmapName, qfalse);
00980 }
00981
00982 static const vec3_t luminosity = {0.2125, 0.7154, 0.0721};
00983
00989 void FinalLightFace (unsigned int facenum)
00990 {
00991 dBspSurface_t *f;
00992 int j, k;
00993 vec3_t dir, intensity;
00994 facelight_t *fl;
00995 float max, d;
00996 byte *dest;
00997
00998 f = &curTile->faces[facenum];
00999 fl = &facelight[config.compile_for_day][facenum];
01000
01001
01002 if (curTile->texinfo[f->texinfo].surfaceFlags & SURF_WARP)
01003 return;
01004
01005 ThreadLock();
01006
01007 f->lightofs[config.compile_for_day] = curTile->lightdatasize[config.compile_for_day];
01008 curTile->lightdatasize[config.compile_for_day] += fl->numsamples * 3;
01009
01010 curTile->lightdatasize[config.compile_for_day] += fl->numsamples * 3;
01011
01012 if (curTile->lightdatasize[config.compile_for_day] > MAX_MAP_LIGHTING)
01013 Sys_Error("MAX_MAP_LIGHTING (%i exceeded %i) - try to reduce the brush size (%s)",
01014 curTile->lightdatasize[config.compile_for_day], MAX_MAP_LIGHTING,
01015 curTile->texinfo[f->texinfo].texture);
01016
01017 ThreadUnlock();
01018
01019
01020 dest = &curTile->lightdata[config.compile_for_day][f->lightofs[config.compile_for_day]];
01021
01022 for (j = 0; j < fl->numsamples; j++) {
01023 vec3_t temp;
01024
01025
01026 VectorCopy((fl->samples + j * 3), temp);
01027
01028
01029 VectorScale(temp, 1.0 / 255.0, temp);
01030
01031
01032 VectorAdd(temp, sun_ambient_color, temp);
01033
01034
01035 VectorScale(temp, config.brightness, temp);
01036
01037 max = 0.0;
01038
01039
01040 for (k = 0; k < 3; k++) {
01041
01042 if (temp[k] < 0.0)
01043 temp[k] = 0.0;
01044
01045 if (temp[k] > max)
01046 max = temp[k];
01047 }
01048
01049 if (max > 255.0)
01050 VectorScale(temp, 255.0 / max, temp);
01051
01052 for (k = 0; k < 3; k++) {
01053 temp[k] -= 0.5;
01054
01055 temp[k] *= config.contrast;
01056
01057 temp[k] += 0.5;
01058
01059 if (temp[k] > 1.0)
01060 temp[k] = 1.0;
01061 else if (temp[k] < 0)
01062 temp[k] = 0;
01063 }
01064
01065
01066 d = DotProduct(temp, luminosity);
01067
01068 VectorSet(intensity, d, d, d);
01069 VectorMix(intensity, temp, config.saturation, temp);
01070
01071 for (k = 0; k < 3; k++) {
01072 temp[k] *= 255.0;
01073
01074 if (temp[k] > 255.0)
01075 temp[k] = 255.0;
01076 else if (temp[k] < 0.0)
01077 temp[k] = 0.0;
01078
01079 *dest++ = (byte)temp[k];
01080 }
01081
01082
01083 VectorCopy((fl->directions + j * 3), dir);
01084 for (k = 0; k < 3; k++)
01085 *dest++ = (byte)((dir[k] + 1.0f) * 127.0f);
01086 }
01087 }