1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "tools/edit_gui_common.h"
30 
31 
32 #include "qe3.h"
33 
34 #define ZERO_EPSILON	1.0E-6
35 
36 class idVec3D {
37 public:
38 	double x, y, z;
operator [](const int index)39 	double &			operator[]( const int index ) {
40 		return (&x)[index];
41 	}
Zero()42 	void Zero() {
43 		x = y = z = 0.0;
44 	}
45 };
46 
47 //
48 // =======================================================================================================================
49 //    compute a determinant using Sarrus rule ++timo "inline" this with a macro NOTE:: the three idVec3D are understood as
50 //    columns of the matrix
51 // =======================================================================================================================
52 //
SarrusDet(idVec3D a,idVec3D b,idVec3D c)53 double SarrusDet(idVec3D a, idVec3D b, idVec3D c) {
54 	return (double)a[0] * (double)b[1] * (double)c[2] + (double)b[0] * (double)c[1] * (double)a[2] + (double)c[0] * (double)a[1] * (double)b[2] - (double)c[0] * (double)b[1] * (double)a[2] - (double)a[1] * (double)b[0] * (double)c[2] -	(double)a[0] * (double)b[2] * (double)c[1];
55 }
56 
57 //
58 // =======================================================================================================================
59 //    ++timo replace everywhere texX by texS etc. ( > and in q3map !) NOTE:: ComputeAxisBase here and in q3map code must
60 //    always BE THE SAME ! WARNING:: special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere
61 //    when x == 0 rotation by (0,RotY,RotZ) assigns X to normal
62 // =======================================================================================================================
63 //
ComputeAxisBase(idVec3 & normal,idVec3D & texS,idVec3D & texT)64 void ComputeAxisBase(idVec3 &normal, idVec3D &texS, idVec3D &texT) {
65 	double	RotY, RotZ;
66 
67 	// do some cleaning
68 	if (idMath::Fabs(normal[0]) < 1e-6) {
69 		normal[0] = 0.0f;
70 	}
71 
72 	if (idMath::Fabs(normal[1]) < 1e-6) {
73 		normal[1] = 0.0f;
74 	}
75 
76 	if (idMath::Fabs(normal[2]) < 1e-6) {
77 		normal[2] = 0.0f;
78 	}
79 
80 	RotY = -atan2(normal[2], idMath::Sqrt(normal[1] * normal[1] + normal[0] * normal[0]));
81 	RotZ = atan2(normal[1], normal[0]);
82 
83 	// rotate (0,1,0) and (0,0,1) to compute texS and texT
84 	texS[0] = -sin(RotZ);
85 	texS[1] = cos(RotZ);
86 	texS[2] = 0;
87 
88 	// the texT vector is along -Z ( T texture coorinates axis )
89 	texT[0] = -sin(RotY) * cos(RotZ);
90 	texT[1] = -sin(RotY) * sin(RotZ);
91 	texT[2] = -cos(RotY);
92 }
93 
94 /*
95  =======================================================================================================================
96  =======================================================================================================================
97  */
FaceToBrushPrimitFace(face_t * f)98 void FaceToBrushPrimitFace(face_t *f) {
99 	idVec3D	texX, texY;
100 	idVec3D	proj;
101 
102 	// ST of (0,0) (1,0) (0,1)
103 	idVec5	ST[3];	// [ point index ] [ xyz ST ]
104 
105 	//
106 	// ++timo not used as long as brushprimit_texdef and texdef are static
107 	// f->brushprimit_texdef.contents=f->texdef.contents;
108 	// f->brushprimit_texdef.flags=f->texdef.flags;
109 	// f->brushprimit_texdef.value=f->texdef.value;
110 	// strcpy(f->brushprimit_texdef.name,f->texdef.name);
111 	//
112 #ifdef _DEBUG
113 	if (f->plane[0] == 0.0f && f->plane[1] == 0.0f && f->plane[2] == 0.0f) {
114 		common->Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n");
115 	}
116 
117 	// check d_texture
118 	if (!f->d_texture) {
119 		common->Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n");
120 		return;
121 	}
122 #endif
123 	// compute axis base
124 	ComputeAxisBase(f->plane.Normal(), texX, texY);
125 
126 	// compute projection vector
127 	VectorCopy( f->plane, proj );
128 	VectorScale(proj, -f->plane[3], proj);
129 
130 	//
131 	// (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the
132 	// affine plane (1,0) in plane axis base is texX in world coordinates + projection
133 	// on the affine plane (0,1) in plane axis base is texY in world coordinates +
134 	// projection on the affine plane use old texture code to compute the ST coords of
135 	// these points
136 	//
137 	VectorCopy(proj, ST[0]);
138 	EmitTextureCoordinates(ST[0], f->d_texture, f);
139 	VectorCopy(texX, ST[1]);
140 	VectorAdd(ST[1], proj, ST[1]);
141 	EmitTextureCoordinates(ST[1], f->d_texture, f);
142 	VectorCopy(texY, ST[2]);
143 	VectorAdd(ST[2], proj, ST[2]);
144 	EmitTextureCoordinates(ST[2], f->d_texture, f);
145 
146 	// compute texture matrix
147 	f->brushprimit_texdef.coords[0][2] = ST[0][3];
148 	f->brushprimit_texdef.coords[1][2] = ST[0][4];
149 	f->brushprimit_texdef.coords[0][0] = ST[1][3] - f->brushprimit_texdef.coords[0][2];
150 	f->brushprimit_texdef.coords[1][0] = ST[1][4] - f->brushprimit_texdef.coords[1][2];
151 	f->brushprimit_texdef.coords[0][1] = ST[2][3] - f->brushprimit_texdef.coords[0][2];
152 	f->brushprimit_texdef.coords[1][1] = ST[2][4] - f->brushprimit_texdef.coords[1][2];
153 }
154 
155 //
156 // =======================================================================================================================
157 //    compute texture coordinates for the winding points
158 // =======================================================================================================================
159 //
EmitBrushPrimitTextureCoordinates(face_t * f,idWinding * w,patchMesh_t * patch)160 void EmitBrushPrimitTextureCoordinates(face_t *f, idWinding *w, patchMesh_t *patch) {
161 	idVec3D	texX, texY;
162 	double	x, y;
163 
164 	if (f== NULL || (w == NULL && patch == NULL)) {
165 		return;
166 	}
167 
168 	// compute axis base
169 	ComputeAxisBase(f->plane.Normal(), texX, texY);
170 
171 	//
172 	// in case the texcoords matrix is empty, build a default one same behaviour as if
173 	// scale[0]==0 && scale[1]==0 in old code
174 	//
175 	if (	f->brushprimit_texdef.coords[0][0] == 0 &&
176 			f->brushprimit_texdef.coords[1][0] == 0 &&
177 			f->brushprimit_texdef.coords[0][1] == 0 &&
178 			f->brushprimit_texdef.coords[1][1] == 0 ) {
179 		f->brushprimit_texdef.coords[0][0] = 1.0f;
180 		f->brushprimit_texdef.coords[1][1] = 1.0f;
181 		ConvertTexMatWithQTexture(&f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture);
182 	}
183 
184 	int i;
185 	if (w) {
186 		for (i = 0; i < w->GetNumPoints(); i++) {
187 			x = DotProduct((*w)[i], texX);
188 			y = DotProduct((*w)[i], texY);
189 			(*w)[i][3] = f->brushprimit_texdef.coords[0][0] * x + f->brushprimit_texdef.coords[0][1] * y + f->brushprimit_texdef.coords[0][2];
190 			(*w)[i][4] = f->brushprimit_texdef.coords[1][0] * x + f->brushprimit_texdef.coords[1][1] * y + f->brushprimit_texdef.coords[1][2];
191 		}
192 	}
193 
194 	if (patch) {
195 		int j;
196 		for ( i = 0; i < patch->width; i++ ) {
197 			for ( j = 0; j < patch->height; j++ ) {
198 				x = DotProduct(patch->ctrl(i, j).xyz, texX);
199 				y = DotProduct(patch->ctrl(i, j).xyz, texY);
200 				patch->ctrl(i, j).st.x = f->brushprimit_texdef.coords[0][0] * x + f->brushprimit_texdef.coords[0][1] * y + f->brushprimit_texdef.coords[0][2];
201 				patch->ctrl(i, j).st.y = f->brushprimit_texdef.coords[1][0] * x + f->brushprimit_texdef.coords[1][1] * y + f->brushprimit_texdef.coords[1][2];
202 			}
203 		}
204 	}
205 }
206 
207 //
208 // =======================================================================================================================
209 //    parse a brush in brush primitive format
210 // =======================================================================================================================
211 //
BrushPrimit_Parse(brush_t * b,bool newFormat,const idVec3 origin)212 void BrushPrimit_Parse(brush_t *b, bool newFormat, const idVec3 origin) {
213 	face_t	*f;
214 	int		i, j;
215 	GetToken(true);
216 	if (strcmp(token, "{")) {
217 		Warning("parsing brush primitive");
218 		return;
219 	}
220 
221 	do {
222 		if (!GetToken(true)) {
223 			break;
224 		}
225 
226 		if (!strcmp(token, "}")) {
227 			break;
228 		}
229 
230 		// reading of b->epairs if any
231 		if (strcmp(token, "(")) {
232 			ParseEpair(&b->epairs);
233 		}
234 		else {	// it's a face
235 			f = Face_Alloc();
236 			f->next = NULL;
237 			if (!b->brush_faces) {
238 				b->brush_faces = f;
239 			}
240 			else {
241 				face_t	*scan;
242 				for (scan = b->brush_faces; scan->next; scan = scan->next)
243 					;
244 				scan->next = f;
245 			}
246 
247 			if (newFormat) {
248 				// read the three point plane definition
249 				idPlane plane;
250 				for (j = 0; j < 4; j++) {
251 					GetToken(false);
252 					plane[j] = atof(token);
253 				}
254 
255 				f->plane = plane;
256 				f->originalPlane = plane;
257 				f->dirty = false;
258 
259 				//idWinding	*w = Brush_MakeFaceWinding(b, f, true);
260 				idWinding w;
261 				w.BaseForPlane( plane );
262 
263 				for (j = 0; j < 3; j++) {
264 					f->planepts[j].x = w[j].x + origin.x;
265 					f->planepts[j].y = w[j].y + origin.y;
266 					f->planepts[j].z = w[j].z + origin.z;
267 				}
268 
269 				GetToken(false);
270 			}
271 			else {
272 				for (i = 0; i < 3; i++) {
273 					if (i != 0) {
274 						GetToken(true);
275 					}
276 
277 					if (strcmp(token, "(")) {
278 						Warning("parsing brush");
279 						return;
280 					}
281 
282 					for (j = 0; j < 3; j++) {
283 						GetToken(false);
284 						f->planepts[i][j] = atof(token);
285 					}
286 
287 					GetToken(false);
288 					if (strcmp(token, ")")) {
289 						Warning("parsing brush");
290 						return;
291 					}
292 				}
293 			}
294 
295 			// texture coordinates
296 			GetToken(false);
297 			if (strcmp(token, "(")) {
298 				Warning("parsing brush primitive");
299 				return;
300 			}
301 
302 			GetToken(false);
303 			if (strcmp(token, "(")) {
304 				Warning("parsing brush primitive");
305 				return;
306 			}
307 
308 			for (j = 0; j < 3; j++) {
309 				GetToken(false);
310 				f->brushprimit_texdef.coords[0][j] = atof(token);
311 			}
312 
313 			GetToken(false);
314 			if (strcmp(token, ")")) {
315 				Warning("parsing brush primitive");
316 				return;
317 			}
318 
319 			GetToken(false);
320 			if (strcmp(token, "(")) {
321 				Warning("parsing brush primitive");
322 				return;
323 			}
324 
325 			for (j = 0; j < 3; j++) {
326 				GetToken(false);
327 				f->brushprimit_texdef.coords[1][j] = atof(token);
328 			}
329 
330 			GetToken(false);
331 			if (strcmp(token, ")")) {
332 				Warning("parsing brush primitive");
333 				return;
334 			}
335 
336 			GetToken(false);
337 			if (strcmp(token, ")")) {
338 				Warning("parsing brush primitive");
339 				return;
340 			}
341 
342 			// read the texturedef
343 			GetToken(false);
344 
345 			// strcpy(f->texdef.name, token);
346 			if (g_qeglobals.mapVersion < 2.0) {
347 				f->texdef.SetName(va("textures/%s", token));
348 			}
349 			else {
350 				f->texdef.SetName(token);
351 			}
352 
353 			if (TokenAvailable()) {
354 				GetToken(false);
355 				GetToken(false);
356 				GetToken(false);
357 				f->texdef.value = atoi(token);
358 			}
359 		}
360 	} while (1);
361 }
362 
363 //
364 // =======================================================================================================================
365 //    compute a fake shift scale rot representation from the texture matrix these shift scale rot values are to be
366 //    understood in the local axis base
367 // =======================================================================================================================
368 //
TexMatToFakeTexCoords(float texMat[2][3],float shift[2],float * rot,float scale[2])369 void TexMatToFakeTexCoords(float texMat[2][3], float shift[2], float *rot, float scale[2])
370 {
371 #ifdef _DEBUG
372 
373 	// check this matrix is orthogonal
374 	if (idMath::Fabs(texMat[0][0] * texMat[0][1] + texMat[1][0] * texMat[1][1]) > ZERO_EPSILON) {
375 		common->Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n");
376 	}
377 #endif
378 	scale[0] = idMath::Sqrt(texMat[0][0] * texMat[0][0] + texMat[1][0] * texMat[1][0]);
379 	scale[1] = idMath::Sqrt(texMat[0][1] * texMat[0][1] + texMat[1][1] * texMat[1][1]);
380 #ifdef _DEBUG
381 	if (scale[0] < ZERO_EPSILON || scale[1] < ZERO_EPSILON) {
382 		common->Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n");
383 	}
384 #endif
385 	// compute rotate value
386 	if (idMath::Fabs(texMat[0][0]) < ZERO_EPSILON)
387 	{
388 #ifdef _DEBUG
389 		// check brushprimit_texdef[1][0] is not zero
390 		if (idMath::Fabs(texMat[1][0]) < ZERO_EPSILON) {
391 			common->Printf("Warning : unexpected texdef[1][0]==0 in TexMatToFakeTexCoords\n");
392 		}
393 #endif
394 		// rotate is +-90
395 		if (texMat[1][0] > 0) {
396 			*rot = 90.0f;
397 		}
398 		else {
399 			*rot = -90.0f;
400 		}
401 	}
402 	else {
403 		*rot = RAD2DEG(atan2(texMat[1][0], texMat[0][0]));
404 	}
405 
406 	shift[0] = -texMat[0][2];
407 	shift[1] = texMat[1][2];
408 }
409 
410 //
411 // =======================================================================================================================
412 //    compute back the texture matrix from fake shift scale rot the matrix returned must be understood as a qtexture_t
413 //    with width=2 height=2 ( the default one )
414 // =======================================================================================================================
415 //
FakeTexCoordsToTexMat(float shift[2],float rot,float scale[2],float texMat[2][3])416 void FakeTexCoordsToTexMat(float shift[2], float rot, float scale[2], float texMat[2][3]) {
417 	texMat[0][0] = scale[0] * cos(DEG2RAD(rot));
418 	texMat[1][0] = scale[0] * sin(DEG2RAD(rot));
419 	texMat[0][1] = -1.0f * scale[1] * sin(DEG2RAD(rot));
420 	texMat[1][1] = scale[1] * cos(DEG2RAD(rot));
421 	texMat[0][2] = -shift[0];
422 	texMat[1][2] = shift[1];
423 }
424 
425 //
426 // =======================================================================================================================
427 //    convert a texture matrix between two qtexture_t if NULL for qtexture_t, basic 2x2 texture is assumed ( straight
428 //    mapping between s/t coordinates and geometric coordinates )
429 // =======================================================================================================================
430 //
ConvertTexMatWithQTexture(float texMat1[2][3],const idMaterial * qtex1,float texMat2[2][3],const idMaterial * qtex2,float sScale=1.0,float tScale=1.0)431 void ConvertTexMatWithQTexture(float texMat1[2][3], const idMaterial *qtex1, float texMat2[2][3], const idMaterial *qtex2, float sScale = 1.0, float tScale = 1.0) {
432 	float	s1, s2;
433 	s1 = (qtex1 ? static_cast<float>(qtex1->GetEditorImage()->uploadWidth) : 2.0f) / (qtex2 ? static_cast<float>(qtex2->GetEditorImage()->uploadWidth) : 2.0f);
434 	s2 = (qtex1 ? static_cast<float>(qtex1->GetEditorImage()->uploadHeight) : 2.0f) / (qtex2 ? static_cast<float>(qtex2->GetEditorImage()->uploadHeight) : 2.0f);
435 	s1 *= sScale;
436 	s2 *= tScale;
437 	texMat2[0][0] = s1 * texMat1[0][0];
438 	texMat2[0][1] = s1 * texMat1[0][1];
439 	texMat2[0][2] = s1 * texMat1[0][2];
440 	texMat2[1][0] = s2 * texMat1[1][0];
441 	texMat2[1][1] = s2 * texMat1[1][1];
442 	texMat2[1][2] = s2 * texMat1[1][2];
443 }
444 
445 /*
446  =======================================================================================================================
447  =======================================================================================================================
448  */
ConvertTexMatWithQTexture(brushprimit_texdef_t * texMat1,const idMaterial * qtex1,brushprimit_texdef_t * texMat2,const idMaterial * qtex2,float sScale,float tScale)449 void ConvertTexMatWithQTexture(brushprimit_texdef_t	*texMat1, const idMaterial *qtex1, brushprimit_texdef_t *texMat2, const idMaterial *qtex2, float sScale, float tScale) {
450 	ConvertTexMatWithQTexture(texMat1->coords, qtex1, texMat2->coords, qtex2, sScale, tScale);
451 }
452 
453 
454 //
455 // =======================================================================================================================
456 //    texture locking
457 // =======================================================================================================================
458 //
Face_MoveTexture_BrushPrimit(face_t * f,idVec3 delta)459 void Face_MoveTexture_BrushPrimit(face_t *f, idVec3 delta) {
460 	idVec3D	texS, texT;
461 	double	tx, ty;
462 	idVec3D	M[3];	// columns of the matrix .. easier that way
463 	double	det;
464 	idVec3D	D[2];
465 
466 	// compute plane axis base ( doesn't change with translation )
467 	ComputeAxisBase(f->plane.Normal(), texS, texT);
468 
469 	// compute translation vector in plane axis base
470 	tx = DotProduct(delta, texS);
471 	ty = DotProduct(delta, texT);
472 
473 	// fill the data vectors
474 	M[0][0] = tx;
475 	M[0][1] = 1.0f + tx;
476 	M[0][2] = tx;
477 	M[1][0] = ty;
478 	M[1][1] = ty;
479 	M[1][2] = 1.0f + ty;
480 	M[2][0] = 1.0f;
481 	M[2][1] = 1.0f;
482 	M[2][2] = 1.0f;
483 	D[0][0] = f->brushprimit_texdef.coords[0][2];
484 	D[0][1] = f->brushprimit_texdef.coords[0][0] + f->brushprimit_texdef.coords[0][2];
485 	D[0][2] = f->brushprimit_texdef.coords[0][1] + f->brushprimit_texdef.coords[0][2];
486 	D[1][0] = f->brushprimit_texdef.coords[1][2];
487 	D[1][1] = f->brushprimit_texdef.coords[1][0] + f->brushprimit_texdef.coords[1][2];
488 	D[1][2] = f->brushprimit_texdef.coords[1][1] + f->brushprimit_texdef.coords[1][2];
489 
490 	// solve
491 	det = SarrusDet(M[0], M[1], M[2]);
492 	f->brushprimit_texdef.coords[0][0] = SarrusDet(D[0], M[1], M[2]) / det;
493 	f->brushprimit_texdef.coords[0][1] = SarrusDet(M[0], D[0], M[2]) / det;
494 	f->brushprimit_texdef.coords[0][2] = SarrusDet(M[0], M[1], D[0]) / det;
495 	f->brushprimit_texdef.coords[1][0] = SarrusDet(D[1], M[1], M[2]) / det;
496 	f->brushprimit_texdef.coords[1][1] = SarrusDet(M[0], D[1], M[2]) / det;
497 	f->brushprimit_texdef.coords[1][2] = SarrusDet(M[0], M[1], D[1]) / det;
498 }
499 
500 //
501 // =======================================================================================================================
502 //    call Face_MoveTexture_BrushPrimit after idVec3D computation
503 // =======================================================================================================================
504 //
Select_ShiftTexture_BrushPrimit(face_t * f,float x,float y,bool autoAdjust)505 void Select_ShiftTexture_BrushPrimit(face_t *f, float x, float y, bool autoAdjust) {
506 #if 0
507 	idVec3D	texS, texT;
508 	idVec3D	delta;
509 	ComputeAxisBase(f->plane.normal, texS, texT);
510 	VectorScale(texS, x, texS);
511 	VectorScale(texT, y, texT);
512 	VectorCopy(texS, delta);
513 	VectorAdd(delta, texT, delta);
514 	Face_MoveTexture_BrushPrimit(f, delta);
515 #else
516 	if (autoAdjust) {
517 		x /= f->d_texture->GetEditorImage()->uploadWidth;
518 		y /= f->d_texture->GetEditorImage()->uploadHeight;
519 	}
520 	f->brushprimit_texdef.coords[0][2] += x;
521 	f->brushprimit_texdef.coords[1][2] += y;
522 	EmitBrushPrimitTextureCoordinates(f, f->face_winding);
523 #endif
524 }
525 
526 //
527 // =======================================================================================================================
528 //    best fitted 2D vector is x.X+y.Y
529 // =======================================================================================================================
530 //
ComputeBest2DVector(idVec3 v,idVec3 X,idVec3 Y,int & x,int & y)531 void ComputeBest2DVector(idVec3 v, idVec3 X, idVec3 Y, int &x, int &y) {
532 	double	sx, sy;
533 	sx = DotProduct(v, X);
534 	sy = DotProduct(v, Y);
535 	if (idMath::Fabs(sy) > idMath::Fabs(sx)) {
536 		x = 0;
537 		if (sy > 0.0) {
538 			y = 1;
539 		}
540 		else {
541 			y = -1;
542 		}
543 	}
544 	else {
545 		y = 0;
546 		if (sx > 0.0) {
547 			x = 1;
548 		}
549 		else {
550 			x = -1;
551 		}
552 	}
553 }
554 
555 //
556 // =======================================================================================================================
557 //    in many case we know three points A,B,C in two axis base B1 and B2 and we want the matrix M so that A(B1) = T *
558 //    A(B2) NOTE: 2D homogeneous space stuff NOTE: we don't do any check to see if there's a solution or we have a
559 //    particular case .. need to make sure before calling NOTE: the third coord of the A,B,C point is ignored NOTE: see
560 //    the commented out section to fill M and D ++timo TODO: update the other members to use this when possible
561 // =======================================================================================================================
562 //
MatrixForPoints(idVec3D M[3],idVec3D D[2],brushprimit_texdef_t * T)563 void MatrixForPoints(idVec3D M[3], idVec3D D[2], brushprimit_texdef_t *T) {
564 	//
565 	// idVec3D M[3]; // columns of the matrix .. easier that way (the indexing is not
566 	// standard! it's column-line .. later computations are easier that way)
567 	//
568 	double	det;
569 
570 	// idVec3D D[2];
571 	M[2][0] = 1.0f;
572 	M[2][1] = 1.0f;
573 	M[2][2] = 1.0f;
574 #if 0
575 
576 	// fill the data vectors
577 	M[0][0] = A2[0];
578 	M[0][1] = B2[0];
579 	M[0][2] = C2[0];
580 	M[1][0] = A2[1];
581 	M[1][1] = B2[1];
582 	M[1][2] = C2[1];
583 	M[2][0] = 1.0f;
584 	M[2][1] = 1.0f;
585 	M[2][2] = 1.0f;
586 	D[0][0] = A1[0];
587 	D[0][1] = B1[0];
588 	D[0][2] = C1[0];
589 	D[1][0] = A1[1];
590 	D[1][1] = B1[1];
591 	D[1][2] = C1[1];
592 #endif
593 	// solve
594 	det = SarrusDet(M[0], M[1], M[2]);
595 	T->coords[0][0] = SarrusDet(D[0], M[1], M[2]) / det;
596 	T->coords[0][1] = SarrusDet(M[0], D[0], M[2]) / det;
597 	T->coords[0][2] = SarrusDet(M[0], M[1], D[0]) / det;
598 	T->coords[1][0] = SarrusDet(D[1], M[1], M[2]) / det;
599 	T->coords[1][1] = SarrusDet(M[0], D[1], M[2]) / det;
600 	T->coords[1][2] = SarrusDet(M[0], M[1], D[1]) / det;
601 }
602 
603 //
604 // =======================================================================================================================
605 //    ++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) can be improved .. bug #107311
606 //    mins and maxs are the face bounding box ++timo fixme: we use the face info, mins and maxs are irrelevant
607 // =======================================================================================================================
608 //
Face_FitTexture_BrushPrimit(face_t * f,idVec3 mins,idVec3 maxs,float height,float width)609 void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float height, float width) {
610 	idVec3D					BBoxSTMin, BBoxSTMax;
611 	idWinding				*w;
612 	int						i, j;
613 	double					val;
614 	idVec3D					M[3], D[2];
615 
616 	// idVec3D N[2],Mf[2];
617 	brushprimit_texdef_t	N;
618 	idVec3D					Mf[2];
619 
620 
621 
622 	//memset(f->brushprimit_texdef.coords, 0, sizeof(f->brushprimit_texdef.coords));
623 	//f->brushprimit_texdef.coords[0][0] = 1.0f;
624 	//f->brushprimit_texdef.coords[1][1] = 1.0f;
625 	//ConvertTexMatWithQTexture(&f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture);
626 	//
627 	// we'll be working on a standardized texture size ConvertTexMatWithQTexture(
628 	// &f->brushprimit_texdef, f->d_texture, &f->brushprimit_texdef, NULL ); compute
629 	// the BBox in ST coords
630 	//
631 	EmitBrushPrimitTextureCoordinates(f, f->face_winding);
632 	BBoxSTMin[0] = BBoxSTMin[1] = BBoxSTMin[2] = 999999;
633 	BBoxSTMax[0] = BBoxSTMax[1] = BBoxSTMax[2] = -999999;
634 
635 	w = f->face_winding;
636 	if (w) {
637 		for (i = 0; i < w->GetNumPoints(); i++) {
638 			// AddPointToBounds in 2D on (S,T) coordinates
639 			for (j = 0; j < 2; j++) {
640 				val = (*w)[i][j + 3];
641 				if (val < BBoxSTMin[j]) {
642 					BBoxSTMin[j] = val;
643 				}
644 
645 				if (val > BBoxSTMax[j]) {
646 					BBoxSTMax[j] = val;
647 				}
648 			}
649 		}
650 	}
651 
652 	//
653 	// we have the three points of the BBox (BBoxSTMin[0].BBoxSTMin[1])
654 	// (BBoxSTMax[0],BBoxSTMin[1]) (BBoxSTMin[0],BBoxSTMax[1]) in ST space the BP
655 	// matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in
656 	// (Sfit,Tfit) space to these three points we have A(Sfit,Tfit) = (0,0) = Mf *
657 	// A(TexS,TexT) = N * M * A(TexS,TexT) = N * A(S,T) so we solve the system for N
658 	// and then Mf = N * M
659 	//
660 	M[0][0] = BBoxSTMin[0];
661 	M[0][1] = BBoxSTMax[0];
662 	M[0][2] = BBoxSTMin[0];
663 	M[1][0] = BBoxSTMin[1];
664 	M[1][1] = BBoxSTMin[1];
665 	M[1][2] = BBoxSTMax[1];
666 	D[0][0] = 0.0f;
667 	D[0][1] = width;
668 	D[0][2] = 0.0f;
669 	D[1][0] = 0.0f;
670 	D[1][1] = 0.0f;
671 	D[1][2] = height;
672 	MatrixForPoints(M, D, &N);
673 
674 #if 0
675 
676 	//
677 	// FIT operation gives coordinates of three points of the bounding box in (S',T'),
678 	// our target axis base A(S',T')=(0,0) B(S',T')=(nWidth,0) C(S',T')=(0,nHeight)
679 	// and we have them in (S,T) axis base: A(S,T)=(BBoxSTMin[0],BBoxSTMin[1])
680 	// B(S,T)=(BBoxSTMax[0],BBoxSTMin[1]) C(S,T)=(BBoxSTMin[0],BBoxSTMax[1]) we
681 	// compute the N transformation so that: A(S',T') = N * A(S,T)
682 	//
683 	N[0][0] = (BBoxSTMax[0] - BBoxSTMin[0]) / width;
684 	N[0][1] = 0.0f;
685 	N[0][2] = BBoxSTMin[0];
686 	N[1][0] = 0.0f;
687 	N[1][1] = (BBoxSTMax[1] - BBoxSTMin[1]) / height;
688 	N[1][2] = BBoxSTMin[1];
689 #endif
690 	// the final matrix is the product (Mf stands for Mfit)
691 	Mf[0][0] = N.coords[0][0] *
692 		f->brushprimit_texdef.coords[0][0] +
693 		N.coords[0][1] *
694 		f->brushprimit_texdef.coords[1][0];
695 	Mf[0][1] = N.coords[0][0] *
696 		f->brushprimit_texdef.coords[0][1] +
697 		N.coords[0][1] *
698 		f->brushprimit_texdef.coords[1][1];
699 	Mf[0][2] = N.coords[0][0] *
700 		f->brushprimit_texdef.coords[0][2] +
701 		N.coords[0][1] *
702 		f->brushprimit_texdef.coords[1][2] +
703 		N.coords[0][2];
704 	Mf[1][0] = N.coords[1][0] *
705 		f->brushprimit_texdef.coords[0][0] +
706 		N.coords[1][1] *
707 		f->brushprimit_texdef.coords[1][0];
708 	Mf[1][1] = N.coords[1][0] *
709 		f->brushprimit_texdef.coords[0][1] +
710 		N.coords[1][1] *
711 		f->brushprimit_texdef.coords[1][1];
712 	Mf[1][2] = N.coords[1][0] *
713 		f->brushprimit_texdef.coords[0][2] +
714 		N.coords[1][1] *
715 		f->brushprimit_texdef.coords[1][2] +
716 		N.coords[1][2];
717 
718 	// copy back
719 	VectorCopy(Mf[0], f->brushprimit_texdef.coords[0]);
720 	VectorCopy(Mf[1], f->brushprimit_texdef.coords[1]);
721 
722 	//
723 	// handle the texture size ConvertTexMatWithQTexture( &f->brushprimit_texdef,
724 	// NULL, &f->brushprimit_texdef, f->d_texture );
725 	//
726 }
727 
728 /*
729  =======================================================================================================================
730  =======================================================================================================================
731  */
Face_ScaleTexture_BrushPrimit(face_t * face,float sS,float sT)732 void Face_ScaleTexture_BrushPrimit(face_t *face, float sS, float sT) {
733 	if (!g_qeglobals.m_bBrushPrimitMode) {
734 		Sys_Status("BP mode required\n");
735 		return;
736 	}
737 
738 	brushprimit_texdef_t	*pBP = &face->brushprimit_texdef;
739 	BPMatScale(pBP->coords, sS, sT);
740 
741 	// now emit the coordinates on the winding
742 	EmitBrushPrimitTextureCoordinates(face, face->face_winding);
743 }
744 
745 /*
746  =======================================================================================================================
747  =======================================================================================================================
748  */
Face_RotateTexture_BrushPrimit(face_t * face,float amount,idVec3 origin)749 void Face_RotateTexture_BrushPrimit(face_t *face, float amount, idVec3 origin) {
750 	brushprimit_texdef_t	*pBP = &face->brushprimit_texdef;
751 	if (amount) {
752 		float	x = pBP->coords[0][0];
753 		float	y = pBP->coords[0][1];
754 		float	x1 = pBP->coords[1][0];
755 		float	y1 = pBP->coords[1][1];
756 		float	s = sin( DEG2RAD( amount ) );
757 		float	c = cos( DEG2RAD( amount ) );
758 		pBP->coords[0][0] = (((x - origin[0]) * c) - ((y - origin[1]) * s)) + origin[0];
759 		pBP->coords[0][1] = (((x - origin[0]) * s) + ((y - origin[1]) * c)) + origin[1];
760 		pBP->coords[1][0] = (((x1 - origin[0]) * c) - ((y1 - origin[1]) * s)) + origin[0];
761 		pBP->coords[1][1] = (((x1 - origin[0]) * s) + ((y1 - origin[1]) * c)) + origin[1];
762 		EmitBrushPrimitTextureCoordinates(face, face->face_winding);
763 	}
764 }
765 
766 //
767 // TEXTURE LOCKING (Relevant to the editor only?)
768 // internally used for texture locking on rotation and flipping the general
769 // algorithm is the same for both lockings, it's only the geometric transformation
770 // part that changes so I wanted to keep it in a single function if there are more
771 // linear transformations that need the locking, going to a C++ or code pointer
772 // solution would be best (but right now I want to keep brush_primit.cpp striclty
773 // C)
774 //
775 bool	txlock_bRotation;
776 
777 // rotation locking params
778 int		txl_nAxis;
779 double	txl_fDeg;
780 idVec3D	txl_vOrigin;
781 
782 // flip locking params
783 idVec3D	txl_matrix[3];
784 idVec3D	txl_origin;
785 
786 /*
787  =======================================================================================================================
788  =======================================================================================================================
789  */
TextureLockTransformation_BrushPrimit(face_t * f)790 void TextureLockTransformation_BrushPrimit(face_t *f) {
791 	idVec3D	Orig, texS, texT;		// axis base of initial plane
792 
793 	// used by transformation algo
794 	idVec3D	temp;
795 	int		j;
796 	//idVec3D	vRotate;				// rotation vector
797 
798 	idVec3D	rOrig, rvecS, rvecT;	// geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base }
799 	idVec3	rNormal;
800 	idVec3D	rtexS, rtexT;	// axis base for the transformed plane
801 	idVec3D	lOrig, lvecS, lvecT;	// [2] are not used ( but usefull for debugging )
802 	idVec3D	M[3];
803 	double	det;
804 	idVec3D	D[2];
805 
806 	// silence compiler warnings
807 	rOrig.Zero();
808 	rvecS = rOrig;
809 	rvecT = rOrig;
810 	rNormal.x = rOrig.x;
811 	rNormal.y = rOrig.y;
812 	rNormal.z = rOrig.z;
813 
814 	// compute plane axis base
815 	ComputeAxisBase(f->plane.Normal(), texS, texT);
816 	Orig.x = vec3_origin.x;
817 	Orig.y = vec3_origin.y;
818 	Orig.z = vec3_origin.z;
819 
820 	//
821 	// compute coordinates of (0,0) (1,0) (0,1) ( expressed in initial plane axis base
822 	// ) after transformation (0,0) (1,0) (0,1) ( expressed in initial plane axis base
823 	// ) <-> (0,0,0) texS texT ( expressed world axis base ) input: Orig, texS, texT
824 	// (and the global locking params) ouput: rOrig, rvecS, rvecT, rNormal
825 	//
826 	if (txlock_bRotation) {
827 /*
828 		// rotation vector
829 		vRotate.x = vec3_origin.x;
830 		vRotate.y = vec3_origin.y;
831 		vRotate.z = vec3_origin.z;
832 		vRotate[txl_nAxis] = txl_fDeg;
833 		VectorRotate3Origin(Orig, vRotate, txl_vOrigin, rOrig);
834 		VectorRotate3Origin(texS, vRotate, txl_vOrigin, rvecS);
835 		VectorRotate3Origin(texT, vRotate, txl_vOrigin, rvecT);
836 
837 		// compute normal of plane after rotation
838 		VectorRotate3(f->plane.Normal(), vRotate, rNormal);
839 */
840 	}
841 	else {
842 		VectorSubtract(Orig, txl_origin, temp);
843 		for (j = 0; j < 3; j++) {
844 			rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
845 		}
846 
847 		VectorSubtract(texS, txl_origin, temp);
848 		for (j = 0; j < 3; j++) {
849 			rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
850 		}
851 
852 		VectorSubtract(texT, txl_origin, temp);
853 		for (j = 0; j < 3; j++) {
854 			rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
855 		}
856 
857 		//
858 		// we also need the axis base of the target plane, apply the transformation matrix
859 		// to the normal too..
860 		//
861 		for (j = 0; j < 3; j++) {
862 			rNormal[j] = DotProduct(f->plane, txl_matrix[j]);
863 		}
864 	}
865 
866 	// compute rotated plane axis base
867 	ComputeAxisBase(rNormal, rtexS, rtexT);
868 
869 	// compute S/T coordinates of the three points in rotated axis base ( in M matrix )
870 	lOrig[0] = DotProduct(rOrig, rtexS);
871 	lOrig[1] = DotProduct(rOrig, rtexT);
872 	lvecS[0] = DotProduct(rvecS, rtexS);
873 	lvecS[1] = DotProduct(rvecS, rtexT);
874 	lvecT[0] = DotProduct(rvecT, rtexS);
875 	lvecT[1] = DotProduct(rvecT, rtexT);
876 	M[0][0] = lOrig[0];
877 	M[1][0] = lOrig[1];
878 	M[2][0] = 1.0f;
879 	M[0][1] = lvecS[0];
880 	M[1][1] = lvecS[1];
881 	M[2][1] = 1.0f;
882 	M[0][2] = lvecT[0];
883 	M[1][2] = lvecT[1];
884 	M[2][2] = 1.0f;
885 
886 	// fill data vector
887 	D[0][0] = f->brushprimit_texdef.coords[0][2];
888 	D[0][1] = f->brushprimit_texdef.coords[0][0] + f->brushprimit_texdef.coords[0][2];
889 	D[0][2] = f->brushprimit_texdef.coords[0][1] + f->brushprimit_texdef.coords[0][2];
890 	D[1][0] = f->brushprimit_texdef.coords[1][2];
891 	D[1][1] = f->brushprimit_texdef.coords[1][0] + f->brushprimit_texdef.coords[1][2];
892 	D[1][2] = f->brushprimit_texdef.coords[1][1] + f->brushprimit_texdef.coords[1][2];
893 
894 	// solve
895 	det = SarrusDet(M[0], M[1], M[2]);
896 	f->brushprimit_texdef.coords[0][0] = SarrusDet(D[0], M[1], M[2]) / det;
897 	f->brushprimit_texdef.coords[0][1] = SarrusDet(M[0], D[0], M[2]) / det;
898 	f->brushprimit_texdef.coords[0][2] = SarrusDet(M[0], M[1], D[0]) / det;
899 	f->brushprimit_texdef.coords[1][0] = SarrusDet(D[1], M[1], M[2]) / det;
900 	f->brushprimit_texdef.coords[1][1] = SarrusDet(M[0], D[1], M[2]) / det;
901 	f->brushprimit_texdef.coords[1][2] = SarrusDet(M[0], M[1], D[1]) / det;
902 }
903 
904 //
905 // =======================================================================================================================
906 //    texture locking called before the points on the face are actually rotated
907 // =======================================================================================================================
908 //
RotateFaceTexture_BrushPrimit(face_t * f,int nAxis,float fDeg,idVec3 vOrigin)909 void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, idVec3 vOrigin) {
910 	// this is a placeholder to call the general texture locking algorithm
911 	txlock_bRotation = true;
912 	txl_nAxis = nAxis;
913 	txl_fDeg = fDeg;
914 	VectorCopy(vOrigin, txl_vOrigin);
915 	TextureLockTransformation_BrushPrimit(f);
916 }
917 
918 //
919 // =======================================================================================================================
920 //    compute the new brush primit texture matrix for a transformation matrix and a flip order flag (change plane o
921 //    rientation) this matches the select_matrix algo used in select.cpp this needs to be called on the face BEFORE any
922 //    geometric transformation it will compute the texture matrix that will represent the same texture on the face after
923 //    the geometric transformation is done
924 // =======================================================================================================================
925 //
ApplyMatrix_BrushPrimit(face_t * f,idMat3 matrix,idVec3 origin)926 void ApplyMatrix_BrushPrimit(face_t *f, idMat3 matrix, idVec3 origin) {
927 	// this is a placeholder to call the general texture locking algorithm
928 	txlock_bRotation = false;
929 	VectorCopy(matrix[0], txl_matrix[0]);
930 	VectorCopy(matrix[1], txl_matrix[1]);
931 	VectorCopy(matrix[2], txl_matrix[2]);
932 	VectorCopy(origin, txl_origin);
933 	TextureLockTransformation_BrushPrimit(f);
934 }
935 
936 //
937 // =======================================================================================================================
938 //    don't do C==A!
939 // =======================================================================================================================
940 //
BPMatMul(float A[2][3],float B[2][3],float C[2][3])941 void BPMatMul(float A[2][3], float B[2][3], float C[2][3]) {
942 	C[0][0] = A[0][0] * B[0][0] + A[0][1] * B[1][0];
943 	C[1][0] = A[1][0] * B[0][0] + A[1][1] * B[1][0];
944 	C[0][1] = A[0][0] * B[0][1] + A[0][1] * B[1][1];
945 	C[1][1] = A[1][0] * B[0][1] + A[1][1] * B[1][1];
946 	C[0][2] = A[0][0] * B[0][2] + A[0][1] * B[1][2] + A[0][2];
947 	C[1][2] = A[1][0] * B[0][2] + A[1][1] * B[1][2] + A[1][2];
948 }
949 
950 /*
951  =======================================================================================================================
952  =======================================================================================================================
953  */
BPMatDump(float A[2][3])954 void BPMatDump(float A[2][3]) {
955 	common->Printf("%g %g %g\n%g %g %g\n0 0 1\n", A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2]);
956 }
957 
958 /*
959  =======================================================================================================================
960  =======================================================================================================================
961  */
BPMatRotate(float A[2][3],float theta)962 void BPMatRotate(float A[2][3], float theta) {
963 	float	m[2][3];
964 	float	aux[2][3];
965 	memset(&m, 0, sizeof (float) *6);
966 	m[0][0] = cos( DEG2RAD( theta ) );
967 	m[0][1] = -sin( DEG2RAD( theta ) );
968 	m[1][0] = -m[0][1];
969 	m[1][1] = m[0][0];
970 	BPMatMul(A, m, aux);
971 	BPMatCopy(aux, A);
972 }
973 
Face_GetScale_BrushPrimit(face_t * face,float * s,float * t,float * rot)974 void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot) {
975 	idVec3D	texS, texT;
976 	ComputeAxisBase(face->plane.Normal(), texS, texT);
977 
978 	if (face == NULL || face->face_winding == NULL) {
979 		return;
980 	}
981 	// find ST coordinates for the center of the face
982 	double	Os = 0, Ot = 0;
983 	for (int i = 0; i < face->face_winding->GetNumPoints(); i++) {
984 		Os += DotProduct((*face->face_winding)[i], texS);
985 		Ot += DotProduct((*face->face_winding)[i], texT);
986 	}
987 
988 	Os /= face->face_winding->GetNumPoints();
989 	Ot /= face->face_winding->GetNumPoints();
990 
991 	brushprimit_texdef_t	*pBP = &face->brushprimit_texdef;
992 
993 	// here we have a special case, M is a translation and it's inverse is easy
994 	float					BPO[2][3];
995 	float					aux[2][3];
996 	float					m[2][3];
997 	memset(&m, 0, sizeof (float) *6);
998 	m[0][0] = 1;
999 	m[1][1] = 1;
1000 	m[0][2] = -Os;
1001 	m[1][2] = -Ot;
1002 	BPMatMul(m, pBP->coords, aux);
1003 	m[0][2] = Os;
1004 	m[1][2] = Ot;			// now M^-1
1005 	BPMatMul(aux, m, BPO);
1006 
1007 	// apply a given scale (on S and T)
1008 	ConvertTexMatWithQTexture(BPO, face->d_texture, aux, NULL);
1009 
1010 	*s = idMath::Sqrt(aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0]);
1011 	*t = idMath::Sqrt(aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1]);
1012 
1013 	// compute rotate value
1014 	if (idMath::Fabs(face->brushprimit_texdef.coords[0][0]) < ZERO_EPSILON)
1015 	{
1016 		// rotate is +-90
1017 		if (face->brushprimit_texdef.coords[1][0] > 0) {
1018 			*rot = 90.0f;
1019 		}
1020 		else {
1021 			*rot = -90.0f;
1022 		}
1023 	}
1024 	else {
1025 		*rot = RAD2DEG(atan2(face->brushprimit_texdef.coords[1][0] / (*s) ? (*s) : 1.0f, face->brushprimit_texdef.coords[0][0] / (*t) ? (*t) : 1.0f));
1026 	}
1027 
1028 
1029 }
1030 
1031 /*
1032  =======================================================================================================================
1033  =======================================================================================================================
1034  */
Face_SetExplicitScale_BrushPrimit(face_t * face,float s,float t)1035 void Face_SetExplicitScale_BrushPrimit(face_t *face, float s, float t) {
1036 	idVec3D	texS, texT;
1037 	ComputeAxisBase(face->plane.Normal(), texS, texT);
1038 
1039 	// find ST coordinates for the center of the face
1040 	double	Os = 0, Ot = 0;
1041 
1042 	for (int i = 0; i < face->face_winding->GetNumPoints(); i++) {
1043 		Os += DotProduct((*face->face_winding)[i], texS);
1044 		Ot += DotProduct((*face->face_winding)[i], texT);
1045 	}
1046 
1047 	Os /= face->face_winding->GetNumPoints();
1048 	Ot /= face->face_winding->GetNumPoints();
1049 
1050 	brushprimit_texdef_t	*pBP = &face->brushprimit_texdef;
1051 
1052 	// here we have a special case, M is a translation and it's inverse is easy
1053 	float					BPO[2][3];
1054 	float					aux[2][3];
1055 	float					m[2][3];
1056 	memset(&m, 0, sizeof (float) *6);
1057 	m[0][0] = 1;
1058 	m[1][1] = 1;
1059 	m[0][2] = -Os;
1060 	m[1][2] = -Ot;
1061 	BPMatMul(m, pBP->coords, aux);
1062 	m[0][2] = Os;
1063 	m[1][2] = Ot;			// now M^-1
1064 	BPMatMul(aux, m, BPO);
1065 
1066 	// apply a given scale (on S and T)
1067 	ConvertTexMatWithQTexture(BPO, face->d_texture, aux, NULL);
1068 
1069 	// reset the scale (normalize the matrix)
1070 	double	v1, v2;
1071 	v1 = idMath::Sqrt(aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0]);
1072 	v2 = idMath::Sqrt(aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1]);
1073 
1074 	if (s == 0.0) {
1075 		s = v1;
1076 	}
1077 	if (t == 0.0) {
1078 		t = v2;
1079 	}
1080 
1081 	double	sS, sT;
1082 
1083 	// put the values for scale on S and T here:
1084 	sS = s / v1;
1085 	sT = t / v2;
1086 	aux[0][0] *= sS;
1087 	aux[1][0] *= sS;
1088 	aux[0][1] *= sT;
1089 	aux[1][1] *= sT;
1090 	ConvertTexMatWithQTexture(aux, NULL, BPO, face->d_texture);
1091 	BPMatMul(m, BPO, aux);	// m is M^-1
1092 	m[0][2] = -Os;
1093 	m[1][2] = -Ot;
1094 	BPMatMul(aux, m, pBP->coords);
1095 
1096 	// now emit the coordinates on the winding
1097 	EmitBrushPrimitTextureCoordinates(face, face->face_winding);
1098 }
1099 
1100 
Face_FlipTexture_BrushPrimit(face_t * f,bool y)1101 void Face_FlipTexture_BrushPrimit(face_t *f, bool y) {
1102 
1103 	float s, t, rot;
1104 	Face_GetScale_BrushPrimit(f, &s, &t, &rot);
1105 	if (y) {
1106 		Face_SetExplicitScale_BrushPrimit(f, 0.0, -t);
1107 	} else {
1108 		Face_SetExplicitScale_BrushPrimit(f, -s, 0.0);
1109 	}
1110 #if 0
1111 
1112 	idVec3D	texS, texT;
1113 	ComputeAxisBase(f->plane.normal, texS, texT);
1114 	double	Os = 0, Ot = 0;
1115 	for (int i = 0; i < f->face_winding->numpoints; i++) {
1116 		Os += DotProduct(f->face_winding->p[i], texS);
1117 		Ot += DotProduct(f->face_winding->p[i], texT);
1118 	}
1119 
1120 	Ot = abs(Ot);
1121 	Ot *= t;
1122 	Ot /= f->d_texture->GetEditorImage()->uploadHeight;
1123 
1124 	Os = abs(Os);
1125 	Os *= s;
1126 	Os /= f->d_texture->GetEditorImage()->uploadWidth;
1127 
1128 
1129 	if (y) {
1130 		Face_FitTexture_BrushPrimit(f, texS, texT, -Ot, 1.0);
1131 	} else {
1132 		Face_FitTexture_BrushPrimit(f, texS, texT, 1.0, -Os);
1133 	}
1134 	EmitBrushPrimitTextureCoordinates(f, f->face_winding);
1135 #endif
1136 }
1137 
Brush_FlipTexture_BrushPrimit(brush_t * b,bool y)1138 void Brush_FlipTexture_BrushPrimit(brush_t *b, bool y) {
1139 	for (face_t *f = b->brush_faces; f; f = f->next) {
1140 		Face_FlipTexture_BrushPrimit(f, y);
1141 	}
1142 }
1143 
Face_SetAxialScale_BrushPrimit(face_t * face,bool y)1144 void Face_SetAxialScale_BrushPrimit(face_t *face, bool y) {
1145 
1146 	if (!face) {
1147 		return;
1148 	}
1149 
1150 	if (!face->face_winding) {
1151 		return;
1152 	}
1153 
1154 	//float oldS, oldT, oldR;
1155 	//Face_GetScale_BrushPrimit(face, &oldS, &oldT, &oldR);
1156 
1157 	idVec3D min, max;
1158 	min.x = min.y = min.z = 999999.0;
1159 	max.x = max.y = max.z = -999999.0;
1160 	for (int i = 0; i < face->face_winding->GetNumPoints(); i++) {
1161 		for (int j = 0; j < 3; j++) {
1162 			if ((*face->face_winding)[i][j] < min[j]) {
1163 				min[j] = (*face->face_winding)[i][j];
1164 			}
1165 			if ((*face->face_winding)[i][j] > max[j]) {
1166 				max[j] = (*face->face_winding)[i][j];
1167 			}
1168 		}
1169 	}
1170 
1171 	idVec3 len;
1172 
1173 	if (g_bAxialMode) {
1174 		if (g_axialAnchor >= 0 && g_axialAnchor < face->face_winding->GetNumPoints() &&
1175 			g_axialDest >= 0 && g_axialDest < face->face_winding->GetNumPoints() &&
1176 			g_axialAnchor != g_axialDest) {
1177 				len = (*face->face_winding)[g_axialDest].ToVec3() - (*face->face_winding)[g_axialAnchor].ToVec3();
1178 		} else {
1179 			return;
1180 		}
1181 	} else {
1182 		if (y) {
1183 			len = (*face->face_winding)[2].ToVec3() - (*face->face_winding)[1].ToVec3();
1184 		} else {
1185 			len = (*face->face_winding)[1].ToVec3() - (*face->face_winding)[0].ToVec3();
1186 		}
1187 	}
1188 
1189 	double dist = len.Length();
1190 	double width = idMath::Fabs(max.x - min.x);
1191 	double height = idMath::Fabs(max.z - min.z);
1192 
1193 	//len = maxs[2] - mins[2];
1194 	//double yDist = len.Length();
1195 
1196 
1197 	if (dist != 0.0) {
1198 		if (dist > face->d_texture->GetEditorImage()->uploadHeight) {
1199 			height = 1.0 / (dist / face->d_texture->GetEditorImage()->uploadHeight);
1200 		} else {
1201 			height /= dist;
1202 		}
1203 		if (dist > face->d_texture->GetEditorImage()->uploadWidth) {
1204 			width = 1.0 / (dist / face->d_texture->GetEditorImage()->uploadWidth);
1205 		} else {
1206 			width /= dist;
1207 		}
1208 	}
1209 
1210 	if (y) {
1211 		Face_SetExplicitScale_BrushPrimit(face, 0.0, height);
1212 		//oldT = oldT / height * 10;
1213 		//Select_ShiftTexture_BrushPrimit(face, 0, -oldT, true);
1214 	} else {
1215 		Face_SetExplicitScale_BrushPrimit(face, width, 0.0);
1216 	}
1217 /*
1218 	common->Printf("Face x: %f  y: %f  xr: %f  yr: %f\n", x, y, xRatio, yRatio);
1219 	common->Printf("Texture x: %i  y: %i  \n",face->d_texture->GetEditorImage()->uploadWidth, face->d_texture->GetEditorImage()->uploadHeight);
1220 
1221 	idVec3D texS, texT;
1222 	ComputeAxisBase(face->plane.normal, texS, texT);
1223 	float	Os = 0, Ot = 0;
1224 	for (int i = 0; i < face->face_winding->numpoints; i++) {
1225 		Os += DotProduct(face->face_winding->p[i], texS);
1226 		Ot += DotProduct(face->face_winding->p[i], texT);
1227 	}
1228 
1229 	common->Printf("Face2 x: %f  y: %f  \n", Os, Ot);
1230 	Os /= face->face_winding->numpoints;
1231 	Ot /= face->face_winding->numpoints;
1232 
1233 
1234 	//Os /= face->face_winding->numpoints;
1235 	//Ot /= face->face_winding->numpoints;
1236 
1237 */
1238 }
1239