1 NOTE: this patch set is autogenerated from the "singlepatches" subdirectory of nexuiz/trunk/misc.
3 Do not commit changes to THIS!
6 sh mergepatches.sh > gtkradiant-nexuiz-patchset.diff
7 before committing new singlepatches!
11 Index: libs/picomodel/pm_obj.c
12 ===================================================================
13 --- libs/picomodel/pm_obj.c (revision 290)
14 +++ libs/picomodel/pm_obj.c (working copy)
20 static int _obj_mtl_load( picoModel_t *model )
22 - //picoShader_t *curShader = NULL;
23 + picoShader_t *curShader = NULL;
25 picoByte_t *mtlBuffer;
28 /* get next token in material file */
29 if (_pico_parse( p,1 ) == NULL)
34 /* skip empty lines */
35 if (p->token == NULL || !strlen( p->token ))
37 else if (!_pico_stricmp(p->token,"map_kd"))
40 + picoShader_t *shader;
42 /* pointer to current shader must be valid */
43 if (curShader == NULL)
45 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
46 _obj_mtl_error_return;
48 + /* create a new pico shader */
49 + shader = PicoNewShader( model );
51 + _obj_mtl_error_return;
52 /* set shader map name */
53 PicoSetShaderMapName( shader,mapName );
56 /* return with success */
62 * loads a wavefront obj model file.
64 PicoSetModelFileName( model,fileName );
66 /* try loading the materials; we don't handle the result */
69 _obj_mtl_load( model );
76 + else if (!_pico_stricmp(p->token,"usemtl"))
78 + picoShader_t *shader;
81 + /* get material name */
82 + name = _pico_parse( p,0 );
84 + /* validate material name */
85 + if (name == NULL || !strlen(name))
87 + _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
91 + shader = PicoFindShader( model, name, 1 );
94 + _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
96 + /* create a new pico shader */
97 + shader = PicoNewShader( model );
100 + PicoSetShaderName( shader,name );
101 + PicoSetShaderMapName( shader,name );
102 + PicoSetSurfaceShader( curSurface, shader );
107 + PicoSetSurfaceShader( curSurface, shader );
111 /* skip unparsed rest of line and continue */
112 _pico_parse_skip_rest( p );
114 Index: tools/quake3/q3map2/convert_map.c
115 ===================================================================
116 --- tools/quake3/q3map2/convert_map.c (revision 191)
117 +++ tools/quake3/q3map2/convert_map.c (working copy)
119 #define SNAP_FLOAT_TO_INT 4
120 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
122 +typedef vec_t vec2_t[2];
124 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
125 + vec_t a10, vec_t a11, vec_t a12,
126 + vec_t a20, vec_t a21, vec_t a22)
129 + a00 * (a11 * a22 - a12 * a21)
130 + - a01 * (a10 * a22 - a12 * a20)
131 + + a02 * (a10 * a21 - a11 * a20);
134 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
136 + bspDrawSurface_t *s;
142 + vec3_t v1v0, v2v0, norm;
143 + bspDrawVert_t *vert[3];
144 + winding_t *polygon;
145 + plane_t *buildPlane = &mapplanes[buildSide->planenum];
148 + // first, start out with NULLs
149 + bestVert[0] = bestVert[1] = bestVert[2] = NULL;
151 + // brute force through all surfaces
152 + for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
154 + if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
156 + if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
158 + for(t = 0; t + 3 <= s->numIndexes; t += 3)
160 + vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
161 + vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
162 + vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
163 + if(s->surfaceType == MST_PLANAR)
165 + VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
166 + VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
167 + VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
171 + // this is more prone to roundoff errors, but with embedded
172 + // models, there is no better way
173 + VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
174 + VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
175 + CrossProduct(v2v0, v1v0, norm);
176 + VectorNormalize(norm, norm);
177 + VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
179 + if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
180 + if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
181 + if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
182 + // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
183 + polygon = CopyWinding(buildSide->winding);
184 + for(i = 0; i < 3; ++i)
189 + vec3_t *v1 = &vert[(i+1)%3]->xyz;
190 + vec3_t *v2 = &vert[(i+2)%3]->xyz;
193 + vec3_t sideDirection;
194 + // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
195 + VectorSubtract(*v2, *v1, sideDirection);
196 + CrossProduct(sideDirection, buildPlane->normal, triNormal);
197 + triDist = DotProduct(*v1, triNormal);
198 + ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
202 + thisarea = WindingArea(polygon);
205 + if(thisarea > best)
208 + bestVert[0] = vert[0];
209 + bestVert[1] = vert[1];
210 + bestVert[2] = vert[2];
212 + FreeWinding(polygon);
217 + //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
218 + // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
221 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
228 + plane_t *buildPlane;
230 + bspDrawVert_t *vert[3];
235 fprintf( f, "\t// brush %d\n", num );
236 fprintf( f, "\t{\n" );
237 + fprintf( f, "\tbrushDef\n" );
238 + fprintf( f, "\t{\n" );
240 /* clear out build brush */
241 for( i = 0; i < buildBrush->numsides; i++ )
244 buildSide = &buildBrush->sides[ i ];
247 + buildPlane = &mapplanes[ buildSide->planenum ];
250 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
253 + // st-texcoords -> texMat block
254 + // start out with dummy
255 + VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
256 + VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
258 + // find surface for this side (by brute force)
260 + // - meshverts point in pairs of three into verts
262 + // - find the triangle that has most in common with our side
263 + GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
266 + if(vert[0] && vert[1] && vert[2])
270 + vec3_t xy1I, xy1J, xy1K;
271 + vec2_t stI, stJ, stK;
272 + vec_t D, D0, D1, D2;
274 + ComputeAxisBase(buildPlane->normal, texX, texY);
276 + VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
277 + VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
278 + VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
279 + stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
280 + stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
281 + stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
283 + // - solve linear equations:
284 + // - (x, y) := xyz . (texX, texY)
285 + // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
286 + // (for three vertices)
288 + xy1I[0], xy1I[1], 1,
289 + xy1J[0], xy1J[1], 1,
290 + xy1K[0], xy1K[1], 1
294 + for(i = 0; i < 2; ++i)
297 + stI[i], xy1I[1], 1,
298 + stJ[i], xy1J[1], 1,
302 + xy1I[0], stI[i], 1,
303 + xy1J[0], stJ[i], 1,
307 + xy1I[0], xy1I[1], stI[i],
308 + xy1J[0], xy1J[1], stJ[i],
309 + xy1K[0], xy1K[1], stK[i]
311 + VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
316 + fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
317 + buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
318 + vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
319 + texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
320 + vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
321 + vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
322 + vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
326 + if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
327 + fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
329 /* get texture name */
330 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
331 @@ -130,14 +313,21 @@
333 /* print brush side */
334 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
335 - fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
336 + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
337 pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
338 pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
339 pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
341 + buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
342 + buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
344 + // DEBUG: valid ? 0 : C_DETAIL
347 + // TODO write brush primitives format here
351 + fprintf( f, "\t}\n" );
352 fprintf( f, "\t}\n\n" );
355 Index: tools/quake3/q3map2/main.c
356 ===================================================================
357 --- tools/quake3/q3map2/main.c (revision 191)
358 +++ tools/quake3/q3map2/main.c (working copy)
360 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
363 + else if( !strcmp( argv[ i ], "-ne" ) )
365 + normalEpsilon = atof( argv[ i + 1 ] );
367 + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
369 + else if( !strcmp( argv[ i ], "-de" ) )
371 + distanceEpsilon = atof( argv[ i + 1 ] );
373 + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
377 /* clean up map name */
378 Index: tools/quake3/q3map2/model.c
379 ===================================================================
380 --- tools/quake3/q3map2/model.c (revision 193)
381 +++ tools/quake3/q3map2/model.c (working copy)
384 picoIndex_t *indexes;
386 + double normalEpsilon_save;
387 + double distanceEpsilon_save;
392 /* ydnar: giant hack land: generate clipping brushes for model triangles */
393 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
395 - vec3_t points[ 3 ], backs[ 3 ];
396 + vec3_t points[ 4 ], backs[ 3 ];
397 vec4_t plane, reverse, pa, pb, pc;
402 @@ -437,90 +438,141 @@
403 /* note: this doesn't work as well as simply using the plane of the triangle, below */
404 for( k = 0; k < 3; k++ )
406 - if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
407 - fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
408 + if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
409 + fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
411 backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
417 + VectorCopy( points[0], points[3] ); // for cyclic usage
419 /* make plane for triangle */
420 + // div0: add some extra spawnflags:
421 + // 0: snap normals to axial planes for extrusion
422 + // 8: extrude with the original normals
423 + // 16: extrude only with up/down normals (ideal for terrain)
424 + // 24: extrude by distance zero (may need engine changes)
425 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
428 + float backPlaneDistance = 2;
430 + if(spawnFlags & 8) // use a DOWN normal
432 + if(spawnFlags & 16)
434 + // 24: normal as is, and zero width (broken)
435 + VectorCopy(plane, bestNormal);
440 + VectorCopy(plane, bestNormal);
445 + if(spawnFlags & 16)
447 + // 16: UP/DOWN normal
448 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
453 + if(fabs(plane[0]) > fabs(plane[1])) // x>y
454 + if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
455 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
457 + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
458 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
460 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
462 + if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
463 + VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
465 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
469 + /* build a brush */
470 + buildBrush = AllocBrush( 48 );
471 + buildBrush->entityNum = mapEntityNum;
472 + buildBrush->original = buildBrush;
473 + buildBrush->contentShader = si;
474 + buildBrush->compileFlags = si->compileFlags;
475 + buildBrush->contentFlags = si->contentFlags;
476 + normalEpsilon_save = normalEpsilon;
477 + distanceEpsilon_save = distanceEpsilon;
478 + if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
480 + buildBrush->detail = qfalse;
482 + // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
483 + if(normalEpsilon > 0)
485 + if(distanceEpsilon > 0)
486 + distanceEpsilon = 0;
489 + buildBrush->detail = qtrue;
491 /* regenerate back points */
492 for( j = 0; j < 3; j++ )
495 dv = &ds->verts[ ds->indexes[ i + j ] ];
498 - VectorCopy( dv->xyz, backs[ j ] );
500 - /* find nearest axial to plane normal and push back points opposite */
501 - for( k = 0; k < 3; k++ )
503 - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
504 - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
506 - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
511 + // shift by some units
512 + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
516 /* make back plane */
517 VectorScale( plane, -1.0f, reverse );
518 - reverse[ 3 ] = -(plane[ 3 ] - 1);
520 - /* make back pyramid point */
521 - VectorCopy( points[ 0 ], nadir );
522 - VectorAdd( nadir, points[ 1 ], nadir );
523 - VectorAdd( nadir, points[ 2 ], nadir );
524 - VectorScale( nadir, 0.3333333333333f, nadir );
525 - VectorMA( nadir, -2.0f, plane, nadir );
527 - /* make 3 more planes */
528 - //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
529 - //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
530 - //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
531 + reverse[ 3 ] = -plane[ 3 ];
532 + if((spawnFlags & 24) != 24)
533 + reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
534 + // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
536 if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
537 - PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
538 - PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
539 + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
540 + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
542 - /* build a brush */
543 - buildBrush = AllocBrush( 48 );
545 - buildBrush->entityNum = mapEntityNum;
546 - buildBrush->original = buildBrush;
547 - buildBrush->contentShader = si;
548 - buildBrush->compileFlags = si->compileFlags;
549 - buildBrush->contentFlags = si->contentFlags;
550 - buildBrush->detail = qtrue;
552 /* set up brush sides */
553 buildBrush->numsides = 5;
554 for( j = 0; j < buildBrush->numsides; j++ )
555 buildBrush->sides[ j ].shaderInfo = si;
557 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
558 - buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
559 - buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
560 - buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
561 - buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
563 - /* add to entity */
564 - if( CreateBrushWindings( buildBrush ) )
567 - //% EmitBrushes( buildBrush, NULL, NULL );
568 - buildBrush->next = entities[ mapEntityNum ].brushes;
569 - entities[ mapEntityNum ].brushes = buildBrush;
570 - entities[ mapEntityNum ].numBrushes++;
573 - free( buildBrush );
574 + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
575 + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
576 + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
577 + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
585 + normalEpsilon = normalEpsilon_save;
586 + distanceEpsilon = distanceEpsilon_save;
588 + /* add to entity */
589 + if( CreateBrushWindings( buildBrush ) )
592 + //% EmitBrushes( buildBrush, NULL, NULL );
593 + buildBrush->next = entities[ mapEntityNum ].brushes;
594 + entities[ mapEntityNum ].brushes = buildBrush;
595 + entities[ mapEntityNum ].numBrushes++;
598 + free( buildBrush );
602 Index: tools/quake3/q3map2/map.c
603 ===================================================================
604 --- tools/quake3/q3map2/map.c (revision 193)
605 +++ tools/quake3/q3map2/map.c (working copy)
607 snaps a plane to normal/distance epsilons
610 -void SnapPlane( vec3_t normal, vec_t *dist )
611 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
613 // SnapPlane disabled by LordHavoc because it often messes up collision
614 // brushes made from triangles of embedded models, and it has little effect
616 SnapPlane reenabled by namespace because of multiple reports of
617 q3map2-crashes which were triggered by this patch.
619 + // div0: ensure the point "center" stays on the plane (actually, this
620 + // rotates the plane around the point center).
621 + // if center lies on the plane, it is guaranteed to stay on the plane by
623 + vec_t centerDist = DotProduct(normal, center);
624 SnapNormal( normal );
625 + *dist += (DotProduct(normal, center) - centerDist);
627 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
628 *dist = Q_rint( *dist );
630 must be within an epsilon distance of the plane
633 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
634 +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
638 @@ -215,10 +221,14 @@
642 + vec3_t centerofweight;
644 + VectorClear(centerofweight);
645 + for(i = 0; i < numPoints; ++i)
646 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
650 - SnapPlane( normal, &dist );
651 + SnapPlane( normal, &dist, centerofweight );
652 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
654 /* search the border bins as well */
659 - SnapPlane( normal, &dist );
660 + vec3_t centerofweight;
662 + VectorClear(centerofweight);
663 + for(i = 0; i < numPoints; ++i)
664 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
666 + SnapPlane( normal, &dist, centerofweight );
667 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
669 if( PlaneEqual( p, normal, dist ) )
670 Index: tools/quake3/q3map2/shaders.c
671 ===================================================================
672 --- tools/quake3/q3map2/shaders.c (revision 191)
673 +++ tools/quake3/q3map2/shaders.c (working copy)
677 if( VectorLength( si->color ) <= 0.0f )
679 ColorNormalize( color, si->color );
680 - VectorScale( color, (1.0f / count), si->averageColor );
681 + VectorScale( color, (1.0f / count), si->averageColor );
685 + VectorCopy( si->color, si->averageColor );
690 Index: tools/quake3/q3map2/light_ydnar.c
691 ===================================================================
692 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
693 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
694 @@ -1767,6 +1864,8 @@
695 float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
697 float stackLightLuxels[ STACK_LL_SIZE ];
702 /* bail if this number exceeds the number of raw lightmaps */
703 @@ -2223,6 +2332,78 @@
704 FreeTraceLights( &trace );
706 /* -----------------------------------------------------------------
708 + ----------------------------------------------------------------- */
712 + /* walk lightmaps */
713 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
716 + if( lm->superLuxels[ lightmapNum ] == NULL )
719 + /* apply floodlight to each luxel */
720 + for( y = 0; y < lm->sh; y++ )
722 + for( x = 0; x < lm->sw; x++ )
725 + cluster = SUPER_CLUSTER( x, y );
726 + //% if( *cluster < 0 )
729 + /* get particulars */
730 + luxel = SUPER_LUXEL( lightmapNum, x, y );
731 + floodlight = SUPER_FLOODLIGHT( x, y );
733 + flood[0]=floodlightRGB[0]*floodlightIntensity;
734 + flood[1]=floodlightRGB[1]*floodlightIntensity;
735 + flood[2]=floodlightRGB[2]*floodlightIntensity;
737 + /* scale light value */
738 + VectorScale( flood, *floodlight, flood );
739 + luxel[0]+=flood[0];
740 + luxel[1]+=flood[1];
741 + luxel[2]+=flood[2];
743 + if (luxel[3]==0) luxel[3]=1;
751 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
754 + if( lm->superLuxels[ lightmapNum ] == NULL )
757 + for( y = 0; y < lm->sh; y++ )
759 + for( x = 0; x < lm->sw; x++ )
762 + cluster = SUPER_CLUSTER( x, y );
763 + //% if( *cluster < 0 )
766 + /* get particulars */
767 + luxel = SUPER_LUXEL( lightmapNum, x, y );
768 + normal = SUPER_NORMAL ( x, y );
770 + luxel[0]=(normal[0]*127)+127;
771 + luxel[1]=(normal[1]*127)+127;
772 + luxel[2]=(normal[2]*127)+127;
778 + /* -----------------------------------------------------------------
780 ----------------------------------------------------------------- */
782 @@ -3587,7 +3768,320 @@
783 CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
786 +/////////////////////////////////////////////////////////////
788 +#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */
789 +#define FLOODLIGHT_NUM_ANGLE_STEPS 16
790 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
791 +#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
793 +static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
794 +static int numFloodVectors = 0;
796 +void SetupFloodLight( void )
799 + float angle, elevation, angleStep, elevationStep;
801 + double v1,v2,v3,v4,v5;
804 + Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
806 + /* calculate angular steps */
807 + angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
808 + elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
810 + /* iterate angle */
812 + for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
814 + /* iterate elevation */
815 + for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
817 + floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
818 + floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
819 + floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
824 + /* emit some statistics */
825 + Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
828 + value = ValueForKey( &entities[ 0 ], "_floodlight" );
830 + if( value[ 0 ] != '\0' )
833 + v4=floodlightDistance;
834 + v5=floodlightIntensity;
836 + sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
838 + floodlightRGB[0]=v1;
839 + floodlightRGB[1]=v2;
840 + floodlightRGB[2]=v3;
842 + if (VectorLength(floodlightRGB)==0)
844 + VectorSet(floodlightRGB,240,240,255);
850 + floodlightDistance=v4;
851 + floodlightIntensity=v5;
853 + floodlighty = qtrue;
854 + Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
858 + VectorSet(floodlightRGB,240,240,255);
859 + //floodlighty = qtrue;
860 + //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
862 + VectorNormalize(floodlightRGB,floodlightRGB);
865 +//27 - lighttracer style ambient occlusion light hack.
866 +//Kudos to the dirtmapping author for most of this source.
867 +void FloodLightRawLightmap( int rawLightmapNum )
869 + int i, x, y, sx, sy, *cluster;
870 + float *origin, *normal, *floodlight, *floodlight2, average, samples;
872 + surfaceInfo_t *info;
875 + /* bail if this number exceeds the number of raw lightmaps */
876 + if( rawLightmapNum >= numRawLightmaps )
880 + lm = &rawLightmaps[ rawLightmapNum ];
882 + memset(&trace,0,sizeof(trace_t));
884 + trace.testOcclusion = qtrue;
885 + trace.forceSunlight = qfalse;
886 + trace.twoSided = qtrue;
887 + trace.recvShadows = lm->recvShadows;
888 + trace.numSurfaces = lm->numLightSurfaces;
889 + trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
890 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
891 + trace.testAll = qfalse;
892 + trace.distance = 1024;
894 + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
895 + //trace.twoSided = qfalse;
896 + for( i = 0; i < trace.numSurfaces; i++ )
899 + info = &surfaceInfos[ trace.surfaces[ i ] ];
901 + /* check twosidedness */
902 + if( info->si->twoSided )
904 + trace.twoSided = qtrue;
910 + for( y = 0; y < lm->sh; y++ )
912 + for( x = 0; x < lm->sw; x++ )
915 + cluster = SUPER_CLUSTER( x, y );
916 + origin = SUPER_ORIGIN( x, y );
917 + normal = SUPER_NORMAL( x, y );
918 + floodlight = SUPER_FLOODLIGHT( x, y );
920 + /* set default dirt */
921 + *floodlight = 0.0f;
923 + /* only look at mapped luxels */
927 + /* copy to trace */
928 + trace.cluster = *cluster;
929 + VectorCopy( origin, trace.origin );
930 + VectorCopy( normal, trace.normal );
935 + *floodlight = FloodLightForSample( &trace );
939 + /* testing no filtering */
942 + /* filter "dirt" */
943 + for( y = 0; y < lm->sh; y++ )
945 + for( x = 0; x < lm->sw; x++ )
948 + cluster = SUPER_CLUSTER( x, y );
949 + floodlight = SUPER_FLOODLIGHT( x, y );
951 + /* filter dirt by adjacency to unmapped luxels */
952 + average = *floodlight;
954 + for( sy = (y - 1); sy <= (y + 1); sy++ )
956 + if( sy < 0 || sy >= lm->sh )
959 + for( sx = (x - 1); sx <= (x + 1); sx++ )
961 + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
964 + /* get neighboring luxel */
965 + cluster = SUPER_CLUSTER( sx, sy );
966 + floodlight2 = SUPER_FLOODLIGHT( sx, sy );
967 + if( *cluster < 0 || *floodlight2 <= 0.0f )
971 + average += *floodlight2;
976 + if( samples <= 0.0f )
981 + if( samples <= 0.0f )
985 + *floodlight = average / samples;
991 +FloodLightForSample()
992 +calculates floodlight value for a given sample
993 +once again, kudos to the dirtmapping coder
995 +float FloodLightForSample( trace_t *trace )
999 + float contribution;
1001 + float gatherLight, outLight;
1002 + vec3_t normal, worldUp, myUp, myRt, direction, displacement;
1010 + if( trace == NULL || trace->cluster < 0 )
1015 + dd = floodlightDistance;
1016 + VectorCopy( trace->normal, normal );
1018 + /* check if the normal is aligned to the world-up */
1019 + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1021 + if( normal[ 2 ] == 1.0f )
1023 + VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1024 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1026 + else if( normal[ 2 ] == -1.0f )
1028 + VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1029 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1034 + VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1035 + CrossProduct( normal, worldUp, myRt );
1036 + VectorNormalize( myRt, myRt );
1037 + CrossProduct( myRt, normal, myUp );
1038 + VectorNormalize( myUp, myUp );
1041 + /* iterate through ordered vectors */
1042 + for( i = 0; i < numFloodVectors; i++ )
1044 + if (floodlight_lowquality==qtrue)
1046 + if (rand()%10 != 0 ) continue;
1051 + /* transform vector into tangent space */
1052 + direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1053 + direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1054 + direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1056 + /* set endpoint */
1057 + VectorMA( trace->origin, dd, direction, trace->end );
1059 + //VectorMA( trace->origin, 1, direction, trace->origin );
1061 + SetupTrace( trace );
1063 + TraceLine( trace );
1066 + if (trace->compileFlags & C_SKY )
1068 + contribution=1.0f;
1070 + else if ( trace->opaque )
1072 + VectorSubtract( trace->hit, trace->origin, displacement );
1073 + d=VectorLength( displacement );
1075 + // d=trace->distance;
1076 + //if (d>256) gatherDirt+=1;
1077 + contribution=d/dd;
1078 + if (contribution>1) contribution=1.0f;
1080 + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1083 + gatherLight+=contribution;
1087 + if( gatherLight <= 0.0f )
1093 + gatherLight/=(sub);
1095 + outLight=gatherLight;
1096 + if( outLight > 1.0f )
1099 + /* return to sender */
1103 Index: tools/quake3/q3map2/light.c
1104 ===================================================================
1105 --- tools/quake3/q3map2/light.c (revision 191)
1106 +++ tools/quake3/q3map2/light.c (working copy)
1107 @@ -1378,6 +1378,56 @@
1111 + /////// Floodlighting for point //////////////////
1112 + //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1118 + col[0]=col[1]=col[2]=floodlightIntensity;
1122 + trace.testOcclusion = qtrue;
1123 + trace.forceSunlight = qfalse;
1124 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1125 + trace.testAll = qtrue;
1129 + if (q==0) //upper hemisphere
1131 + trace.normal[0]=0;
1132 + trace.normal[1]=0;
1133 + trace.normal[2]=1;
1135 + else //lower hemisphere
1137 + trace.normal[0]=0;
1138 + trace.normal[1]=0;
1139 + trace.normal[2]=-1;
1142 + f = FloodLightForSample(&trace);
1144 + contributions[ numCon ].color[0]=col[0]*f;
1145 + contributions[ numCon ].color[1]=col[1]*f;
1146 + contributions[ numCon ].color[2]=col[2]*f;
1148 + contributions[ numCon ].dir[0]=dir[0];
1149 + contributions[ numCon ].dir[1]=dir[1];
1150 + contributions[ numCon ].dir[2]=dir[2];
1152 + contributions[ numCon ].style = 0;
1154 + /* push average direction around */
1155 + addSize = VectorLength( col );
1156 + VectorMA( gp->dir, addSize, dir, gp->dir );
1159 + /////////////////////
1161 /* normalize to get primary light direction */
1162 VectorNormalize( gp->dir, gp->dir );
1164 @@ -1661,6 +1711,12 @@
1165 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1168 + /* floodlight them up */
1171 + Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1172 + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1175 /* ydnar: set up light envelopes */
1176 SetupEnvelopes( qfalse, fast );
1177 @@ -1703,6 +1759,7 @@
1180 VectorClear( ambientColor );
1181 + floodlighty = false;
1183 /* generate diffuse lights */
1185 @@ -2191,6 +2256,21 @@
1187 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
1189 + else if( !strcmp( argv[ i ], "-floodlight" ) )
1191 + floodlighty = qtrue;
1192 + Sys_Printf( "FloodLighting enabled\n" );
1194 + else if( !strcmp( argv[ i ], "-debugnormals" ) )
1196 + debugnormals = qtrue;
1197 + Sys_Printf( "DebugNormals enabled\n" );
1199 + else if( !strcmp( argv[ i ], "-lowquality" ) )
1201 + floodlight_lowquality = qtrue;
1202 + Sys_Printf( "Low Quality FloodLighting enabled\n" );
1205 /* r7: dirtmapping */
1206 else if( !strcmp( argv[ i ], "-dirty" ) )
1207 @@ -2279,6 +2359,7 @@
1208 /* ydnar: set up optimization */
1211 + SetupFloodLight();
1212 SetupSurfaceLightmaps();
1214 /* initialize the surface facet tracing */
1215 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1216 ===================================================================
1217 --- tools/quake3/q3map2/lightmaps_ydnar.c (revision 191)
1218 +++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy)
1219 @@ -414,6 +414,12 @@
1220 lm->superNormals = safe_malloc( size );
1221 memset( lm->superNormals, 0, size );
1223 + /* allocate floodlight map storage */
1224 + size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1225 + if( lm->superFloodLight == NULL )
1226 + lm->superFloodLight = safe_malloc( size );
1227 + memset( lm->superFloodLight, 0, size );
1229 /* allocate cluster map storage */
1230 size = lm->sw * lm->sh * sizeof( int );
1231 if( lm->superClusters == NULL )
1232 Index: tools/quake3/q3map2/q3map2.h
1233 ===================================================================
1234 --- tools/quake3/q3map2/q3map2.h (revision 191)
1235 +++ tools/quake3/q3map2/q3map2.h (working copy)
1237 #define SUPER_NORMAL_SIZE 4
1238 #define SUPER_DELUXEL_SIZE 3
1239 #define BSP_DELUXEL_SIZE 3
1240 +#define SUPER_FLOODLIGHT_SIZE 1
1242 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1243 #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1245 #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1246 #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1247 #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */
1248 +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )
1252 @@ -1392,6 +1395,7 @@
1254 float *superDeluxels; /* average light direction */
1256 + float *superFloodLight;
1260 @@ -1704,6 +1708,10 @@
1261 float DirtForSample( trace_t *trace );
1262 void DirtyRawLightmap( int num );
1264 +void SetupFloodLight();
1265 +float FloodLightForSample( trace_t *trace );
1266 +void FloodLightRawLightmap( int num );
1268 void IlluminateRawLightmap( int num );
1269 void IlluminateVertexes( int num );
1271 @@ -2098,6 +2106,13 @@
1272 Q_EXTERN float dirtScale Q_ASSIGN( 1.0f );
1273 Q_EXTERN float dirtGain Q_ASSIGN( 1.0f );
1275 +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse );
1276 +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse );
1277 +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse );
1278 +Q_EXTERN vec3_t floodlightRGB;
1279 +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 );
1280 +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 );
1282 Q_EXTERN qboolean dump Q_ASSIGN( qfalse );
1283 Q_EXTERN qboolean debug Q_ASSIGN( qfalse );
1284 Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse );
1285 Index: tools/quake3/q3map2/game_ja.h
1286 ===================================================================
1287 --- tools/quake3/q3map2/game_ja.h (revision 191)
1288 +++ tools/quake3/q3map2/game_ja.h (working copy)
1290 qfalse, /* wolf lighting model? */
1291 128, /* lightmap width/height */
1292 1.0f, /* lightmap gamma */
1293 + 1.0f, /* lightmap exposure */
1294 1.0f, /* lightmap compensate */
1295 "RBSP", /* bsp file prefix */
1296 1, /* bsp file version */
1297 Index: tools/quake3/q3map2/game_tremulous.h
1298 ===================================================================
1299 --- tools/quake3/q3map2/game_tremulous.h (revision 191)
1300 +++ tools/quake3/q3map2/game_tremulous.h (working copy)
1302 qfalse, /* wolf lighting model? */
1303 128, /* lightmap width/height */
1304 1.0f, /* lightmap gamma */
1305 + 1.0f, /* lightmap exposure */
1306 1.0f, /* lightmap compensate */
1307 "IBSP", /* bsp file prefix */
1308 46, /* bsp file version */
1309 Index: tools/quake3/q3map2/game_wolfet.h
1310 ===================================================================
1311 --- tools/quake3/q3map2/game_wolfet.h (revision 191)
1312 +++ tools/quake3/q3map2/game_wolfet.h (working copy)
1314 qtrue, /* wolf lighting model? */
1315 128, /* lightmap width/height */
1316 1.0f, /* lightmap gamma */
1317 + 1.0f, /* lightmap exposure */
1318 1.0f, /* lightmap compensate */
1319 "IBSP", /* bsp file prefix */
1320 47, /* bsp file version */
1321 Index: tools/quake3/q3map2/game_wolf.h
1322 ===================================================================
1323 --- tools/quake3/q3map2/game_wolf.h (revision 191)
1324 +++ tools/quake3/q3map2/game_wolf.h (working copy)
1326 qtrue, /* wolf lighting model? */
1327 128, /* lightmap width/height */
1328 1.0f, /* lightmap gamma */
1329 + 1.0f, /* lightmap exposure */
1330 1.0f, /* lightmap compensate */
1331 "IBSP", /* bsp file prefix */
1332 47, /* bsp file version */
1333 Index: tools/quake3/q3map2/game_sof2.h
1334 ===================================================================
1335 --- tools/quake3/q3map2/game_sof2.h (revision 191)
1336 +++ tools/quake3/q3map2/game_sof2.h (working copy)
1338 qfalse, /* wolf lighting model? */
1339 128, /* lightmap width/height */
1340 1.0f, /* lightmap gamma */
1341 + 1.0f, /* lightmap exposure */
1342 1.0f, /* lightmap compensate */
1343 "RBSP", /* bsp file prefix */
1344 1, /* bsp file version */
1345 Index: tools/quake3/q3map2/game_etut.h
1346 ===================================================================
1347 --- tools/quake3/q3map2/game_etut.h (revision 191)
1348 +++ tools/quake3/q3map2/game_etut.h (working copy)
1350 qfalse, /* wolf lighting model? */
1351 128, /* lightmap width/height */
1352 2.2f, /* lightmap gamma */
1353 + 1.0f, /* lightmap exposure */
1354 1.0f, /* lightmap compensate */
1355 "IBSP", /* bsp file prefix */
1356 47, /* bsp file version */
1357 Index: tools/quake3/q3map2/game_jk2.h
1358 ===================================================================
1359 --- tools/quake3/q3map2/game_jk2.h (revision 191)
1360 +++ tools/quake3/q3map2/game_jk2.h (working copy)
1362 qfalse, /* wolf lighting model? */
1363 128, /* lightmap width/height */
1364 1.0f, /* lightmap gamma */
1365 + 1.0f, /* lightmap exposure */
1366 1.0f, /* lightmap compensate */
1367 "RBSP", /* bsp file prefix */
1368 1, /* bsp file version */
1369 Index: tools/quake3/q3map2/game_qfusion.h
1370 ===================================================================
1371 --- tools/quake3/q3map2/game_qfusion.h (revision 191)
1372 +++ tools/quake3/q3map2/game_qfusion.h (working copy)
1374 qfalse, /* wolf lighting model? */
1375 512, /* lightmap width/height */
1376 1.0f, /* lightmap gamma */
1377 + 1.0f, /* lightmap exposure */
1378 1.0f, /* lightmap compensate */
1379 "FBSP", /* bsp file prefix */
1380 1, /* bsp file version */
1381 Index: tools/quake3/q3map2/game_tenebrae.h
1382 ===================================================================
1383 --- tools/quake3/q3map2/game_tenebrae.h (revision 191)
1384 +++ tools/quake3/q3map2/game_tenebrae.h (working copy)
1386 qfalse, /* wolf lighting model? */
1387 512, /* lightmap width/height */
1388 2.0f, /* lightmap gamma */
1389 + 1.0f, /* lightmap exposure */
1390 1.0f, /* lightmap compensate */
1391 "IBSP", /* bsp file prefix */
1392 46, /* bsp file version */
1393 Index: tools/quake3/q3map2/game_quake3.h
1394 ===================================================================
1395 --- tools/quake3/q3map2/game_quake3.h (revision 191)
1396 +++ tools/quake3/q3map2/game_quake3.h (working copy)
1398 qfalse, /* wolf lighting model? */
1399 128, /* lightmap width/height */
1400 1.0f, /* lightmap gamma */
1401 + 1.0f, /* lightmap exposure */
1402 1.0f, /* lightmap compensate */
1403 "IBSP", /* bsp file prefix */
1404 46, /* bsp file version */
1405 Index: tools/quake3/q3map2/game_ef.h
1406 ===================================================================
1407 --- tools/quake3/q3map2/game_ef.h (revision 191)
1408 +++ tools/quake3/q3map2/game_ef.h (working copy)
1410 qfalse, /* wolf lighting model? */
1411 128, /* lightmap width/height */
1412 1.0f, /* lightmap gamma */
1413 + 1.0f, /* lightmap exposure */
1414 1.0f, /* lightmap compensate */
1415 "IBSP", /* bsp file prefix */
1416 46, /* bsp file version */
1417 Index: tools/quake3/q3map2/light_ydnar.c
1418 ===================================================================
1419 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
1420 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
1428 /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
1431 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
1434 + if (lightmapExposure == 1)
1436 + /* clamp with color normalization */
1437 + max = sample[ 0 ];
1438 + if( sample[ 1 ] > max )
1439 + max = sample[ 1 ];
1440 + if( sample[ 2 ] > max )
1441 + max = sample[ 2 ];
1442 + if( max > 255.0f )
1443 + VectorScale( sample, (255.0f / max), sample );
1447 + if (lightmapExposure==0)
1449 + lightmapExposure=1.0f;
1451 + inv=1.f/lightmapExposure;
1454 + max = sample[ 0 ];
1455 + if( sample[ 1 ] > max )
1456 + max = sample[ 1 ];
1457 + if( sample[ 2 ] > max )
1458 + max = sample[ 2 ];
1460 + dif = (1- exp(-max * inv) ) * 255;
1478 - /* clamp with color normalization */
1479 - max = sample[ 0 ];
1480 - if( sample[ 1 ] > max )
1481 - max = sample[ 1 ];
1482 - if( sample[ 2 ] > max )
1483 - max = sample[ 2 ];
1484 - if( max > 255.0f )
1485 - VectorScale( sample, (255.0f / max), sample );
1487 /* compensate for ingame overbrighting/bitshifting */
1488 VectorScale( sample, (1.0f / lightmapCompensate), sample );
1490 Index: tools/quake3/q3map2/light.c
1491 ===================================================================
1492 --- tools/quake3/q3map2/light.c (revision 191)
1493 +++ tools/quake3/q3map2/light.c (working copy)
1494 @@ -1836,6 +1893,14 @@
1498 + else if( !strcmp( argv[ i ], "-exposure" ) )
1500 + f = atof( argv[ i + 1 ] );
1501 + lightmapExposure = f;
1502 + Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
1506 else if( !strcmp( argv[ i ], "-compensate" ) )
1508 f = atof( argv[ i + 1 ] );
1509 Index: tools/quake3/q3map2/q3map2.h
1510 ===================================================================
1511 --- tools/quake3/q3map2/q3map2.h (revision 191)
1512 +++ tools/quake3/q3map2/q3map2.h (working copy)
1514 qboolean wolfLight; /* when true, lights work like wolf q3map */
1515 int lightmapSize; /* bsp lightmap width/height */
1516 float lightmapGamma; /* default lightmap gamma */
1517 + float lightmapExposure; /* default lightmap exposure */
1518 float lightmapCompensate; /* default lightmap compensate value */
1519 char *bspIdent; /* 4-letter bsp file prefix */
1520 int bspVersion; /* bsp version to use */
1521 @@ -2117,6 +2132,7 @@
1523 /* ydnar: lightmap gamma/compensation */
1524 Q_EXTERN float lightmapGamma Q_ASSIGN( 1.0f );
1525 +Q_EXTERN float lightmapExposure Q_ASSIGN( 1.0f );
1526 Q_EXTERN float lightmapCompensate Q_ASSIGN( 1.0f );
1528 /* ydnar: for runtime tweaking of falloff tolerance */
1529 Index: tools/quake3/q3map2/light_ydnar.c
1530 ===================================================================
1531 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
1532 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
1535 #define BOGUS_NUDGE -99999.0f
1537 -static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
1538 +static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
1540 int i, x, y, numClusters, *clusters, pointCluster, *cluster;
1541 float *luxel, *origin, *normal, d, lightmapSampleOffset;
1542 @@ -392,6 +428,12 @@
1546 + vec3_t cverts[ 3 ];
1548 + vec4_t sideplane, hostplane;
1553 static float nudges[][ 2 ] =
1555 @@ -485,6 +527,51 @@
1556 /* non axial lightmap projection (explicit xyz) */
1558 VectorCopy( dv->xyz, origin );
1560 + //////////////////////
1561 + //27's test to make sure samples stay within the triangle boundaries
1562 + //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
1563 + //2) if it does, nudge it onto the correct side.
1565 + if (worldverts!=NULL)
1569 + VectorCopy(worldverts[j],cverts[j]);
1571 + PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
1577 + //build plane using 2 edges and a normal
1580 + VectorCopy(cverts[next],temp);
1581 + VectorAdd(temp,hostplane,temp);
1582 + PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
1584 + //planetest sample point
1585 + e=DotProduct(origin,sideplane);
1590 + //VectorClear(origin);
1591 + //Move the sample point back inside triangle bounds
1592 + origin[0]-=sideplane[0]*(e+1);
1593 + origin[1]-=sideplane[1]*(e+1);
1594 + origin[2]-=sideplane[2]*(e+1);
1596 + VectorClear(origin);
1603 + ////////////////////////
1605 /* planar surfaces have precalculated lightmap vectors for nudging */
1606 if( lm->plane != NULL )
1607 @@ -516,8 +603,13 @@
1609 origin[ lm->axisNum ] += lightmapSampleOffset;
1611 + VectorCopy(origin,origintwo);
1612 + origintwo[0]+=vecs[2][0];
1613 + origintwo[1]+=vecs[2][1];
1614 + origintwo[2]+=vecs[2][2];
1617 - pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
1618 + pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
1620 /* another retarded hack, storing nudge count in luxel[ 1 ] */
1622 @@ -533,14 +625,14 @@
1623 for( i = 0; i < 3; i++ )
1625 /* set nudged point*/
1626 - nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1627 + nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1631 /* get pvs cluster */
1632 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
1633 - if( pointCluster >= 0 )
1634 - VectorCopy( nudged, origin );
1635 + //if( pointCluster >= 0 )
1636 + // VectorCopy( nudged, origin );
1642 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
1643 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
1644 - if( pointCluster >= 0 )
1645 - VectorCopy( nudged, origin );
1646 + //if( pointCluster >= 0 )
1647 + // VectorCopy( nudged, origin );
1652 than the distance between two luxels (thanks jc :)
1655 -static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
1656 +static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
1658 bspDrawVert_t mid, *dv2[ 3 ];
1662 /* split the longest edge and map it */
1663 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1664 - MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
1665 + MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
1667 /* push the point up a little bit to account for fp creep (fixme: revisit this) */
1668 //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
1669 @@ -653,12 +745,12 @@
1670 /* recurse to first triangle */
1671 VectorCopy( dv, dv2 );
1673 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1674 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1676 /* recurse to second triangle */
1677 VectorCopy( dv, dv2 );
1678 dv2[ (max + 1) % 3 ] = ∣
1679 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1680 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1687 vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
1688 + vec3_t worldverts[ 3 ];
1691 /* get plane if possible */
1692 @@ -699,16 +792,20 @@
1696 + VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
1697 + VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
1698 + VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
1700 /* map the vertexes */
1701 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1702 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1703 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1704 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
1705 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
1706 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
1708 /* 2002-11-20: prefer axial triangle edges */
1711 /* subdivide the triangle */
1712 - MapTriangle_r( lm, info, dv, plane, stv, ttv );
1713 + MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
1718 dv2[ 2 ] = dv[ (i + 1) % 3 ];
1720 /* map the degenerate triangle */
1721 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1722 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1727 LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
1729 /* map the vertexes */
1730 - MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
1731 - MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
1732 + MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
1733 + MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
1737 @@ -878,10 +975,10 @@
1740 /* map the vertexes */
1741 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1742 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1743 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1744 - MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
1745 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
1746 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
1747 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
1748 + MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
1750 /* subdivide the quad */
1751 MapQuad_r( lm, info, dv, plane, stv, ttv );
1752 @@ -1173,7 +1270,7 @@
1755 /* map the fake vert */
1756 - MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
1757 + MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1761 @@ -1963,22 +2062,32 @@
1762 deluxel = SUPER_DELUXEL( x, y );
1763 origin = SUPER_ORIGIN( x, y );
1764 normal = SUPER_NORMAL( x, y );
1766 - /* set contribution count */
1767 - lightLuxel[ 3 ] = 1.0f;
1770 - trace.cluster = *cluster;
1771 - VectorCopy( origin, trace.origin );
1772 - VectorCopy( normal, trace.normal );
1774 - /* get light for this sample */
1775 - LightContributionToSample( &trace );
1776 - VectorCopy( trace.color, lightLuxel );
1778 - /* add to count */
1779 - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1781 + ////////// 27's temp hack for testing edge clipping ////
1782 + if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
1784 + lightLuxel[ 1 ] = 255;
1785 + lightLuxel[ 3 ] = 1.0f;
1790 + /* set contribution count */
1791 + lightLuxel[ 3 ] = 1.0f;
1794 + trace.cluster = *cluster;
1795 + VectorCopy( origin, trace.origin );
1796 + VectorCopy( normal, trace.normal );
1798 + /* get light for this sample */
1799 + LightContributionToSample( &trace );
1800 + VectorCopy( trace.color, lightLuxel );
1802 + /* add to count */
1803 + if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1807 /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
1809 Index: tools/quake3/q3map2/q3map2.h
1810 ===================================================================
1811 --- tools/quake3/q3map2/q3map2.h (revision 303)
1812 +++ tools/quake3/q3map2/q3map2.h (working copy)
1817 -#define Q3MAP_VERSION "2.5.17"
1818 -#define Q3MAP_MOTD "Last one turns the lights off"
1819 +#define Q3MAP_VERSION "2.5.17-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
1820 +#define Q3MAP_MOTD "Light some candles, put them on a wooden table, take a photo, and paste it on the lightmaps!"
1824 Index: include/version.default
1825 ===================================================================
1826 --- include/version.default (revision 290)
1827 +++ include/version.default (working copy)