Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

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 }