]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/EditorBrushPrimit.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / EditorBrushPrimit.cpp
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 "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "qe3.h"
33
34 #define ZERO_EPSILON    1.0E-6
35
36 class idVec3D {
37 public:
38         double x, y, z;
39         double &                        operator[]( const int index ) {
40                 return (&x)[index];
41         }
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 //
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 //
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  */
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 //
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 //
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 //
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 //
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 //
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  */
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 //
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 //
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 //
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 //
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 //
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  */
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  */
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  */
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 //
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 //
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 //
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  */
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  */
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
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  */
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
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
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
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