2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
34 #define ZERO_EPSILON 1.0E-6
39 double & operator[]( const int index ) {
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 // =======================================================================================================================
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];
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 // =======================================================================================================================
64 void ComputeAxisBase(idVec3 &normal, idVec3D &texS, idVec3D &texT) {
68 if (idMath::Fabs(normal[0]) < 1e-6) {
72 if (idMath::Fabs(normal[1]) < 1e-6) {
76 if (idMath::Fabs(normal[2]) < 1e-6) {
80 RotY = -atan2(normal[2], idMath::Sqrt(normal[1] * normal[1] + normal[0] * normal[0]));
81 RotZ = atan2(normal[1], normal[0]);
83 // rotate (0,1,0) and (0,0,1) to compute texS and texT
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);
95 =======================================================================================================================
96 =======================================================================================================================
98 void FaceToBrushPrimitFace(face_t *f) {
102 // ST of (0,0) (1,0) (0,1)
103 idVec5 ST[3]; // [ point index ] [ xyz ST ]
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);
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");
119 common->Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n");
124 ComputeAxisBase(f->plane.Normal(), texX, texY);
126 // compute projection vector
127 VectorCopy( f->plane, proj );
128 VectorScale(proj, -f->plane[3], proj);
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
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);
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];
156 // =======================================================================================================================
157 // compute texture coordinates for the winding points
158 // =======================================================================================================================
160 void EmitBrushPrimitTextureCoordinates(face_t *f, idWinding *w, patchMesh_t *patch) {
164 if (f== NULL || (w == NULL && patch == NULL)) {
169 ComputeAxisBase(f->plane.Normal(), texX, texY);
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
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);
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];
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];
208 // =======================================================================================================================
209 // parse a brush in brush primitive format
210 // =======================================================================================================================
212 void BrushPrimit_Parse(brush_t *b, bool newFormat, const idVec3 origin) {
216 if (strcmp(token, "{")) {
217 Warning("parsing brush primitive");
222 if (!GetToken(true)) {
226 if (!strcmp(token, "}")) {
230 // reading of b->epairs if any
231 if (strcmp(token, "(")) {
232 ParseEpair(&b->epairs);
234 else { // it's a face
237 if (!b->brush_faces) {
242 for (scan = b->brush_faces; scan->next; scan = scan->next)
248 // read the three point plane definition
250 for (j = 0; j < 4; j++) {
252 plane[j] = atof(token);
256 f->originalPlane = plane;
259 //idWinding *w = Brush_MakeFaceWinding(b, f, true);
261 w.BaseForPlane( plane );
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;
272 for (i = 0; i < 3; i++) {
277 if (strcmp(token, "(")) {
278 Warning("parsing brush");
282 for (j = 0; j < 3; j++) {
284 f->planepts[i][j] = atof(token);
288 if (strcmp(token, ")")) {
289 Warning("parsing brush");
295 // texture coordinates
297 if (strcmp(token, "(")) {
298 Warning("parsing brush primitive");
303 if (strcmp(token, "(")) {
304 Warning("parsing brush primitive");
308 for (j = 0; j < 3; j++) {
310 f->brushprimit_texdef.coords[0][j] = atof(token);
314 if (strcmp(token, ")")) {
315 Warning("parsing brush primitive");
320 if (strcmp(token, "(")) {
321 Warning("parsing brush primitive");
325 for (j = 0; j < 3; j++) {
327 f->brushprimit_texdef.coords[1][j] = atof(token);
331 if (strcmp(token, ")")) {
332 Warning("parsing brush primitive");
337 if (strcmp(token, ")")) {
338 Warning("parsing brush primitive");
342 // read the texturedef
345 // strcpy(f->texdef.name, token);
346 if (g_qeglobals.mapVersion < 2.0) {
347 f->texdef.SetName(va("textures/%s", token));
350 f->texdef.SetName(token);
353 if (TokenAvailable()) {
357 f->texdef.value = atoi(token);
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 // =======================================================================================================================
369 void TexMatToFakeTexCoords(float texMat[2][3], float shift[2], float *rot, float scale[2])
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");
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]);
381 if (scale[0] < ZERO_EPSILON || scale[1] < ZERO_EPSILON) {
382 common->Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n");
385 // compute rotate value
386 if (idMath::Fabs(texMat[0][0]) < ZERO_EPSILON)
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");
395 if (texMat[1][0] > 0) {
403 *rot = RAD2DEG(atan2(texMat[1][0], texMat[0][0]));
406 shift[0] = -texMat[0][2];
407 shift[1] = texMat[1][2];
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 // =======================================================================================================================
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];
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 // =======================================================================================================================
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) {
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);
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];
446 =======================================================================================================================
447 =======================================================================================================================
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);
455 // =======================================================================================================================
457 // =======================================================================================================================
459 void Face_MoveTexture_BrushPrimit(face_t *f, idVec3 delta) {
462 idVec3D M[3]; // columns of the matrix .. easier that way
466 // compute plane axis base ( doesn't change with translation )
467 ComputeAxisBase(f->plane.Normal(), texS, texT);
469 // compute translation vector in plane axis base
470 tx = DotProduct(delta, texS);
471 ty = DotProduct(delta, texT);
473 // fill the data vectors
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];
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;
501 // =======================================================================================================================
502 // call Face_MoveTexture_BrushPrimit after idVec3D computation
503 // =======================================================================================================================
505 void Select_ShiftTexture_BrushPrimit(face_t *f, float x, float y, bool autoAdjust) {
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);
517 x /= f->d_texture->GetEditorImage()->uploadWidth;
518 y /= f->d_texture->GetEditorImage()->uploadHeight;
520 f->brushprimit_texdef.coords[0][2] += x;
521 f->brushprimit_texdef.coords[1][2] += y;
522 EmitBrushPrimitTextureCoordinates(f, f->face_winding);
527 // =======================================================================================================================
528 // best fitted 2D vector is x.X+y.Y
529 // =======================================================================================================================
531 void ComputeBest2DVector(idVec3 v, idVec3 X, idVec3 Y, int &x, int &y) {
533 sx = DotProduct(v, X);
534 sy = DotProduct(v, Y);
535 if (idMath::Fabs(sy) > idMath::Fabs(sx)) {
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 // =======================================================================================================================
563 void MatrixForPoints(idVec3D M[3], idVec3D D[2], brushprimit_texdef_t *T) {
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)
576 // fill the data vectors
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;
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 // =======================================================================================================================
609 void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float height, float width) {
610 idVec3D BBoxSTMin, BBoxSTMax;
616 // idVec3D N[2],Mf[2];
617 brushprimit_texdef_t N;
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);
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
631 EmitBrushPrimitTextureCoordinates(f, f->face_winding);
632 BBoxSTMin[0] = BBoxSTMin[1] = BBoxSTMin[2] = 999999;
633 BBoxSTMax[0] = BBoxSTMax[1] = BBoxSTMax[2] = -999999;
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]) {
645 if (val > BBoxSTMax[j]) {
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
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];
672 MatrixForPoints(M, D, &N);
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)
683 N[0][0] = (BBoxSTMax[0] - BBoxSTMin[0]) / width;
685 N[0][2] = BBoxSTMin[0];
687 N[1][1] = (BBoxSTMax[1] - BBoxSTMin[1]) / height;
688 N[1][2] = BBoxSTMin[1];
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] +
694 f->brushprimit_texdef.coords[1][0];
695 Mf[0][1] = N.coords[0][0] *
696 f->brushprimit_texdef.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] +
702 f->brushprimit_texdef.coords[1][2] +
704 Mf[1][0] = N.coords[1][0] *
705 f->brushprimit_texdef.coords[0][0] +
707 f->brushprimit_texdef.coords[1][0];
708 Mf[1][1] = N.coords[1][0] *
709 f->brushprimit_texdef.coords[0][1] +
711 f->brushprimit_texdef.coords[1][1];
712 Mf[1][2] = N.coords[1][0] *
713 f->brushprimit_texdef.coords[0][2] +
715 f->brushprimit_texdef.coords[1][2] +
719 VectorCopy(Mf[0], f->brushprimit_texdef.coords[0]);
720 VectorCopy(Mf[1], f->brushprimit_texdef.coords[1]);
723 // handle the texture size ConvertTexMatWithQTexture( &f->brushprimit_texdef,
724 // NULL, &f->brushprimit_texdef, f->d_texture );
729 =======================================================================================================================
730 =======================================================================================================================
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");
738 brushprimit_texdef_t *pBP = &face->brushprimit_texdef;
739 BPMatScale(pBP->coords, sS, sT);
741 // now emit the coordinates on the winding
742 EmitBrushPrimitTextureCoordinates(face, face->face_winding);
746 =======================================================================================================================
747 =======================================================================================================================
749 void Face_RotateTexture_BrushPrimit(face_t *face, float amount, idVec3 origin) {
750 brushprimit_texdef_t *pBP = &face->brushprimit_texdef;
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);
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
775 bool txlock_bRotation;
777 // rotation locking params
782 // flip locking params
783 idVec3D txl_matrix[3];
787 =======================================================================================================================
788 =======================================================================================================================
790 void TextureLockTransformation_BrushPrimit(face_t *f) {
791 idVec3D Orig, texS, texT; // axis base of initial plane
793 // used by transformation algo
796 //idVec3D vRotate; // rotation vector
798 idVec3D rOrig, rvecS, rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base }
800 idVec3D rtexS, rtexT; // axis base for the transformed plane
801 idVec3D lOrig, lvecS, lvecT; // [2] are not used ( but usefull for debugging )
806 // silence compiler warnings
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;
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
826 if (txlock_bRotation) {
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);
837 // compute normal of plane after rotation
838 VectorRotate3(f->plane.Normal(), vRotate, rNormal);
842 VectorSubtract(Orig, txl_origin, temp);
843 for (j = 0; j < 3; j++) {
844 rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
847 VectorSubtract(texS, txl_origin, temp);
848 for (j = 0; j < 3; j++) {
849 rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
852 VectorSubtract(texT, txl_origin, temp);
853 for (j = 0; j < 3; j++) {
854 rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
858 // we also need the axis base of the target plane, apply the transformation matrix
859 // to the normal too..
861 for (j = 0; j < 3; j++) {
862 rNormal[j] = DotProduct(f->plane, txl_matrix[j]);
866 // compute rotated plane axis base
867 ComputeAxisBase(rNormal, rtexS, rtexT);
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);
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];
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;
905 // =======================================================================================================================
906 // texture locking called before the points on the face are actually rotated
907 // =======================================================================================================================
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;
914 VectorCopy(vOrigin, txl_vOrigin);
915 TextureLockTransformation_BrushPrimit(f);
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 // =======================================================================================================================
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);
937 // =======================================================================================================================
939 // =======================================================================================================================
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];
951 =======================================================================================================================
952 =======================================================================================================================
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]);
959 =======================================================================================================================
960 =======================================================================================================================
962 void BPMatRotate(float A[2][3], float theta) {
965 memset(&m, 0, sizeof (float) *6);
966 m[0][0] = cos( DEG2RAD( theta ) );
967 m[0][1] = -sin( DEG2RAD( theta ) );
974 void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot) {
976 ComputeAxisBase(face->plane.Normal(), texS, texT);
978 if (face == NULL || face->face_winding == NULL) {
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);
988 Os /= face->face_winding->GetNumPoints();
989 Ot /= face->face_winding->GetNumPoints();
991 brushprimit_texdef_t *pBP = &face->brushprimit_texdef;
993 // here we have a special case, M is a translation and it's inverse is easy
997 memset(&m, 0, sizeof (float) *6);
1002 BPMatMul(m, pBP->coords, aux);
1004 m[1][2] = Ot; // now M^-1
1005 BPMatMul(aux, m, BPO);
1007 // apply a given scale (on S and T)
1008 ConvertTexMatWithQTexture(BPO, face->d_texture, aux, NULL);
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]);
1013 // compute rotate value
1014 if (idMath::Fabs(face->brushprimit_texdef.coords[0][0]) < ZERO_EPSILON)
1017 if (face->brushprimit_texdef.coords[1][0] > 0) {
1025 *rot = RAD2DEG(atan2(face->brushprimit_texdef.coords[1][0] / (*s) ? (*s) : 1.0f, face->brushprimit_texdef.coords[0][0] / (*t) ? (*t) : 1.0f));
1032 =======================================================================================================================
1033 =======================================================================================================================
1035 void Face_SetExplicitScale_BrushPrimit(face_t *face, float s, float t) {
1037 ComputeAxisBase(face->plane.Normal(), texS, texT);
1039 // find ST coordinates for the center of the face
1040 double Os = 0, Ot = 0;
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);
1047 Os /= face->face_winding->GetNumPoints();
1048 Ot /= face->face_winding->GetNumPoints();
1050 brushprimit_texdef_t *pBP = &face->brushprimit_texdef;
1052 // here we have a special case, M is a translation and it's inverse is easy
1056 memset(&m, 0, sizeof (float) *6);
1061 BPMatMul(m, pBP->coords, aux);
1063 m[1][2] = Ot; // now M^-1
1064 BPMatMul(aux, m, BPO);
1066 // apply a given scale (on S and T)
1067 ConvertTexMatWithQTexture(BPO, face->d_texture, aux, NULL);
1069 // reset the scale (normalize the matrix)
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]);
1083 // put the values for scale on S and T here:
1090 ConvertTexMatWithQTexture(aux, NULL, BPO, face->d_texture);
1091 BPMatMul(m, BPO, aux); // m is M^-1
1094 BPMatMul(aux, m, pBP->coords);
1096 // now emit the coordinates on the winding
1097 EmitBrushPrimitTextureCoordinates(face, face->face_winding);
1101 void Face_FlipTexture_BrushPrimit(face_t *f, bool y) {
1104 Face_GetScale_BrushPrimit(f, &s, &t, &rot);
1106 Face_SetExplicitScale_BrushPrimit(f, 0.0, -t);
1108 Face_SetExplicitScale_BrushPrimit(f, -s, 0.0);
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);
1122 Ot /= f->d_texture->GetEditorImage()->uploadHeight;
1126 Os /= f->d_texture->GetEditorImage()->uploadWidth;
1130 Face_FitTexture_BrushPrimit(f, texS, texT, -Ot, 1.0);
1132 Face_FitTexture_BrushPrimit(f, texS, texT, 1.0, -Os);
1134 EmitBrushPrimitTextureCoordinates(f, f->face_winding);
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);
1144 void Face_SetAxialScale_BrushPrimit(face_t *face, bool y) {
1150 if (!face->face_winding) {
1154 //float oldS, oldT, oldR;
1155 //Face_GetScale_BrushPrimit(face, &oldS, &oldT, &oldR);
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];
1165 if ((*face->face_winding)[i][j] > max[j]) {
1166 max[j] = (*face->face_winding)[i][j];
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();
1183 len = (*face->face_winding)[2].ToVec3() - (*face->face_winding)[1].ToVec3();
1185 len = (*face->face_winding)[1].ToVec3() - (*face->face_winding)[0].ToVec3();
1189 double dist = len.Length();
1190 double width = idMath::Fabs(max.x - min.x);
1191 double height = idMath::Fabs(max.z - min.z);
1193 //len = maxs[2] - mins[2];
1194 //double yDist = len.Length();
1198 if (dist > face->d_texture->GetEditorImage()->uploadHeight) {
1199 height = 1.0 / (dist / face->d_texture->GetEditorImage()->uploadHeight);
1203 if (dist > face->d_texture->GetEditorImage()->uploadWidth) {
1204 width = 1.0 / (dist / face->d_texture->GetEditorImage()->uploadWidth);
1211 Face_SetExplicitScale_BrushPrimit(face, 0.0, height);
1212 //oldT = oldT / height * 10;
1213 //Select_ShiftTexture_BrushPrimit(face, 0, -oldT, true);
1215 Face_SetExplicitScale_BrushPrimit(face, width, 0.0);
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);
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);
1229 common->Printf("Face2 x: %f y: %f \n", Os, Ot);
1230 Os /= face->face_winding->numpoints;
1231 Ot /= face->face_winding->numpoints;
1234 //Os /= face->face_winding->numpoints;
1235 //Ot /= face->face_winding->numpoints;