brush_primit.cpp (15922B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 #include "stdafx.h" 23 #include "qe3.h" 24 25 // compute a determinant using Sarrus rule 26 //++timo "inline" this with a macro 27 // NOTE : the three vec3_t are understood as columns of the matrix 28 vec_t SarrusDet(vec3_t a, vec3_t b, vec3_t c) 29 { 30 return a[0]*b[1]*c[2]+b[0]*c[1]*a[2]+c[0]*a[1]*b[2] 31 -c[0]*b[1]*a[2]-a[1]*b[0]*c[2]-a[0]*b[2]*c[1]; 32 } 33 34 //++timo replace everywhere texX by texS etc. ( ----> and in q3map !) 35 // NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME ! 36 // WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0 37 // rotation by (0,RotY,RotZ) assigns X to normal 38 void ComputeAxisBase(vec3_t normal,vec3_t texS,vec3_t texT ) 39 { 40 vec_t RotY,RotZ; 41 // do some cleaning 42 if (fabs(normal[0])<1e-6) 43 normal[0]=0.0f; 44 if (fabs(normal[1])<1e-6) 45 normal[1]=0.0f; 46 if (fabs(normal[2])<1e-6) 47 normal[2]=0.0f; 48 RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0])); 49 RotZ=atan2(normal[1],normal[0]); 50 // rotate (0,1,0) and (0,0,1) to compute texS and texT 51 texS[0]=-sin(RotZ); 52 texS[1]=cos(RotZ); 53 texS[2]=0; 54 // the texT vector is along -Z ( T texture coorinates axis ) 55 texT[0]=-sin(RotY)*cos(RotZ); 56 texT[1]=-sin(RotY)*sin(RotZ); 57 texT[2]=-cos(RotY); 58 } 59 60 void FaceToBrushPrimitFace(face_t *f) 61 { 62 vec3_t texX,texY; 63 vec3_t proj; 64 // ST of (0,0) (1,0) (0,1) 65 vec_t ST[3][5]; // [ point index ] [ xyz ST ] 66 //++timo not used as long as brushprimit_texdef and texdef are static 67 /* f->brushprimit_texdef.contents=f->texdef.contents; 68 f->brushprimit_texdef.flags=f->texdef.flags; 69 f->brushprimit_texdef.value=f->texdef.value; 70 strcpy(f->brushprimit_texdef.name,f->texdef.name); */ 71 #ifdef _DEBUG 72 if ( f->plane.normal[0]==0.0f && f->plane.normal[1]==0.0f && f->plane.normal[2]==0.0f ) 73 { 74 Sys_Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n"); 75 } 76 // check d_texture 77 if (!f->d_texture) 78 { 79 Sys_Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n"); 80 return; 81 } 82 #endif 83 // compute axis base 84 ComputeAxisBase(f->plane.normal,texX,texY); 85 // compute projection vector 86 VectorCopy(f->plane.normal,proj); 87 VectorScale(proj,f->plane.dist,proj); 88 // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the affine plane 89 // (1,0) in plane axis base is texX in world coordinates + projection on the affine plane 90 // (0,1) in plane axis base is texY in world coordinates + projection on the affine plane 91 // use old texture code to compute the ST coords of these points 92 VectorCopy(proj,ST[0]); 93 EmitTextureCoordinates(ST[0], f->d_texture, f); 94 VectorCopy(texX,ST[1]); 95 VectorAdd(ST[1],proj,ST[1]); 96 EmitTextureCoordinates(ST[1], f->d_texture, f); 97 VectorCopy(texY,ST[2]); 98 VectorAdd(ST[2],proj,ST[2]); 99 EmitTextureCoordinates(ST[2], f->d_texture, f); 100 // compute texture matrix 101 f->brushprimit_texdef.coords[0][2]=ST[0][3]; 102 f->brushprimit_texdef.coords[1][2]=ST[0][4]; 103 f->brushprimit_texdef.coords[0][0]=ST[1][3]-f->brushprimit_texdef.coords[0][2]; 104 f->brushprimit_texdef.coords[1][0]=ST[1][4]-f->brushprimit_texdef.coords[1][2]; 105 f->brushprimit_texdef.coords[0][1]=ST[2][3]-f->brushprimit_texdef.coords[0][2]; 106 f->brushprimit_texdef.coords[1][1]=ST[2][4]-f->brushprimit_texdef.coords[1][2]; 107 } 108 109 // compute texture coordinates for the winding points 110 void EmitBrushPrimitTextureCoordinates(face_t * f, winding_t * w) 111 { 112 vec3_t texX,texY; 113 vec_t x,y; 114 // compute axis base 115 ComputeAxisBase(f->plane.normal,texX,texY); 116 // in case the texcoords matrix is empty, build a default one 117 // same behaviour as if scale[0]==0 && scale[1]==0 in old code 118 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) 119 { 120 f->brushprimit_texdef.coords[0][0] = 1.0f; 121 f->brushprimit_texdef.coords[1][1] = 1.0f; 122 ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture ); 123 } 124 int i; 125 for (i=0 ; i<w->numpoints ; i++) 126 { 127 x=DotProduct(w->points[i],texX); 128 y=DotProduct(w->points[i],texY); 129 #ifdef _DEBUG 130 if (g_qeglobals.bNeedConvert) 131 { 132 // check we compute the same ST as the traditional texture computation used before 133 vec_t S=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; 134 vec_t T=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; 135 if ( fabs(S-w->points[i][3])>1e-2 || fabs(T-w->points[i][4])>1e-2 ) 136 { 137 if ( fabs(S-w->points[i][3])>1e-4 || fabs(T-w->points[i][4])>1e-4 ) 138 Sys_Printf("Warning : precision loss in brush -> brush primitive texture computation\n"); 139 else 140 Sys_Printf("Warning : brush -> brush primitive texture computation bug detected\n"); 141 } 142 } 143 #endif 144 w->points[i][3]=f->brushprimit_texdef.coords[0][0]*x+f->brushprimit_texdef.coords[0][1]*y+f->brushprimit_texdef.coords[0][2]; 145 w->points[i][4]=f->brushprimit_texdef.coords[1][0]*x+f->brushprimit_texdef.coords[1][1]*y+f->brushprimit_texdef.coords[1][2]; 146 } 147 } 148 149 // parse a brush in brush primitive format 150 void BrushPrimit_Parse(brush_t *b) 151 { 152 epair_t *ep; 153 face_t *f; 154 int i,j; 155 GetToken (true); 156 if (strcmp (token, "{")) 157 { 158 Warning ("parsing brush primitive"); 159 return; 160 } 161 do 162 { 163 if (!GetToken (true)) 164 break; 165 if (!strcmp (token, "}") ) 166 break; 167 // reading of b->epairs if any 168 if (strcmp (token, "(") ) 169 { 170 ep = ParseEpair(); 171 ep->next = b->epairs; 172 b->epairs = ep; 173 } 174 else 175 // it's a face 176 { 177 f = Face_Alloc(); 178 f->next = NULL; 179 if (!b->brush_faces) 180 b->brush_faces = f; 181 else 182 { 183 face_t *scan; 184 for (scan=b->brush_faces ; scan->next ; scan=scan->next) 185 ; 186 scan->next = f; 187 } 188 189 // read the three point plane definition 190 for (i=0 ; i<3 ; i++) 191 { 192 if (i != 0) 193 GetToken (true); 194 if (strcmp (token, "(") ) 195 { 196 Warning ("parsing brush"); 197 return; 198 } 199 for (j=0 ; j<3 ; j++) 200 { 201 GetToken (false); 202 f->planepts[i][j] = atof(token); 203 } 204 GetToken (false); 205 if (strcmp (token, ")") ) 206 { 207 Warning ("parsing brush"); 208 return; 209 } 210 } 211 // texture coordinates 212 GetToken (false); 213 if (strcmp(token, "(")) 214 { 215 Warning ("parsing brush primitive"); 216 return; 217 } 218 GetToken (false); 219 if (strcmp(token, "(")) 220 { 221 Warning ("parsing brush primitive"); 222 return; 223 } 224 for (j=0;j<3;j++) 225 { 226 GetToken(false); 227 f->brushprimit_texdef.coords[0][j]=atof(token); 228 } 229 GetToken (false); 230 if (strcmp(token, ")")) 231 { 232 Warning ("parsing brush primitive"); 233 return; 234 } 235 GetToken (false); 236 if (strcmp(token, "(")) 237 { 238 Warning ("parsing brush primitive"); 239 return; 240 } 241 for (j=0;j<3;j++) 242 { 243 GetToken(false); 244 f->brushprimit_texdef.coords[1][j]=atof(token); 245 } 246 GetToken (false); 247 if (strcmp(token, ")")) 248 { 249 Warning ("parsing brush primitive"); 250 return; 251 } 252 GetToken (false); 253 if (strcmp(token, ")")) 254 { 255 Warning ("parsing brush primitive"); 256 return; 257 } 258 // read the texturedef 259 GetToken (false); 260 //strcpy(f->texdef.name, token); 261 f->texdef.SetName(token); 262 if (TokenAvailable ()) 263 { 264 GetToken (false); 265 f->texdef.contents = atoi(token); 266 GetToken (false); 267 f->texdef.flags = atoi(token); 268 GetToken (false); 269 f->texdef.value = atoi(token); 270 } 271 } 272 } while (1); 273 } 274 275 // compute a fake shift scale rot representation from the texture matrix 276 // these shift scale rot values are to be understood in the local axis base 277 void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] ) 278 { 279 #ifdef _DEBUG 280 // check this matrix is orthogonal 281 if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON) 282 Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n"); 283 #endif 284 scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]); 285 scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]); 286 #ifdef _DEBUG 287 if (scale[0]<ZERO_EPSILON || scale[1]<ZERO_EPSILON) 288 Sys_Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n"); 289 #endif 290 // compute rotate value 291 if (fabs(texMat[0][0])<ZERO_EPSILON) 292 { 293 #ifdef _DEBUG 294 // check brushprimit_texdef[1][0] is not zero 295 if (fabs(texMat[1][0])<ZERO_EPSILON) 296 Sys_Printf("Warning : unexpected texdef[1][0]==0 in TexMatToFakeTexCoords\n"); 297 #endif 298 // rotate is +-90 299 if (texMat[1][0]>0) 300 *rot=90.0f; 301 else 302 *rot=-90.0f; 303 } 304 else 305 *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) ); 306 shift[0] = -texMat[0][2]; 307 shift[1] = texMat[1][2]; 308 } 309 310 // compute back the texture matrix from fake shift scale rot 311 // the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one ) 312 void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] ) 313 { 314 texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) ); 315 texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) ); 316 texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) ); 317 texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) ); 318 texMat[0][2] = -shift[0]; 319 texMat[1][2] = shift[1]; 320 } 321 322 // convert a texture matrix between two qtexture_t 323 // if NULL for qtexture_t, basic 2x2 texture is assumed ( straight mapping between s/t coordinates and geometric coordinates ) 324 void ConvertTexMatWithQTexture( brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2 ) 325 { 326 float s1,s2; 327 s1 = ( qtex1 ? static_cast<float>( qtex1->width ) : 2.0f ) / ( qtex2 ? static_cast<float>( qtex2->width ) : 2.0f ); 328 s2 = ( qtex1 ? static_cast<float>( qtex1->height ) : 2.0f ) / ( qtex2 ? static_cast<float>( qtex2->height ) : 2.0f ); 329 texMat2->coords[0][0]=s1*texMat1->coords[0][0]; 330 texMat2->coords[0][1]=s1*texMat1->coords[0][1]; 331 texMat2->coords[0][2]=s1*texMat1->coords[0][2]; 332 texMat2->coords[1][0]=s2*texMat1->coords[1][0]; 333 texMat2->coords[1][1]=s2*texMat1->coords[1][1]; 334 texMat2->coords[1][2]=s2*texMat1->coords[1][2]; 335 } 336 337 // texture locking 338 void Face_MoveTexture_BrushPrimit(face_t *f, vec3_t delta) 339 { 340 vec3_t texS,texT; 341 vec_t tx,ty; 342 vec3_t M[3]; // columns of the matrix .. easier that way 343 vec_t det; 344 vec3_t D[2]; 345 // compute plane axis base ( doesn't change with translation ) 346 ComputeAxisBase( f->plane.normal, texS, texT ); 347 // compute translation vector in plane axis base 348 tx = DotProduct( delta, texS ); 349 ty = DotProduct( delta, texT ); 350 // fill the data vectors 351 M[0][0]=tx; M[0][1]=1.0f+tx; M[0][2]=tx; 352 M[1][0]=ty; M[1][1]=ty; M[1][2]=1.0f+ty; 353 M[2][0]=1.0f; M[2][1]=1.0f; M[2][2]=1.0f; 354 D[0][0]=f->brushprimit_texdef.coords[0][2]; 355 D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; 356 D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; 357 D[1][0]=f->brushprimit_texdef.coords[1][2]; 358 D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; 359 D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; 360 // solve 361 det = SarrusDet( M[0], M[1], M[2] ); 362 f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; 363 f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; 364 f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; 365 f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; 366 f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; 367 f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; 368 } 369 370 // call Face_MoveTexture_BrushPrimit after vec3_t computation 371 void Select_ShiftTexture_BrushPrimit( face_t *f, int x, int y ) 372 { 373 vec3_t texS,texT; 374 vec3_t delta; 375 ComputeAxisBase( f->plane.normal, texS, texT ); 376 VectorScale( texS, static_cast<float>(x), texS ); 377 VectorScale( texT, static_cast<float>(y), texT ); 378 VectorCopy( texS, delta ); 379 VectorAdd( delta, texT, delta ); 380 Face_MoveTexture_BrushPrimit( f, delta ); 381 } 382 383 // texture locking 384 // called before the points on the face are actually rotated 385 void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin ) 386 { 387 vec3_t texS,texT; // axis base of the initial plane 388 vec3_t vRotate; // rotation vector 389 vec3_t Orig; 390 vec3_t rOrig,rvecS,rvecT; // (0,0) (1,0) (0,1) ( initial plane axis base ) after rotation ( world axis base ) 391 vec3_t rNormal; // normal of the plane after rotation 392 vec3_t rtexS,rtexT; // axis base of the rotated plane 393 vec3_t lOrig,lvecS,lvecT; // [2] are not used ( but usefull for debugging ) 394 vec3_t M[3]; 395 vec_t det; 396 vec3_t D[2]; 397 // compute plane axis base 398 ComputeAxisBase( f->plane.normal, texS, texT ); 399 // compute coordinates of (0,0) (1,0) (0,1) ( initial plane axis base ) after rotation 400 // (0,0) (1,0) (0,1) ( initial plane axis base ) <-> (0,0,0) texS texT ( world axis base ) 401 // rotation vector 402 VectorSet( vRotate, 0.0f, 0.0f, 0.0f ); 403 vRotate[nAxis]=fDeg; 404 VectorSet( Orig, 0.0f, 0.0f, 0.0f ); 405 VectorRotate( Orig, vRotate, vOrigin, rOrig ); 406 VectorRotate( texS, vRotate, vOrigin, rvecS ); 407 VectorRotate( texT, vRotate, vOrigin, rvecT ); 408 // compute normal of plane after rotation 409 VectorRotate( f->plane.normal, vRotate, rNormal ); 410 // compute rotated plane axis base 411 ComputeAxisBase( rNormal, rtexS, rtexT ); 412 // compute S/T coordinates of the three points in rotated axis base ( in M matrix ) 413 lOrig[0] = DotProduct( rOrig, rtexS ); 414 lOrig[1] = DotProduct( rOrig, rtexT ); 415 lvecS[0] = DotProduct( rvecS, rtexS ); 416 lvecS[1] = DotProduct( rvecS, rtexT ); 417 lvecT[0] = DotProduct( rvecT, rtexS ); 418 lvecT[1] = DotProduct( rvecT, rtexT ); 419 M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f; 420 M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f; 421 M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f; 422 // fill data vector 423 D[0][0]=f->brushprimit_texdef.coords[0][2]; 424 D[0][1]=f->brushprimit_texdef.coords[0][0]+f->brushprimit_texdef.coords[0][2]; 425 D[0][2]=f->brushprimit_texdef.coords[0][1]+f->brushprimit_texdef.coords[0][2]; 426 D[1][0]=f->brushprimit_texdef.coords[1][2]; 427 D[1][1]=f->brushprimit_texdef.coords[1][0]+f->brushprimit_texdef.coords[1][2]; 428 D[1][2]=f->brushprimit_texdef.coords[1][1]+f->brushprimit_texdef.coords[1][2]; 429 // solve 430 det = SarrusDet( M[0], M[1], M[2] ); 431 f->brushprimit_texdef.coords[0][0] = SarrusDet( D[0], M[1], M[2] ) / det; 432 f->brushprimit_texdef.coords[0][1] = SarrusDet( M[0], D[0], M[2] ) / det; 433 f->brushprimit_texdef.coords[0][2] = SarrusDet( M[0], M[1], D[0] ) / det; 434 f->brushprimit_texdef.coords[1][0] = SarrusDet( D[1], M[1], M[2] ) / det; 435 f->brushprimit_texdef.coords[1][1] = SarrusDet( M[0], D[1], M[2] ) / det; 436 f->brushprimit_texdef.coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det; 437 } 438 439 // best fitted 2D vector is x.X+y.Y 440 void ComputeBest2DVector( vec3_t v, vec3_t X, vec3_t Y, int &x, int &y ) 441 { 442 double sx,sy; 443 sx = DotProduct( v, X ); 444 sy = DotProduct( v, Y ); 445 if ( fabs(sy) > fabs(sx) ) 446 { 447 x = 0; 448 if ( sy > 0.0 ) 449 y = 1; 450 else 451 y = -1; 452 } 453 else 454 { 455 y = 0; 456 if ( sx > 0.0 ) 457 x = 1; 458 else 459 x = -1; 460 } 461 }