}
}
+long double HighestImpactSign (long double a, long double b)
+{
+ // returns the sign of the value with larger abs
+ if (a + b > 0)
+ return +1;
+ else
+ return -1;
+}
+
+void Face_TexdefFromTextureVectors (face_t *f, long double STfromXYZ[2][4], vec3_t pvecs[2], int sv, int tv)
+{
+ texdef_t *td;
+ qtexture_t *q;
+ int j;
+ long double ang;
+
+ td = &f->texdef;
+ q = f->d_texture;
+
+ // undo the texture transform
+ for (j=0 ; j<4 ; j++) {
+ STfromXYZ[0][j] *= q->width;
+ STfromXYZ[1][j] *= q->height;
+ }
+
+ // shift
+ td->shift[0] = STfromXYZ[0][3];
+ td->shift[1] = STfromXYZ[1][3];
+
+ /**
+ * SOLVE:
+ * STfromXYZ[0][sv] = (cosv * pvecs[0][sv] - sinv * pvecs[0][tv]) / td->scale[0];
+ * STfromXYZ[0][tv] = (sinv * pvecs[0][sv] + cosv * pvecs[0][tv]) / td->scale[0];
+ * STfromXYZ[1][sv] = (cosv * pvecs[1][sv] - sinv * pvecs[1][tv]) / td->scale[1];
+ * STfromXYZ[1][tv] = (sinv * pvecs[1][sv] + cosv * pvecs[1][tv]) / td->scale[1];
+ * FOR:
+ * sinv, cosv, td->scale[0], td->scale[1]
+ * WE KNOW:
+ * sinv^2 + cosv^2 = 1
+ * pvecs[0][sv] is +/-1
+ * pvecs[0][tv] is 0
+ * pvecs[1][sv] is 0
+ * pvecs[1][tv] is +/-1
+ * THUS:
+ * STfromXYZ[0][sv] = +cosv * pvecs[0][sv] / td->scale[0];
+ * STfromXYZ[0][tv] = +sinv * pvecs[0][sv] / td->scale[0];
+ * STfromXYZ[1][sv] = -sinv * pvecs[1][tv] / td->scale[1];
+ * STfromXYZ[1][tv] = +cosv * pvecs[1][tv] / td->scale[1];
+ */
+
+ td->scale[0] = sqrt(STfromXYZ[0][sv]*STfromXYZ[0][sv] + STfromXYZ[0][tv]*STfromXYZ[0][tv]);
+ td->scale[1] = sqrt(STfromXYZ[1][sv]*STfromXYZ[1][sv] + STfromXYZ[1][tv]*STfromXYZ[1][tv]);
+
+ if (td->scale[0])
+ td->scale[0] = 1 / td->scale[0]; // avoid NaNs
+ if (td->scale[1])
+ td->scale[1] = 1 / td->scale[1];
+
+ long double sign0tv = (STfromXYZ[0][tv] > 0) ? +1 : -1;
+ ang = atan2( sign0tv * STfromXYZ[0][tv], sign0tv * STfromXYZ[0][sv]); // atan2(y, x) with y positive is in [0, PI[
+
+ // STOP
+ // We have until now ignored the fact that td->scale[0] or td->scale[1] may
+ // have either sign (+ or -). Due to roundoff errors, our choice of
+ // sign0tv may even have been wrong in a sense.
+ // sign0tv may NOT indicate the appropriate sign for td->scale[0] (namely,
+ // if cosv is near zero)!
+ // let's look at the signs again
+ // sign0sv = signcosv * pvecs[0][sv] / td->scale[0]sign
+ // sign0tv = pvecs[0][sv] / td->scale[0]sign
+ // sign1sv = -1 * pvecs[1][tv] / td->scale[1]sign
+ // sign1tv = signcosv * pvecs[1][tv] / td->scale[1]sign
+ // -->
+ // td->scale[1]sign = sign1tv * signcosv * pvecs[1][tv]
+ // td->scale[1]sign = -sign1sv * signsinv * pvecs[1][tv]
+ // td->scale[0]sign = sign0tv * signsinv * pvecs[0][sv]
+ // td->scale[0]sign = sign0sv * signcosv * pvecs[0][sv]
+ // which to choose?
+ // the one with the larger impact on the original texcoords, of course
+ // to minimize the effect of roundoff errors that may flip the signs!
+
+ td->scale[0] *= HighestImpactSign(STfromXYZ[0][tv] * +sin(ang), STfromXYZ[0][sv] * cos(ang)) * pvecs[0][sv];
+ td->scale[1] *= HighestImpactSign(STfromXYZ[1][sv] * -sin(ang), STfromXYZ[1][tv] * cos(ang)) * pvecs[1][tv];
+
+ td->rotate = ang * 180 / Q_PI; // FIXME possibly snap this to 0/90/180 (270 can't happen)?
+}
+
+
/*
================
Face_MakePlane
xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
}
+long double SarrusDetScalar(long double a1, long double b1, long double c1, long double a2, long double b2, long double c2, long double a3, long double b3, long double c3)
+{
+ return a1 * b2 * c3 + a2 * b3 * c1 + a3 * b1 * c2
+ - a1 * c2 * b3 - a2 * c3 * b1 - a3 * c1 * b2;
+}
+
+void SarrusSolve(long double a1, long double b1, long double c1, long double d1, long double a2, long double b2, long double c2, long double d2, long double a3, long double b3, long double c3, long double d3, long double *a, long double *b, long double *c)
+{
+ long double det;
+ det = SarrusDetScalar(a1, b1, c1,
+ a2, b2, c2,
+ a3, b3, c3);
+ *a = SarrusDetScalar(d1, b1, c1,
+ d2, b2, c2,
+ d3, b3, c3) / det;
+ *b = SarrusDetScalar(a1, d1, c1,
+ a2, d2, c2,
+ a3, d3, c3) / det;
+ *c = SarrusDetScalar(a1, b1, d1,
+ a2, b2, d2,
+ a3, b3, d3) / det;
+}
+
+void Face_TexdefFromTextureCoordinates ( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f)
+{
+ vec3_t pvecs[2];
+ int sv, tv, uv;
+
+ long double STfromXYZ[2][4];
+
+ // get natural texture axis
+ TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
+
+ if (pvecs[0][0])
+ sv = 0;
+ else if (pvecs[0][1])
+ sv = 1;
+ else
+ sv = 2;
+
+ if (pvecs[1][0])
+ tv = 0;
+ else if (pvecs[1][1])
+ tv = 1;
+ else
+ tv = 2;
+
+ uv = 3 - sv - tv; // the "other one"
+
+ // find the STfromXYZ 4-vectors
+ /*
+ SARRUS-SOLVE:
+ xyzst1[3] == xyzst1[sv] * STfromXYZ[0][sv] + xyzst1[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
+ xyzst2[3] == xyzst2[sv] * STfromXYZ[0][sv] + xyzst2[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
+ xyzst3[3] == xyzst3[sv] * STfromXYZ[0][sv] + xyzst3[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
+ FOR: STfromXYZ[0]
+ GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
+ SARRUS-SOLVE:
+ xyzst1[4] == xyzst1[sv] * STfromXYZ[1][sv] + xyzst1[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
+ xyzst2[4] == xyzst2[sv] * STfromXYZ[1][sv] + xyzst2[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
+ xyzst3[4] == xyzst3[sv] * STfromXYZ[1][sv] + xyzst3[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
+ FOR: STfromXYZ[1]
+ GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
+ */
+
+ STfromXYZ[0][uv] = 0;
+ SarrusSolve(
+ xyzst1[sv], xyzst1[tv], 1, xyzst1[3],
+ xyzst2[sv], xyzst2[tv], 1, xyzst2[3],
+ xyzst3[sv], xyzst3[tv], 1, xyzst3[3],
+ &STfromXYZ[0][sv], &STfromXYZ[0][tv], &STfromXYZ[0][3]
+ );
+
+ STfromXYZ[1][uv] = 0;
+ SarrusSolve(
+ xyzst1[sv], xyzst1[tv], 1, xyzst1[4],
+ xyzst2[sv], xyzst2[tv], 1, xyzst2[4],
+ xyzst3[sv], xyzst3[tv], 1, xyzst3[4],
+ &STfromXYZ[1][sv], &STfromXYZ[1][tv], &STfromXYZ[1][3]
+ );
+
+ /*
+ printf("%s\n", q->name);
+
+ printf("%f == %Lf\n", xyzst1[3], DotProduct (xyzst1, STfromXYZ[0]) + STfromXYZ[0][3]);
+ printf("%f == %Lf\n", xyzst2[3], DotProduct (xyzst2, STfromXYZ[0]) + STfromXYZ[0][3]);
+ printf("%f == %Lf\n", xyzst3[3], DotProduct (xyzst3, STfromXYZ[0]) + STfromXYZ[0][3]);
+ printf("%f == %Lf\n", xyzst1[4], DotProduct (xyzst1, STfromXYZ[1]) + STfromXYZ[1][3]);
+ printf("%f == %Lf\n", xyzst2[4], DotProduct (xyzst2, STfromXYZ[1]) + STfromXYZ[1][3]);
+ printf("%f == %Lf\n", xyzst3[4], DotProduct (xyzst3, STfromXYZ[1]) + STfromXYZ[1][3]);
+
+ float newSTfromXYZ[2][4];
+
+ printf("old: %Lf,%Lf,%Lf,%Lf %Lf,%Lf,%Lf,%Lf\n",
+ STfromXYZ[0][0], STfromXYZ[0][1], STfromXYZ[0][2], STfromXYZ[0][3],
+ STfromXYZ[1][0], STfromXYZ[1][1], STfromXYZ[1][2], STfromXYZ[1][3]);
+ */
+
+ Face_TexdefFromTextureVectors (f, STfromXYZ, pvecs, sv, tv);
+
+ /*
+ Face_TextureVectors(f, newSTfromXYZ);
+
+ printf("new: %f,%f,%f,%f %f,%f,%f,%f\n",
+ newSTfromXYZ[0][0], newSTfromXYZ[0][1], newSTfromXYZ[0][2], newSTfromXYZ[0][3],
+ newSTfromXYZ[1][0], newSTfromXYZ[1][1], newSTfromXYZ[1][2], newSTfromXYZ[1][3]);
+
+ float newxyzst1[5];
+ float newxyzst2[5];
+ float newxyzst3[5];
+ VectorCopy(xyzst1, newxyzst1);
+ VectorCopy(xyzst2, newxyzst2);
+ VectorCopy(xyzst3, newxyzst3);
+ EmitTextureCoordinates (newxyzst1, q, f);
+ EmitTextureCoordinates (newxyzst2, q, f);
+ EmitTextureCoordinates (newxyzst3, q, f);
+ printf("Face_TexdefFromTextureCoordinates: %f,%f %f,%f %f,%f -> %f,%f %f,%f %f,%f\n",
+ xyzst1[3], xyzst1[4],
+ xyzst2[3], xyzst2[4],
+ xyzst3[3], xyzst3[4],
+ newxyzst1[3], newxyzst1[4],
+ newxyzst2[3], newxyzst2[4],
+ newxyzst3[3], newxyzst3[4]);
+ // TODO why do these differ, but not the previous ones? this makes no sense whatsoever
+ */
+}
+
+
+
//==========================================================================
/*
T->coords[1][2] = SarrusDet( M[0], M[1], D[1] ) / det;
}
-//++timo replace everywhere texX by texS etc. ( ----> and in q3map !)
+//++timo replace everywhere texX by texS etc. ( ----> and in q3map !)
// NOTE : ComputeAxisBase here and in q3map code must always BE THE SAME !
// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
// rotation by (0,RotY,RotZ) assigns X to normal
vec3_t M[3],D[2];
// vec3_t N[2],Mf[2];
brushprimit_texdef_t N;
- vec3_t Mf[2];
+ vec3_t Mf[2];
// we'll be working on a standardized texture size
EmitBrushPrimitTextureCoordinates( f, f->face_winding );
ClearBounds( BBoxSTMin, BBoxSTMax );
w = f->face_winding;
- for (i=0 ; i<w->numpoints ; i++)
- {
+ for (i=0 ; i<w->numpoints ; i++)
+ {
// AddPointToBounds in 2D on (S,T) coordinates
for (j=0 ; j<2 ; j++)
{
if (val > BBoxSTMax[j])
BBoxSTMax[j] = val;
}
- }
+ }
// we have the three points of the BBox (BBoxSTMin[0].BBoxSTMin[1]) (BBoxSTMax[0],BBoxSTMin[1]) (BBoxSTMin[0],BBoxSTMax[1]) in ST space
- // the BP matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in (Sfit,Tfit) space to these three points
+ // the BP matrix we are looking for gives (0,0) (nwidth,0) (0,nHeight) coordinates in (Sfit,Tfit) space to these three points
// we have A(Sfit,Tfit) = (0,0) = Mf * A(TexS,TexT) = N * M * A(TexS,TexT) = N * A(S,T)
// so we solve the system for N and then Mf = N * M
M[0][0] = BBoxSTMin[0]; M[0][1] = BBoxSTMax[0]; M[0][2] = BBoxSTMin[0];
M[1][0] = BBoxSTMin[1]; M[1][1] = BBoxSTMin[1]; M[1][2] = BBoxSTMax[1];
D[0][0] = 0.0f; D[0][1] = nWidth; D[0][2] = 0.0f;
D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = nHeight;
- MatrixForPoints( M, D, &N );
+ MatrixForPoints( M, D, &N );
#if 0
- // FIT operation gives coordinates of three points of the bounding box in (S',T'), our target axis base
+ // FIT operation gives coordinates of three points of the bounding box in (S',T'), our target axis base
// A(S',T')=(0,0) B(S',T')=(nWidth,0) C(S',T')=(0,nHeight)
// and we have them in (S,T) axis base: A(S,T)=(BBoxSTMin[0],BBoxSTMin[1]) B(S,T)=(BBoxSTMax[0],BBoxSTMin[1]) C(S,T)=(BBoxSTMin[0],BBoxSTMax[1])
// we compute the N transformation so that: A(S',T') = N * A(S,T)
- VectorSet( N[0], (BBoxSTMax[0]-BBoxSTMin[0])/(float)nWidth, 0.0f, BBoxSTMin[0] );
+ VectorSet( N[0], (BBoxSTMax[0]-BBoxSTMin[0])/(float)nWidth, 0.0f, BBoxSTMin[0] );
VectorSet( N[1], 0.0f, (BBoxSTMax[1]-BBoxSTMin[1])/(float)nHeight, BBoxSTMin[1] );
#endif
// the final matrix is the product (Mf stands for Mfit)
- Mf[0][0] = N.coords[0][0] * f->brushprimit_texdef.coords[0][0] + N.coords[0][1] * f->brushprimit_texdef.coords[1][0];
+ Mf[0][0] = N.coords[0][0] * f->brushprimit_texdef.coords[0][0] + N.coords[0][1] * f->brushprimit_texdef.coords[1][0];
Mf[0][1] = N.coords[0][0] * f->brushprimit_texdef.coords[0][1] + N.coords[0][1] * f->brushprimit_texdef.coords[1][1];
Mf[0][2] = N.coords[0][0] * f->brushprimit_texdef.coords[0][2] + N.coords[0][1] * f->brushprimit_texdef.coords[1][2] + N.coords[0][2];
- Mf[1][0] = N.coords[1][0] * f->brushprimit_texdef.coords[0][0] + N.coords[1][1] * f->brushprimit_texdef.coords[1][0];
+ Mf[1][0] = N.coords[1][0] * f->brushprimit_texdef.coords[0][0] + N.coords[1][1] * f->brushprimit_texdef.coords[1][0];
Mf[1][1] = N.coords[1][0] * f->brushprimit_texdef.coords[0][1] + N.coords[1][1] * f->brushprimit_texdef.coords[1][1];
Mf[1][2] = N.coords[1][0] * f->brushprimit_texdef.coords[0][2] + N.coords[1][1] * f->brushprimit_texdef.coords[1][2] + N.coords[1][2];
// copy back
// ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture );
}
-void BrushPrimitFaceToFace(face_t *face)
+void BrushPrimitFaceToFace(face_t *f)
{
- // we have parsed brush primitives and need conversion back to standard format
- // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
- // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
- // I tried various tweaks, no luck .. seems shifting is lost
- brushprimit_texdef_t aux;
- ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
- TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
- face->texdef.scale[0]/=2.0;
- face->texdef.scale[1]/=2.0;
+#if 0
+ // we have parsed brush primitives and need conversion back to standard format
+ // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
+ // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
+ // I tried various tweaks, no luck .. seems shifting is lost
+ brushprimit_texdef_t aux;
+ ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
+ TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
+ face->texdef.scale[0]/=2.0;
+ face->texdef.scale[1]/=2.0;
+#else
+ // new method by divVerent@alientrap.org: Shift and scale no longer get lost when opening a BP map in texdef mode.
+ vec3_t texX,texY;
+ vec3_t proj;
+ vec_t ST[3][5];
+
+ ComputeAxisBase(f->plane.normal,texX,texY);
+ VectorCopy(f->plane.normal,proj);
+ VectorScale(proj,f->plane.dist,proj);
+ VectorCopy(proj,ST[0]);
+ VectorCopy(texX,ST[1]);
+ VectorAdd(ST[1],proj,ST[1]);
+ VectorCopy(texY,ST[2]);
+ VectorAdd(ST[2],proj,ST[2]);
+
+ ST[0][3] = f->brushprimit_texdef.coords[0][2];
+ ST[0][4] = f->brushprimit_texdef.coords[1][2];
+ ST[1][3] = f->brushprimit_texdef.coords[0][0] + ST[0][3];
+ ST[1][4] = f->brushprimit_texdef.coords[1][0] + ST[0][4];
+ ST[2][3] = f->brushprimit_texdef.coords[0][1] + ST[0][3];
+ ST[2][4] = f->brushprimit_texdef.coords[1][1] + ST[0][4];
+
+ Face_TexdefFromTextureCoordinates(ST[0], ST[1], ST[2], f->d_texture, f);
+#endif
}
// TEXTURE LOCKING -----------------------------------------------------------------------------------------------------
void TextureLockTransformation_BrushPrimit(face_t *f)
{
- vec3_t Orig,texS,texT; // axis base of initial plane
- // used by transformation algo
- vec3_t temp; int j;
+ vec3_t Orig,texS,texT; // axis base of initial plane
+ // used by transformation algo
+ vec3_t temp; int j;
vec3_t vRotate; // rotation vector
- vec3_t rOrig,rvecS,rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base }
- vec3_t rNormal,rtexS,rtexT; // axis base for the transformed plane
+ vec3_t rOrig,rvecS,rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base }
+ vec3_t rNormal,rtexS,rtexT; // axis base for the transformed plane
vec3_t lOrig,lvecS,lvecT; // [2] are not used ( but usefull for debugging )
vec3_t M[3];
vec_t det;
// compute plane axis base
ComputeAxisBase( f->plane.normal, texS, texT );
- VectorSet(Orig, 0.0f, 0.0f, 0.0f);
+ VectorSet(Orig, 0.0f, 0.0f, 0.0f);
// compute coordinates of (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) after transformation
// (0,0) (1,0) (0,1) ( expressed in initial plane axis base ) <-> (0,0,0) texS texT ( expressed world axis base )
- // input: Orig, texS, texT (and the global locking params)
- // ouput: rOrig, rvecS, rvecT, rNormal
- if (txlock_bRotation) {
- // rotation vector
- VectorSet( vRotate, 0.0f, 0.0f, 0.0f );
- vRotate[txl_nAxis]=txl_fDeg;
- VectorRotateOrigin ( Orig, vRotate, txl_vOrigin, rOrig );
- VectorRotateOrigin ( texS, vRotate, txl_vOrigin, rvecS );
- VectorRotateOrigin ( texT, vRotate, txl_vOrigin, rvecT );
- // compute normal of plane after rotation
- VectorRotate ( f->plane.normal, vRotate, rNormal );
- }
- else
- {
- VectorSubtract (Orig, txl_origin, temp);
- for (j=0 ; j<3 ; j++)
- rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
- VectorSubtract (texS, txl_origin, temp);
- for (j=0 ; j<3 ; j++)
- rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
- VectorSubtract (texT, txl_origin, temp);
- for (j=0 ; j<3 ; j++)
- rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
- // we also need the axis base of the target plane, apply the transformation matrix to the normal too..
- for (j=0 ; j<3 ; j++)
- rNormal[j] = DotProduct(f->plane.normal, txl_matrix[j]);
- }
+ // input: Orig, texS, texT (and the global locking params)
+ // ouput: rOrig, rvecS, rvecT, rNormal
+ if (txlock_bRotation) {
+ // rotation vector
+ VectorSet( vRotate, 0.0f, 0.0f, 0.0f );
+ vRotate[txl_nAxis]=txl_fDeg;
+ VectorRotateOrigin ( Orig, vRotate, txl_vOrigin, rOrig );
+ VectorRotateOrigin ( texS, vRotate, txl_vOrigin, rvecS );
+ VectorRotateOrigin ( texT, vRotate, txl_vOrigin, rvecT );
+ // compute normal of plane after rotation
+ VectorRotate ( f->plane.normal, vRotate, rNormal );
+ }
+ else
+ {
+ VectorSubtract (Orig, txl_origin, temp);
+ for (j=0 ; j<3 ; j++)
+ rOrig[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
+ VectorSubtract (texS, txl_origin, temp);
+ for (j=0 ; j<3 ; j++)
+ rvecS[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
+ VectorSubtract (texT, txl_origin, temp);
+ for (j=0 ; j<3 ; j++)
+ rvecT[j] = DotProduct(temp, txl_matrix[j]) + txl_origin[j];
+ // we also need the axis base of the target plane, apply the transformation matrix to the normal too..
+ for (j=0 ; j<3 ; j++)
+ rNormal[j] = DotProduct(f->plane.normal, txl_matrix[j]);
+ }
// compute rotated plane axis base
ComputeAxisBase( rNormal, rtexS, rtexT );
// called before the points on the face are actually rotated
void RotateFaceTexture_BrushPrimit(face_t *f, int nAxis, float fDeg, vec3_t vOrigin )
{
- // this is a placeholder to call the general texture locking algorithm
- txlock_bRotation = true;
- txl_nAxis = nAxis;
- txl_fDeg = fDeg;
- VectorCopy(vOrigin, txl_vOrigin);
- TextureLockTransformation_BrushPrimit(f);
+ // this is a placeholder to call the general texture locking algorithm
+ txlock_bRotation = true;
+ txl_nAxis = nAxis;
+ txl_fDeg = fDeg;
+ VectorCopy(vOrigin, txl_vOrigin);
+ TextureLockTransformation_BrushPrimit(f);
}
// compute the new brush primit texture matrix for a transformation matrix and a flip order flag (change plane orientation)