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