From 7ea8bd120e4807485cbfef41f0f0e1c56acf7df0 Mon Sep 17 00:00:00 2001 From: div0 Date: Wed, 2 Jul 2008 10:48:29 +0000 Subject: [PATCH] fix patches for ZeroRadiant git-svn-id: svn://svn.icculus.org/nexuiz/trunk@3758 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- .../gtkradiant-nexuiz-patchset.diff | 1062 ++--------------- misc/gtkradiant/mergepatches.sh | 10 +- .../both-UTpicomodelase.diff | 0 .../both-UTpicomodelnormals.diff | 0 .../singlepatches-radiant15/both-obj.diff | 83 ++ .../gtkradiant-modelnormals.diff | 0 .../gtkradiant-nexuizfixes.diff | 0 .../q3map2-UTavgcolorfix.diff | 20 + .../q3map2-UTfloodlight.diff | 595 +++++++++ .../q3map2-UTlmexposure.diff | 0 .../q3map2-UTtrianglecheck.diff | 280 +++++ .../q3map2-decomptexcoords.diff | 264 ++++ .../q3map2-snapplane.diff | 292 +++++ misc/gtkradiant/singlepatches/both-obj.diff | 32 +- .../singlepatches/q3map2-UTavgcolorfix.diff | 4 +- .../singlepatches/q3map2-UTfloodlight.diff | 94 +- .../singlepatches/q3map2-UTtrianglecheck.diff | 34 +- .../singlepatches/q3map2-decomptexcoords.diff | 18 +- .../singlepatches/q3map2-snapplane.diff | 25 +- 19 files changed, 1761 insertions(+), 1052 deletions(-) rename misc/gtkradiant/{singlepatches => singlepatches-radiant15}/both-UTpicomodelase.diff (100%) rename misc/gtkradiant/{singlepatches => singlepatches-radiant15}/both-UTpicomodelnormals.diff (100%) create mode 100644 misc/gtkradiant/singlepatches-radiant15/both-obj.diff rename misc/gtkradiant/{singlepatches => singlepatches-radiant15}/gtkradiant-modelnormals.diff (100%) rename misc/gtkradiant/{singlepatches => singlepatches-radiant15}/gtkradiant-nexuizfixes.diff (100%) create mode 100644 misc/gtkradiant/singlepatches-radiant15/q3map2-UTavgcolorfix.diff create mode 100644 misc/gtkradiant/singlepatches-radiant15/q3map2-UTfloodlight.diff rename misc/gtkradiant/{singlepatches => singlepatches-radiant15}/q3map2-UTlmexposure.diff (100%) create mode 100644 misc/gtkradiant/singlepatches-radiant15/q3map2-UTtrianglecheck.diff create mode 100644 misc/gtkradiant/singlepatches-radiant15/q3map2-decomptexcoords.diff create mode 100644 misc/gtkradiant/singlepatches-radiant15/q3map2-snapplane.diff diff --git a/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff b/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff index c6f590e0f..8243fa667 100644 --- a/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff +++ b/misc/gtkradiant/gtkradiant-nexuiz-patchset.diff @@ -10,9 +10,21 @@ before committing new singlepatches! Index: libs/picomodel/pm_obj.c =================================================================== ---- libs/picomodel/pm_obj.c (revision 193) +--- libs/picomodel/pm_obj.c (revision 290) +++ libs/picomodel/pm_obj.c (working copy) -@@ -265,7 +265,7 @@ +@@ -215,10 +215,9 @@ + } + } + +-#if 0 + static int _obj_mtl_load( picoModel_t *model ) + { +- //picoShader_t *curShader = NULL; ++ picoShader_t *curShader = NULL; + picoParser_t *p; + picoByte_t *mtlBuffer; + int mtlBufSize; +@@ -266,7 +265,7 @@ /* get next token in material file */ if (_pico_parse( p,1 ) == NULL) break; @@ -21,7 +33,7 @@ Index: libs/picomodel/pm_obj.c /* skip empty lines */ if (p->token == NULL || !strlen( p->token )) -@@ -307,6 +307,7 @@ +@@ -308,6 +307,7 @@ else if (!_pico_stricmp(p->token,"map_kd")) { char *mapName; @@ -29,7 +41,7 @@ Index: libs/picomodel/pm_obj.c /* pointer to current shader must be valid */ if (curShader == NULL) -@@ -321,6 +322,10 @@ +@@ -322,6 +322,10 @@ _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine); _obj_mtl_error_return; } @@ -40,7 +52,15 @@ Index: libs/picomodel/pm_obj.c /* set shader map name */ PicoSetShaderMapName( shader,mapName ); } -@@ -521,7 +526,7 @@ +@@ -478,7 +482,6 @@ + /* return with success */ + return 1; + } +-#endif + + /* _obj_load: + * loads a wavefront obj model file. +@@ -523,7 +526,7 @@ PicoSetModelFileName( model,fileName ); /* try loading the materials; we don't handle the result */ @@ -49,7 +69,7 @@ Index: libs/picomodel/pm_obj.c _obj_mtl_load( model ); #endif -@@ -830,6 +835,41 @@ +@@ -832,6 +835,41 @@ curVertex += max; } } @@ -91,618 +111,11 @@ Index: libs/picomodel/pm_obj.c /* skip unparsed rest of line and continue */ _pico_parse_skip_rest( p ); } -Index: libs/picomodel/pm_ase.c -=================================================================== ---- libs/picomodel/pm_ase.c (revision 191) -+++ libs/picomodel/pm_ase.c (working copy) -@@ -32,6 +32,7 @@ - - ----------------------------------------------------------------------------- */ - -+void Sys_Printf (const char *format, ...); - - /* marker */ - #define PM_ASE_C -@@ -253,7 +254,6 @@ - struct aseVertex_s - { - picoVec3_t xyz; -- picoVec3_t normal; - picoIndex_t id; - }; - -@@ -276,6 +276,8 @@ - picoIndex_t smoothingGroup; - picoIndex_t materialId; - picoIndex_t subMaterialId; -+ picoVec3_t facenormal; -+ picoVec3_t vertexnormal[3]; - }; - typedef aseFace_t* aseFacesIter_t; - -@@ -455,33 +457,157 @@ - - #endif - -+static int VectorCompareExtn( picoVec3_t n1, picoVec3_t n2, float epsilon ) -+{ -+ int i; -+ -+ -+ /* test */ -+ for( i= 0; i < 3; i++ ) -+ if( fabs( n1[ i ] - n2[ i ]) > epsilon ) -+ return -1; -+ return 1; -+} -+ -+#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]) -+ - 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 ) - { -- aseFacesIter_t i = faces, end = faces + numFaces; -- for(; i != end; ++i) -+ -+ picoVec3_t accum; -+ int index; -+ int counter; -+ aseFacesIter_t i = faces, end = faces + numFaces; -+ counter=0; -+ -+ //rebuild normals -+ for(i=faces; i != end; ++i) -+ { -+ -+ //&(*i).facenormal -+ //vec3_t v1, v2; -+ //VectorSubtract(va, vb, v1); -+ //VectorSubtract(vc, vb, v2); -+ //CrossProduct(v1, v2, out); -+ -+ picoVec3_t a,b,c; -+ picoVec3_t v1,v2,v3; -+ int j; -+ counter++; -+ for (j=0;j<3;j++) -+ { -+ a[j] = vertices[(*i).indices[0]].xyz[j]; -+ b[j] = vertices[(*i).indices[1]].xyz[j]; -+ c[j] = vertices[(*i).indices[2]].xyz[j]; -+ } -+ for (j=0;j<3;j++) -+ { -+ v1[j]=a[j]-b[j]; -+ v2[j]=c[j]-b[j]; -+ } -+ -+ CrossProductTemp(v1,v2,v3); -+ _pico_normalize_vec(v3); -+ (*i).facenormal[0]=v3[0]; -+ (*i).facenormal[1]=v3[1]; -+ (*i).facenormal[2]=v3[2]; -+ -+ -+ } -+ -+ -+ //if (counter>0) Sys_Printf( "Rebuilding %d Normals\n", counter * 3 ); -+ for(i=faces; i != end; ++i) - { -- /* look up the shader for the material/submaterial pair */ -+ /* look up the shader for the material/submaterial pair */ - aseSubMaterial_t* subMtl = _ase_get_submaterial_or_default( materials, (*i).materialId, (*i).subMaterialId ); -- if( subMtl == NULL ) -+ -+ if( subMtl == NULL ) - { - return; - } - - { - picoVec3_t* xyz[3]; -+ picoVec3_t *a[3]; - picoVec3_t* normal[3]; - picoVec2_t* st[3]; - picoColor_t* color[3]; - picoIndex_t smooth[3]; -- int j; -- /* we pull the data from the vertex, color and texcoord arrays using the face index data */ -- for ( j = 0 ; j < 3 ; j ++ ) -+ -+ int j,z; -+ -+ -+ -+ /* we pull the data from the vertex, color and texcoord arrays using the face index data */ -+ for ( j = 0 ; j < 3 ; j ++ ) - { -- xyz[j] = &vertices[(*i).indices[j]].xyz; -- normal[j] = &vertices[(*i).indices[j]].normal; -+ aseFacesIter_t q = faces; -+ aseFacesIter_t qend = faces + numFaces; -+ -+ xyz[j] = &vertices[(*i).indices[j]].xyz; -+ -+ // Use Face normal -+ normal[j] = &(*i).facenormal; -+ -+ -+ //Oooor we can use the smoothing group -+ -+ //Slow method, but testing -+ //Find All faces that use this vertex, average their facenormals. -+ // skip where smoothgroups both equal 0, or don't have any shared bits (x & y) -+ index=(*i).indices[j]; -+ -+// accum[0]=0; -+ // accum[1]=0; -+ // accum[2]=0; -+ accum[0]=(*i).facenormal[0]; -+ accum[1]=(*i).facenormal[1]; -+ accum[2]=(*i).facenormal[2]; -+ counter=1; -+ -+ -+ z=0; -+ for(; q != qend; ++q) -+ { -+ z++; -+ if (q==i) -+ continue; -+ // if ( (*q).indices[0]==index || (*q).indices[1]==index || (*q).indices[2]==index) -+ a[0]= &vertices[(*q).indices[0] ].xyz; -+ a[1]= &vertices[(*q).indices[1] ].xyz; -+ a[2]= &vertices[(*q).indices[2] ].xyz; -+ -+ if ( VectorCompareExtn(*a[0],*xyz[j],0.01f)>0 || -+ VectorCompareExtn(*a[1],*xyz[j],0.01f)>0 || -+ VectorCompareExtn(*a[2],*xyz[j],0.01f)>0 -+ ) -+ { -+ if ( (*i).smoothingGroup==0 && (*q).smoothingGroup ==0 ) -+ continue; -+ -+ if ( (*i).smoothingGroup & (*q).smoothingGroup ) -+ { -+ accum[0]+=(*q).facenormal[0]; -+ accum[1]+=(*q).facenormal[1]; -+ accum[2]+=(*q).facenormal[2]; -+ -+ counter++; -+ -+ } -+ } -+ } -+ _pico_normalize_vec(accum); -+ -+ (*i).vertexnormal[j][0]=accum[0]; -+ (*i).vertexnormal[j][1]=accum[1]; -+ (*i).vertexnormal[j][2]=accum[2]; -+ normal[j]=&(*i).vertexnormal[j]; -+ -+ - st[j] = &texcoords[(*i).indices[j + 3]].texcoord; -- -- if( colors != NULL && (*i).indices[j + 6] >= 0 ) -+ -+ if( colors != NULL && (*i).indices[j + 6] >= 0 ) - { - color[j] = &colors[(*i).indices[j + 6]].color; - } -@@ -490,30 +616,18 @@ - color[j] = &white; - } - -- smooth[j] = (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */ -+ smooth[j] = 0;// (vertices[(*i).indices[j]].id * (1 << 16)) + (*i).smoothingGroup; /* don't merge vertices */ - - } - - /* submit the triangle to the model */ - PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader, smooth ); - } -+ - } - } - --static void shadername_convert(char* shaderName) --{ -- /* unix-style path separators */ -- char* s = shaderName; -- for(; *s != '\0'; ++s) -- { -- if(*s == '\\') -- { -- *s = '/'; -- } -- } --} - -- - /* _ase_load: - * loads a 3dsmax ase model file. - */ -@@ -534,6 +648,9 @@ - int numColorVertices = 0; - int numColorVertexFaces = 0; - int vertexId = 0; -+ int currentVertexFace=0; -+ int currentVertexIndex=0; -+ int counter=0; - - aseMaterial_t* materials = NULL; - -@@ -610,10 +727,11 @@ - } - else if (!_pico_stricmp(p->token,"*mesh_numvertex")) - { -- if (!_pico_parse_int( p, &numVertices) ) -+ if (!_pico_parse_int( p, &numVertices) ) - _ase_error_return("Missing MESH_NUMVERTEX value"); - - vertices = _pico_calloc(numVertices, sizeof(aseVertex_t)); -+ currentVertexIndex=0; - } - else if (!_pico_stricmp(p->token,"*mesh_numfaces")) - { -@@ -621,6 +739,7 @@ - _ase_error_return("Missing MESH_NUMFACES value"); - - faces = _pico_calloc(numFaces, sizeof(aseFace_t)); -+ - } - else if (!_pico_stricmp(p->token,"*mesh_numtvertex")) - { -@@ -685,7 +804,20 @@ - - vertices[index].id = vertexId++; - } -- /* model mesh vertex normal */ -+ else if (!_pico_stricmp(p->token,"*mesh_facenormal")) -+ { -+ //Grab the faceindex for the next vertex normals. -+ if( numVertices == 0 ) -+ _ase_error_return("Vertex parse error (facenormals)"); -+ -+ if (!_pico_parse_int( p,¤tVertexFace )) -+ _ase_error_return("Vertex parse error"); -+ -+ if (!_pico_parse_vec( p,faces[currentVertexFace].facenormal )) -+ _ase_error_return("Vertex parse error"); -+ -+ } -+ /* model mesh vertex normal */ - else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) - { - int index; -@@ -696,10 +828,25 @@ - /* get vertex data (orig: index +y -x +z) */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Vertex parse error"); -- if (!_pico_parse_vec( p,vertices[index].normal )) -+ -+ //^^ Index is 'wrong' in .ase models. they reference the same vert index with multiple normals.. -+ // I've tried, this is a lost cause. Use the SG's -+ // -+ /* -+ -+ if (!_pico_parse_vec( p,vertices[counter].normal )) - _ase_error_return("Vertex parse error"); -+ vertices[counter].faceid=index; -+ counter++; -+ */ - } - /* model mesh face */ -+ else if (!_pico_stricmp(p->token,"*mesh_normals")) -+ { -+ // counter=0; //part of the above vertex normals fix -+ } -+ -+ /* model mesh face */ - else if (!_pico_stricmp(p->token,"*mesh_face")) - { - picoIndex_t indexes[3]; -@@ -736,8 +883,35 @@ - } - if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" )) - { -- _pico_parse_int ( p , &faces[index].smoothingGroup ); -- } -+ int total=0; -+ char* point; -+ char* start; -+ _pico_parse(p,0); -+ -+ point=p->token; -+ start=point; -+ faces[index].smoothingGroup=0; -+ -+ //Super dodgy comma delimited string parse -+ while (*point<'A') -+ { -+ if (*point<=32 || *point==',') -+ { -+ total=atoi(start); -+ if (total!=0) -+ { -+ faces[index].smoothingGroup+=1<token,"*MESH_MTLID" )) - { - _pico_parse_int ( p , &faces[index].subMaterialId ); -@@ -755,19 +929,19 @@ - int index; - - if( numVertices == 0 ) -- _ase_error_return("Texture Vertex parse error"); -+ _ase_error_return("Vertex parse error"); - - /* get uv vertex index */ -- if (!_pico_parse_int( p,&index ) || index >= numTextureVertices) -- _ase_error_return("Texture vertex parse error"); -+ if (!_pico_parse_int( p,&index )) -+ _ase_error_return("UV vertex parse error"); - - /* get uv vertex s */ - if (!_pico_parse_float( p,&texcoords[index].texcoord[0] )) -- _ase_error_return("Texture vertex parse error"); -+ _ase_error_return("UV vertex parse error"); - - /* get uv vertex t */ - if (!_pico_parse_float( p,&texcoords[index].texcoord[1] )) -- _ase_error_return("Texture vertex parse error"); -+ _ase_error_return("UV vertex parse error"); - - /* ydnar: invert t */ - texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ]; -@@ -831,6 +1005,13 @@ - - /* leave alpha alone since we don't get any data from the ASE format */ - colors[index].color[3] = 255; -+ -+ /* 27 hack, red as alpha */ -+ colors[index].color[3]=colors[index].color[0]; -+ colors[index].color[0]=255; -+ colors[index].color[1]=255; -+ colors[index].color[2]=255; -+ - } - /* model color face */ - else if (!_pico_stricmp(p->token,"*mesh_cface")) -@@ -900,7 +1081,6 @@ - { - /* set material name */ - _pico_first_token( materialName ); -- shadername_convert(materialName); - PicoSetShaderName( shader, materialName); - - /* set shader's transparency */ -@@ -1085,7 +1265,6 @@ - } - - /* set material name */ -- shadername_convert(materialName); - PicoSetShaderName( shader,materialName ); - - /* set shader's transparency */ -@@ -1115,8 +1294,18 @@ - char* p = mapname; - - /* convert to shader-name format */ -- shadername_convert(mapname); - { -+ /* unix-style path separators */ -+ char* s = mapname; -+ for(; *s != '\0'; ++s) -+ { -+ if(*s == '\\') -+ { -+ *s = '/'; -+ } -+ } -+ } -+ { - /* remove extension */ - char* last_period = strrchr(p, '.'); - if(last_period != NULL) -@@ -1125,14 +1314,32 @@ - } - } - -- /* find shader path */ -+ /* find game root */ - for(; *p != '\0'; ++p) - { -- if(_pico_strnicmp(p, "models/", 7) == 0 || _pico_strnicmp(p, "textures/", 9) == 0) -+ if(_pico_strnicmp(p, "quake", 5) == 0 || _pico_strnicmp(p, "doom", 4) == 0) - { - break; - } - } -+ /* root-relative */ -+ for(; *p != '\0'; ++p) -+ { -+ if(*p == '/') -+ { -+ ++p; -+ break; -+ } -+ } -+ /* game-relative */ -+ for(; *p != '\0'; ++p) -+ { -+ if(*p == '/') -+ { -+ ++p; -+ break; -+ } -+ } - - if(*p != '\0') - { -Index: libs/picomodel/picomodel.c -=================================================================== ---- libs/picomodel/picomodel.c (revision 191) -+++ libs/picomodel/picomodel.c (working copy) -@@ -295,10 +295,7 @@ - model = PicoModuleLoadModel(module, fileName, buffer, bufSize, frameNum); - } - -- if(model != 0) -- { -- _pico_free(buffer); -- } -+ _pico_free(buffer); - - /* return */ - return model; -@@ -1573,6 +1570,7 @@ - { - int i, j; - -+// Sys_Printf(" %f %f %f\n", normal[0] , normal[1] , normal[2] ); - - /* dummy check */ - if( surface == NULL || surface->numVertexes <= 0 ) -@@ -1861,13 +1859,10 @@ - typedef picoVec3_t* picoNormalIter_t; - typedef picoIndex_t* picoIndexIter_t; - --#define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1 -- - void _pico_triangles_generate_weighted_normals(picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals) - { - for(; first != end; first += 3) - { --#if (THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL) - picoVec3_t weightedNormal; - { - float* a = xyz[*(first + 0)]; -@@ -1878,24 +1873,11 @@ - _pico_subtract_vec( c, a, ca ); - _pico_cross_vec( ca, ba, weightedNormal ); - } --#endif - { - int j = 0; - for(; j < 3; ++j) - { - float* normal = normals[*(first + j)]; --#if (!THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL) -- picoVec3_t weightedNormal; -- { -- float* a = xyz[*(first + ((j + 0) % 3))]; -- float* b = xyz[*(first + ((j + 1) % 3))]; -- float* c = xyz[*(first + ((j + 2) % 3))]; -- picoVec3_t ba, ca; -- _pico_subtract_vec( b, a, ba ); -- _pico_subtract_vec( c, a, ca ); -- _pico_cross_vec( ca, ba, weightedNormal ); -- } --#endif - _pico_add_vec(weightedNormal, normal, normal); - } - } -@@ -1941,7 +1923,8 @@ - { - for(; first != last; ++first, ++generated) - { -- if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated)) -+ //27 - fix for badly generated normals thing. -+ // if(!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated)) - { - _pico_copy_vec(*generated, *first); - } -@@ -1954,10 +1937,11 @@ - - _pico_normals_zero(normals, normals + surface->numVertexes); - -+ //Just build standard no sg normals for now - _pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz, normals); - _pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes); - -- _pico_normals_normalize(normals, normals + surface->numVertexes); -+ _pico_normals_normalize(normals, normals + surface->numVertexes); - - _pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals); - -@@ -2261,7 +2245,7 @@ - int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface ); - - /* get the index of the vertex that we're going to store at newVertIndex */ -- vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]); -+ vertDataIndex = -1;// PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i], smoothingGroup[i]); - - /* the vertex wasn't found, so create a new vertex in the pool from the data we have */ - if ( vertDataIndex == -1 ) -@@ -2290,3 +2274,5 @@ - PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex ); - } - } -+ -+ -Index: plugins/model/model.cpp -=================================================================== ---- plugins/model/model.cpp (revision 193) -+++ plugins/model/model.cpp (working copy) -@@ -123,14 +123,27 @@ - } - glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex); - glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data()); -+ - #if defined(_DEBUG) -+ GLfloat modelview[16]; -+ glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // I know this is slow as hell, but hey - we're in _DEBUG -+ Matrix4 modelview_inv( -+ modelview[0], modelview[1], modelview[2], modelview[3], -+ modelview[4], modelview[5], modelview[6], modelview[7], -+ modelview[8], modelview[9], modelview[10], modelview[11], -+ modelview[12], modelview[13], modelview[14], modelview[15]); -+ matrix4_full_invert(modelview_inv); -+ Matrix4 modelview_inv_transposed = matrix4_transposed(modelview_inv); -+ - glBegin(GL_LINES); - - for(Array::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i) - { -- Vector3 normal = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal3f_to_vector3((*i).normal), 8)); -+ Vector3 normal = normal3f_to_vector3((*i).normal); -+ normal = matrix4_transformed_direction(modelview_inv, vector3_normalised(matrix4_transformed_direction(modelview_inv_transposed, normal))); // do some magic -+ Vector3 normalTransformed = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal, 8)); - glVertex3fv(vertex3f_to_array((*i).vertex)); -- glVertex3fv(vector3_to_array(normal)); -+ glVertex3fv(vector3_to_array(normalTransformed)); - } - glEnd(); - #endif -Index: games/NexuizPack/games/nexuiz.game -=================================================================== ---- games/NexuizPack/games/nexuiz.game (revision 26) -+++ games/NexuizPack/games/nexuiz.game (working copy) -@@ -17,7 +17,7 @@ - shaderpath="scripts" - archivetypes="pk3" - texturetypes="tga jpg png" -- modeltypes="md3 mdl md2 ase" -+ modeltypes="md3 mdl md2 ase obj" - maptypes="mapq3" - shaders="quake3" - entityclass="quake3" Index: tools/quake3/q3map2/convert_map.c =================================================================== ---- tools/quake3/q3map2/convert_map.c (revision 191) +--- tools/quake3/q3map2/convert_map.c (revision 290) +++ tools/quake3/q3map2/convert_map.c (working copy) -@@ -46,6 +46,105 @@ +@@ -45,6 +45,105 @@ #define SNAP_FLOAT_TO_INT 4 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT) @@ -808,7 +221,7 @@ Index: tools/quake3/q3map2/convert_map.c static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) { int i, j; -@@ -54,12 +153,17 @@ +@@ -53,12 +152,17 @@ bspShader_t *shader; char *texture; bspPlane_t *plane; @@ -826,7 +239,7 @@ Index: tools/quake3/q3map2/convert_map.c /* clear out build brush */ for( i = 0; i < buildBrush->numsides; i++ ) -@@ -109,9 +213,88 @@ +@@ -108,9 +212,88 @@ /* get build side */ buildSide = &buildBrush->sides[ i ]; @@ -915,7 +328,7 @@ Index: tools/quake3/q3map2/convert_map.c /* get texture name */ if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) -@@ -130,14 +313,21 @@ +@@ -129,14 +312,21 @@ /* print brush side */ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ @@ -941,11 +354,11 @@ Index: tools/quake3/q3map2/convert_map.c Index: tools/quake3/q3map2/main.c =================================================================== ---- tools/quake3/q3map2/main.c (revision 191) +--- tools/quake3/q3map2/main.c (revision 290) +++ tools/quake3/q3map2/main.c (working copy) -@@ -541,6 +541,18 @@ - Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); - } +@@ -276,6 +276,18 @@ + else + Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); } + else if( !strcmp( argv[ i ], "-ne" ) ) + { @@ -964,9 +377,9 @@ Index: tools/quake3/q3map2/main.c /* clean up map name */ Index: tools/quake3/q3map2/model.c =================================================================== ---- tools/quake3/q3map2/model.c (revision 193) +--- tools/quake3/q3map2/model.c (revision 290) +++ tools/quake3/q3map2/model.c (working copy) -@@ -222,6 +222,8 @@ +@@ -221,6 +221,8 @@ byte *color; picoIndex_t *indexes; remap_t *rm, *glob; @@ -975,7 +388,7 @@ Index: tools/quake3/q3map2/model.c /* get model */ -@@ -398,9 +400,8 @@ +@@ -399,9 +401,8 @@ /* ydnar: giant hack land: generate clipping brushes for model triangles */ if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */ { @@ -1188,32 +601,27 @@ Index: tools/quake3/q3map2/model.c } Index: tools/quake3/q3map2/map.c =================================================================== ---- tools/quake3/q3map2/map.c (revision 193) +--- tools/quake3/q3map2/map.c (revision 290) +++ tools/quake3/q3map2/map.c (working copy) -@@ -184,7 +184,7 @@ +@@ -183,9 +183,15 @@ snaps a plane to normal/distance epsilons */ -void SnapPlane( vec3_t normal, vec_t *dist ) +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center ) { - // SnapPlane disabled by LordHavoc because it often messes up collision - // brushes made from triangles of embedded models, and it has little effect -@@ -193,7 +193,13 @@ - SnapPlane reenabled by namespace because of multiple reports of - q3map2-crashes which were triggered by this patch. - */ +- SnapNormal( normal ); + // div0: ensure the point "center" stays on the plane (actually, this + // rotates the plane around the point center). + // if center lies on the plane, it is guaranteed to stay on the plane by + // this fix. + vec_t centerDist = DotProduct(normal, center); - SnapNormal( normal ); ++ SnapNormal( normal ); + *dist += (DotProduct(normal, center) - centerDist); if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) *dist = Q_rint( *dist ); -@@ -207,7 +213,7 @@ +@@ -199,7 +205,7 @@ must be within an epsilon distance of the plane */ @@ -1222,7 +630,7 @@ Index: tools/quake3/q3map2/map.c #ifdef USE_HASHING -@@ -215,10 +221,14 @@ +@@ -207,10 +213,14 @@ int i, j, hash, h; plane_t *p; vec_t d; @@ -1239,7 +647,7 @@ Index: tools/quake3/q3map2/map.c hash = (PLANE_HASHES - 1) & (int) fabs( dist ); /* search the border bins as well */ -@@ -259,7 +269,13 @@ +@@ -251,7 +261,13 @@ plane_t *p; @@ -1256,9 +664,9 @@ Index: tools/quake3/q3map2/map.c if( PlaneEqual( p, normal, dist ) ) Index: tools/quake3/q3map2/shaders.c =================================================================== ---- tools/quake3/q3map2/shaders.c (revision 191) +--- tools/quake3/q3map2/shaders.c (revision 290) +++ tools/quake3/q3map2/shaders.c (working copy) -@@ -793,8 +793,14 @@ +@@ -747,8 +747,14 @@ } if( VectorLength( si->color ) <= 0.0f ) @@ -1276,21 +684,22 @@ Index: tools/quake3/q3map2/shaders.c Index: tools/quake3/q3map2/light_ydnar.c =================================================================== ---- tools/quake3/q3map2/light_ydnar.c (revision 191) +--- tools/quake3/q3map2/light_ydnar.c (revision 290) +++ tools/quake3/q3map2/light_ydnar.c (working copy) -@@ -1767,6 +1864,8 @@ +@@ -1449,6 +1449,8 @@ + vec3_t color, averageColor, averageDir, total, temp, temp2; float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; trace_t trace; - float stackLightLuxels[ STACK_LL_SIZE ]; + vec3_t flood; + float *floodlight; /* bail if this number exceeds the number of raw lightmaps */ -@@ -2223,6 +2332,78 @@ +@@ -1871,6 +1873,78 @@ + /* free light list */ FreeTraceLights( &trace ); - /* ----------------------------------------------------------------- ++ /* ----------------------------------------------------------------- + floodlight pass + ----------------------------------------------------------------- */ + @@ -1362,11 +771,10 @@ Index: tools/quake3/q3map2/light_ydnar.c + } + } + -+ /* ----------------------------------------------------------------- - dirt pass - ----------------------------------------------------------------- */ - -@@ -3587,7 +3768,320 @@ + /* ----------------------------------------------------------------- + filter pass + ----------------------------------------------------------------- */ +@@ -3123,7 +3197,320 @@ CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace ); } @@ -1689,9 +1097,9 @@ Index: tools/quake3/q3map2/light_ydnar.c + Index: tools/quake3/q3map2/light.c =================================================================== ---- tools/quake3/q3map2/light.c (revision 191) +--- tools/quake3/q3map2/light.c (revision 290) +++ tools/quake3/q3map2/light.c (working copy) -@@ -1378,6 +1378,56 @@ +@@ -1363,6 +1363,56 @@ break; } @@ -1748,9 +1156,9 @@ Index: tools/quake3/q3map2/light.c /* normalize to get primary light direction */ VectorNormalize( gp->dir, gp->dir ); -@@ -1661,6 +1711,12 @@ - RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap ); - } +@@ -1544,6 +1594,12 @@ + qboolean minVertex, minGrid; + const char *value; + /* floodlight them up */ + if( floodlighty ) @@ -1759,9 +1167,9 @@ Index: tools/quake3/q3map2/light.c + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap ); + } - /* ydnar: set up light envelopes */ - SetupEnvelopes( qfalse, fast ); -@@ -1703,6 +1759,7 @@ + /* ydnar: smooth normals */ + if( shade ) +@@ -1675,6 +1731,7 @@ /* flag bouncing */ bouncing = qtrue; VectorClear( ambientColor ); @@ -1769,9 +1177,9 @@ Index: tools/quake3/q3map2/light.c /* generate diffuse lights */ RadFreeLights(); -@@ -2191,6 +2256,21 @@ - cpmaHack = qtrue; - Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" ); +@@ -2114,6 +2171,21 @@ + loMem = qtrue; + Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" ); } + else if( !strcmp( argv[ i ], "-floodlight" ) ) + { @@ -1789,21 +1197,21 @@ Index: tools/quake3/q3map2/light.c + Sys_Printf( "Low Quality FloodLighting enabled\n" ); + } - /* r7: dirtmapping */ - else if( !strcmp( argv[ i ], "-dirty" ) ) -@@ -2279,6 +2359,7 @@ + else + Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); +@@ -2156,6 +2228,7 @@ + /* ydnar: set up optimization */ SetupBrushes(); - SetupDirt(); + SetupFloodLight(); SetupSurfaceLightmaps(); /* initialize the surface facet tracing */ Index: tools/quake3/q3map2/lightmaps_ydnar.c =================================================================== ---- tools/quake3/q3map2/lightmaps_ydnar.c (revision 191) +--- tools/quake3/q3map2/lightmaps_ydnar.c (revision 290) +++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy) -@@ -414,6 +414,12 @@ +@@ -413,6 +413,12 @@ lm->superNormals = safe_malloc( size ); memset( lm->superNormals, 0, size ); @@ -1818,25 +1226,25 @@ Index: tools/quake3/q3map2/lightmaps_ydnar.c if( lm->superClusters == NULL ) Index: tools/quake3/q3map2/q3map2.h =================================================================== ---- tools/quake3/q3map2/q3map2.h (revision 191) +--- tools/quake3/q3map2/q3map2.h (revision 290) +++ tools/quake3/q3map2/q3map2.h (working copy) -@@ -267,6 +267,7 @@ - #define SUPER_NORMAL_SIZE 4 +@@ -265,6 +265,7 @@ + #define SUPER_NORMAL_SIZE 3 #define SUPER_DELUXEL_SIZE 3 #define BSP_DELUXEL_SIZE 3 +#define SUPER_FLOODLIGHT_SIZE 1 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) -@@ -279,6 +280,7 @@ +@@ -273,6 +274,7 @@ + #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE)) #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE)) - #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */ +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) ) - - - -@@ -1392,6 +1395,7 @@ + #define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x))) + #define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) + #define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE)) +@@ -1364,6 +1366,7 @@ float *superDeluxels; /* average light direction */ float *bspDeluxels; @@ -1844,280 +1252,34 @@ Index: tools/quake3/q3map2/q3map2.h } rawLightmap_t; -@@ -1704,6 +1708,10 @@ - float DirtForSample( trace_t *trace ); - void DirtyRawLightmap( int num ); +@@ -1670,6 +1673,9 @@ + void SmoothNormals( void ); + void MapRawLightmap( int num ); +void SetupFloodLight(); +float FloodLightForSample( trace_t *trace ); +void FloodLightRawLightmap( int num ); -+ void IlluminateRawLightmap( int num ); void IlluminateVertexes( int num ); -@@ -2098,6 +2106,13 @@ - Q_EXTERN float dirtScale Q_ASSIGN( 1.0f ); - Q_EXTERN float dirtGain Q_ASSIGN( 1.0f ); - +@@ -2037,6 +2043,12 @@ + Q_EXTERN qboolean sunOnly; + Q_EXTERN int approximateTolerance Q_ASSIGN( 0 ); + Q_EXTERN qboolean noCollapse; +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse ); +Q_EXTERN vec3_t floodlightRGB; +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 ); +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 ); -+ - Q_EXTERN qboolean dump Q_ASSIGN( qfalse ); - Q_EXTERN qboolean debug Q_ASSIGN( qfalse ); - Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse ); -Index: tools/quake3/q3map2/game_ja.h -=================================================================== ---- tools/quake3/q3map2/game_ja.h (revision 191) -+++ tools/quake3/q3map2/game_ja.h (working copy) -@@ -67,6 +67,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "RBSP", /* bsp file prefix */ - 1, /* bsp file version */ -Index: tools/quake3/q3map2/game_tremulous.h -=================================================================== ---- tools/quake3/q3map2/game_tremulous.h (revision 191) -+++ tools/quake3/q3map2/game_tremulous.h (working copy) -@@ -70,6 +70,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 46, /* bsp file version */ -Index: tools/quake3/q3map2/game_wolfet.h -=================================================================== ---- tools/quake3/q3map2/game_wolfet.h (revision 191) -+++ tools/quake3/q3map2/game_wolfet.h (working copy) -@@ -66,6 +66,7 @@ - qtrue, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 47, /* bsp file version */ -Index: tools/quake3/q3map2/game_wolf.h -=================================================================== ---- tools/quake3/q3map2/game_wolf.h (revision 191) -+++ tools/quake3/q3map2/game_wolf.h (working copy) -@@ -129,6 +129,7 @@ - qtrue, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 47, /* bsp file version */ -Index: tools/quake3/q3map2/game_sof2.h -=================================================================== ---- tools/quake3/q3map2/game_sof2.h (revision 191) -+++ tools/quake3/q3map2/game_sof2.h (working copy) -@@ -139,6 +139,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "RBSP", /* bsp file prefix */ - 1, /* bsp file version */ -Index: tools/quake3/q3map2/game_etut.h -=================================================================== ---- tools/quake3/q3map2/game_etut.h (revision 191) -+++ tools/quake3/q3map2/game_etut.h (working copy) -@@ -148,6 +148,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 2.2f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 47, /* bsp file version */ -Index: tools/quake3/q3map2/game_jk2.h -=================================================================== ---- tools/quake3/q3map2/game_jk2.h (revision 191) -+++ tools/quake3/q3map2/game_jk2.h (working copy) -@@ -64,6 +64,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "RBSP", /* bsp file prefix */ - 1, /* bsp file version */ -Index: tools/quake3/q3map2/game_qfusion.h -=================================================================== ---- tools/quake3/q3map2/game_qfusion.h (revision 191) -+++ tools/quake3/q3map2/game_qfusion.h (working copy) -@@ -115,6 +115,7 @@ - qfalse, /* wolf lighting model? */ - 512, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "FBSP", /* bsp file prefix */ - 1, /* bsp file version */ -Index: tools/quake3/q3map2/game_tenebrae.h -=================================================================== ---- tools/quake3/q3map2/game_tenebrae.h (revision 191) -+++ tools/quake3/q3map2/game_tenebrae.h (working copy) -@@ -112,6 +112,7 @@ - qfalse, /* wolf lighting model? */ - 512, /* lightmap width/height */ - 2.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 46, /* bsp file version */ -Index: tools/quake3/q3map2/game_quake3.h -=================================================================== ---- tools/quake3/q3map2/game_quake3.h (revision 191) -+++ tools/quake3/q3map2/game_quake3.h (working copy) -@@ -112,6 +112,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 46, /* bsp file version */ -Index: tools/quake3/q3map2/game_ef.h -=================================================================== ---- tools/quake3/q3map2/game_ef.h (revision 191) -+++ tools/quake3/q3map2/game_ef.h (working copy) -@@ -113,6 +113,7 @@ - qfalse, /* wolf lighting model? */ - 128, /* lightmap width/height */ - 1.0f, /* lightmap gamma */ -+ 1.0f, /* lightmap exposure */ - 1.0f, /* lightmap compensate */ - "IBSP", /* bsp file prefix */ - 46, /* bsp file version */ -Index: tools/quake3/q3map2/light_ydnar.c -=================================================================== ---- tools/quake3/q3map2/light_ydnar.c (revision 191) -+++ tools/quake3/q3map2/light_ydnar.c (working copy) -@@ -49,6 +49,7 @@ - int i; - float max, gamma; - vec3_t sample; -+ float inv, dif; - - - /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */ -@@ -72,16 +73,51 @@ - /* gamma */ - sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f; - } -+ -+ if (lightmapExposure == 1) -+ { -+ /* clamp with color normalization */ -+ max = sample[ 0 ]; -+ if( sample[ 1 ] > max ) -+ max = sample[ 1 ]; -+ if( sample[ 2 ] > max ) -+ max = sample[ 2 ]; -+ if( max > 255.0f ) -+ VectorScale( sample, (255.0f / max), sample ); -+ } -+ else -+ { -+ if (lightmapExposure==0) -+ { -+ lightmapExposure=1.0f; -+ } -+ inv=1.f/lightmapExposure; -+ //Exposure -+ -+ max = sample[ 0 ]; -+ if( sample[ 1 ] > max ) -+ max = sample[ 1 ]; -+ if( sample[ 2 ] > max ) -+ max = sample[ 2 ]; -+ -+ dif = (1- exp(-max * inv) ) * 255; -+ -+ if (max >0) -+ { -+ dif = dif / max; -+ } -+ else -+ { -+ dif = 0; -+ } -+ -+ for (i=0;i<3;i++) -+ { -+ sample[i]*=dif; -+ } -+ } -+ - -- /* clamp with color normalization */ -- max = sample[ 0 ]; -- if( sample[ 1 ] > max ) -- max = sample[ 1 ]; -- if( sample[ 2 ] > max ) -- max = sample[ 2 ]; -- if( max > 255.0f ) -- VectorScale( sample, (255.0f / max), sample ); -- - /* compensate for ingame overbrighting/bitshifting */ - VectorScale( sample, (1.0f / lightmapCompensate), sample ); - -Index: tools/quake3/q3map2/light.c -=================================================================== ---- tools/quake3/q3map2/light.c (revision 191) -+++ tools/quake3/q3map2/light.c (working copy) -@@ -1836,6 +1893,14 @@ - i++; - } - -+ else if( !strcmp( argv[ i ], "-exposure" ) ) -+ { -+ f = atof( argv[ i + 1 ] ); -+ lightmapExposure = f; -+ Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure ); -+ i++; -+ } -+ - else if( !strcmp( argv[ i ], "-compensate" ) ) - { - f = atof( argv[ i + 1 ] ); -Index: tools/quake3/q3map2/q3map2.h -=================================================================== ---- tools/quake3/q3map2/q3map2.h (revision 191) -+++ tools/quake3/q3map2/q3map2.h (working copy) -@@ -543,6 +545,7 @@ - qboolean wolfLight; /* when true, lights work like wolf q3map */ - int lightmapSize; /* bsp lightmap width/height */ - float lightmapGamma; /* default lightmap gamma */ -+ float lightmapExposure; /* default lightmap exposure */ - float lightmapCompensate; /* default lightmap compensate value */ - char *bspIdent; /* 4-letter bsp file prefix */ - int bspVersion; /* bsp version to use */ -@@ -2117,6 +2132,7 @@ - - /* ydnar: lightmap gamma/compensation */ - Q_EXTERN float lightmapGamma Q_ASSIGN( 1.0f ); -+Q_EXTERN float lightmapExposure Q_ASSIGN( 1.0f ); - Q_EXTERN float lightmapCompensate Q_ASSIGN( 1.0f ); - - /* ydnar: for runtime tweaking of falloff tolerance */ + Q_EXTERN qboolean debug; + Q_EXTERN qboolean debugSurfaces; + Q_EXTERN qboolean debugUnused; Index: tools/quake3/q3map2/light_ydnar.c =================================================================== ---- tools/quake3/q3map2/light_ydnar.c (revision 191) +--- tools/quake3/q3map2/light_ydnar.c (revision 290) +++ tools/quake3/q3map2/light_ydnar.c (working copy) -@@ -384,7 +420,7 @@ +@@ -372,7 +372,7 @@ #define NUDGE 0.5f #define BOGUS_NUDGE -99999.0f @@ -2126,7 +1288,7 @@ Index: tools/quake3/q3map2/light_ydnar.c { int i, x, y, numClusters, *clusters, pointCluster, *cluster; float *luxel, *origin, *normal, d, lightmapSampleOffset; -@@ -392,6 +428,12 @@ +@@ -380,6 +380,12 @@ vec3_t pNormal; vec3_t vecs[ 3 ]; vec3_t nudged; @@ -2139,7 +1301,7 @@ Index: tools/quake3/q3map2/light_ydnar.c float *nudge; static float nudges[][ 2 ] = { -@@ -485,6 +527,51 @@ +@@ -473,6 +479,51 @@ /* non axial lightmap projection (explicit xyz) */ else VectorCopy( dv->xyz, origin ); @@ -2191,7 +1353,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* planar surfaces have precalculated lightmap vectors for nudging */ if( lm->plane != NULL ) -@@ -516,8 +603,13 @@ +@@ -504,8 +555,13 @@ else origin[ lm->axisNum ] += lightmapSampleOffset; @@ -2206,7 +1368,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* another retarded hack, storing nudge count in luxel[ 1 ] */ luxel[ 1 ] = 0.0f; -@@ -533,14 +625,14 @@ +@@ -521,14 +577,14 @@ for( i = 0; i < 3; i++ ) { /* set nudged point*/ @@ -2224,7 +1386,7 @@ Index: tools/quake3/q3map2/light_ydnar.c luxel[ 1 ] += 1.0f; } } -@@ -550,8 +642,8 @@ +@@ -538,8 +594,8 @@ { VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged ); pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); @@ -2235,7 +1397,7 @@ Index: tools/quake3/q3map2/light_ydnar.c luxel[ 1 ] += 1.0f; } -@@ -597,7 +689,7 @@ +@@ -585,7 +641,7 @@ than the distance between two luxels (thanks jc :) */ @@ -2244,7 +1406,7 @@ Index: tools/quake3/q3map2/light_ydnar.c { bspDrawVert_t mid, *dv2[ 3 ]; int max; -@@ -645,7 +737,7 @@ +@@ -633,7 +689,7 @@ /* split the longest edge and map it */ LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); @@ -2253,7 +1415,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* push the point up a little bit to account for fp creep (fixme: revisit this) */ //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz ); -@@ -653,12 +745,12 @@ +@@ -641,12 +697,12 @@ /* recurse to first triangle */ VectorCopy( dv, dv2 ); dv2[ max ] = ∣ @@ -2268,7 +1430,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } -@@ -674,6 +766,7 @@ +@@ -662,6 +718,7 @@ int i; vec4_t plane; vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ]; @@ -2276,7 +1438,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* get plane if possible */ -@@ -699,16 +792,20 @@ +@@ -687,16 +744,20 @@ ttv = NULL; } @@ -2301,7 +1463,7 @@ Index: tools/quake3/q3map2/light_ydnar.c return qtrue; } -@@ -730,7 +827,7 @@ +@@ -718,7 +779,7 @@ dv2[ 2 ] = dv[ (i + 1) % 3 ]; /* map the degenerate triangle */ @@ -2310,7 +1472,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } } -@@ -792,8 +889,8 @@ +@@ -780,8 +841,8 @@ LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] ); /* map the vertexes */ @@ -2321,7 +1483,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* 0 and 2 */ if( max == 0 ) -@@ -878,10 +975,10 @@ +@@ -866,10 +927,10 @@ } /* map the vertexes */ @@ -2336,7 +1498,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* subdivide the quad */ MapQuad_r( lm, info, dv, plane, stv, ttv ); -@@ -1173,7 +1270,7 @@ +@@ -1161,7 +1222,7 @@ continue; /* map the fake vert */ @@ -2345,7 +1507,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } } } -@@ -1963,22 +2062,32 @@ +@@ -1636,22 +1697,32 @@ deluxel = SUPER_DELUXEL( x, y ); origin = SUPER_ORIGIN( x, y ); normal = SUPER_NORMAL( x, y ); @@ -2403,7 +1565,7 @@ Index: tools/quake3/q3map2/q3map2.h /* version */ -#define Q3MAP_VERSION "2.5.17" -#define Q3MAP_MOTD "Last one turns the lights off" -+#define Q3MAP_VERSION "2.5.17-div0-obj-UTpicomodelase-UTpicomodelnormals-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck" ++#define Q3MAP_VERSION "2.5.17-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTtrianglecheck" +#define Q3MAP_MOTD "Blackhole Box ate all the light" @@ -2414,4 +1576,4 @@ Index: include/version.default +++ include/version.default (working copy) @@ -1 +1 @@ -1.5.0 -+1.5.0-div0-obj-UTpicomodelase-UTpicomodelnormals-modelnormals-nexuizfixes ++1.5.0-div0-obj diff --git a/misc/gtkradiant/mergepatches.sh b/misc/gtkradiant/mergepatches.sh index 85f2ffba3..679e49b64 100755 --- a/misc/gtkradiant/mergepatches.sh +++ b/misc/gtkradiant/mergepatches.sh @@ -43,12 +43,12 @@ Index: tools/quake3/q3map2/q3map2.h /* version */ --#define Q3MAP_VERSION "2.5.17" --#define Q3MAP_MOTD "Last one turns the lights off" -+#define Q3MAP_VERSION "2.5.17-div0$pq" +-#define Q3MAP_VERSION "2.5.11" +-#define Q3MAP_MOTD "A well-oiled toaster oven" ++#define Q3MAP_VERSION "2.5.11-div0$pq" +#define Q3MAP_MOTD "Blackhole Box ate all the light" - - + + Index: include/version.default =================================================================== diff --git a/misc/gtkradiant/singlepatches/both-UTpicomodelase.diff b/misc/gtkradiant/singlepatches-radiant15/both-UTpicomodelase.diff similarity index 100% rename from misc/gtkradiant/singlepatches/both-UTpicomodelase.diff rename to misc/gtkradiant/singlepatches-radiant15/both-UTpicomodelase.diff diff --git a/misc/gtkradiant/singlepatches/both-UTpicomodelnormals.diff b/misc/gtkradiant/singlepatches-radiant15/both-UTpicomodelnormals.diff similarity index 100% rename from misc/gtkradiant/singlepatches/both-UTpicomodelnormals.diff rename to misc/gtkradiant/singlepatches-radiant15/both-UTpicomodelnormals.diff diff --git a/misc/gtkradiant/singlepatches-radiant15/both-obj.diff b/misc/gtkradiant/singlepatches-radiant15/both-obj.diff new file mode 100644 index 000000000..574d2ac2d --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/both-obj.diff @@ -0,0 +1,83 @@ +Index: libs/picomodel/pm_obj.c +=================================================================== +--- libs/picomodel/pm_obj.c (revision 193) ++++ libs/picomodel/pm_obj.c (working copy) +@@ -265,7 +265,7 @@ + /* get next token in material file */ + if (_pico_parse( p,1 ) == NULL) + break; +-#if 0 ++#if 1 + + /* skip empty lines */ + if (p->token == NULL || !strlen( p->token )) +@@ -307,6 +307,7 @@ + else if (!_pico_stricmp(p->token,"map_kd")) + { + char *mapName; ++ picoShader_t *shader; + + /* pointer to current shader must be valid */ + if (curShader == NULL) +@@ -321,6 +322,10 @@ + _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine); + _obj_mtl_error_return; + } ++ /* create a new pico shader */ ++ shader = PicoNewShader( model ); ++ if (shader == NULL) ++ _obj_mtl_error_return; + /* set shader map name */ + PicoSetShaderMapName( shader,mapName ); + } +@@ -521,7 +526,7 @@ + PicoSetModelFileName( model,fileName ); + + /* try loading the materials; we don't handle the result */ +-#if 0 ++#if 1 + _obj_mtl_load( model ); + #endif + +@@ -830,6 +835,41 @@ + curVertex += max; + } + } ++ else if (!_pico_stricmp(p->token,"usemtl")) ++ { ++ picoShader_t *shader; ++ char *name; ++ ++ /* get material name */ ++ name = _pico_parse( p,0 ); ++ ++ /* validate material name */ ++ if (name == NULL || !strlen(name)) ++ { ++ _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine); ++ } ++ else ++ { ++ shader = PicoFindShader( model, name, 1 ); ++ if (shader == NULL) ++ { ++ _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine); ++ ++ /* create a new pico shader */ ++ shader = PicoNewShader( model ); ++ if (shader != NULL) ++ { ++ PicoSetShaderName( shader,name ); ++ PicoSetShaderMapName( shader,name ); ++ PicoSetSurfaceShader( curSurface, shader ); ++ } ++ } ++ else ++ { ++ PicoSetSurfaceShader( curSurface, shader ); ++ } ++ } ++ } + /* skip unparsed rest of line and continue */ + _pico_parse_skip_rest( p ); + } diff --git a/misc/gtkradiant/singlepatches/gtkradiant-modelnormals.diff b/misc/gtkradiant/singlepatches-radiant15/gtkradiant-modelnormals.diff similarity index 100% rename from misc/gtkradiant/singlepatches/gtkradiant-modelnormals.diff rename to misc/gtkradiant/singlepatches-radiant15/gtkradiant-modelnormals.diff diff --git a/misc/gtkradiant/singlepatches/gtkradiant-nexuizfixes.diff b/misc/gtkradiant/singlepatches-radiant15/gtkradiant-nexuizfixes.diff similarity index 100% rename from misc/gtkradiant/singlepatches/gtkradiant-nexuizfixes.diff rename to misc/gtkradiant/singlepatches-radiant15/gtkradiant-nexuizfixes.diff diff --git a/misc/gtkradiant/singlepatches-radiant15/q3map2-UTavgcolorfix.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTavgcolorfix.diff new file mode 100644 index 000000000..2d147960f --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTavgcolorfix.diff @@ -0,0 +1,20 @@ +Index: tools/quake3/q3map2/shaders.c +=================================================================== +--- tools/quake3/q3map2/shaders.c (revision 191) ++++ tools/quake3/q3map2/shaders.c (working copy) +@@ -793,8 +793,14 @@ + } + + if( VectorLength( si->color ) <= 0.0f ) ++ { + ColorNormalize( color, si->color ); +- VectorScale( color, (1.0f / count), si->averageColor ); ++ VectorScale( color, (1.0f / count), si->averageColor ); ++ } ++ else ++ { ++ VectorCopy( si->color, si->averageColor ); ++ } + } + + diff --git a/misc/gtkradiant/singlepatches-radiant15/q3map2-UTfloodlight.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTfloodlight.diff new file mode 100644 index 000000000..454432376 --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTfloodlight.diff @@ -0,0 +1,595 @@ +Index: tools/quake3/q3map2/light_ydnar.c +=================================================================== +--- tools/quake3/q3map2/light_ydnar.c (revision 191) ++++ tools/quake3/q3map2/light_ydnar.c (working copy) +@@ -1767,6 +1864,8 @@ + float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; + trace_t trace; + float stackLightLuxels[ STACK_LL_SIZE ]; ++ vec3_t flood; ++ float *floodlight; + + + /* bail if this number exceeds the number of raw lightmaps */ +@@ -2223,6 +2332,78 @@ + FreeTraceLights( &trace ); + + /* ----------------------------------------------------------------- ++ floodlight pass ++ ----------------------------------------------------------------- */ ++ ++ if( floodlighty ) ++ { ++ /* walk lightmaps */ ++ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) ++ { ++ /* early out */ ++ if( lm->superLuxels[ lightmapNum ] == NULL ) ++ continue; ++ ++ /* apply floodlight to each luxel */ ++ for( y = 0; y < lm->sh; y++ ) ++ { ++ for( x = 0; x < lm->sw; x++ ) ++ { ++ /* get cluster */ ++ cluster = SUPER_CLUSTER( x, y ); ++ //% if( *cluster < 0 ) ++ //% continue; ++ ++ /* get particulars */ ++ luxel = SUPER_LUXEL( lightmapNum, x, y ); ++ floodlight = SUPER_FLOODLIGHT( x, y ); ++ ++ flood[0]=floodlightRGB[0]*floodlightIntensity; ++ flood[1]=floodlightRGB[1]*floodlightIntensity; ++ flood[2]=floodlightRGB[2]*floodlightIntensity; ++ ++ /* scale light value */ ++ VectorScale( flood, *floodlight, flood ); ++ luxel[0]+=flood[0]; ++ luxel[1]+=flood[1]; ++ luxel[2]+=flood[2]; ++ ++ if (luxel[3]==0) luxel[3]=1; ++ } ++ } ++ } ++ } ++ ++ if (debugnormals) ++ { ++ for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) ++ { ++ /* early out */ ++ if( lm->superLuxels[ lightmapNum ] == NULL ) ++ continue; ++ ++ for( y = 0; y < lm->sh; y++ ) ++ { ++ for( x = 0; x < lm->sw; x++ ) ++ { ++ /* get cluster */ ++ cluster = SUPER_CLUSTER( x, y ); ++ //% if( *cluster < 0 ) ++ //% continue; ++ ++ /* get particulars */ ++ luxel = SUPER_LUXEL( lightmapNum, x, y ); ++ normal = SUPER_NORMAL ( x, y ); ++ ++ luxel[0]=(normal[0]*127)+127; ++ luxel[1]=(normal[1]*127)+127; ++ luxel[2]=(normal[2]*127)+127; ++ } ++ } ++ } ++ } ++ ++ /* ----------------------------------------------------------------- + dirt pass + ----------------------------------------------------------------- */ + +@@ -3587,7 +3768,320 @@ + CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace ); + } + ++///////////////////////////////////////////////////////////// + ++#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */ ++#define FLOODLIGHT_NUM_ANGLE_STEPS 16 ++#define FLOODLIGHT_NUM_ELEVATION_STEPS 4 ++#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS) + ++static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ]; ++static int numFloodVectors = 0; + ++void SetupFloodLight( void ) ++{ ++ int i, j; ++ float angle, elevation, angleStep, elevationStep; ++ const char *value; ++ double v1,v2,v3,v4,v5; ++ ++ /* note it */ ++ Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" ); ++ ++ /* calculate angular steps */ ++ angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS ); ++ elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS ); ++ ++ /* iterate angle */ ++ angle = 0.0f; ++ for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep ) ++ { ++ /* iterate elevation */ ++ for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep ) ++ { ++ floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle ); ++ floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle ); ++ floodVectors[ numFloodVectors ][ 2 ] = cos( elevation ); ++ numFloodVectors++; ++ } ++ } ++ ++ /* emit some statistics */ ++ Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors ); + ++ /* floodlight */ ++ value = ValueForKey( &entities[ 0 ], "_floodlight" ); ++ ++ if( value[ 0 ] != '\0' ) ++ { ++ v1=v2=v3=0; ++ v4=floodlightDistance; ++ v5=floodlightIntensity; ++ ++ sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5); ++ ++ floodlightRGB[0]=v1; ++ floodlightRGB[1]=v2; ++ floodlightRGB[2]=v3; ++ ++ if (VectorLength(floodlightRGB)==0) ++ { ++ VectorSet(floodlightRGB,240,240,255); ++ } ++ ++ if (v4<1) v4=1024; ++ if (v5<1) v5=128; ++ ++ floodlightDistance=v4; ++ floodlightIntensity=v5; ++ ++ floodlighty = qtrue; ++ Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" ); ++ } ++ else ++ { ++ VectorSet(floodlightRGB,240,240,255); ++ //floodlighty = qtrue; ++ //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" ); ++ } ++ VectorNormalize(floodlightRGB,floodlightRGB); ++} ++ ++//27 - lighttracer style ambient occlusion light hack. ++//Kudos to the dirtmapping author for most of this source. ++void FloodLightRawLightmap( int rawLightmapNum ) ++{ ++ int i, x, y, sx, sy, *cluster; ++ float *origin, *normal, *floodlight, *floodlight2, average, samples; ++ rawLightmap_t *lm; ++ surfaceInfo_t *info; ++ trace_t trace; ++ ++ /* bail if this number exceeds the number of raw lightmaps */ ++ if( rawLightmapNum >= numRawLightmaps ) ++ return; ++ ++ /* get lightmap */ ++ lm = &rawLightmaps[ rawLightmapNum ]; ++ ++ memset(&trace,0,sizeof(trace_t)); ++ /* setup trace */ ++ trace.testOcclusion = qtrue; ++ trace.forceSunlight = qfalse; ++ trace.twoSided = qtrue; ++ trace.recvShadows = lm->recvShadows; ++ trace.numSurfaces = lm->numLightSurfaces; ++ trace.surfaces = &lightSurfaces[ lm->firstLightSurface ]; ++ trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; ++ trace.testAll = qfalse; ++ trace.distance = 1024; ++ ++ /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ ++ //trace.twoSided = qfalse; ++ for( i = 0; i < trace.numSurfaces; i++ ) ++ { ++ /* get surface */ ++ info = &surfaceInfos[ trace.surfaces[ i ] ]; ++ ++ /* check twosidedness */ ++ if( info->si->twoSided ) ++ { ++ trace.twoSided = qtrue; ++ break; ++ } ++ } ++ ++ /* gather dirt */ ++ for( y = 0; y < lm->sh; y++ ) ++ { ++ for( x = 0; x < lm->sw; x++ ) ++ { ++ /* get luxel */ ++ cluster = SUPER_CLUSTER( x, y ); ++ origin = SUPER_ORIGIN( x, y ); ++ normal = SUPER_NORMAL( x, y ); ++ floodlight = SUPER_FLOODLIGHT( x, y ); ++ ++ /* set default dirt */ ++ *floodlight = 0.0f; ++ ++ /* only look at mapped luxels */ ++ if( *cluster < 0 ) ++ continue; ++ ++ /* copy to trace */ ++ trace.cluster = *cluster; ++ VectorCopy( origin, trace.origin ); ++ VectorCopy( normal, trace.normal ); ++ ++ ++ ++ /* get dirt */ ++ *floodlight = FloodLightForSample( &trace ); ++ } ++ } ++ ++ /* testing no filtering */ ++ return; ++ ++ /* filter "dirt" */ ++ for( y = 0; y < lm->sh; y++ ) ++ { ++ for( x = 0; x < lm->sw; x++ ) ++ { ++ /* get luxel */ ++ cluster = SUPER_CLUSTER( x, y ); ++ floodlight = SUPER_FLOODLIGHT( x, y ); ++ ++ /* filter dirt by adjacency to unmapped luxels */ ++ average = *floodlight; ++ samples = 1.0f; ++ for( sy = (y - 1); sy <= (y + 1); sy++ ) ++ { ++ if( sy < 0 || sy >= lm->sh ) ++ continue; ++ ++ for( sx = (x - 1); sx <= (x + 1); sx++ ) ++ { ++ if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) ) ++ continue; ++ ++ /* get neighboring luxel */ ++ cluster = SUPER_CLUSTER( sx, sy ); ++ floodlight2 = SUPER_FLOODLIGHT( sx, sy ); ++ if( *cluster < 0 || *floodlight2 <= 0.0f ) ++ continue; ++ ++ /* add it */ ++ average += *floodlight2; ++ samples += 1.0f; ++ } ++ ++ /* bail */ ++ if( samples <= 0.0f ) ++ break; ++ } ++ ++ /* bail */ ++ if( samples <= 0.0f ) ++ continue; ++ ++ /* scale dirt */ ++ *floodlight = average / samples; ++ } ++ } ++} ++ ++/* ++FloodLightForSample() ++calculates floodlight value for a given sample ++once again, kudos to the dirtmapping coder ++*/ ++float FloodLightForSample( trace_t *trace ) ++{ ++ int i; ++ float d; ++ float contribution; ++ int sub = 0; ++ float gatherLight, outLight; ++ vec3_t normal, worldUp, myUp, myRt, direction, displacement; ++ float dd; ++ int vecs = 0; ++ ++ gatherLight=0; ++ /* dummy check */ ++ //if( !dirty ) ++ // return 1.0f; ++ if( trace == NULL || trace->cluster < 0 ) ++ return 0.0f; ++ ++ ++ /* setup */ ++ dd = floodlightDistance; ++ VectorCopy( trace->normal, normal ); ++ ++ /* check if the normal is aligned to the world-up */ ++ if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f ) ++ { ++ if( normal[ 2 ] == 1.0f ) ++ { ++ VectorSet( myRt, 1.0f, 0.0f, 0.0f ); ++ VectorSet( myUp, 0.0f, 1.0f, 0.0f ); ++ } ++ else if( normal[ 2 ] == -1.0f ) ++ { ++ VectorSet( myRt, -1.0f, 0.0f, 0.0f ); ++ VectorSet( myUp, 0.0f, 1.0f, 0.0f ); ++ } ++ } ++ else ++ { ++ VectorSet( worldUp, 0.0f, 0.0f, 1.0f ); ++ CrossProduct( normal, worldUp, myRt ); ++ VectorNormalize( myRt, myRt ); ++ CrossProduct( myRt, normal, myUp ); ++ VectorNormalize( myUp, myUp ); ++ } ++ ++ /* iterate through ordered vectors */ ++ for( i = 0; i < numFloodVectors; i++ ) ++ { ++ if (floodlight_lowquality==qtrue) ++ { ++ if (rand()%10 != 0 ) continue; ++ } ++ ++ vecs++; ++ ++ /* transform vector into tangent space */ ++ direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ]; ++ direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ]; ++ direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ]; ++ ++ /* set endpoint */ ++ VectorMA( trace->origin, dd, direction, trace->end ); ++ ++ //VectorMA( trace->origin, 1, direction, trace->origin ); ++ ++ SetupTrace( trace ); ++ /* trace */ ++ TraceLine( trace ); ++ contribution=1; ++ ++ if (trace->compileFlags & C_SKY ) ++ { ++ contribution=1.0f; ++ } ++ else if ( trace->opaque ) ++ { ++ VectorSubtract( trace->hit, trace->origin, displacement ); ++ d=VectorLength( displacement ); ++ ++ // d=trace->distance; ++ //if (d>256) gatherDirt+=1; ++ contribution=d/dd; ++ if (contribution>1) contribution=1.0f; ++ ++ //gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); ++ } ++ ++ gatherLight+=contribution; ++ } ++ ++ /* early out */ ++ if( gatherLight <= 0.0f ) ++ return 0.0f; ++ ++ sub=vecs; ++ ++ if (sub<1) sub=1; ++ gatherLight/=(sub); ++ ++ outLight=gatherLight; ++ if( outLight > 1.0f ) ++ outLight = 1.0f; ++ ++ /* return to sender */ ++ return outLight; ++} ++ +Index: tools/quake3/q3map2/light.c +=================================================================== +--- tools/quake3/q3map2/light.c (revision 191) ++++ tools/quake3/q3map2/light.c (working copy) +@@ -1378,6 +1378,56 @@ + break; + } + ++ /////// Floodlighting for point ////////////////// ++ //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir ++ if (floodlighty) ++ { ++ int q; ++ float addSize,f; ++ vec3_t col,dir; ++ col[0]=col[1]=col[2]=floodlightIntensity; ++ dir[0]=dir[1]=0; ++ dir[2]=1; ++ ++ trace.testOcclusion = qtrue; ++ trace.forceSunlight = qfalse; ++ trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; ++ trace.testAll = qtrue; ++ ++ for (q=0;q<2;q++) ++ { ++ if (q==0) //upper hemisphere ++ { ++ trace.normal[0]=0; ++ trace.normal[1]=0; ++ trace.normal[2]=1; ++ } ++ else //lower hemisphere ++ { ++ trace.normal[0]=0; ++ trace.normal[1]=0; ++ trace.normal[2]=-1; ++ } ++ ++ f = FloodLightForSample(&trace); ++ ++ contributions[ numCon ].color[0]=col[0]*f; ++ contributions[ numCon ].color[1]=col[1]*f; ++ contributions[ numCon ].color[2]=col[2]*f; ++ ++ contributions[ numCon ].dir[0]=dir[0]; ++ contributions[ numCon ].dir[1]=dir[1]; ++ contributions[ numCon ].dir[2]=dir[2]; ++ ++ contributions[ numCon ].style = 0; ++ numCon++; ++ /* push average direction around */ ++ addSize = VectorLength( col ); ++ VectorMA( gp->dir, addSize, dir, gp->dir ); ++ } ++ } ++ ///////////////////// ++ + /* normalize to get primary light direction */ + VectorNormalize( gp->dir, gp->dir ); + +@@ -1661,6 +1711,12 @@ + RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap ); + } + ++ /* floodlight them up */ ++ if( floodlighty ) ++ { ++ Sys_Printf( "--- FloodlightRawLightmap ---\n" ); ++ RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap ); ++ } + + /* ydnar: set up light envelopes */ + SetupEnvelopes( qfalse, fast ); +@@ -1703,6 +1759,7 @@ + /* flag bouncing */ + bouncing = qtrue; + VectorClear( ambientColor ); ++ floodlighty = false; + + /* generate diffuse lights */ + RadFreeLights(); +@@ -2191,6 +2256,21 @@ + cpmaHack = qtrue; + Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" ); + } ++ else if( !strcmp( argv[ i ], "-floodlight" ) ) ++ { ++ floodlighty = qtrue; ++ Sys_Printf( "FloodLighting enabled\n" ); ++ } ++ else if( !strcmp( argv[ i ], "-debugnormals" ) ) ++ { ++ debugnormals = qtrue; ++ Sys_Printf( "DebugNormals enabled\n" ); ++ } ++ else if( !strcmp( argv[ i ], "-lowquality" ) ) ++ { ++ floodlight_lowquality = qtrue; ++ Sys_Printf( "Low Quality FloodLighting enabled\n" ); ++ } + + /* r7: dirtmapping */ + else if( !strcmp( argv[ i ], "-dirty" ) ) +@@ -2279,6 +2359,7 @@ + /* ydnar: set up optimization */ + SetupBrushes(); + SetupDirt(); ++ SetupFloodLight(); + SetupSurfaceLightmaps(); + + /* initialize the surface facet tracing */ +Index: tools/quake3/q3map2/lightmaps_ydnar.c +=================================================================== +--- tools/quake3/q3map2/lightmaps_ydnar.c (revision 191) ++++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy) +@@ -414,6 +414,12 @@ + lm->superNormals = safe_malloc( size ); + memset( lm->superNormals, 0, size ); + ++ /* allocate floodlight map storage */ ++ size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float ); ++ if( lm->superFloodLight == NULL ) ++ lm->superFloodLight = safe_malloc( size ); ++ memset( lm->superFloodLight, 0, size ); ++ + /* allocate cluster map storage */ + size = lm->sw * lm->sh * sizeof( int ); + if( lm->superClusters == NULL ) +Index: tools/quake3/q3map2/q3map2.h +=================================================================== +--- tools/quake3/q3map2/q3map2.h (revision 191) ++++ tools/quake3/q3map2/q3map2.h (working copy) +@@ -267,6 +267,7 @@ + #define SUPER_NORMAL_SIZE 4 + #define SUPER_DELUXEL_SIZE 3 + #define BSP_DELUXEL_SIZE 3 ++#define SUPER_FLOODLIGHT_SIZE 1 + + #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) + #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) +@@ -279,6 +280,7 @@ + #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE)) + #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE)) + #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */ ++#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) ) + + + +@@ -1392,6 +1395,7 @@ + + float *superDeluxels; /* average light direction */ + float *bspDeluxels; ++ float *superFloodLight; + } + rawLightmap_t; + +@@ -1704,6 +1708,10 @@ + float DirtForSample( trace_t *trace ); + void DirtyRawLightmap( int num ); + ++void SetupFloodLight(); ++float FloodLightForSample( trace_t *trace ); ++void FloodLightRawLightmap( int num ); ++ + void IlluminateRawLightmap( int num ); + void IlluminateVertexes( int num ); + +@@ -2098,6 +2106,13 @@ + Q_EXTERN float dirtScale Q_ASSIGN( 1.0f ); + Q_EXTERN float dirtGain Q_ASSIGN( 1.0f ); + ++Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse ); ++Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse ); ++Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse ); ++Q_EXTERN vec3_t floodlightRGB; ++Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 ); ++Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 ); ++ + Q_EXTERN qboolean dump Q_ASSIGN( qfalse ); + Q_EXTERN qboolean debug Q_ASSIGN( qfalse ); + Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse ); diff --git a/misc/gtkradiant/singlepatches/q3map2-UTlmexposure.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTlmexposure.diff similarity index 100% rename from misc/gtkradiant/singlepatches/q3map2-UTlmexposure.diff rename to misc/gtkradiant/singlepatches-radiant15/q3map2-UTlmexposure.diff diff --git a/misc/gtkradiant/singlepatches-radiant15/q3map2-UTtrianglecheck.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTtrianglecheck.diff new file mode 100644 index 000000000..98eed9da8 --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/q3map2-UTtrianglecheck.diff @@ -0,0 +1,280 @@ +Index: tools/quake3/q3map2/light_ydnar.c +=================================================================== +--- tools/quake3/q3map2/light_ydnar.c (revision 191) ++++ tools/quake3/q3map2/light_ydnar.c (working copy) +@@ -384,7 +420,7 @@ + #define NUDGE 0.5f + #define BOGUS_NUDGE -99999.0f + +-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 ] ) ++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 ] ) + { + int i, x, y, numClusters, *clusters, pointCluster, *cluster; + float *luxel, *origin, *normal, d, lightmapSampleOffset; +@@ -392,6 +428,12 @@ + vec3_t pNormal; + vec3_t vecs[ 3 ]; + vec3_t nudged; ++ vec3_t cverts[ 3 ]; ++ vec3_t temp; ++ vec4_t sideplane, hostplane; ++ vec3_t origintwo; ++ int j, next; ++ float e; + float *nudge; + static float nudges[][ 2 ] = + { +@@ -485,6 +527,51 @@ + /* non axial lightmap projection (explicit xyz) */ + else + VectorCopy( dv->xyz, origin ); ++ ++ ////////////////////// ++ //27's test to make sure samples stay within the triangle boundaries ++ //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y) ++ //2) if it does, nudge it onto the correct side. ++ ++ if (worldverts!=NULL) ++ { ++ for (j=0;j<3;j++) ++ { ++ VectorCopy(worldverts[j],cverts[j]); ++ } ++ PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]); ++ ++ for (j=0;j<3;j++) ++ { ++ for (i=0;i<3;i++) ++ { ++ //build plane using 2 edges and a normal ++ next=(i+1)%3; ++ ++ VectorCopy(cverts[next],temp); ++ VectorAdd(temp,hostplane,temp); ++ PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp); ++ ++ //planetest sample point ++ e=DotProduct(origin,sideplane); ++ e=e-sideplane[3]; ++ if (e>0) ++ { ++ //we're bad. ++ //VectorClear(origin); ++ //Move the sample point back inside triangle bounds ++ origin[0]-=sideplane[0]*(e+1); ++ origin[1]-=sideplane[1]*(e+1); ++ origin[2]-=sideplane[2]*(e+1); ++#ifdef DEBUG_27_1 ++ VectorClear(origin); ++#endif ++ } ++ } ++ } ++ } ++ ++ //////////////////////// + + /* planar surfaces have precalculated lightmap vectors for nudging */ + if( lm->plane != NULL ) +@@ -516,8 +603,13 @@ + else + origin[ lm->axisNum ] += lightmapSampleOffset; + ++ VectorCopy(origin,origintwo); ++ origintwo[0]+=vecs[2][0]; ++ origintwo[1]+=vecs[2][1]; ++ origintwo[2]+=vecs[2][2]; ++ + /* get cluster */ +- pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters ); ++ pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters ); + + /* another retarded hack, storing nudge count in luxel[ 1 ] */ + luxel[ 1 ] = 0.0f; +@@ -533,14 +625,14 @@ + for( i = 0; i < 3; i++ ) + { + /* set nudged point*/ +- nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]); ++ nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]); + } + nudge += 2; + + /* get pvs cluster */ + pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 ); +- if( pointCluster >= 0 ) +- VectorCopy( nudged, origin ); ++ //if( pointCluster >= 0 ) ++ // VectorCopy( nudged, origin ); + luxel[ 1 ] += 1.0f; + } + } +@@ -550,8 +642,8 @@ + { + VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged ); + pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); +- if( pointCluster >= 0 ) +- VectorCopy( nudged, origin ); ++ //if( pointCluster >= 0 ) ++ // VectorCopy( nudged, origin ); + luxel[ 1 ] += 1.0f; + } + +@@ -597,7 +689,7 @@ + than the distance between two luxels (thanks jc :) + */ + +-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 ] ) ++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 ] ) + { + bspDrawVert_t mid, *dv2[ 3 ]; + int max; +@@ -645,7 +737,7 @@ + + /* split the longest edge and map it */ + LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); +- MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv ); ++ MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts ); + + /* push the point up a little bit to account for fp creep (fixme: revisit this) */ + //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz ); +@@ -653,12 +745,12 @@ + /* recurse to first triangle */ + VectorCopy( dv, dv2 ); + dv2[ max ] = ∣ +- MapTriangle_r( lm, info, dv2, plane, stv, ttv ); ++ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); + + /* recurse to second triangle */ + VectorCopy( dv, dv2 ); + dv2[ (max + 1) % 3 ] = ∣ +- MapTriangle_r( lm, info, dv2, plane, stv, ttv ); ++ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); + } + + +@@ -674,6 +766,7 @@ + int i; + vec4_t plane; + vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ]; ++ vec3_t worldverts[ 3 ]; + + + /* get plane if possible */ +@@ -699,16 +792,20 @@ + ttv = NULL; + } + ++ VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] ); ++ VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] ); ++ VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] ); ++ + /* map the vertexes */ +- MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); ++ MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts ); ++ MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts ); ++ MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts ); + + /* 2002-11-20: prefer axial triangle edges */ + if( mapNonAxial ) + { + /* subdivide the triangle */ +- MapTriangle_r( lm, info, dv, plane, stv, ttv ); ++ MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts ); + return qtrue; + } + +@@ -730,7 +827,7 @@ + dv2[ 2 ] = dv[ (i + 1) % 3 ]; + + /* map the degenerate triangle */ +- MapTriangle_r( lm, info, dv2, plane, stv, ttv ); ++ MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); + } + } + +@@ -792,8 +889,8 @@ + LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] ); + + /* map the vertexes */ +- MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv ); ++ MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL ); ++ MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL ); + + /* 0 and 2 */ + if( max == 0 ) +@@ -878,10 +975,10 @@ + } + + /* map the vertexes */ +- MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); +- MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv ); ++ MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL ); ++ MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL ); ++ MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL ); ++ MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL ); + + /* subdivide the quad */ + MapQuad_r( lm, info, dv, plane, stv, ttv ); +@@ -1173,7 +1270,7 @@ + continue; + + /* map the fake vert */ +- MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL ); ++ MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL ); + } + } + } +@@ -1963,22 +2062,32 @@ + deluxel = SUPER_DELUXEL( x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); +- +- /* set contribution count */ +- lightLuxel[ 3 ] = 1.0f; +- +- /* setup trace */ +- trace.cluster = *cluster; +- VectorCopy( origin, trace.origin ); +- VectorCopy( normal, trace.normal ); +- +- /* get light for this sample */ +- LightContributionToSample( &trace ); +- VectorCopy( trace.color, lightLuxel ); +- +- /* add to count */ +- if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) ++ ++ ////////// 27's temp hack for testing edge clipping //// ++ if( origin[0]==0 && origin[1]==0 && origin[2]==0 ) ++ { ++ lightLuxel[ 1 ] = 255; ++ lightLuxel[ 3 ] = 1.0f; + totalLighted++; ++ } ++ else ++ { ++ /* set contribution count */ ++ lightLuxel[ 3 ] = 1.0f; ++ ++ /* setup trace */ ++ trace.cluster = *cluster; ++ VectorCopy( origin, trace.origin ); ++ VectorCopy( normal, trace.normal ); ++ ++ /* get light for this sample */ ++ LightContributionToSample( &trace ); ++ VectorCopy( trace.color, lightLuxel ); ++ ++ /* add to count */ ++ if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) ++ totalLighted++; ++ } + + /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */ + if( deluxemap ) diff --git a/misc/gtkradiant/singlepatches-radiant15/q3map2-decomptexcoords.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-decomptexcoords.diff new file mode 100644 index 000000000..808888f26 --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/q3map2-decomptexcoords.diff @@ -0,0 +1,264 @@ +Index: tools/quake3/q3map2/convert_map.c +=================================================================== +--- tools/quake3/q3map2/convert_map.c (revision 191) ++++ tools/quake3/q3map2/convert_map.c (working copy) +@@ -46,6 +46,105 @@ + #define SNAP_FLOAT_TO_INT 4 + #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT) + ++typedef vec_t vec2_t[2]; ++ ++static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02, ++ vec_t a10, vec_t a11, vec_t a12, ++ vec_t a20, vec_t a21, vec_t a22) ++{ ++ return ++ a00 * (a11 * a22 - a12 * a21) ++ - a01 * (a10 * a22 - a12 * a20) ++ + a02 * (a10 * a21 - a11 * a20); ++} ++ ++void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3]) ++{ ++ bspDrawSurface_t *s; ++ int i; ++ int t; ++ vec_t best = 0; ++ vec_t thisarea; ++ vec3_t normdiff; ++ vec3_t v1v0, v2v0, norm; ++ bspDrawVert_t *vert[3]; ++ winding_t *polygon; ++ plane_t *buildPlane = &mapplanes[buildSide->planenum]; ++ int matches = 0; ++ ++ // first, start out with NULLs ++ bestVert[0] = bestVert[1] = bestVert[2] = NULL; ++ ++ // brute force through all surfaces ++ for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s) ++ { ++ if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP) ++ continue; ++ if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader)) ++ continue; ++ for(t = 0; t + 3 <= s->numIndexes; t += 3) ++ { ++ vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]]; ++ vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]]; ++ vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]]; ++ if(s->surfaceType == MST_PLANAR) ++ { ++ VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; ++ VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; ++ VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; ++ } ++ else ++ { ++ // this is more prone to roundoff errors, but with embedded ++ // models, there is no better way ++ VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0); ++ VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0); ++ CrossProduct(v2v0, v1v0, norm); ++ VectorNormalize(norm, norm); ++ VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; ++ } ++ if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; ++ if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; ++ if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; ++ // Okay. Correct surface type, correct shader, correct plane. Let's start with the business... ++ polygon = CopyWinding(buildSide->winding); ++ for(i = 0; i < 3; ++i) ++ { ++ // 0: 1, 2 ++ // 1: 2, 0 ++ // 2; 0, 1 ++ vec3_t *v1 = &vert[(i+1)%3]->xyz; ++ vec3_t *v2 = &vert[(i+2)%3]->xyz; ++ vec3_t triNormal; ++ vec_t triDist; ++ vec3_t sideDirection; ++ // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1). ++ VectorSubtract(*v2, *v1, sideDirection); ++ CrossProduct(sideDirection, buildPlane->normal, triNormal); ++ triDist = DotProduct(*v1, triNormal); ++ ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon); ++ if(!polygon) ++ goto exwinding; ++ } ++ thisarea = WindingArea(polygon); ++ if(thisarea > 0) ++ ++matches; ++ if(thisarea > best) ++ { ++ best = thisarea; ++ bestVert[0] = vert[0]; ++ bestVert[1] = vert[1]; ++ bestVert[2] = vert[2]; ++ } ++ FreeWinding(polygon); ++exwinding: ++ ; ++ } ++ } ++ //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16)) ++ // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best); ++} ++ + static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) + { + int i, j; +@@ -54,12 +153,17 @@ + bspShader_t *shader; + char *texture; + bspPlane_t *plane; ++ plane_t *buildPlane; + vec3_t pts[ 3 ]; ++ bspDrawVert_t *vert[3]; ++ int valid; + + + /* start brush */ + fprintf( f, "\t// brush %d\n", num ); + fprintf( f, "\t{\n" ); ++ fprintf( f, "\tbrushDef\n" ); ++ fprintf( f, "\t{\n" ); + + /* clear out build brush */ + for( i = 0; i < buildBrush->numsides; i++ ) +@@ -109,9 +213,88 @@ + /* get build side */ + buildSide = &buildBrush->sides[ i ]; + ++ /* get plane */ ++ buildPlane = &mapplanes[ buildSide->planenum ]; ++ + /* dummy check */ + if( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) + continue; ++ ++ // st-texcoords -> texMat block ++ // start out with dummy ++ VectorSet(buildSide->texMat[0], 1/32.0, 0, 0); ++ VectorSet(buildSide->texMat[1], 0, 1/32.0, 0); ++ ++ // find surface for this side (by brute force) ++ // surface format: ++ // - meshverts point in pairs of three into verts ++ // - (triangles) ++ // - find the triangle that has most in common with our side ++ GetBestSurfaceTriangleMatchForBrushside(buildSide, vert); ++ valid = 0; ++ ++ if(vert[0] && vert[1] && vert[2]) ++ { ++ int i; ++ vec3_t texX, texY; ++ vec3_t xy1I, xy1J, xy1K; ++ vec2_t stI, stJ, stK; ++ vec_t D, D0, D1, D2; ++ ++ ComputeAxisBase(buildPlane->normal, texX, texY); ++ ++ VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1); ++ VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1); ++ VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1); ++ stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1]; ++ stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1]; ++ stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1]; ++ ++ // - solve linear equations: ++ // - (x, y) := xyz . (texX, texY) ++ // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2] ++ // (for three vertices) ++ D = Det3x3( ++ xy1I[0], xy1I[1], 1, ++ xy1J[0], xy1J[1], 1, ++ xy1K[0], xy1K[1], 1 ++ ); ++ if(D != 0) ++ { ++ for(i = 0; i < 2; ++i) ++ { ++ D0 = Det3x3( ++ stI[i], xy1I[1], 1, ++ stJ[i], xy1J[1], 1, ++ stK[i], xy1K[1], 1 ++ ); ++ D1 = Det3x3( ++ xy1I[0], stI[i], 1, ++ xy1J[0], stJ[i], 1, ++ xy1K[0], stK[i], 1 ++ ); ++ D2 = Det3x3( ++ xy1I[0], xy1I[1], stI[i], ++ xy1J[0], xy1J[1], stJ[i], ++ xy1K[0], xy1K[1], stK[i] ++ ); ++ VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D); ++ valid = 1; ++ } ++ } ++ else ++ 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", ++ buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], ++ vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], ++ texX[0], texX[1], texX[2], texY[0], texY[1], texY[2], ++ vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1], ++ vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1], ++ vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1] ++ ); ++ } ++ else ++ if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16)) ++ fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader); + + /* get texture name */ + if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) +@@ -130,14 +313,21 @@ + + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ +- 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", ++ fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], +- texture ); ++ buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2], ++ buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2], ++ texture, ++ // DEBUG: valid ? 0 : C_DETAIL ++ 0 ++ ); ++ // TODO write brush primitives format here + } + + /* end brush */ ++ fprintf( f, "\t}\n" ); + fprintf( f, "\t}\n\n" ); + } + +Index: tools/quake3/q3map2/main.c +=================================================================== +--- tools/quake3/q3map2/main.c (revision 191) ++++ tools/quake3/q3map2/main.c (working copy) +@@ -541,6 +541,18 @@ + Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); + } + } ++ else if( !strcmp( argv[ i ], "-ne" ) ) ++ { ++ normalEpsilon = atof( argv[ i + 1 ] ); ++ i++; ++ Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon ); ++ } ++ else if( !strcmp( argv[ i ], "-de" ) ) ++ { ++ distanceEpsilon = atof( argv[ i + 1 ] ); ++ i++; ++ Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon ); ++ } + } + + /* clean up map name */ diff --git a/misc/gtkradiant/singlepatches-radiant15/q3map2-snapplane.diff b/misc/gtkradiant/singlepatches-radiant15/q3map2-snapplane.diff new file mode 100644 index 000000000..b5e3d6bfa --- /dev/null +++ b/misc/gtkradiant/singlepatches-radiant15/q3map2-snapplane.diff @@ -0,0 +1,292 @@ +Index: tools/quake3/q3map2/model.c +=================================================================== +--- tools/quake3/q3map2/model.c (revision 193) ++++ tools/quake3/q3map2/model.c (working copy) +@@ -222,6 +222,8 @@ + byte *color; + picoIndex_t *indexes; + remap_t *rm, *glob; ++ double normalEpsilon_save; ++ double distanceEpsilon_save; + + + /* get model */ +@@ -398,9 +400,8 @@ + /* ydnar: giant hack land: generate clipping brushes for model triangles */ + if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */ + { +- vec3_t points[ 3 ], backs[ 3 ]; ++ vec3_t points[ 4 ], backs[ 3 ]; + vec4_t plane, reverse, pa, pb, pc; +- vec3_t nadir; + + + /* temp hack */ +@@ -437,90 +438,141 @@ + /* note: this doesn't work as well as simply using the plane of the triangle, below */ + for( k = 0; k < 3; k++ ) + { +- if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) && +- fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) ) ++ if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) && ++ fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) ) + { + backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f; + break; + } + } + } ++ ++ VectorCopy( points[0], points[3] ); // for cyclic usage + + /* make plane for triangle */ ++ // div0: add some extra spawnflags: ++ // 0: snap normals to axial planes for extrusion ++ // 8: extrude with the original normals ++ // 16: extrude only with up/down normals (ideal for terrain) ++ // 24: extrude by distance zero (may need engine changes) + if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) ) + { ++ vec3_t bestNormal; ++ float backPlaneDistance = 2; ++ ++ if(spawnFlags & 8) // use a DOWN normal ++ { ++ if(spawnFlags & 16) ++ { ++ // 24: normal as is, and zero width (broken) ++ VectorCopy(plane, bestNormal); ++ } ++ else ++ { ++ // 8: normal as is ++ VectorCopy(plane, bestNormal); ++ } ++ } ++ else ++ { ++ if(spawnFlags & 16) ++ { ++ // 16: UP/DOWN normal ++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); ++ } ++ else ++ { ++ // 0: axial normal ++ if(fabs(plane[0]) > fabs(plane[1])) // x>y ++ if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z ++ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); ++ else // x>y, z>=y ++ if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y ++ VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); ++ else // z>=x, x>y ++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); ++ else // y>=x ++ if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x ++ VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0); ++ else // z>=y, y>=x ++ VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); ++ } ++ } ++ ++ /* build a brush */ ++ buildBrush = AllocBrush( 48 ); ++ buildBrush->entityNum = mapEntityNum; ++ buildBrush->original = buildBrush; ++ buildBrush->contentShader = si; ++ buildBrush->compileFlags = si->compileFlags; ++ buildBrush->contentFlags = si->contentFlags; ++ normalEpsilon_save = normalEpsilon; ++ distanceEpsilon_save = distanceEpsilon; ++ if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here ++ { ++ buildBrush->detail = qfalse; ++ ++ // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model) ++ if(normalEpsilon > 0) ++ normalEpsilon = 0; ++ if(distanceEpsilon > 0) ++ distanceEpsilon = 0; ++ } ++ else ++ buildBrush->detail = qtrue; ++ + /* regenerate back points */ + for( j = 0; j < 3; j++ ) + { + /* get vertex */ + dv = &ds->verts[ ds->indexes[ i + j ] ]; +- +- /* copy xyz */ +- VectorCopy( dv->xyz, backs[ j ] ); +- +- /* find nearest axial to plane normal and push back points opposite */ +- for( k = 0; k < 3; k++ ) +- { +- if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) && +- fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) ) +- { +- backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f; +- break; +- } +- } ++ ++ // shift by some units ++ VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit + } +- ++ + /* make back plane */ + VectorScale( plane, -1.0f, reverse ); +- reverse[ 3 ] = -(plane[ 3 ] - 1); +- +- /* make back pyramid point */ +- VectorCopy( points[ 0 ], nadir ); +- VectorAdd( nadir, points[ 1 ], nadir ); +- VectorAdd( nadir, points[ 2 ], nadir ); +- VectorScale( nadir, 0.3333333333333f, nadir ); +- VectorMA( nadir, -2.0f, plane, nadir ); +- +- /* make 3 more planes */ +- //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) && +- //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) && +- //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) ) ++ reverse[ 3 ] = -plane[ 3 ]; ++ if((spawnFlags & 24) != 24) ++ reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance; ++ // 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) ++ + if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) && +- PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) && +- PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) ) ++ PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) && ++ PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) ) + { +- /* build a brush */ +- buildBrush = AllocBrush( 48 ); +- +- buildBrush->entityNum = mapEntityNum; +- buildBrush->original = buildBrush; +- buildBrush->contentShader = si; +- buildBrush->compileFlags = si->compileFlags; +- buildBrush->contentFlags = si->contentFlags; +- buildBrush->detail = qtrue; +- + /* set up brush sides */ + buildBrush->numsides = 5; + for( j = 0; j < buildBrush->numsides; j++ ) + buildBrush->sides[ j ].shaderInfo = si; ++ + buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points ); +- buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] ); +- buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] ); +- buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] ); +- buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points ); +- +- /* add to entity */ +- if( CreateBrushWindings( buildBrush ) ) +- { +- AddBrushBevels(); +- //% EmitBrushes( buildBrush, NULL, NULL ); +- buildBrush->next = entities[ mapEntityNum ].brushes; +- entities[ mapEntityNum ].brushes = buildBrush; +- entities[ mapEntityNum ].numBrushes++; +- } +- else +- free( buildBrush ); ++ buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2] ++ buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1] ++ buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3] ++ buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs ); + } ++ else ++ { ++ free(buildBrush); ++ continue; ++ } ++ ++ normalEpsilon = normalEpsilon_save; ++ distanceEpsilon = distanceEpsilon_save; ++ ++ /* add to entity */ ++ if( CreateBrushWindings( buildBrush ) ) ++ { ++ AddBrushBevels(); ++ //% EmitBrushes( buildBrush, NULL, NULL ); ++ buildBrush->next = entities[ mapEntityNum ].brushes; ++ entities[ mapEntityNum ].brushes = buildBrush; ++ entities[ mapEntityNum ].numBrushes++; ++ } ++ else ++ free( buildBrush ); + } + } + } +Index: tools/quake3/q3map2/map.c +=================================================================== +--- tools/quake3/q3map2/map.c (revision 193) ++++ tools/quake3/q3map2/map.c (working copy) +@@ -184,7 +184,7 @@ + snaps a plane to normal/distance epsilons + */ + +-void SnapPlane( vec3_t normal, vec_t *dist ) ++void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center ) + { + // SnapPlane disabled by LordHavoc because it often messes up collision + // brushes made from triangles of embedded models, and it has little effect +@@ -193,7 +193,13 @@ + SnapPlane reenabled by namespace because of multiple reports of + q3map2-crashes which were triggered by this patch. + */ ++ // div0: ensure the point "center" stays on the plane (actually, this ++ // rotates the plane around the point center). ++ // if center lies on the plane, it is guaranteed to stay on the plane by ++ // this fix. ++ vec_t centerDist = DotProduct(normal, center); + SnapNormal( normal ); ++ *dist += (DotProduct(normal, center) - centerDist); + + if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) + *dist = Q_rint( *dist ); +@@ -207,7 +213,7 @@ + must be within an epsilon distance of the plane + */ + +-int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) ++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? + + #ifdef USE_HASHING + +@@ -215,10 +221,14 @@ + int i, j, hash, h; + plane_t *p; + vec_t d; ++ vec3_t centerofweight; ++ ++ VectorClear(centerofweight); ++ for(i = 0; i < numPoints; ++i) ++ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight); + +- + /* hash the plane */ +- SnapPlane( normal, &dist ); ++ SnapPlane( normal, &dist, centerofweight ); + hash = (PLANE_HASHES - 1) & (int) fabs( dist ); + + /* search the border bins as well */ +@@ -259,7 +269,13 @@ + plane_t *p; + + +- SnapPlane( normal, &dist ); ++ vec3_t centerofweight; ++ ++ VectorClear(centerofweight); ++ for(i = 0; i < numPoints; ++i) ++ VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight); ++ ++ SnapPlane( normal, &dist, centerofweight ); + for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ ) + { + if( PlaneEqual( p, normal, dist ) ) diff --git a/misc/gtkradiant/singlepatches/both-obj.diff b/misc/gtkradiant/singlepatches/both-obj.diff index 574d2ac2d..77e03a9a0 100644 --- a/misc/gtkradiant/singlepatches/both-obj.diff +++ b/misc/gtkradiant/singlepatches/both-obj.diff @@ -1,8 +1,20 @@ Index: libs/picomodel/pm_obj.c =================================================================== ---- libs/picomodel/pm_obj.c (revision 193) +--- libs/picomodel/pm_obj.c (revision 290) +++ libs/picomodel/pm_obj.c (working copy) -@@ -265,7 +265,7 @@ +@@ -215,10 +215,9 @@ + } + } + +-#if 0 + static int _obj_mtl_load( picoModel_t *model ) + { +- //picoShader_t *curShader = NULL; ++ picoShader_t *curShader = NULL; + picoParser_t *p; + picoByte_t *mtlBuffer; + int mtlBufSize; +@@ -266,7 +265,7 @@ /* get next token in material file */ if (_pico_parse( p,1 ) == NULL) break; @@ -11,7 +23,7 @@ Index: libs/picomodel/pm_obj.c /* skip empty lines */ if (p->token == NULL || !strlen( p->token )) -@@ -307,6 +307,7 @@ +@@ -308,6 +307,7 @@ else if (!_pico_stricmp(p->token,"map_kd")) { char *mapName; @@ -19,7 +31,7 @@ Index: libs/picomodel/pm_obj.c /* pointer to current shader must be valid */ if (curShader == NULL) -@@ -321,6 +322,10 @@ +@@ -322,6 +322,10 @@ _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine); _obj_mtl_error_return; } @@ -30,7 +42,15 @@ Index: libs/picomodel/pm_obj.c /* set shader map name */ PicoSetShaderMapName( shader,mapName ); } -@@ -521,7 +526,7 @@ +@@ -478,7 +482,6 @@ + /* return with success */ + return 1; + } +-#endif + + /* _obj_load: + * loads a wavefront obj model file. +@@ -523,7 +526,7 @@ PicoSetModelFileName( model,fileName ); /* try loading the materials; we don't handle the result */ @@ -39,7 +59,7 @@ Index: libs/picomodel/pm_obj.c _obj_mtl_load( model ); #endif -@@ -830,6 +835,41 @@ +@@ -832,6 +835,41 @@ curVertex += max; } } diff --git a/misc/gtkradiant/singlepatches/q3map2-UTavgcolorfix.diff b/misc/gtkradiant/singlepatches/q3map2-UTavgcolorfix.diff index 2d147960f..f920c78f9 100644 --- a/misc/gtkradiant/singlepatches/q3map2-UTavgcolorfix.diff +++ b/misc/gtkradiant/singlepatches/q3map2-UTavgcolorfix.diff @@ -1,8 +1,8 @@ Index: tools/quake3/q3map2/shaders.c =================================================================== ---- tools/quake3/q3map2/shaders.c (revision 191) +--- tools/quake3/q3map2/shaders.c (revision 290) +++ tools/quake3/q3map2/shaders.c (working copy) -@@ -793,8 +793,14 @@ +@@ -747,8 +747,14 @@ } if( VectorLength( si->color ) <= 0.0f ) diff --git a/misc/gtkradiant/singlepatches/q3map2-UTfloodlight.diff b/misc/gtkradiant/singlepatches/q3map2-UTfloodlight.diff index 454432376..b3a1970ce 100644 --- a/misc/gtkradiant/singlepatches/q3map2-UTfloodlight.diff +++ b/misc/gtkradiant/singlepatches/q3map2-UTfloodlight.diff @@ -1,20 +1,21 @@ Index: tools/quake3/q3map2/light_ydnar.c =================================================================== ---- tools/quake3/q3map2/light_ydnar.c (revision 191) +--- tools/quake3/q3map2/light_ydnar.c (revision 290) +++ tools/quake3/q3map2/light_ydnar.c (working copy) -@@ -1767,6 +1864,8 @@ +@@ -1449,6 +1449,8 @@ + vec3_t color, averageColor, averageDir, total, temp, temp2; float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; trace_t trace; - float stackLightLuxels[ STACK_LL_SIZE ]; + vec3_t flood; + float *floodlight; /* bail if this number exceeds the number of raw lightmaps */ -@@ -2223,6 +2332,78 @@ +@@ -1871,6 +1873,78 @@ + /* free light list */ FreeTraceLights( &trace ); - /* ----------------------------------------------------------------- ++ /* ----------------------------------------------------------------- + floodlight pass + ----------------------------------------------------------------- */ + @@ -86,11 +87,10 @@ Index: tools/quake3/q3map2/light_ydnar.c + } + } + -+ /* ----------------------------------------------------------------- - dirt pass - ----------------------------------------------------------------- */ - -@@ -3587,7 +3768,320 @@ + /* ----------------------------------------------------------------- + filter pass + ----------------------------------------------------------------- */ +@@ -3123,7 +3197,320 @@ CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace ); } @@ -413,9 +413,9 @@ Index: tools/quake3/q3map2/light_ydnar.c + Index: tools/quake3/q3map2/light.c =================================================================== ---- tools/quake3/q3map2/light.c (revision 191) +--- tools/quake3/q3map2/light.c (revision 290) +++ tools/quake3/q3map2/light.c (working copy) -@@ -1378,6 +1378,56 @@ +@@ -1363,6 +1363,56 @@ break; } @@ -472,9 +472,9 @@ Index: tools/quake3/q3map2/light.c /* normalize to get primary light direction */ VectorNormalize( gp->dir, gp->dir ); -@@ -1661,6 +1711,12 @@ - RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap ); - } +@@ -1544,6 +1594,12 @@ + qboolean minVertex, minGrid; + const char *value; + /* floodlight them up */ + if( floodlighty ) @@ -483,9 +483,9 @@ Index: tools/quake3/q3map2/light.c + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap ); + } - /* ydnar: set up light envelopes */ - SetupEnvelopes( qfalse, fast ); -@@ -1703,6 +1759,7 @@ + /* ydnar: smooth normals */ + if( shade ) +@@ -1675,6 +1731,7 @@ /* flag bouncing */ bouncing = qtrue; VectorClear( ambientColor ); @@ -493,9 +493,9 @@ Index: tools/quake3/q3map2/light.c /* generate diffuse lights */ RadFreeLights(); -@@ -2191,6 +2256,21 @@ - cpmaHack = qtrue; - Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" ); +@@ -2114,6 +2171,21 @@ + loMem = qtrue; + Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" ); } + else if( !strcmp( argv[ i ], "-floodlight" ) ) + { @@ -513,21 +513,21 @@ Index: tools/quake3/q3map2/light.c + Sys_Printf( "Low Quality FloodLighting enabled\n" ); + } - /* r7: dirtmapping */ - else if( !strcmp( argv[ i ], "-dirty" ) ) -@@ -2279,6 +2359,7 @@ + else + Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); +@@ -2156,6 +2228,7 @@ + /* ydnar: set up optimization */ SetupBrushes(); - SetupDirt(); + SetupFloodLight(); SetupSurfaceLightmaps(); /* initialize the surface facet tracing */ Index: tools/quake3/q3map2/lightmaps_ydnar.c =================================================================== ---- tools/quake3/q3map2/lightmaps_ydnar.c (revision 191) +--- tools/quake3/q3map2/lightmaps_ydnar.c (revision 290) +++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy) -@@ -414,6 +414,12 @@ +@@ -413,6 +413,12 @@ lm->superNormals = safe_malloc( size ); memset( lm->superNormals, 0, size ); @@ -542,25 +542,25 @@ Index: tools/quake3/q3map2/lightmaps_ydnar.c if( lm->superClusters == NULL ) Index: tools/quake3/q3map2/q3map2.h =================================================================== ---- tools/quake3/q3map2/q3map2.h (revision 191) +--- tools/quake3/q3map2/q3map2.h (revision 290) +++ tools/quake3/q3map2/q3map2.h (working copy) -@@ -267,6 +267,7 @@ - #define SUPER_NORMAL_SIZE 4 +@@ -265,6 +265,7 @@ + #define SUPER_NORMAL_SIZE 3 #define SUPER_DELUXEL_SIZE 3 #define BSP_DELUXEL_SIZE 3 +#define SUPER_FLOODLIGHT_SIZE 1 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) -@@ -279,6 +280,7 @@ +@@ -273,6 +274,7 @@ + #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE)) #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE)) - #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */ +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) ) - - - -@@ -1392,6 +1395,7 @@ + #define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x))) + #define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) + #define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE)) +@@ -1364,6 +1366,7 @@ float *superDeluxels; /* average light direction */ float *bspDeluxels; @@ -568,28 +568,26 @@ Index: tools/quake3/q3map2/q3map2.h } rawLightmap_t; -@@ -1704,6 +1708,10 @@ - float DirtForSample( trace_t *trace ); - void DirtyRawLightmap( int num ); +@@ -1670,6 +1673,9 @@ + void SmoothNormals( void ); + void MapRawLightmap( int num ); +void SetupFloodLight(); +float FloodLightForSample( trace_t *trace ); +void FloodLightRawLightmap( int num ); -+ void IlluminateRawLightmap( int num ); void IlluminateVertexes( int num ); -@@ -2098,6 +2106,13 @@ - Q_EXTERN float dirtScale Q_ASSIGN( 1.0f ); - Q_EXTERN float dirtGain Q_ASSIGN( 1.0f ); - +@@ -2037,6 +2043,12 @@ + Q_EXTERN qboolean sunOnly; + Q_EXTERN int approximateTolerance Q_ASSIGN( 0 ); + Q_EXTERN qboolean noCollapse; +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse ); +Q_EXTERN vec3_t floodlightRGB; +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 ); +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 ); -+ - Q_EXTERN qboolean dump Q_ASSIGN( qfalse ); - Q_EXTERN qboolean debug Q_ASSIGN( qfalse ); - Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse ); + Q_EXTERN qboolean debug; + Q_EXTERN qboolean debugSurfaces; + Q_EXTERN qboolean debugUnused; diff --git a/misc/gtkradiant/singlepatches/q3map2-UTtrianglecheck.diff b/misc/gtkradiant/singlepatches/q3map2-UTtrianglecheck.diff index 98eed9da8..724f11cdc 100644 --- a/misc/gtkradiant/singlepatches/q3map2-UTtrianglecheck.diff +++ b/misc/gtkradiant/singlepatches/q3map2-UTtrianglecheck.diff @@ -1,8 +1,8 @@ Index: tools/quake3/q3map2/light_ydnar.c =================================================================== ---- tools/quake3/q3map2/light_ydnar.c (revision 191) +--- tools/quake3/q3map2/light_ydnar.c (revision 290) +++ tools/quake3/q3map2/light_ydnar.c (working copy) -@@ -384,7 +420,7 @@ +@@ -372,7 +372,7 @@ #define NUDGE 0.5f #define BOGUS_NUDGE -99999.0f @@ -11,7 +11,7 @@ Index: tools/quake3/q3map2/light_ydnar.c { int i, x, y, numClusters, *clusters, pointCluster, *cluster; float *luxel, *origin, *normal, d, lightmapSampleOffset; -@@ -392,6 +428,12 @@ +@@ -380,6 +380,12 @@ vec3_t pNormal; vec3_t vecs[ 3 ]; vec3_t nudged; @@ -24,7 +24,7 @@ Index: tools/quake3/q3map2/light_ydnar.c float *nudge; static float nudges[][ 2 ] = { -@@ -485,6 +527,51 @@ +@@ -473,6 +479,51 @@ /* non axial lightmap projection (explicit xyz) */ else VectorCopy( dv->xyz, origin ); @@ -76,7 +76,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* planar surfaces have precalculated lightmap vectors for nudging */ if( lm->plane != NULL ) -@@ -516,8 +603,13 @@ +@@ -504,8 +555,13 @@ else origin[ lm->axisNum ] += lightmapSampleOffset; @@ -91,7 +91,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* another retarded hack, storing nudge count in luxel[ 1 ] */ luxel[ 1 ] = 0.0f; -@@ -533,14 +625,14 @@ +@@ -521,14 +577,14 @@ for( i = 0; i < 3; i++ ) { /* set nudged point*/ @@ -109,7 +109,7 @@ Index: tools/quake3/q3map2/light_ydnar.c luxel[ 1 ] += 1.0f; } } -@@ -550,8 +642,8 @@ +@@ -538,8 +594,8 @@ { VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged ); pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); @@ -120,7 +120,7 @@ Index: tools/quake3/q3map2/light_ydnar.c luxel[ 1 ] += 1.0f; } -@@ -597,7 +689,7 @@ +@@ -585,7 +641,7 @@ than the distance between two luxels (thanks jc :) */ @@ -129,7 +129,7 @@ Index: tools/quake3/q3map2/light_ydnar.c { bspDrawVert_t mid, *dv2[ 3 ]; int max; -@@ -645,7 +737,7 @@ +@@ -633,7 +689,7 @@ /* split the longest edge and map it */ LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); @@ -138,7 +138,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* push the point up a little bit to account for fp creep (fixme: revisit this) */ //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz ); -@@ -653,12 +745,12 @@ +@@ -641,12 +697,12 @@ /* recurse to first triangle */ VectorCopy( dv, dv2 ); dv2[ max ] = ∣ @@ -153,7 +153,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } -@@ -674,6 +766,7 @@ +@@ -662,6 +718,7 @@ int i; vec4_t plane; vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ]; @@ -161,7 +161,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* get plane if possible */ -@@ -699,16 +792,20 @@ +@@ -687,16 +744,20 @@ ttv = NULL; } @@ -186,7 +186,7 @@ Index: tools/quake3/q3map2/light_ydnar.c return qtrue; } -@@ -730,7 +827,7 @@ +@@ -718,7 +779,7 @@ dv2[ 2 ] = dv[ (i + 1) % 3 ]; /* map the degenerate triangle */ @@ -195,7 +195,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } } -@@ -792,8 +889,8 @@ +@@ -780,8 +841,8 @@ LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] ); /* map the vertexes */ @@ -206,7 +206,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* 0 and 2 */ if( max == 0 ) -@@ -878,10 +975,10 @@ +@@ -866,10 +927,10 @@ } /* map the vertexes */ @@ -221,7 +221,7 @@ Index: tools/quake3/q3map2/light_ydnar.c /* subdivide the quad */ MapQuad_r( lm, info, dv, plane, stv, ttv ); -@@ -1173,7 +1270,7 @@ +@@ -1161,7 +1222,7 @@ continue; /* map the fake vert */ @@ -230,7 +230,7 @@ Index: tools/quake3/q3map2/light_ydnar.c } } } -@@ -1963,22 +2062,32 @@ +@@ -1636,22 +1697,32 @@ deluxel = SUPER_DELUXEL( x, y ); origin = SUPER_ORIGIN( x, y ); normal = SUPER_NORMAL( x, y ); diff --git a/misc/gtkradiant/singlepatches/q3map2-decomptexcoords.diff b/misc/gtkradiant/singlepatches/q3map2-decomptexcoords.diff index 808888f26..3f19de8a5 100644 --- a/misc/gtkradiant/singlepatches/q3map2-decomptexcoords.diff +++ b/misc/gtkradiant/singlepatches/q3map2-decomptexcoords.diff @@ -1,8 +1,8 @@ Index: tools/quake3/q3map2/convert_map.c =================================================================== ---- tools/quake3/q3map2/convert_map.c (revision 191) +--- tools/quake3/q3map2/convert_map.c (revision 290) +++ tools/quake3/q3map2/convert_map.c (working copy) -@@ -46,6 +46,105 @@ +@@ -45,6 +45,105 @@ #define SNAP_FLOAT_TO_INT 4 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT) @@ -108,7 +108,7 @@ Index: tools/quake3/q3map2/convert_map.c static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) { int i, j; -@@ -54,12 +153,17 @@ +@@ -53,12 +152,17 @@ bspShader_t *shader; char *texture; bspPlane_t *plane; @@ -126,7 +126,7 @@ Index: tools/quake3/q3map2/convert_map.c /* clear out build brush */ for( i = 0; i < buildBrush->numsides; i++ ) -@@ -109,9 +213,88 @@ +@@ -108,9 +212,88 @@ /* get build side */ buildSide = &buildBrush->sides[ i ]; @@ -215,7 +215,7 @@ Index: tools/quake3/q3map2/convert_map.c /* get texture name */ if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) -@@ -130,14 +313,21 @@ +@@ -129,14 +312,21 @@ /* print brush side */ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ @@ -241,11 +241,11 @@ Index: tools/quake3/q3map2/convert_map.c Index: tools/quake3/q3map2/main.c =================================================================== ---- tools/quake3/q3map2/main.c (revision 191) +--- tools/quake3/q3map2/main.c (revision 290) +++ tools/quake3/q3map2/main.c (working copy) -@@ -541,6 +541,18 @@ - Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); - } +@@ -276,6 +276,18 @@ + else + Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); } + else if( !strcmp( argv[ i ], "-ne" ) ) + { diff --git a/misc/gtkradiant/singlepatches/q3map2-snapplane.diff b/misc/gtkradiant/singlepatches/q3map2-snapplane.diff index b5e3d6bfa..56fe516e7 100644 --- a/misc/gtkradiant/singlepatches/q3map2-snapplane.diff +++ b/misc/gtkradiant/singlepatches/q3map2-snapplane.diff @@ -1,8 +1,8 @@ Index: tools/quake3/q3map2/model.c =================================================================== ---- tools/quake3/q3map2/model.c (revision 193) +--- tools/quake3/q3map2/model.c (revision 290) +++ tools/quake3/q3map2/model.c (working copy) -@@ -222,6 +222,8 @@ +@@ -221,6 +221,8 @@ byte *color; picoIndex_t *indexes; remap_t *rm, *glob; @@ -11,7 +11,7 @@ Index: tools/quake3/q3map2/model.c /* get model */ -@@ -398,9 +400,8 @@ +@@ -399,9 +401,8 @@ /* ydnar: giant hack land: generate clipping brushes for model triangles */ if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */ { @@ -224,32 +224,27 @@ Index: tools/quake3/q3map2/model.c } Index: tools/quake3/q3map2/map.c =================================================================== ---- tools/quake3/q3map2/map.c (revision 193) +--- tools/quake3/q3map2/map.c (revision 290) +++ tools/quake3/q3map2/map.c (working copy) -@@ -184,7 +184,7 @@ +@@ -183,9 +183,15 @@ snaps a plane to normal/distance epsilons */ -void SnapPlane( vec3_t normal, vec_t *dist ) +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center ) { - // SnapPlane disabled by LordHavoc because it often messes up collision - // brushes made from triangles of embedded models, and it has little effect -@@ -193,7 +193,13 @@ - SnapPlane reenabled by namespace because of multiple reports of - q3map2-crashes which were triggered by this patch. - */ +- SnapNormal( normal ); + // div0: ensure the point "center" stays on the plane (actually, this + // rotates the plane around the point center). + // if center lies on the plane, it is guaranteed to stay on the plane by + // this fix. + vec_t centerDist = DotProduct(normal, center); - SnapNormal( normal ); ++ SnapNormal( normal ); + *dist += (DotProduct(normal, center) - centerDist); if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon ) *dist = Q_rint( *dist ); -@@ -207,7 +213,7 @@ +@@ -199,7 +205,7 @@ must be within an epsilon distance of the plane */ @@ -258,7 +253,7 @@ Index: tools/quake3/q3map2/map.c #ifdef USE_HASHING -@@ -215,10 +221,14 @@ +@@ -207,10 +213,14 @@ int i, j, hash, h; plane_t *p; vec_t d; @@ -275,7 +270,7 @@ Index: tools/quake3/q3map2/map.c hash = (PLANE_HASHES - 1) & (int) fabs( dist ); /* search the border bins as well */ -@@ -259,7 +269,13 @@ +@@ -251,7 +261,13 @@ plane_t *p; -- 2.39.2