Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

brush_primit.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "stdafx.h"
00023 #include "qe3.h"
00024 
00025 // compute a determinant using Sarrus rule
00026 //++timo "inline" this with a macro
00027 // NOTE : the three vec3_t are understood as columns of the matrix
00028 vec_t SarrusDet(vec3_t a, vec3_t b, vec3_t c)
00029 {
00030     return a[0]*b[1]*c[2]+b[0]*c[1]*a[2]+c[0]*a[1]*b[2]
00031         -c[0]*b[1]*a[2]-a[1]*b[0]*c[2]-a[0]*b[2]*c[1];
00032 }
00033 
00034 //++timo replace everywhere texX by texS etc. ( ----> and in q3map !) 
00035 // NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME !
00036 // WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
00037 // rotation by (0,RotY,RotZ) assigns X to normal
00038 void ComputeAxisBase(vec3_t normal,vec3_t texS,vec3_t texT )
00039 {
00040     vec_t RotY,RotZ;
00041     // do some cleaning
00042     if (fabs(normal[0])<1e-6)
00043         normal[0]=0.0f;
00044     if (fabs(normal[1])<1e-6)
00045         normal[1]=0.0f;
00046     if (fabs(normal[2])<1e-6)
00047         normal[2]=0.0f;
00048     RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0]));
00049     RotZ=atan2(normal[1],normal[0]);
00050     // rotate (0,1,0) and (0,0,1) to compute texS and texT
00051     texS[0]=-sin(RotZ);
00052     texS[1]=cos(RotZ);
00053     texS[2]=0;
00054     // the texT vector is along -Z ( T texture coorinates axis )
00055     texT[0]=-sin(RotY)*cos(RotZ);
00056     texT[1]=-sin(RotY)*sin(RotZ);
00057     texT[2]=-cos(RotY);
00058 }
00059 
00060 void FaceToBrushPrimitFace(face_t *f)
00061 {
00062     vec3_t texX,texY;
00063     vec3_t proj;
00064     // ST of (0,0) (1,0) (0,1)
00065     vec_t ST[3][5]; // [ point index ] [ xyz ST ]
00066     //++timo not used as long as brushprimit_texdef and texdef are static
00067 /*  f->brushprimit_texdef.contents=f->texdef.contents;
00068     f->brushprimit_texdef.flags=f->texdef.flags;
00069     f->brushprimit_texdef.value=f->texdef.value;
00070     strcpy(f->brushprimit_texdef.name,f->texdef.name); */
00071 #ifdef _DEBUG
00072     if ( f->plane.normal[0]==0.0f && f->plane.normal[1]==0.0f && f->plane.normal[2]==0.0f )
00073     {
00074         Sys_Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n");
00075     }
00076     // check d_texture
00077     if (!f->d_texture)
00078     {
00079         Sys_Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n");
00080         return;
00081     }
00082 #endif
00083     // compute axis base
00084     ComputeAxisBase(f->plane.normal,texX,texY);
00085     // compute projection vector
00086     VectorCopy(f->plane.normal,proj);
00087     VectorScale(proj,f->plane.dist,proj);
00088     // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane
00089     // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane
00090     // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane
00091     // use old texture code to compute the ST coords of these points
00092     VectorCopy(proj,ST[0]);
00093     EmitTextureCoordinates(ST[0], f->d_texture, f);
00094     VectorCopy(texX,ST[1]);
00095     VectorAdd(ST[1],proj,ST[1]);
00096     EmitTextureCoordinates(ST[1], f->d_texture, f);
00097     VectorCopy(texY,ST[2]);
00098     VectorAdd(ST[2],proj,ST[2]);
00099     EmitTextureCoordinates(ST[2], f->d_texture, f);
00100     // compute texture matrix
00101     f->brushprimit_texdef.coords[0][2]=ST[0][3];
00102     f->brushprimit_texdef.coords[1][2]=ST[0][4];
00103     f->brushprimit_texdef.coords[0][0]=ST[1][3]-f->brushprimit_texdef.coords[0][2];
00104     f->brushprimit_texdef.coords[1][0]=ST[1][4]-f->brushprimit_texdef.coords[1][2];
00105     f->brushprimit_texdef.coords[0][1]=ST[2][3]-f->brushprimit_texdef.coords[0][2];
00106     f->brushprimit_texdef.coords[1][1]=ST[2][4]-f->brushprimit_texdef.coords[1][2];
00107 }
00108 
00109 // compute texture coordinates for the winding points
00110 void EmitBrushPrimitTextureCoordinates(face_t * f, winding_t * w)
00111 {
00112     vec3_t texX,texY;
00113     vec_t x,y;
00114     // compute axis base
00115     ComputeAxisBase(f->plane.normal,texX,texY);
00116     // in case the texcoords matrix is empty, build a default one
00117     // same behaviour as if scale[0]==0 && scale[1]==0 in old code
00118     if (f->brushprimit_texdef.coords[0][0]==0 && f->brushprimit_texdef.coords[1][0]==0 && f->brushprimit_texdef.coords[0][1]==0 && f->brushprimit_texdef.coords[1][1]==0)
00119     {
00120         f->brushprimit_texdef.coords[0][0] = 1.0f;
00121         f->brushprimit_texdef.coords[1][1] = 1.0f;
00122         ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture );
00123     }
00124     int i;
00125     for (i=0 ; i<w->numpoints ; i++)
00126     {
00127         x=DotProduct(w->points[i],texX);
00128         y=DotProduct(w->points[i],texY);
00129 #ifdef _DEBUG
00130         if (g_qeglobals.bNeedConvert)
00131         {
00132             // check we compute the same ST as the traditional texture computation used before
00133             vec_t S=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2];
00134             vec_t T=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2];
00135             if ( fabs(S-w->points[i][3])>1e-2 || fabs(T-w->points[i][4])>1e-2 )
00136             {
00137                 if ( fabs(S-w->points[i][3])>1e-4 || fabs(T-w->points[i][4])>1e-4 )
00138                     Sys_Printf("Warning : precision loss in brush -> brush primitive texture computation\n");
00139                 else
00140                     Sys_Printf("Warning : brush -> brush primitive texture computation bug detected\n");
00141             }
00142         }
00143 #endif
00144         w->points[i][3]=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2];
00145         w->points[i][4]=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2];
00146     }
00147 }
00148 
00149 // parse a brush in brush primitive format
00150 void BrushPrimit_Parse(brush_t  *b)
00151 {
00152     epair_t     *ep;
00153     face_t      *f;
00154     int         i,j;
00155     GetToken (true);
00156     if (strcmp (token, "{"))
00157     {
00158         Warning ("parsing brush primitive");
00159         return;
00160     }
00161     do
00162     {
00163         if (!GetToken (true))
00164             break;
00165         if (!strcmp (token, "}") )
00166             break;
00167         // reading of b->epairs if any
00168         if (strcmp (token, "(") )
00169         {
00170             ep = ParseEpair();
00171             ep->next = b->epairs;
00172             b->epairs = ep;
00173         }
00174         else
00175         // it's a face
00176         {
00177             f = Face_Alloc();
00178             f->next = NULL;
00179             if (!b->brush_faces)
00180                 b->brush_faces = f;
00181             else
00182             {
00183                 face_t *scan;
00184                 for (scan=b->brush_faces ; scan->next ; scan=scan->next)
00185                     ;
00186                 scan->next = f;
00187             }
00188 
00189             // read the three point plane definition
00190             for (i=0 ; i<3 ; i++)
00191             {
00192                 if (i != 0)
00193                     GetToken (true);
00194                 if (strcmp (token, "(") )
00195                 {
00196                     Warning ("parsing brush");
00197                     return;
00198                 }
00199                 for (j=0 ; j<3 ; j++)
00200                 {
00201                     GetToken (false);
00202                     f->planepts[i][j] = atof(token);
00203                 }
00204                 GetToken (false);
00205                 if (strcmp (token, ")") )
00206                 {
00207                     Warning ("parsing brush");
00208                     return;
00209                 }
00210             }
00211             // texture coordinates
00212             GetToken (false);
00213             if (strcmp(token, "("))
00214             {
00215                 Warning ("parsing brush primitive");
00216                 return;
00217             }
00218             GetToken (false);
00219             if (strcmp(token, "("))
00220             {
00221                 Warning ("parsing brush primitive");
00222                 return;
00223             }
00224             for (j=0;j<3;j++)
00225             {
00226                 GetToken(false);
00227                 f->brushprimit_texdef.coords[0][j]=atof(token);
00228             }
00229             GetToken (false);
00230             if (strcmp(token, ")"))
00231             {
00232                 Warning ("parsing brush primitive");
00233                 return;
00234             }
00235             GetToken (false);
00236             if (strcmp(token, "("))
00237             {
00238                 Warning ("parsing brush primitive");
00239                 return;
00240             }
00241             for (j=0;j<3;j++)
00242             {
00243                 GetToken(false);
00244                 f->brushprimit_texdef.coords[1][j]=atof(token);
00245             }
00246             GetToken (false);
00247             if (strcmp(token, ")"))
00248             {
00249                 Warning ("parsing brush primitive");
00250                 return;
00251             }
00252             GetToken (false);
00253             if (strcmp(token, ")"))
00254             {
00255                 Warning ("parsing brush primitive");
00256                 return;
00257             }
00258             // read the texturedef
00259             GetToken (false);
00260             //strcpy(f->texdef.name, token);
00261             f->texdef.SetName(token);
00262             if (TokenAvailable ())
00263             {
00264                 GetToken (false);
00265                 f->texdef.contents = atoi(token);
00266         GetToken (false);
00267                 f->texdef.flags = atoi(token);
00268                 GetToken (false);
00269                 f->texdef.value = atoi(token);
00270             }
00271         }
00272     } while (1);
00273 }
00274 
00275 // compute a fake shift scale rot representation from the texture matrix
00276 // these shift scale rot values are to be understood in the local axis base
00277 void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] )
00278 {
00279 #ifdef _DEBUG
00280     // check this matrix is orthogonal
00281     if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON)
00282         Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n");
00283 #endif
00284     scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]);
00285     scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]);
00286 #ifdef _DEBUG
00287     if (scale[0]<ZERO_EPSILON || scale[1]<ZERO_EPSILON)
00288         Sys_Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n");
00289 #endif
00290     // compute rotate value
00291     if (fabs(texMat[0][0])<ZERO_EPSILON)
00292     {
00293 #ifdef _DEBUG
00294         // check brushprimit_texdef[1][0] is not zero
00295         if (fabs(texMat[1][0])<ZERO_EPSILON)
00296             Sys_Printf("Warning : unexpected texdef[1][0]==0 in TexMatToFakeTexCoords\n");
00297 #endif
00298         // rotate is +-90
00299         if (texMat[1][0]>0)
00300             *rot=90.0f;
00301         else
00302             *rot=-90.0f;
00303     }
00304     else
00305     *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) );
00306     shift[0] = -texMat[0][2];
00307     shift[1] = texMat[1][2];
00308 }
00309 
00310 // compute back the texture matrix from fake shift scale rot
00311 // the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one )
00312 void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] )
00313 {
00314     texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) );
00315     texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) );
00316     texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) );
00317     texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) );
00318     texMat[0][2] = -shift[0];
00319     texMat[1][2] = shift[1];
00320 }
00321 
00322 // convert a texture matrix between two qtexture_t
00323 // if NULL for qtexture_t, basic 2x2 texture is assumed ( straight mapping between s/t coordinates and geometric coordinates )
00324 void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 )
00325 {
00326     float s1,s2;
00327     s1 = ( qtex1 ? static_cast<float>( qtex1->width ) : 2.0f ) / ( qtex2 ? static_cast<float>( qtex2->width ) : 2.0f );
00328     s2 = ( qtex1 ? static_cast<float>( qtex1->height ) : 2.0f ) / ( qtex2 ? static_cast<float>( qtex2->height ) : 2.0f );
00329     texMat2->coords[0][0]=s1*texMat1->coords[0][0];
00330     texMat2->coords[0][1]=s1*texMat1->coords[0][1];
00331     texMat2->coords[0][2]=s1*texMat1->coords[0][2];
00332     texMat2->coords[1][0]=s2*texMat1->coords[1][0];
00333     texMat2->coords[1][1]=s2*texMat1->coords[1][1];
00334     texMat2->coords[1][2]=s2*texMat1->coords[1][2];
00335 }
00336 
00337 // texture locking
00338 void Face_MoveTexture_BrushPrimit(face_t *f, vec3_t delta)
00339 {
00340     vec3_t texS,texT;
00341     vec_t tx,ty;
00342     vec3_t M[3]; // columns of the matrix .. easier that way
00343     vec_t det;
00344     vec3_t D[2];
00345     // compute plane axis base ( doesn't change with translation )
00346     ComputeAxisBase( f->plane.normal, texS, texT );
00347     // compute translation vector in plane axis base
00348     tx = DotProduct( delta, texS );
00349     ty = DotProduct( delta, texT );
00350     // fill the data vectors
00351     M[0][0]=tx; M[0][1]=1.0f+tx; M[0][2]=tx;
00352     M[1][0]=ty; M[1][1]=ty; M[1][2]=1.0f+ty;
00353     M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f;
00354     D[0][0]=f->brushprimit_texdef.coords[0][2];
00355     D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2];
00356     D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2];
00357     D[1][0]=f->brushprimit_texdef.coords[1][2];
00358     D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2];
00359     D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2];
00360     // solve
00361     det = SarrusDet( M[0], M[1], M[2] );
00362     f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det;
00363     f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det;
00364     f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det;
00365     f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det;
00366     f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det;
00367     f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det;
00368 }
00369 
00370 // call Face_MoveTexture_BrushPrimit after vec3_t computation
00371 void Select_ShiftTexture_BrushPrimit( face_t *f, int x, int y )
00372 {
00373     vec3_t texS,texT;
00374     vec3_t delta;
00375     ComputeAxisBase( f->plane.normal, texS, texT );
00376     VectorScale( texS, static_cast<float>(x), texS );
00377     VectorScale( texT, static_cast<float>(y), texT );
00378     VectorCopy( texS, delta );
00379     VectorAdd( delta, texT, delta );
00380     Face_MoveTexture_BrushPrimit( f, delta );
00381 }
00382 
00383 // texture locking
00384 // called before the points on the face are actually rotated
00385 void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin )
00386 {
00387     vec3_t texS,texT;           // axis base of the initial plane
00388     vec3_t vRotate;             // rotation vector
00389     vec3_t Orig;
00390     vec3_t rOrig,rvecS,rvecT;   // (0,0) (1,0) (0,1) ( initial plane axis base ) after rotation ( world axis base )
00391     vec3_t rNormal;             // normal of the plane after rotation
00392     vec3_t rtexS,rtexT;         // axis base of the rotated plane
00393     vec3_t lOrig,lvecS,lvecT;   // [2] are not used ( but usefull for debugging )
00394     vec3_t M[3];
00395     vec_t det;
00396     vec3_t D[2];
00397     // compute plane axis base
00398     ComputeAxisBase( f->plane.normal, texS, texT );
00399     // compute coordinates of (0,0) (1,0) (0,1) ( initial plane axis base ) after rotation
00400     // (0,0) (1,0) (0,1) ( initial plane axis base ) <-> (0,0,0) texS texT ( world axis base )
00401     // rotation vector
00402     VectorSet( vRotate, 0.0f, 0.0f, 0.0f );
00403     vRotate[nAxis]=fDeg;
00404     VectorSet( Orig, 0.0f, 0.0f, 0.0f );
00405     VectorRotate( Orig, vRotate, vOrigin, rOrig );
00406     VectorRotate( texS, vRotate, vOrigin, rvecS );
00407     VectorRotate( texT, vRotate, vOrigin, rvecT );
00408     // compute normal of plane after rotation
00409     VectorRotate( f->plane.normal, vRotate, rNormal );
00410     // compute rotated plane axis base
00411     ComputeAxisBase( rNormal, rtexS, rtexT );
00412     // compute S/T coordinates of the three points in rotated axis base ( in M matrix )
00413     lOrig[0] = DotProduct( rOrig, rtexS );
00414     lOrig[1] = DotProduct( rOrig, rtexT );
00415     lvecS[0] = DotProduct( rvecS, rtexS );
00416     lvecS[1] = DotProduct( rvecS, rtexT );
00417     lvecT[0] = DotProduct( rvecT, rtexS );
00418     lvecT[1] = DotProduct( rvecT, rtexT );
00419     M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f;
00420     M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f;
00421     M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f;
00422     // fill data vector
00423     D[0][0]=f->brushprimit_texdef.coords[0][2];
00424     D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2];
00425     D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2];
00426     D[1][0]=f->brushprimit_texdef.coords[1][2];
00427     D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2];
00428     D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2];
00429     // solve
00430     det = SarrusDet( M[0], M[1], M[2] );
00431     f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det;
00432     f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det;
00433     f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det;
00434     f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det;
00435     f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det;
00436     f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det;
00437 }
00438 
00439 // best fitted 2D vector is x.X+y.Y
00440 void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y )
00441 {
00442     double sx,sy;
00443     sx = DotProduct( v, X );
00444     sy = DotProduct( v, Y );
00445     if ( fabs(sy) > fabs(sx) )
00446     {
00447         x = 0;
00448         if ( sy > 0.0 )
00449             y =  1;
00450         else
00451             y = -1;
00452     }
00453     else
00454     {
00455         y = 0;
00456         if ( sx > 0.0 )
00457             x =  1;
00458         else
00459             x = -1;
00460     }
00461 }

Generated on Thu Aug 25 12:38:26 2005 for Quake III Arena by  doxygen 1.3.9.1