brush_primit.cpp 16 KB

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