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 193)
14 +++ libs/picomodel/pm_obj.c (working copy)
16 /* get next token in material file */
17 if (_pico_parse( p,1 ) == NULL)
22 /* skip empty lines */
23 if (p->token == NULL || !strlen( p->token ))
25 else if (!_pico_stricmp(p->token,"map_kd"))
28 + picoShader_t *shader;
30 /* pointer to current shader must be valid */
31 if (curShader == NULL)
33 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
34 _obj_mtl_error_return;
36 + /* create a new pico shader */
37 + shader = PicoNewShader( model );
39 + _obj_mtl_error_return;
40 /* set shader map name */
41 PicoSetShaderMapName( shader,mapName );
44 PicoSetModelFileName( model,fileName );
46 /* try loading the materials; we don't handle the result */
49 _obj_mtl_load( model );
56 + else if (!_pico_stricmp(p->token,"usemtl"))
58 + picoShader_t *shader;
61 + /* get material name */
62 + name = _pico_parse( p,0 );
64 + /* validate material name */
65 + if (name == NULL || !strlen(name))
67 + _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
71 + shader = PicoFindShader( model, name, 1 );
74 + _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
76 + /* create a new pico shader */
77 + shader = PicoNewShader( model );
80 + PicoSetShaderName( shader,name );
81 + PicoSetShaderMapName( shader,name );
82 + PicoSetSurfaceShader( curSurface, shader );
87 + PicoSetSurfaceShader( curSurface, shader );
91 /* skip unparsed rest of line and continue */
92 _pico_parse_skip_rest( p );
94 Index: libs/picomodel/pm_ase.c
95 ===================================================================
96 --- libs/picomodel/pm_ase.c (revision 191)
97 +++ libs/picomodel/pm_ase.c (working copy)
100 ----------------------------------------------------------------------------- */
102 +void Sys_Printf (const char *format, ...);
115 picoIndex_t smoothingGroup;
116 picoIndex_t materialId;
117 picoIndex_t subMaterialId;
118 + picoVec3_t facenormal;
119 + picoVec3_t vertexnormal[3];
121 typedef aseFace_t* aseFacesIter_t;
123 @@ -455,33 +457,157 @@
127 +static int VectorCompareExtn( picoVec3_t n1, picoVec3_t n2, float epsilon )
133 + for( i= 0; i < 3; i++ )
134 + if( fabs( n1[ i ] - n2[ i ]) > epsilon )
139 +#define CrossProductTemp(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
141 static void _ase_submit_triangles( picoModel_t* model , aseMaterial_t* materials , aseVertex_t* vertices, aseTexCoord_t* texcoords, aseColor_t* colors, aseFace_t* faces, int numFaces )
143 - aseFacesIter_t i = faces, end = faces + numFaces;
144 - for(; i != end; ++i)
149 + aseFacesIter_t i = faces, end = faces + numFaces;
153 + for(i=faces; i != end; ++i)
158 + //VectorSubtract(va, vb, v1);
159 + //VectorSubtract(vc, vb, v2);
160 + //CrossProduct(v1, v2, out);
163 + picoVec3_t v1,v2,v3;
168 + a[j] = vertices[(*i).indices[0]].xyz[j];
169 + b[j] = vertices[(*i).indices[1]].xyz[j];
170 + c[j] = vertices[(*i).indices[2]].xyz[j];
178 + CrossProductTemp(v1,v2,v3);
179 + _pico_normalize_vec(v3);
180 + (*i).facenormal[0]=v3[0];
181 + (*i).facenormal[1]=v3[1];
182 + (*i).facenormal[2]=v3[2];
188 + //if (counter>0) Sys_Printf( "Rebuilding %d Normals\n", counter * 3 );
189 + for(i=faces; i != end; ++i)
191 - /* look up the shader for the material/submaterial pair */
192 + /* look up the shader for the material/submaterial pair */
193 aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId );
194 - if( subMtl == NULL )
196 + if( subMtl == NULL )
204 picoVec3_t* normal[3];
206 picoColor_t* color[3];
207 picoIndex_t smooth[3];
209 - /* we pull the data from the vertex, color and texcoord arrays using the face index data */
210 - for ( j = 0 ; j < 3 ; j ++ )
216 + /* we pull the data from the vertex, color and texcoord arrays using the face index data */
217 + for ( j = 0 ; j < 3 ; j ++ )
219 - xyz[j] = &vertices[(*i).indices[j]].xyz;
220 - normal[j] = &vertices[(*i).indices[j]].normal;
221 + aseFacesIter_t q = faces;
222 + aseFacesIter_t qend = faces + numFaces;
224 + xyz[j] = &vertices[(*i).indices[j]].xyz;
227 + normal[j] = &(*i).facenormal;
230 + //Oooor we can use the smoothing group
232 + //Slow method, but testing
233 + //Find All faces that use this vertex, average their facenormals.
234 + // skip where smoothgroups both equal 0, or don't have any shared bits (x & y)
235 + index=(*i).indices[j];
240 + accum[0]=(*i).facenormal[0];
241 + accum[1]=(*i).facenormal[1];
242 + accum[2]=(*i).facenormal[2];
247 + for(; q != qend; ++q)
252 + // if ( (*q).indices[0]==index || (*q).indices[1]==index || (*q).indices[2]==index)
253 + a[0]= &vertices[(*q).indices[0] ].xyz;
254 + a[1]= &vertices[(*q).indices[1] ].xyz;
255 + a[2]= &vertices[(*q).indices[2] ].xyz;
257 + if ( VectorCompareExtn(*a[0],*xyz[j],0.01f)>0 ||
258 + VectorCompareExtn(*a[1],*xyz[j],0.01f)>0 ||
259 + VectorCompareExtn(*a[2],*xyz[j],0.01f)>0
262 + if ( (*i).smoothingGroup==0 && (*q).smoothingGroup ==0 )
265 + if ( (*i).smoothingGroup & (*q).smoothingGroup )
267 + accum[0]+=(*q).facenormal[0];
268 + accum[1]+=(*q).facenormal[1];
269 + accum[2]+=(*q).facenormal[2];
276 + _pico_normalize_vec(accum);
278 + (*i).vertexnormal[j][0]=accum[0];
279 + (*i).vertexnormal[j][1]=accum[1];
280 + (*i).vertexnormal[j][2]=accum[2];
281 + normal[j]=&(*i).vertexnormal[j];
284 st[j] = &texcoords[(*i).indices[j + 3]].texcoord;
286 - if( colors != NULL && (*i).indices[j + 6] >= 0 )
288 + if( colors != NULL && (*i).indices[j + 6] >= 0 )
290 color[j] = &colors[(*i).indices[j + 6]].color;
292 @@ -490,30 +616,18 @@
296 - smooth[j] = (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
297 + smooth[j] = 0;// (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */
301 /* submit the triangle to the model */
302 PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader, smooth );
308 -static void shadername_convert(char* shaderName)
310 - /* unix-style path separators */
311 - char* s = shaderName;
312 - for(; *s != '\0'; ++s)
323 * loads a 3dsmax ase model file.
326 int numColorVertices = 0;
327 int numColorVertexFaces = 0;
329 + int currentVertexFace=0;
330 + int currentVertexIndex=0;
333 aseMaterial_t* materials = NULL;
335 @@ -610,10 +727,11 @@
337 else if (!_pico_stricmp(p->token,"*mesh_numvertex"))
339 - if (!_pico_parse_int( p, &numVertices) )
340 + if (!_pico_parse_int( p, &numVertices) )
341 _ase_error_return("Missing MESH_NUMVERTEX value");
343 vertices = _pico_calloc(numVertices, sizeof(aseVertex_t));
344 + currentVertexIndex=0;
346 else if (!_pico_stricmp(p->token,"*mesh_numfaces"))
349 _ase_error_return("Missing MESH_NUMFACES value");
351 faces = _pico_calloc(numFaces, sizeof(aseFace_t));
354 else if (!_pico_stricmp(p->token,"*mesh_numtvertex"))
358 vertices[index].id = vertexId++;
360 - /* model mesh vertex normal */
361 + else if (!_pico_stricmp(p->token,"*mesh_facenormal"))
363 + //Grab the faceindex for the next vertex normals.
364 + if( numVertices == 0 )
365 + _ase_error_return("Vertex parse error (facenormals)");
367 + if (!_pico_parse_int( p,¤tVertexFace ))
368 + _ase_error_return("Vertex parse error");
370 + if (!_pico_parse_vec( p,faces[currentVertexFace].facenormal ))
371 + _ase_error_return("Vertex parse error");
374 + /* model mesh vertex normal */
375 else if (!_pico_stricmp(p->token,"*mesh_vertexnormal"))
378 @@ -696,10 +828,25 @@
379 /* get vertex data (orig: index +y -x +z) */
380 if (!_pico_parse_int( p,&index ))
381 _ase_error_return("Vertex parse error");
382 - if (!_pico_parse_vec( p,vertices[index].normal ))
384 + //^^ Index is 'wrong' in .ase models. they reference the same vert index with multiple normals..
385 + // I've tried, this is a lost cause. Use the SG's
389 + if (!_pico_parse_vec( p,vertices[counter].normal ))
390 _ase_error_return("Vertex parse error");
391 + vertices[counter].faceid=index;
395 /* model mesh face */
396 + else if (!_pico_stricmp(p->token,"*mesh_normals"))
398 + // counter=0; //part of the above vertex normals fix
401 + /* model mesh face */
402 else if (!_pico_stricmp(p->token,"*mesh_face"))
404 picoIndex_t indexes[3];
407 if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" ))
409 - _pico_parse_int ( p , &faces[index].smoothingGroup );
418 + faces[index].smoothingGroup=0;
420 + //Super dodgy comma delimited string parse
423 + if (*point<=32 || *point==',')
428 + faces[index].smoothingGroup+=1<<total;
440 if (!_pico_stricmp (p->token,"*MESH_MTLID" ))
442 _pico_parse_int ( p , &faces[index].subMaterialId );
443 @@ -755,19 +929,19 @@
446 if( numVertices == 0 )
447 - _ase_error_return("Texture Vertex parse error");
448 + _ase_error_return("Vertex parse error");
450 /* get uv vertex index */
451 - if (!_pico_parse_int( p,&index ) || index >= numTextureVertices)
452 - _ase_error_return("Texture vertex parse error");
453 + if (!_pico_parse_int( p,&index ))
454 + _ase_error_return("UV vertex parse error");
456 /* get uv vertex s */
457 if (!_pico_parse_float( p,&texcoords[index].texcoord[0] ))
458 - _ase_error_return("Texture vertex parse error");
459 + _ase_error_return("UV vertex parse error");
461 /* get uv vertex t */
462 if (!_pico_parse_float( p,&texcoords[index].texcoord[1] ))
463 - _ase_error_return("Texture vertex parse error");
464 + _ase_error_return("UV vertex parse error");
466 /* ydnar: invert t */
467 texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ];
468 @@ -831,6 +1005,13 @@
470 /* leave alpha alone since we don't get any data from the ASE format */
471 colors[index].color[3] = 255;
473 + /* 27 hack, red as alpha */
474 + colors[index].color[3]=colors[index].color[0];
475 + colors[index].color[0]=255;
476 + colors[index].color[1]=255;
477 + colors[index].color[2]=255;
480 /* model color face */
481 else if (!_pico_stricmp(p->token,"*mesh_cface"))
484 /* set material name */
485 _pico_first_token( materialName );
486 - shadername_convert(materialName);
487 PicoSetShaderName( shader, materialName);
489 /* set shader's transparency */
490 @@ -1085,7 +1265,6 @@
493 /* set material name */
494 - shadername_convert(materialName);
495 PicoSetShaderName( shader,materialName );
497 /* set shader's transparency */
498 @@ -1115,8 +1294,18 @@
501 /* convert to shader-name format */
502 - shadername_convert(mapname);
504 + /* unix-style path separators */
506 + for(; *s != '\0'; ++s)
515 /* remove extension */
516 char* last_period = strrchr(p, '.');
517 if(last_period != NULL)
518 @@ -1125,14 +1314,32 @@
522 - /* find shader path */
523 + /* find game root */
524 for(; *p != '\0'; ++p)
526 - if(_pico_strnicmp(p, "models/", 7) == 0 || _pico_strnicmp(p, "textures/", 9) == 0)
527 + if(_pico_strnicmp(p, "quake", 5) == 0 || _pico_strnicmp(p, "doom", 4) == 0)
532 + /* root-relative */
533 + for(; *p != '\0'; ++p)
541 + /* game-relative */
542 + for(; *p != '\0'; ++p)
553 Index: libs/picomodel/picomodel.c
554 ===================================================================
555 --- libs/picomodel/picomodel.c (revision 191)
556 +++ libs/picomodel/picomodel.c (working copy)
558 model = PicoModuleLoadModel(module, fileName, buffer, bufSize, frameNum);
563 - _pico_free(buffer);
565 + _pico_free(buffer);
569 @@ -1573,6 +1570,7 @@
573 +// Sys_Printf(" %f %f %f\n", normal[0] , normal[1] , normal[2] );
576 if( surface == NULL || surface->numVertexes <= 0 )
577 @@ -1861,13 +1859,10 @@
578 typedef picoVec3_t* picoNormalIter_t;
579 typedef picoIndex_t* picoIndexIter_t;
581 -#define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
583 void _pico_triangles_generate_weighted_normals(picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals)
585 for(; first != end; first += 3)
587 -#if (THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
588 picoVec3_t weightedNormal;
590 float* a = xyz[*(first + 0)];
591 @@ -1878,24 +1873,11 @@
592 _pico_subtract_vec( c, a, ca );
593 _pico_cross_vec( ca, ba, weightedNormal );
600 float* normal = normals[*(first + j)];
601 -#if (!THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL)
602 - picoVec3_t weightedNormal;
604 - float* a = xyz[*(first + ((j + 0) % 3))];
605 - float* b = xyz[*(first + ((j + 1) % 3))];
606 - float* c = xyz[*(first + ((j + 2) % 3))];
608 - _pico_subtract_vec( b, a, ba );
609 - _pico_subtract_vec( c, a, ca );
610 - _pico_cross_vec( ca, ba, weightedNormal );
613 _pico_add_vec(weightedNormal, normal, normal);
616 @@ -1941,7 +1923,8 @@
618 for(; first != last; ++first, ++generated)
620 - if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated))
621 + //27 - fix for badly generated normals thing.
622 + // if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated))
624 _pico_copy_vec(*generated, *first);
626 @@ -1954,10 +1937,11 @@
628 _pico_normals_zero(normals, normals + surface->numVertexes);
630 + //Just build standard no sg normals for now
631 _pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz, normals);
632 _pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes);
634 - _pico_normals_normalize(normals, normals + surface->numVertexes);
635 + _pico_normals_normalize(normals, normals + surface->numVertexes);
637 _pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals);
639 @@ -2261,7 +2245,7 @@
640 int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface );
642 /* get the index of the vertex that we're going to store at newVertIndex */
643 - vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]);
644 + vertDataIndex = -1;// PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]);
646 /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
647 if ( vertDataIndex == -1 )
648 @@ -2290,3 +2274,5 @@
649 PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex );
654 Index: plugins/model/model.cpp
655 ===================================================================
656 --- plugins/model/model.cpp (revision 193)
657 +++ plugins/model/model.cpp (working copy)
658 @@ -123,14 +123,27 @@
660 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex);
661 glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data());
664 + GLfloat modelview[16];
665 + glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // I know this is slow as hell, but hey - we're in _DEBUG
666 + Matrix4 modelview_inv(
667 + modelview[0], modelview[1], modelview[2], modelview[3],
668 + modelview[4], modelview[5], modelview[6], modelview[7],
669 + modelview[8], modelview[9], modelview[10], modelview[11],
670 + modelview[12], modelview[13], modelview[14], modelview[15]);
671 + matrix4_full_invert(modelview_inv);
672 + Matrix4 modelview_inv_transposed = matrix4_transposed(modelview_inv);
676 for(Array<ArbitraryMeshVertex>::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
678 - Vector3 normal = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal3f_to_vector3((*i).normal), 8));
679 + Vector3 normal = normal3f_to_vector3((*i).normal);
680 + normal = matrix4_transformed_direction(modelview_inv, vector3_normalised(matrix4_transformed_direction(modelview_inv_transposed, normal))); // do some magic
681 + Vector3 normalTransformed = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal, 8));
682 glVertex3fv(vertex3f_to_array((*i).vertex));
683 - glVertex3fv(vector3_to_array(normal));
684 + glVertex3fv(vector3_to_array(normalTransformed));
688 Index: games/NexuizPack/games/nexuiz.game
689 ===================================================================
690 --- games/NexuizPack/games/nexuiz.game (revision 26)
691 +++ games/NexuizPack/games/nexuiz.game (working copy)
695 texturetypes="tga jpg png"
696 - modeltypes="md3 mdl md2 ase"
697 + modeltypes="md3 mdl md2 ase obj"
701 Index: tools/quake3/q3map2/convert_map.c
702 ===================================================================
703 --- tools/quake3/q3map2/convert_map.c (revision 191)
704 +++ tools/quake3/q3map2/convert_map.c (working copy)
706 #define SNAP_FLOAT_TO_INT 4
707 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
709 +typedef vec_t vec2_t[2];
711 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
712 + vec_t a10, vec_t a11, vec_t a12,
713 + vec_t a20, vec_t a21, vec_t a22)
716 + a00 * (a11 * a22 - a12 * a21)
717 + - a01 * (a10 * a22 - a12 * a20)
718 + + a02 * (a10 * a21 - a11 * a20);
721 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
723 + bspDrawSurface_t *s;
729 + vec3_t v1v0, v2v0, norm;
730 + bspDrawVert_t *vert[3];
731 + winding_t *polygon;
732 + plane_t *buildPlane = &mapplanes[buildSide->planenum];
735 + // first, start out with NULLs
736 + bestVert[0] = bestVert[1] = bestVert[2] = NULL;
738 + // brute force through all surfaces
739 + for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
741 + if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
743 + if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
745 + for(t = 0; t + 3 <= s->numIndexes; t += 3)
747 + vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
748 + vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
749 + vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
750 + if(s->surfaceType == MST_PLANAR)
752 + VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
753 + VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
754 + VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
758 + // this is more prone to roundoff errors, but with embedded
759 + // models, there is no better way
760 + VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
761 + VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
762 + CrossProduct(v2v0, v1v0, norm);
763 + VectorNormalize(norm, norm);
764 + VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
766 + if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
767 + if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
768 + if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
769 + // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
770 + polygon = CopyWinding(buildSide->winding);
771 + for(i = 0; i < 3; ++i)
776 + vec3_t *v1 = &vert[(i+1)%3]->xyz;
777 + vec3_t *v2 = &vert[(i+2)%3]->xyz;
780 + vec3_t sideDirection;
781 + // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
782 + VectorSubtract(*v2, *v1, sideDirection);
783 + CrossProduct(sideDirection, buildPlane->normal, triNormal);
784 + triDist = DotProduct(*v1, triNormal);
785 + ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
789 + thisarea = WindingArea(polygon);
792 + if(thisarea > best)
795 + bestVert[0] = vert[0];
796 + bestVert[1] = vert[1];
797 + bestVert[2] = vert[2];
799 + FreeWinding(polygon);
804 + //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
805 + // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
808 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
815 + plane_t *buildPlane;
817 + bspDrawVert_t *vert[3];
822 fprintf( f, "\t// brush %d\n", num );
823 fprintf( f, "\t{\n" );
824 + fprintf( f, "\tbrushDef\n" );
825 + fprintf( f, "\t{\n" );
827 /* clear out build brush */
828 for( i = 0; i < buildBrush->numsides; i++ )
831 buildSide = &buildBrush->sides[ i ];
834 + buildPlane = &mapplanes[ buildSide->planenum ];
837 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
840 + // st-texcoords -> texMat block
841 + // start out with dummy
842 + VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
843 + VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
845 + // find surface for this side (by brute force)
847 + // - meshverts point in pairs of three into verts
849 + // - find the triangle that has most in common with our side
850 + GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
853 + if(vert[0] && vert[1] && vert[2])
857 + vec3_t xy1I, xy1J, xy1K;
858 + vec2_t stI, stJ, stK;
859 + vec_t D, D0, D1, D2;
861 + ComputeAxisBase(buildPlane->normal, texX, texY);
863 + VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
864 + VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
865 + VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
866 + stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
867 + stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
868 + stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
870 + // - solve linear equations:
871 + // - (x, y) := xyz . (texX, texY)
872 + // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
873 + // (for three vertices)
875 + xy1I[0], xy1I[1], 1,
876 + xy1J[0], xy1J[1], 1,
877 + xy1K[0], xy1K[1], 1
881 + for(i = 0; i < 2; ++i)
884 + stI[i], xy1I[1], 1,
885 + stJ[i], xy1J[1], 1,
889 + xy1I[0], stI[i], 1,
890 + xy1J[0], stJ[i], 1,
894 + xy1I[0], xy1I[1], stI[i],
895 + xy1J[0], xy1J[1], stJ[i],
896 + xy1K[0], xy1K[1], stK[i]
898 + VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
903 + 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",
904 + buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
905 + vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
906 + texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
907 + vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
908 + vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
909 + vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
913 + if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
914 + fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
916 /* get texture name */
917 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
918 @@ -130,14 +313,21 @@
920 /* print brush side */
921 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
922 - 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",
923 + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
924 pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
925 pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
926 pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
928 + buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
929 + buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
931 + // DEBUG: valid ? 0 : C_DETAIL
934 + // TODO write brush primitives format here
938 + fprintf( f, "\t}\n" );
939 fprintf( f, "\t}\n\n" );
942 Index: tools/quake3/q3map2/main.c
943 ===================================================================
944 --- tools/quake3/q3map2/main.c (revision 191)
945 +++ tools/quake3/q3map2/main.c (working copy)
947 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
950 + else if( !strcmp( argv[ i ], "-ne" ) )
952 + normalEpsilon = atof( argv[ i + 1 ] );
954 + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
956 + else if( !strcmp( argv[ i ], "-de" ) )
958 + distanceEpsilon = atof( argv[ i + 1 ] );
960 + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
964 /* clean up map name */
965 Index: tools/quake3/q3map2/model.c
966 ===================================================================
967 --- tools/quake3/q3map2/model.c (revision 193)
968 +++ tools/quake3/q3map2/model.c (working copy)
971 picoIndex_t *indexes;
973 + double normalEpsilon_save;
974 + double distanceEpsilon_save;
979 /* ydnar: giant hack land: generate clipping brushes for model triangles */
980 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
982 - vec3_t points[ 3 ], backs[ 3 ];
983 + vec3_t points[ 4 ], backs[ 3 ];
984 vec4_t plane, reverse, pa, pb, pc;
989 @@ -437,90 +438,141 @@
990 /* note: this doesn't work as well as simply using the plane of the triangle, below */
991 for( k = 0; k < 3; k++ )
993 - if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
994 - fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
995 + if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
996 + fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
998 backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
1004 + VectorCopy( points[0], points[3] ); // for cyclic usage
1006 /* make plane for triangle */
1007 + // div0: add some extra spawnflags:
1008 + // 0: snap normals to axial planes for extrusion
1009 + // 8: extrude with the original normals
1010 + // 16: extrude only with up/down normals (ideal for terrain)
1011 + // 24: extrude by distance zero (may need engine changes)
1012 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
1014 + vec3_t bestNormal;
1015 + float backPlaneDistance = 2;
1017 + if(spawnFlags & 8) // use a DOWN normal
1019 + if(spawnFlags & 16)
1021 + // 24: normal as is, and zero width (broken)
1022 + VectorCopy(plane, bestNormal);
1026 + // 8: normal as is
1027 + VectorCopy(plane, bestNormal);
1032 + if(spawnFlags & 16)
1034 + // 16: UP/DOWN normal
1035 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1039 + // 0: axial normal
1040 + if(fabs(plane[0]) > fabs(plane[1])) // x>y
1041 + if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
1042 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1044 + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
1045 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1047 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1049 + if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
1050 + VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
1051 + else // z>=y, y>=x
1052 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1056 + /* build a brush */
1057 + buildBrush = AllocBrush( 48 );
1058 + buildBrush->entityNum = mapEntityNum;
1059 + buildBrush->original = buildBrush;
1060 + buildBrush->contentShader = si;
1061 + buildBrush->compileFlags = si->compileFlags;
1062 + buildBrush->contentFlags = si->contentFlags;
1063 + normalEpsilon_save = normalEpsilon;
1064 + distanceEpsilon_save = distanceEpsilon;
1065 + if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
1067 + buildBrush->detail = qfalse;
1069 + // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
1070 + if(normalEpsilon > 0)
1071 + normalEpsilon = 0;
1072 + if(distanceEpsilon > 0)
1073 + distanceEpsilon = 0;
1076 + buildBrush->detail = qtrue;
1078 /* regenerate back points */
1079 for( j = 0; j < 3; j++ )
1082 dv = &ds->verts[ ds->indexes[ i + j ] ];
1085 - VectorCopy( dv->xyz, backs[ j ] );
1087 - /* find nearest axial to plane normal and push back points opposite */
1088 - for( k = 0; k < 3; k++ )
1090 - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
1091 - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
1093 - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1098 + // shift by some units
1099 + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1103 /* make back plane */
1104 VectorScale( plane, -1.0f, reverse );
1105 - reverse[ 3 ] = -(plane[ 3 ] - 1);
1107 - /* make back pyramid point */
1108 - VectorCopy( points[ 0 ], nadir );
1109 - VectorAdd( nadir, points[ 1 ], nadir );
1110 - VectorAdd( nadir, points[ 2 ], nadir );
1111 - VectorScale( nadir, 0.3333333333333f, nadir );
1112 - VectorMA( nadir, -2.0f, plane, nadir );
1114 - /* make 3 more planes */
1115 - //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1116 - //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1117 - //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1118 + reverse[ 3 ] = -plane[ 3 ];
1119 + if((spawnFlags & 24) != 24)
1120 + reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1121 + // 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)
1123 if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1124 - PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1125 - PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1126 + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1127 + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1129 - /* build a brush */
1130 - buildBrush = AllocBrush( 48 );
1132 - buildBrush->entityNum = mapEntityNum;
1133 - buildBrush->original = buildBrush;
1134 - buildBrush->contentShader = si;
1135 - buildBrush->compileFlags = si->compileFlags;
1136 - buildBrush->contentFlags = si->contentFlags;
1137 - buildBrush->detail = qtrue;
1139 /* set up brush sides */
1140 buildBrush->numsides = 5;
1141 for( j = 0; j < buildBrush->numsides; j++ )
1142 buildBrush->sides[ j ].shaderInfo = si;
1144 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1145 - buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1146 - buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1147 - buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1148 - buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1150 - /* add to entity */
1151 - if( CreateBrushWindings( buildBrush ) )
1154 - //% EmitBrushes( buildBrush, NULL, NULL );
1155 - buildBrush->next = entities[ mapEntityNum ].brushes;
1156 - entities[ mapEntityNum ].brushes = buildBrush;
1157 - entities[ mapEntityNum ].numBrushes++;
1160 - free( buildBrush );
1161 + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1162 + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1163 + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1164 + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1172 + normalEpsilon = normalEpsilon_save;
1173 + distanceEpsilon = distanceEpsilon_save;
1175 + /* add to entity */
1176 + if( CreateBrushWindings( buildBrush ) )
1179 + //% EmitBrushes( buildBrush, NULL, NULL );
1180 + buildBrush->next = entities[ mapEntityNum ].brushes;
1181 + entities[ mapEntityNum ].brushes = buildBrush;
1182 + entities[ mapEntityNum ].numBrushes++;
1185 + free( buildBrush );
1189 Index: tools/quake3/q3map2/map.c
1190 ===================================================================
1191 --- tools/quake3/q3map2/map.c (revision 193)
1192 +++ tools/quake3/q3map2/map.c (working copy)
1194 snaps a plane to normal/distance epsilons
1197 -void SnapPlane( vec3_t normal, vec_t *dist )
1198 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1200 // SnapPlane disabled by LordHavoc because it often messes up collision
1201 // brushes made from triangles of embedded models, and it has little effect
1202 @@ -193,7 +193,13 @@
1203 SnapPlane reenabled by namespace because of multiple reports of
1204 q3map2-crashes which were triggered by this patch.
1206 + // div0: ensure the point "center" stays on the plane (actually, this
1207 + // rotates the plane around the point center).
1208 + // if center lies on the plane, it is guaranteed to stay on the plane by
1210 + vec_t centerDist = DotProduct(normal, center);
1211 SnapNormal( normal );
1212 + *dist += (DotProduct(normal, center) - centerDist);
1214 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1215 *dist = Q_rint( *dist );
1217 must be within an epsilon distance of the plane
1220 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1221 +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?
1225 @@ -215,10 +221,14 @@
1229 + vec3_t centerofweight;
1231 + VectorClear(centerofweight);
1232 + for(i = 0; i < numPoints; ++i)
1233 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1236 /* hash the plane */
1237 - SnapPlane( normal, &dist );
1238 + SnapPlane( normal, &dist, centerofweight );
1239 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1241 /* search the border bins as well */
1242 @@ -259,7 +269,13 @@
1246 - SnapPlane( normal, &dist );
1247 + vec3_t centerofweight;
1249 + VectorClear(centerofweight);
1250 + for(i = 0; i < numPoints; ++i)
1251 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1253 + SnapPlane( normal, &dist, centerofweight );
1254 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1256 if( PlaneEqual( p, normal, dist ) )
1257 Index: tools/quake3/q3map2/shaders.c
1258 ===================================================================
1259 --- tools/quake3/q3map2/shaders.c (revision 191)
1260 +++ tools/quake3/q3map2/shaders.c (working copy)
1261 @@ -793,8 +793,14 @@
1264 if( VectorLength( si->color ) <= 0.0f )
1266 ColorNormalize( color, si->color );
1267 - VectorScale( color, (1.0f / count), si->averageColor );
1268 + VectorScale( color, (1.0f / count), si->averageColor );
1272 + VectorCopy( si->color, si->averageColor );
1277 Index: tools/quake3/q3map2/light_ydnar.c
1278 ===================================================================
1279 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
1280 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
1281 @@ -1767,6 +1864,8 @@
1282 float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1284 float stackLightLuxels[ STACK_LL_SIZE ];
1286 + float *floodlight;
1289 /* bail if this number exceeds the number of raw lightmaps */
1290 @@ -2223,6 +2332,78 @@
1291 FreeTraceLights( &trace );
1293 /* -----------------------------------------------------------------
1295 + ----------------------------------------------------------------- */
1299 + /* walk lightmaps */
1300 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1303 + if( lm->superLuxels[ lightmapNum ] == NULL )
1306 + /* apply floodlight to each luxel */
1307 + for( y = 0; y < lm->sh; y++ )
1309 + for( x = 0; x < lm->sw; x++ )
1312 + cluster = SUPER_CLUSTER( x, y );
1313 + //% if( *cluster < 0 )
1316 + /* get particulars */
1317 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1318 + floodlight = SUPER_FLOODLIGHT( x, y );
1320 + flood[0]=floodlightRGB[0]*floodlightIntensity;
1321 + flood[1]=floodlightRGB[1]*floodlightIntensity;
1322 + flood[2]=floodlightRGB[2]*floodlightIntensity;
1324 + /* scale light value */
1325 + VectorScale( flood, *floodlight, flood );
1326 + luxel[0]+=flood[0];
1327 + luxel[1]+=flood[1];
1328 + luxel[2]+=flood[2];
1330 + if (luxel[3]==0) luxel[3]=1;
1338 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1341 + if( lm->superLuxels[ lightmapNum ] == NULL )
1344 + for( y = 0; y < lm->sh; y++ )
1346 + for( x = 0; x < lm->sw; x++ )
1349 + cluster = SUPER_CLUSTER( x, y );
1350 + //% if( *cluster < 0 )
1353 + /* get particulars */
1354 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1355 + normal = SUPER_NORMAL ( x, y );
1357 + luxel[0]=(normal[0]*127)+127;
1358 + luxel[1]=(normal[1]*127)+127;
1359 + luxel[2]=(normal[2]*127)+127;
1365 + /* -----------------------------------------------------------------
1367 ----------------------------------------------------------------- */
1369 @@ -3587,7 +3768,320 @@
1370 CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1373 +/////////////////////////////////////////////////////////////
1375 +#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */
1376 +#define FLOODLIGHT_NUM_ANGLE_STEPS 16
1377 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1378 +#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1380 +static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1381 +static int numFloodVectors = 0;
1383 +void SetupFloodLight( void )
1386 + float angle, elevation, angleStep, elevationStep;
1387 + const char *value;
1388 + double v1,v2,v3,v4,v5;
1391 + Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1393 + /* calculate angular steps */
1394 + angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1395 + elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1397 + /* iterate angle */
1399 + for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1401 + /* iterate elevation */
1402 + for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1404 + floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1405 + floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1406 + floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1407 + numFloodVectors++;
1411 + /* emit some statistics */
1412 + Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1415 + value = ValueForKey( &entities[ 0 ], "_floodlight" );
1417 + if( value[ 0 ] != '\0' )
1420 + v4=floodlightDistance;
1421 + v5=floodlightIntensity;
1423 + sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1425 + floodlightRGB[0]=v1;
1426 + floodlightRGB[1]=v2;
1427 + floodlightRGB[2]=v3;
1429 + if (VectorLength(floodlightRGB)==0)
1431 + VectorSet(floodlightRGB,240,240,255);
1434 + if (v4<1) v4=1024;
1437 + floodlightDistance=v4;
1438 + floodlightIntensity=v5;
1440 + floodlighty = qtrue;
1441 + Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1445 + VectorSet(floodlightRGB,240,240,255);
1446 + //floodlighty = qtrue;
1447 + //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1449 + VectorNormalize(floodlightRGB,floodlightRGB);
1452 +//27 - lighttracer style ambient occlusion light hack.
1453 +//Kudos to the dirtmapping author for most of this source.
1454 +void FloodLightRawLightmap( int rawLightmapNum )
1456 + int i, x, y, sx, sy, *cluster;
1457 + float *origin, *normal, *floodlight, *floodlight2, average, samples;
1458 + rawLightmap_t *lm;
1459 + surfaceInfo_t *info;
1462 + /* bail if this number exceeds the number of raw lightmaps */
1463 + if( rawLightmapNum >= numRawLightmaps )
1466 + /* get lightmap */
1467 + lm = &rawLightmaps[ rawLightmapNum ];
1469 + memset(&trace,0,sizeof(trace_t));
1471 + trace.testOcclusion = qtrue;
1472 + trace.forceSunlight = qfalse;
1473 + trace.twoSided = qtrue;
1474 + trace.recvShadows = lm->recvShadows;
1475 + trace.numSurfaces = lm->numLightSurfaces;
1476 + trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1477 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1478 + trace.testAll = qfalse;
1479 + trace.distance = 1024;
1481 + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1482 + //trace.twoSided = qfalse;
1483 + for( i = 0; i < trace.numSurfaces; i++ )
1486 + info = &surfaceInfos[ trace.surfaces[ i ] ];
1488 + /* check twosidedness */
1489 + if( info->si->twoSided )
1491 + trace.twoSided = qtrue;
1497 + for( y = 0; y < lm->sh; y++ )
1499 + for( x = 0; x < lm->sw; x++ )
1502 + cluster = SUPER_CLUSTER( x, y );
1503 + origin = SUPER_ORIGIN( x, y );
1504 + normal = SUPER_NORMAL( x, y );
1505 + floodlight = SUPER_FLOODLIGHT( x, y );
1507 + /* set default dirt */
1508 + *floodlight = 0.0f;
1510 + /* only look at mapped luxels */
1511 + if( *cluster < 0 )
1514 + /* copy to trace */
1515 + trace.cluster = *cluster;
1516 + VectorCopy( origin, trace.origin );
1517 + VectorCopy( normal, trace.normal );
1522 + *floodlight = FloodLightForSample( &trace );
1526 + /* testing no filtering */
1529 + /* filter "dirt" */
1530 + for( y = 0; y < lm->sh; y++ )
1532 + for( x = 0; x < lm->sw; x++ )
1535 + cluster = SUPER_CLUSTER( x, y );
1536 + floodlight = SUPER_FLOODLIGHT( x, y );
1538 + /* filter dirt by adjacency to unmapped luxels */
1539 + average = *floodlight;
1541 + for( sy = (y - 1); sy <= (y + 1); sy++ )
1543 + if( sy < 0 || sy >= lm->sh )
1546 + for( sx = (x - 1); sx <= (x + 1); sx++ )
1548 + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1551 + /* get neighboring luxel */
1552 + cluster = SUPER_CLUSTER( sx, sy );
1553 + floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1554 + if( *cluster < 0 || *floodlight2 <= 0.0f )
1558 + average += *floodlight2;
1563 + if( samples <= 0.0f )
1568 + if( samples <= 0.0f )
1572 + *floodlight = average / samples;
1578 +FloodLightForSample()
1579 +calculates floodlight value for a given sample
1580 +once again, kudos to the dirtmapping coder
1582 +float FloodLightForSample( trace_t *trace )
1586 + float contribution;
1588 + float gatherLight, outLight;
1589 + vec3_t normal, worldUp, myUp, myRt, direction, displacement;
1597 + if( trace == NULL || trace->cluster < 0 )
1602 + dd = floodlightDistance;
1603 + VectorCopy( trace->normal, normal );
1605 + /* check if the normal is aligned to the world-up */
1606 + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1608 + if( normal[ 2 ] == 1.0f )
1610 + VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1611 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1613 + else if( normal[ 2 ] == -1.0f )
1615 + VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1616 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1621 + VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1622 + CrossProduct( normal, worldUp, myRt );
1623 + VectorNormalize( myRt, myRt );
1624 + CrossProduct( myRt, normal, myUp );
1625 + VectorNormalize( myUp, myUp );
1628 + /* iterate through ordered vectors */
1629 + for( i = 0; i < numFloodVectors; i++ )
1631 + if (floodlight_lowquality==qtrue)
1633 + if (rand()%10 != 0 ) continue;
1638 + /* transform vector into tangent space */
1639 + direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1640 + direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1641 + direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1643 + /* set endpoint */
1644 + VectorMA( trace->origin, dd, direction, trace->end );
1646 + //VectorMA( trace->origin, 1, direction, trace->origin );
1648 + SetupTrace( trace );
1650 + TraceLine( trace );
1653 + if (trace->compileFlags & C_SKY )
1655 + contribution=1.0f;
1657 + else if ( trace->opaque )
1659 + VectorSubtract( trace->hit, trace->origin, displacement );
1660 + d=VectorLength( displacement );
1662 + // d=trace->distance;
1663 + //if (d>256) gatherDirt+=1;
1664 + contribution=d/dd;
1665 + if (contribution>1) contribution=1.0f;
1667 + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1670 + gatherLight+=contribution;
1674 + if( gatherLight <= 0.0f )
1680 + gatherLight/=(sub);
1682 + outLight=gatherLight;
1683 + if( outLight > 1.0f )
1686 + /* return to sender */
1690 Index: tools/quake3/q3map2/light.c
1691 ===================================================================
1692 --- tools/quake3/q3map2/light.c (revision 191)
1693 +++ tools/quake3/q3map2/light.c (working copy)
1694 @@ -1378,6 +1378,56 @@
1698 + /////// Floodlighting for point //////////////////
1699 + //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1705 + col[0]=col[1]=col[2]=floodlightIntensity;
1709 + trace.testOcclusion = qtrue;
1710 + trace.forceSunlight = qfalse;
1711 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1712 + trace.testAll = qtrue;
1716 + if (q==0) //upper hemisphere
1718 + trace.normal[0]=0;
1719 + trace.normal[1]=0;
1720 + trace.normal[2]=1;
1722 + else //lower hemisphere
1724 + trace.normal[0]=0;
1725 + trace.normal[1]=0;
1726 + trace.normal[2]=-1;
1729 + f = FloodLightForSample(&trace);
1731 + contributions[ numCon ].color[0]=col[0]*f;
1732 + contributions[ numCon ].color[1]=col[1]*f;
1733 + contributions[ numCon ].color[2]=col[2]*f;
1735 + contributions[ numCon ].dir[0]=dir[0];
1736 + contributions[ numCon ].dir[1]=dir[1];
1737 + contributions[ numCon ].dir[2]=dir[2];
1739 + contributions[ numCon ].style = 0;
1741 + /* push average direction around */
1742 + addSize = VectorLength( col );
1743 + VectorMA( gp->dir, addSize, dir, gp->dir );
1746 + /////////////////////
1748 /* normalize to get primary light direction */
1749 VectorNormalize( gp->dir, gp->dir );
1751 @@ -1661,6 +1711,12 @@
1752 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1755 + /* floodlight them up */
1758 + Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1759 + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1762 /* ydnar: set up light envelopes */
1763 SetupEnvelopes( qfalse, fast );
1764 @@ -1703,6 +1759,7 @@
1767 VectorClear( ambientColor );
1768 + floodlighty = false;
1770 /* generate diffuse lights */
1772 @@ -2191,6 +2256,21 @@
1774 Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
1776 + else if( !strcmp( argv[ i ], "-floodlight" ) )
1778 + floodlighty = qtrue;
1779 + Sys_Printf( "FloodLighting enabled\n" );
1781 + else if( !strcmp( argv[ i ], "-debugnormals" ) )
1783 + debugnormals = qtrue;
1784 + Sys_Printf( "DebugNormals enabled\n" );
1786 + else if( !strcmp( argv[ i ], "-lowquality" ) )
1788 + floodlight_lowquality = qtrue;
1789 + Sys_Printf( "Low Quality FloodLighting enabled\n" );
1792 /* r7: dirtmapping */
1793 else if( !strcmp( argv[ i ], "-dirty" ) )
1794 @@ -2279,6 +2359,7 @@
1795 /* ydnar: set up optimization */
1798 + SetupFloodLight();
1799 SetupSurfaceLightmaps();
1801 /* initialize the surface facet tracing */
1802 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1803 ===================================================================
1804 --- tools/quake3/q3map2/lightmaps_ydnar.c (revision 191)
1805 +++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy)
1806 @@ -414,6 +414,12 @@
1807 lm->superNormals = safe_malloc( size );
1808 memset( lm->superNormals, 0, size );
1810 + /* allocate floodlight map storage */
1811 + size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1812 + if( lm->superFloodLight == NULL )
1813 + lm->superFloodLight = safe_malloc( size );
1814 + memset( lm->superFloodLight, 0, size );
1816 /* allocate cluster map storage */
1817 size = lm->sw * lm->sh * sizeof( int );
1818 if( lm->superClusters == NULL )
1819 Index: tools/quake3/q3map2/q3map2.h
1820 ===================================================================
1821 --- tools/quake3/q3map2/q3map2.h (revision 191)
1822 +++ tools/quake3/q3map2/q3map2.h (working copy)
1824 #define SUPER_NORMAL_SIZE 4
1825 #define SUPER_DELUXEL_SIZE 3
1826 #define BSP_DELUXEL_SIZE 3
1827 +#define SUPER_FLOODLIGHT_SIZE 1
1829 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1830 #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1832 #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1833 #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1834 #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */
1835 +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )
1839 @@ -1392,6 +1395,7 @@
1841 float *superDeluxels; /* average light direction */
1843 + float *superFloodLight;
1847 @@ -1704,6 +1708,10 @@
1848 float DirtForSample( trace_t *trace );
1849 void DirtyRawLightmap( int num );
1851 +void SetupFloodLight();
1852 +float FloodLightForSample( trace_t *trace );
1853 +void FloodLightRawLightmap( int num );
1855 void IlluminateRawLightmap( int num );
1856 void IlluminateVertexes( int num );
1858 @@ -2098,6 +2106,13 @@
1859 Q_EXTERN float dirtScale Q_ASSIGN( 1.0f );
1860 Q_EXTERN float dirtGain Q_ASSIGN( 1.0f );
1862 +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse );
1863 +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse );
1864 +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse );
1865 +Q_EXTERN vec3_t floodlightRGB;
1866 +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 );
1867 +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 );
1869 Q_EXTERN qboolean dump Q_ASSIGN( qfalse );
1870 Q_EXTERN qboolean debug Q_ASSIGN( qfalse );
1871 Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse );
1872 Index: tools/quake3/q3map2/game_ja.h
1873 ===================================================================
1874 --- tools/quake3/q3map2/game_ja.h (revision 191)
1875 +++ tools/quake3/q3map2/game_ja.h (working copy)
1877 qfalse, /* wolf lighting model? */
1878 128, /* lightmap width/height */
1879 1.0f, /* lightmap gamma */
1880 + 1.0f, /* lightmap exposure */
1881 1.0f, /* lightmap compensate */
1882 "RBSP", /* bsp file prefix */
1883 1, /* bsp file version */
1884 Index: tools/quake3/q3map2/game_tremulous.h
1885 ===================================================================
1886 --- tools/quake3/q3map2/game_tremulous.h (revision 191)
1887 +++ tools/quake3/q3map2/game_tremulous.h (working copy)
1889 qfalse, /* wolf lighting model? */
1890 128, /* lightmap width/height */
1891 1.0f, /* lightmap gamma */
1892 + 1.0f, /* lightmap exposure */
1893 1.0f, /* lightmap compensate */
1894 "IBSP", /* bsp file prefix */
1895 46, /* bsp file version */
1896 Index: tools/quake3/q3map2/game_wolfet.h
1897 ===================================================================
1898 --- tools/quake3/q3map2/game_wolfet.h (revision 191)
1899 +++ tools/quake3/q3map2/game_wolfet.h (working copy)
1901 qtrue, /* wolf lighting model? */
1902 128, /* lightmap width/height */
1903 1.0f, /* lightmap gamma */
1904 + 1.0f, /* lightmap exposure */
1905 1.0f, /* lightmap compensate */
1906 "IBSP", /* bsp file prefix */
1907 47, /* bsp file version */
1908 Index: tools/quake3/q3map2/game_wolf.h
1909 ===================================================================
1910 --- tools/quake3/q3map2/game_wolf.h (revision 191)
1911 +++ tools/quake3/q3map2/game_wolf.h (working copy)
1913 qtrue, /* wolf lighting model? */
1914 128, /* lightmap width/height */
1915 1.0f, /* lightmap gamma */
1916 + 1.0f, /* lightmap exposure */
1917 1.0f, /* lightmap compensate */
1918 "IBSP", /* bsp file prefix */
1919 47, /* bsp file version */
1920 Index: tools/quake3/q3map2/game_sof2.h
1921 ===================================================================
1922 --- tools/quake3/q3map2/game_sof2.h (revision 191)
1923 +++ tools/quake3/q3map2/game_sof2.h (working copy)
1925 qfalse, /* wolf lighting model? */
1926 128, /* lightmap width/height */
1927 1.0f, /* lightmap gamma */
1928 + 1.0f, /* lightmap exposure */
1929 1.0f, /* lightmap compensate */
1930 "RBSP", /* bsp file prefix */
1931 1, /* bsp file version */
1932 Index: tools/quake3/q3map2/game_etut.h
1933 ===================================================================
1934 --- tools/quake3/q3map2/game_etut.h (revision 191)
1935 +++ tools/quake3/q3map2/game_etut.h (working copy)
1937 qfalse, /* wolf lighting model? */
1938 128, /* lightmap width/height */
1939 2.2f, /* lightmap gamma */
1940 + 1.0f, /* lightmap exposure */
1941 1.0f, /* lightmap compensate */
1942 "IBSP", /* bsp file prefix */
1943 47, /* bsp file version */
1944 Index: tools/quake3/q3map2/game_jk2.h
1945 ===================================================================
1946 --- tools/quake3/q3map2/game_jk2.h (revision 191)
1947 +++ tools/quake3/q3map2/game_jk2.h (working copy)
1949 qfalse, /* wolf lighting model? */
1950 128, /* lightmap width/height */
1951 1.0f, /* lightmap gamma */
1952 + 1.0f, /* lightmap exposure */
1953 1.0f, /* lightmap compensate */
1954 "RBSP", /* bsp file prefix */
1955 1, /* bsp file version */
1956 Index: tools/quake3/q3map2/game_qfusion.h
1957 ===================================================================
1958 --- tools/quake3/q3map2/game_qfusion.h (revision 191)
1959 +++ tools/quake3/q3map2/game_qfusion.h (working copy)
1961 qfalse, /* wolf lighting model? */
1962 512, /* lightmap width/height */
1963 1.0f, /* lightmap gamma */
1964 + 1.0f, /* lightmap exposure */
1965 1.0f, /* lightmap compensate */
1966 "FBSP", /* bsp file prefix */
1967 1, /* bsp file version */
1968 Index: tools/quake3/q3map2/game_tenebrae.h
1969 ===================================================================
1970 --- tools/quake3/q3map2/game_tenebrae.h (revision 191)
1971 +++ tools/quake3/q3map2/game_tenebrae.h (working copy)
1973 qfalse, /* wolf lighting model? */
1974 512, /* lightmap width/height */
1975 2.0f, /* lightmap gamma */
1976 + 1.0f, /* lightmap exposure */
1977 1.0f, /* lightmap compensate */
1978 "IBSP", /* bsp file prefix */
1979 46, /* bsp file version */
1980 Index: tools/quake3/q3map2/game_quake3.h
1981 ===================================================================
1982 --- tools/quake3/q3map2/game_quake3.h (revision 191)
1983 +++ tools/quake3/q3map2/game_quake3.h (working copy)
1985 qfalse, /* wolf lighting model? */
1986 128, /* lightmap width/height */
1987 1.0f, /* lightmap gamma */
1988 + 1.0f, /* lightmap exposure */
1989 1.0f, /* lightmap compensate */
1990 "IBSP", /* bsp file prefix */
1991 46, /* bsp file version */
1992 Index: tools/quake3/q3map2/game_ef.h
1993 ===================================================================
1994 --- tools/quake3/q3map2/game_ef.h (revision 191)
1995 +++ tools/quake3/q3map2/game_ef.h (working copy)
1997 qfalse, /* wolf lighting model? */
1998 128, /* lightmap width/height */
1999 1.0f, /* lightmap gamma */
2000 + 1.0f, /* lightmap exposure */
2001 1.0f, /* lightmap compensate */
2002 "IBSP", /* bsp file prefix */
2003 46, /* bsp file version */
2004 Index: tools/quake3/q3map2/light_ydnar.c
2005 ===================================================================
2006 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
2007 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
2015 /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
2018 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
2021 + if (lightmapExposure == 1)
2023 + /* clamp with color normalization */
2024 + max = sample[ 0 ];
2025 + if( sample[ 1 ] > max )
2026 + max = sample[ 1 ];
2027 + if( sample[ 2 ] > max )
2028 + max = sample[ 2 ];
2029 + if( max > 255.0f )
2030 + VectorScale( sample, (255.0f / max), sample );
2034 + if (lightmapExposure==0)
2036 + lightmapExposure=1.0f;
2038 + inv=1.f/lightmapExposure;
2041 + max = sample[ 0 ];
2042 + if( sample[ 1 ] > max )
2043 + max = sample[ 1 ];
2044 + if( sample[ 2 ] > max )
2045 + max = sample[ 2 ];
2047 + dif = (1- exp(-max * inv) ) * 255;
2065 - /* clamp with color normalization */
2066 - max = sample[ 0 ];
2067 - if( sample[ 1 ] > max )
2068 - max = sample[ 1 ];
2069 - if( sample[ 2 ] > max )
2070 - max = sample[ 2 ];
2071 - if( max > 255.0f )
2072 - VectorScale( sample, (255.0f / max), sample );
2074 /* compensate for ingame overbrighting/bitshifting */
2075 VectorScale( sample, (1.0f / lightmapCompensate), sample );
2077 Index: tools/quake3/q3map2/light.c
2078 ===================================================================
2079 --- tools/quake3/q3map2/light.c (revision 191)
2080 +++ tools/quake3/q3map2/light.c (working copy)
2081 @@ -1836,6 +1893,14 @@
2085 + else if( !strcmp( argv[ i ], "-exposure" ) )
2087 + f = atof( argv[ i + 1 ] );
2088 + lightmapExposure = f;
2089 + Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2093 else if( !strcmp( argv[ i ], "-compensate" ) )
2095 f = atof( argv[ i + 1 ] );
2096 Index: tools/quake3/q3map2/q3map2.h
2097 ===================================================================
2098 --- tools/quake3/q3map2/q3map2.h (revision 191)
2099 +++ tools/quake3/q3map2/q3map2.h (working copy)
2101 qboolean wolfLight; /* when true, lights work like wolf q3map */
2102 int lightmapSize; /* bsp lightmap width/height */
2103 float lightmapGamma; /* default lightmap gamma */
2104 + float lightmapExposure; /* default lightmap exposure */
2105 float lightmapCompensate; /* default lightmap compensate value */
2106 char *bspIdent; /* 4-letter bsp file prefix */
2107 int bspVersion; /* bsp version to use */
2108 @@ -2117,6 +2132,7 @@
2110 /* ydnar: lightmap gamma/compensation */
2111 Q_EXTERN float lightmapGamma Q_ASSIGN( 1.0f );
2112 +Q_EXTERN float lightmapExposure Q_ASSIGN( 1.0f );
2113 Q_EXTERN float lightmapCompensate Q_ASSIGN( 1.0f );
2115 /* ydnar: for runtime tweaking of falloff tolerance */
2116 Index: tools/quake3/q3map2/light_ydnar.c
2117 ===================================================================
2118 --- tools/quake3/q3map2/light_ydnar.c (revision 191)
2119 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
2122 #define BOGUS_NUDGE -99999.0f
2124 -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 ] )
2125 +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 ] )
2127 int i, x, y, numClusters, *clusters, pointCluster, *cluster;
2128 float *luxel, *origin, *normal, d, lightmapSampleOffset;
2129 @@ -392,6 +428,12 @@
2133 + vec3_t cverts[ 3 ];
2135 + vec4_t sideplane, hostplane;
2140 static float nudges[][ 2 ] =
2142 @@ -485,6 +527,51 @@
2143 /* non axial lightmap projection (explicit xyz) */
2145 VectorCopy( dv->xyz, origin );
2147 + //////////////////////
2148 + //27's test to make sure samples stay within the triangle boundaries
2149 + //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
2150 + //2) if it does, nudge it onto the correct side.
2152 + if (worldverts!=NULL)
2156 + VectorCopy(worldverts[j],cverts[j]);
2158 + PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2164 + //build plane using 2 edges and a normal
2167 + VectorCopy(cverts[next],temp);
2168 + VectorAdd(temp,hostplane,temp);
2169 + PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2171 + //planetest sample point
2172 + e=DotProduct(origin,sideplane);
2177 + //VectorClear(origin);
2178 + //Move the sample point back inside triangle bounds
2179 + origin[0]-=sideplane[0]*(e+1);
2180 + origin[1]-=sideplane[1]*(e+1);
2181 + origin[2]-=sideplane[2]*(e+1);
2183 + VectorClear(origin);
2190 + ////////////////////////
2192 /* planar surfaces have precalculated lightmap vectors for nudging */
2193 if( lm->plane != NULL )
2194 @@ -516,8 +603,13 @@
2196 origin[ lm->axisNum ] += lightmapSampleOffset;
2198 + VectorCopy(origin,origintwo);
2199 + origintwo[0]+=vecs[2][0];
2200 + origintwo[1]+=vecs[2][1];
2201 + origintwo[2]+=vecs[2][2];
2204 - pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2205 + pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2207 /* another retarded hack, storing nudge count in luxel[ 1 ] */
2209 @@ -533,14 +625,14 @@
2210 for( i = 0; i < 3; i++ )
2212 /* set nudged point*/
2213 - nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2214 + nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2218 /* get pvs cluster */
2219 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2220 - if( pointCluster >= 0 )
2221 - VectorCopy( nudged, origin );
2222 + //if( pointCluster >= 0 )
2223 + // VectorCopy( nudged, origin );
2229 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2230 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2231 - if( pointCluster >= 0 )
2232 - VectorCopy( nudged, origin );
2233 + //if( pointCluster >= 0 )
2234 + // VectorCopy( nudged, origin );
2239 than the distance between two luxels (thanks jc :)
2242 -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 ] )
2243 +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 ] )
2245 bspDrawVert_t mid, *dv2[ 3 ];
2249 /* split the longest edge and map it */
2250 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2251 - MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2252 + MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2254 /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2255 //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2256 @@ -653,12 +745,12 @@
2257 /* recurse to first triangle */
2258 VectorCopy( dv, dv2 );
2260 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2261 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2263 /* recurse to second triangle */
2264 VectorCopy( dv, dv2 );
2265 dv2[ (max + 1) % 3 ] = ∣
2266 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2267 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2274 vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2275 + vec3_t worldverts[ 3 ];
2278 /* get plane if possible */
2279 @@ -699,16 +792,20 @@
2283 + VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2284 + VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2285 + VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2287 /* map the vertexes */
2288 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2289 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2290 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2291 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2292 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2293 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2295 /* 2002-11-20: prefer axial triangle edges */
2298 /* subdivide the triangle */
2299 - MapTriangle_r( lm, info, dv, plane, stv, ttv );
2300 + MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2305 dv2[ 2 ] = dv[ (i + 1) % 3 ];
2307 /* map the degenerate triangle */
2308 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2309 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2314 LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2316 /* map the vertexes */
2317 - MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2318 - MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2319 + MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2320 + MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2324 @@ -878,10 +975,10 @@
2327 /* map the vertexes */
2328 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2329 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2330 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2331 - MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2332 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2333 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2334 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2335 + MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2337 /* subdivide the quad */
2338 MapQuad_r( lm, info, dv, plane, stv, ttv );
2339 @@ -1173,7 +1270,7 @@
2342 /* map the fake vert */
2343 - MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2344 + MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2348 @@ -1963,22 +2062,32 @@
2349 deluxel = SUPER_DELUXEL( x, y );
2350 origin = SUPER_ORIGIN( x, y );
2351 normal = SUPER_NORMAL( x, y );
2353 - /* set contribution count */
2354 - lightLuxel[ 3 ] = 1.0f;
2357 - trace.cluster = *cluster;
2358 - VectorCopy( origin, trace.origin );
2359 - VectorCopy( normal, trace.normal );
2361 - /* get light for this sample */
2362 - LightContributionToSample( &trace );
2363 - VectorCopy( trace.color, lightLuxel );
2365 - /* add to count */
2366 - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2368 + ////////// 27's temp hack for testing edge clipping ////
2369 + if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2371 + lightLuxel[ 1 ] = 255;
2372 + lightLuxel[ 3 ] = 1.0f;
2377 + /* set contribution count */
2378 + lightLuxel[ 3 ] = 1.0f;
2381 + trace.cluster = *cluster;
2382 + VectorCopy( origin, trace.origin );
2383 + VectorCopy( normal, trace.normal );
2385 + /* get light for this sample */
2386 + LightContributionToSample( &trace );
2387 + VectorCopy( trace.color, lightLuxel );
2389 + /* add to count */
2390 + if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2394 /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2396 Index: tools/quake3/q3map2/q3map2.h
2397 ===================================================================
2398 --- tools/quake3/q3map2/q3map2.h (revision 193)
2399 +++ tools/quake3/q3map2/q3map2.h (working copy)
2404 -#define Q3MAP_VERSION "2.5.17"
2405 -#define Q3MAP_MOTD "Last one turns the lights off"
2406 +#define Q3MAP_VERSION "2.5.17-div0-obj-UTpicomodelase-UTpicomodelnormals-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
2407 +#define Q3MAP_MOTD "Blackhole Box ate all the light"
2411 Index: include/version.default
2412 ===================================================================
2413 --- include/version.default (revision 193)
2414 +++ include/version.default (working copy)
2417 +1.5.0-div0-obj-UTpicomodelase-UTpicomodelnormals-modelnormals-nexuizfixes