/* ======================================================================================================================= ======================================================================================================================= */ void Face_ScaleTexture_BrushPrimit(face_t *face, float sS, float sT) { if (!g_qeglobals.m_bBrushPrimitMode) { Sys_Status("BP mode required\n"); return; } brushprimit_texdef_t *pBP = &face->brushprimit_texdef; BPMatScale(pBP->coords, sS, sT); // now emit the coordinates on the winding EmitBrushPrimitTextureCoordinates(face, face->face_winding); }
/* ======================================================================================================================= ======================================================================================================================= */ void Face_RotateTexture_BrushPrimit(face_t *face, float amount, idVec3 origin) { brushprimit_texdef_t *pBP = &face->brushprimit_texdef; if (amount) { float x = pBP->coords[0][0]; float y = pBP->coords[0][1]; float x1 = pBP->coords[1][0]; float y1 = pBP->coords[1][1]; float s = sin( DEG2RAD( amount ) ); float c = cos( DEG2RAD( amount ) ); pBP->coords[0][0] = (((x - origin[0]) * c) - ((y - origin[1]) * s)) + origin[0]; pBP->coords[0][1] = (((x - origin[0]) * s) + ((y - origin[1]) * c)) + origin[1]; pBP->coords[1][0] = (((x1 - origin[0]) * c) - ((y1 - origin[1]) * s)) + origin[0]; pBP->coords[1][1] = (((x1 - origin[0]) * s) + ((y1 - origin[1]) * c)) + origin[1]; EmitBrushPrimitTextureCoordinates(face, face->face_winding); } }
// // ======================================================================================================================= // call Face_MoveTexture_BrushPrimit after idVec3D computation // ======================================================================================================================= // void Select_ShiftTexture_BrushPrimit(face_t *f, float x, float y, bool autoAdjust) { #if 0 idVec3D texS, texT; idVec3D delta; ComputeAxisBase(f->plane.normal, texS, texT); VectorScale(texS, x, texS); VectorScale(texT, y, texT); VectorCopy(texS, delta); VectorAdd(delta, texT, delta); Face_MoveTexture_BrushPrimit(f, delta); #else if (autoAdjust) { x /= f->d_texture->GetEditorImage()->uploadWidth; y /= f->d_texture->GetEditorImage()->uploadHeight; } f->brushprimit_texdef.coords[0][2] += x; f->brushprimit_texdef.coords[1][2] += y; EmitBrushPrimitTextureCoordinates(f, f->face_winding); #endif }
void Face_FlipTexture_BrushPrimit(face_t *f, bool y) { float s, t, rot; Face_GetScale_BrushPrimit(f, &s, &t, &rot); if (y) { Face_SetExplicitScale_BrushPrimit(f, 0.0, -t); } else { Face_SetExplicitScale_BrushPrimit(f, -s, 0.0); } #if 0 idVec3D texS, texT; ComputeAxisBase(f->plane.normal, texS, texT); double Os = 0, Ot = 0; for (int i = 0; i < f->face_winding->numpoints; i++) { Os += DotProduct(f->face_winding->p[i], texS); Ot += DotProduct(f->face_winding->p[i], texT); } Ot = abs(Ot); Ot *= t; Ot /= f->d_texture->GetEditorImage()->uploadHeight; Os = abs(Os); Os *= s; Os /= f->d_texture->GetEditorImage()->uploadWidth; if (y) { Face_FitTexture_BrushPrimit(f, texS, texT, -Ot, 1.0); } else { Face_FitTexture_BrushPrimit(f, texS, texT, 1.0, -Os); } EmitBrushPrimitTextureCoordinates(f, f->face_winding); #endif }
// // ======================================================================================================================= // ++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) can be improved .. bug #107311 // mins and maxs are the face bounding box ++timo fixme: we use the face info, mins and maxs are irrelevant // ======================================================================================================================= // void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float height, float width) { idVec3D BBoxSTMin, BBoxSTMax; idWinding *w; int i, j; double val; idVec3D M[3], D[2]; // idVec3D N[2],Mf[2]; brushprimit_texdef_t N; idVec3D Mf[2]; //memset(f->brushprimit_texdef.coords, 0, sizeof(f->brushprimit_texdef.coords)); //f->brushprimit_texdef.coords[0][0] = 1.0f; //f->brushprimit_texdef.coords[1][1] = 1.0f; //ConvertTexMatWithQTexture(&f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture); // // we'll be working on a standardized texture size ConvertTexMatWithQTexture( // &f->brushprimit_texdef, f->d_texture, &f->brushprimit_texdef, NULL ); compute // the BBox in ST coords // EmitBrushPrimitTextureCoordinates(f, f->face_winding); BBoxSTMin[0] = BBoxSTMin[1] = BBoxSTMin[2] = 999999; BBoxSTMax[0] = BBoxSTMax[1] = BBoxSTMax[2] = -999999; w = f->face_winding; if (w) { for (i = 0; i < w->GetNumPoints(); i++) { // AddPointToBounds in 2D on (S,T) coordinates for (j = 0; j < 2; j++) { val = (*w)[i][j + 3]; if (val < BBoxSTMin[j]) { BBoxSTMin[j] = val; } 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 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] = width; D[0][2] = 0.0f; D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = height; MatrixForPoints(M, D, &N); #if 0 // // 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) // N[0][0] = (BBoxSTMax[0] - BBoxSTMin[0]) / width; N[0][1] = 0.0f; N[0][2] = BBoxSTMin[0]; N[1][0] = 0.0f; N[1][1] = (BBoxSTMax[1] - BBoxSTMin[1]) / height; N[1][2] = 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][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][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 VectorCopy(Mf[0], f->brushprimit_texdef.coords[0]); VectorCopy(Mf[1], f->brushprimit_texdef.coords[1]); // // handle the texture size ConvertTexMatWithQTexture( &f->brushprimit_texdef, // NULL, &f->brushprimit_texdef, f->d_texture ); // }
/* ======================================================================================================================= ======================================================================================================================= */ void Face_SetExplicitScale_BrushPrimit(face_t *face, float s, float t) { idVec3D texS, texT; ComputeAxisBase(face->plane.Normal(), texS, texT); // find ST coordinates for the center of the face double Os = 0, Ot = 0; for (int i = 0; i < face->face_winding->GetNumPoints(); i++) { Os += DotProduct((*face->face_winding)[i], texS); Ot += DotProduct((*face->face_winding)[i], texT); } Os /= face->face_winding->GetNumPoints(); Ot /= face->face_winding->GetNumPoints(); brushprimit_texdef_t *pBP = &face->brushprimit_texdef; // here we have a special case, M is a translation and it's inverse is easy float BPO[2][3]; float aux[2][3]; float m[2][3]; memset(&m, 0, sizeof (float) *6); m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; BPMatMul(m, pBP->coords, aux); m[0][2] = Os; m[1][2] = Ot; // now M^-1 BPMatMul(aux, m, BPO); // apply a given scale (on S and T) ConvertTexMatWithQTexture(BPO, face->d_texture, aux, NULL); // reset the scale (normalize the matrix) double v1, v2; v1 = idMath::Sqrt(aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0]); v2 = idMath::Sqrt(aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1]); if (s == 0.0) { s = v1; } if (t == 0.0) { t = v2; } double sS, sT; // put the values for scale on S and T here: sS = s / v1; sT = t / v2; aux[0][0] *= sS; aux[1][0] *= sS; aux[0][1] *= sT; aux[1][1] *= sT; ConvertTexMatWithQTexture(aux, NULL, BPO, face->d_texture); BPMatMul(m, BPO, aux); // m is M^-1 m[0][2] = -Os; m[1][2] = -Ot; BPMatMul(aux, m, pBP->coords); // now emit the coordinates on the winding EmitBrushPrimitTextureCoordinates(face, face->face_winding); }
// experimental stuff, work directly on BP static void OnTest( GtkWidget *widget, gpointer data ){ if ( !g_qeglobals.m_bBrushPrimitMode ) { Sys_FPrintf( SYS_WRN, "BP mode required\n" ); return; } if ( g_ptrSelectedFaces.GetSize() != 1 ) { Sys_FPrintf( SYS_WRN, "Expected single face selection\n" ); return; } brush_t *b = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( 0 ) ); face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( 0 ) ); // get the ST axis base for the face vec3_t texS,texT; ComputeAxisBase( selFace->plane.normal, texS, texT ); // find ST coordinates for the center of the face float Os = 0,Ot = 0; int i; for ( i = 0; i < selFace->face_winding->numpoints; i++ ) { Os += DotProduct( selFace->face_winding->points[i],texS ); Ot += DotProduct( selFace->face_winding->points[i],texT ); } Os /= selFace->face_winding->numpoints; Ot /= selFace->face_winding->numpoints; brushprimit_texdef_t *pBP = &selFace->brushprimit_texdef; // (FIXME: initial version, before axis base change optimize) // we need to compute our BP matrix in this new axis base (O,texS,texT) // the general case if BPO = M * BP * M^-1 // where BPO is transformation expressed in (O,texS,texT) // M is the axis base change from (origin,texS,texT) to (O,texS,texT) // here we have a special case, M is a translation and it's inverse is easy vec_t BPO[2][3]; vec_t aux[2][3]; vec_t m[2][3]; memset( &m, 0, sizeof( vec_t ) * 6 ); m[0][0] = 1; m[1][1] = 1; m[0][2] = -Os; m[1][2] = -Ot; BPMatMul( m, pBP->coords, aux ); m[0][2] = Os; m[1][2] = Ot; // now M^-1 BPMatMul( aux, m, BPO ); #if 0 // apply a scaling // scale factors against S and T axis, we apply on top of the existing matrix // <1 will decrease the texel/world resolution, >1 will increase float sS = 1.025,sT = 1.025; BPMatScale( BPO,sS,sT ); #endif #if 0 // apply a rotation float theta = 5; BPMatRotate( BPO,theta ); #endif #if 0 // read the scale ConvertTexMatWithQTexture( BPO, selFace->d_texture, aux, NULL ); // reset the scale (normalize the matrix) vec_t v1,v2; v1 = sqrt( aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0] ); v2 = sqrt( aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1] ); // if reading the scale values, we have them here: Sys_Printf( "Current Scale: S: %g T: %g\n", v1, v2 ); return; #endif #if 1 // apply a given scale (on S and T) ConvertTexMatWithQTexture( BPO, selFace->d_texture, aux, NULL ); // reset the scale (normalize the matrix) vec_t v1,v2; v1 = sqrt( aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0] ); v2 = sqrt( aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1] ); vec_t sS,sT; // put the values for scale on S and T here: sS = 1.2 / v1; sT = 0.8 / v2; aux[0][0] *= sS; aux[1][0] *= sS; aux[0][1] *= sT; aux[1][1] *= sT; ConvertTexMatWithQTexture( aux, NULL, BPO, selFace->d_texture ); #endif // now BPO must be expressed back in (origin,texS,texT) axis base BP = M^-1 * BPO * M BPMatMul( m, BPO, aux ); // m is M^-1 m[0][2] = -Os; m[1][2] = -Ot; BPMatMul( aux, m, pBP->coords ); // now emit the coordinates on the winding EmitBrushPrimitTextureCoordinates( selFace, selFace->face_winding ); Sys_UpdateWindows( W_CAMERA ); }