/* ======================================================================================================================= ======================================================================================================================= */ void FaceToBrushPrimitFace(face_t *f) { idVec3D texX, texY; idVec3D proj; // ST of (0,0) (1,0) (0,1) idVec5 ST[3]; // [ point index ] [ xyz ST ] // // ++timo not used as long as brushprimit_texdef and texdef are static // f->brushprimit_texdef.contents=f->texdef.contents; // f->brushprimit_texdef.flags=f->texdef.flags; // f->brushprimit_texdef.value=f->texdef.value; // strcpy(f->brushprimit_texdef.name,f->texdef.name); // #ifdef _DEBUG if (f->plane[0] == 0.0f && f->plane[1] == 0.0f && f->plane[2] == 0.0f) { common->Printf("Warning : f->plane.normal is (0,0,0) in FaceToBrushPrimitFace\n"); } // check d_texture if (!f->d_texture) { common->Printf("Warning : f.d_texture is NULL in FaceToBrushPrimitFace\n"); return; } #endif // compute axis base ComputeAxisBase(f->plane.Normal(), texX, texY); // compute projection vector VectorCopy( f->plane, proj ); VectorScale(proj, -f->plane[3], proj); // // (0,0) in plane axis base is (0,0,0) in world coordinates + projection on the // affine plane (1,0) in plane axis base is texX in world coordinates + projection // on the affine plane (0,1) in plane axis base is texY in world coordinates + // projection on the affine plane use old texture code to compute the ST coords of // these points // VectorCopy(proj, ST[0]); EmitTextureCoordinates(ST[0], f->d_texture, f); VectorCopy(texX, ST[1]); VectorAdd(ST[1], proj, ST[1]); EmitTextureCoordinates(ST[1], f->d_texture, f); VectorCopy(texY, ST[2]); VectorAdd(ST[2], proj, ST[2]); EmitTextureCoordinates(ST[2], f->d_texture, f); // compute texture matrix f->brushprimit_texdef.coords[0][2] = ST[0][3]; f->brushprimit_texdef.coords[1][2] = ST[0][4]; f->brushprimit_texdef.coords[0][0] = ST[1][3] - f->brushprimit_texdef.coords[0][2]; f->brushprimit_texdef.coords[1][0] = ST[1][4] - f->brushprimit_texdef.coords[1][2]; f->brushprimit_texdef.coords[0][1] = ST[2][3] - f->brushprimit_texdef.coords[0][2]; f->brushprimit_texdef.coords[1][1] = ST[2][4] - f->brushprimit_texdef.coords[1][2]; }
void Face_GetScale_BrushPrimit(face_t *face, float *s, float *t, float *rot) { idVec3D texS, texT; ComputeAxisBase(face->plane.Normal(), texS, texT); if (face == NULL || face->face_winding == NULL) { return; } // 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); *s = idMath::Sqrt(aux[0][0] * aux[0][0] + aux[1][0] * aux[1][0]); *t = idMath::Sqrt(aux[0][1] * aux[0][1] + aux[1][1] * aux[1][1]); // compute rotate value if (idMath::Fabs(face->brushprimit_texdef.coords[0][0]) < ZERO_EPSILON) { // rotate is +-90 if (face->brushprimit_texdef.coords[1][0] > 0) { *rot = 90.0f; } else { *rot = -90.0f; } } else { *rot = RAD2DEG(atan2(face->brushprimit_texdef.coords[1][0] / (*s) ? (*s) : 1.0f, face->brushprimit_texdef.coords[0][0] / (*t) ? (*t) : 1.0f)); } }
/* ================= idMapBrushSide::GetTextureVectors ================= */ void idMapBrushSide::GetTextureVectors( idVec4 v[2] ) const { int i; idVec3 texX, texY; ComputeAxisBase( plane.Normal(), texX, texY ); for ( i = 0; i < 2; i++ ) { v[i][0] = texX[0] * texMat[i][0] + texY[0] * texMat[i][1]; v[i][1] = texX[1] * texMat[i][0] + texY[1] * texMat[i][1]; v[i][2] = texX[2] * texMat[i][0] + texY[2] * texMat[i][1]; v[i][3] = texMat[i][2] + ( origin * v[i].ToVec3() ); } }
// // ======================================================================================================================= // compute texture coordinates for the winding points // ======================================================================================================================= // void EmitBrushPrimitTextureCoordinates(face_t *f, idWinding *w, patchMesh_t *patch) { idVec3D texX, texY; double x, y; if (f== NULL || (w == NULL && patch == NULL)) { return; } // compute axis base ComputeAxisBase(f->plane.Normal(), texX, texY); // // in case the texcoords matrix is empty, build a default one same behaviour as if // scale[0]==0 && scale[1]==0 in old code // if ( f->brushprimit_texdef.coords[0][0] == 0 && f->brushprimit_texdef.coords[1][0] == 0 && f->brushprimit_texdef.coords[0][1] == 0 && f->brushprimit_texdef.coords[1][1] == 0 ) { 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); } int i; if (w) { for (i = 0; i < w->GetNumPoints(); i++) { x = DotProduct((*w)[i], texX); y = DotProduct((*w)[i], texY); (*w)[i][3] = f->brushprimit_texdef.coords[0][0] * x + f->brushprimit_texdef.coords[0][1] * y + f->brushprimit_texdef.coords[0][2]; (*w)[i][4] = f->brushprimit_texdef.coords[1][0] * x + f->brushprimit_texdef.coords[1][1] * y + f->brushprimit_texdef.coords[1][2]; } } if (patch) { int j; for ( i = 0; i < patch->width; i++ ) { for ( j = 0; j < patch->height; j++ ) { x = DotProduct(patch->ctrl(i, j).xyz, texX); y = DotProduct(patch->ctrl(i, j).xyz, texY); 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]; 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]; } } } }
// // ======================================================================================================================= // 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 }
// // ======================================================================================================================= // texture locking // ======================================================================================================================= // void Face_MoveTexture_BrushPrimit(face_t *f, idVec3 delta) { idVec3D texS, texT; double tx, ty; idVec3D M[3]; // columns of the matrix .. easier that way double det; idVec3D D[2]; // compute plane axis base ( doesn't change with translation ) ComputeAxisBase(f->plane.Normal(), texS, texT); // compute translation vector in plane axis base tx = DotProduct(delta, texS); ty = DotProduct(delta, texT); // fill the data vectors M[0][0] = tx; M[0][1] = 1.0f + tx; M[0][2] = tx; M[1][0] = ty; M[1][1] = ty; M[1][2] = 1.0f + ty; M[2][0] = 1.0f; M[2][1] = 1.0f; M[2][2] = 1.0f; D[0][0] = f->brushprimit_texdef.coords[0][2]; D[0][1] = f->brushprimit_texdef.coords[0][0] + f->brushprimit_texdef.coords[0][2]; D[0][2] = f->brushprimit_texdef.coords[0][1] + f->brushprimit_texdef.coords[0][2]; D[1][0] = f->brushprimit_texdef.coords[1][2]; D[1][1] = f->brushprimit_texdef.coords[1][0] + f->brushprimit_texdef.coords[1][2]; D[1][2] = f->brushprimit_texdef.coords[1][1] + f->brushprimit_texdef.coords[1][2]; // solve det = SarrusDet(M[0], M[1], M[2]); f->brushprimit_texdef.coords[0][0] = SarrusDet(D[0], M[1], M[2]) / det; f->brushprimit_texdef.coords[0][1] = SarrusDet(M[0], D[0], M[2]) / det; f->brushprimit_texdef.coords[0][2] = SarrusDet(M[0], M[1], D[0]) / det; f->brushprimit_texdef.coords[1][0] = SarrusDet(D[1], M[1], M[2]) / det; f->brushprimit_texdef.coords[1][1] = SarrusDet(M[0], D[1], M[2]) / det; f->brushprimit_texdef.coords[1][2] = SarrusDet(M[0], M[1], D[1]) / det; }
// Timo // brush primitive texture shifting, using camera view to select translations : void CCamWnd::ShiftTexture_BrushPrimit(face_t *f, int x, int y) { vec3_t texS,texT; vec3_t viewX,viewY; int XS,XT,YS,YT; int outS,outT; #ifdef _DEBUG if (!g_qeglobals.m_bBrushPrimitMode) { Sys_Printf("Warning : unexpected call to CCamWnd::ShiftTexture_BrushPrimit with brush primitive mode disbaled\n"); return; } #endif // compute face axis base ComputeAxisBase( f->plane.normal, texS, texT ); // compute camera view vectors VectorCopy( m_Camera.vup, viewY ); VectorCopy( m_Camera.vright, viewX ); // compute best vectors ComputeBest2DVector( viewX, texS, texT, XS, XT ); ComputeBest2DVector( viewY, texS, texT, YS, YT ); // check this is not a degenerate case if ( ( XS == YS ) && ( XT == YT ) ) { #ifdef _DEBUG Sys_Printf("Warning : degenerate best vectors axis base in CCamWnd::ShiftTexture_BrushPrimit\n"); #endif // forget it Select_ShiftTexture_BrushPrimit( f, x, y ); return; } // compute best fitted translation in face axis base outS = XS*x + YS*y; outT = XT*x + YT*y; // call actual texture shifting code Select_ShiftTexture_BrushPrimit( f, outS, outT ); }
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 }
/* ==================== ChopFaceByBrush There may be a fragment contained in the brush ==================== */ qboolean ChopFaceByBrush(drawSurface_t * ds, bspBrush_t * b) { int i, j; side_t *s; plane_t *plane; winding_t *w; winding_t *front, *back; winding_t *outside[MAX_BRUSH_SIDES]; int numOutside; drawSurface_t *newds; drawVert_t *dv; shaderInfo_t *si; float mins[2]; // brush primitive : // axis base vec3_t texX, texY; vec_t x, y; w = WindingFromDrawSurf(ds); numOutside = 0; for(i = 0; i < b->numsides; i++) { s = &b->sides[i]; if(s->backSide) { continue; } plane = &mapPlanes[s->planenum]; // handle coplanar outfacing (don't fog) if(ds->side->planenum == s->planenum) { return qfalse; } // handle coplanar infacing (keep inside) if((ds->side->planenum ^ 1) == s->planenum) { continue; } // general case ClipWindingEpsilon(w, plane->normal, plane->dist, ON_EPSILON, &front, &back); FreeWinding(w); if(!back) { // nothing actually contained inside for(j = 0; j < numOutside; j++) { FreeWinding(outside[j]); } return qfalse; } if(front) { if(numOutside == MAX_BRUSH_SIDES) { Error("MAX_BRUSH_SIDES"); } outside[numOutside] = front; numOutside++; } w = back; } // all of outside fragments become seperate drawsurfs // linked to the same side c_fogFragment += numOutside; s = ds->side; for(i = 0; i < numOutside; i++) { newds = DrawSurfaceForSide(ds->mapBrush, s, outside[i]); FreeWinding(outside[i]); } // replace ds->verts with the verts for w ds->numVerts = w->numpoints; free(ds->verts); ds->verts = malloc(ds->numVerts * sizeof(*ds->verts)); memset(ds->verts, 0, ds->numVerts * sizeof(*ds->verts)); si = s->shaderInfo; mins[0] = 9999; mins[1] = 9999; // compute s/t coordinates from brush primitive texture matrix // compute axis base ComputeAxisBase(mapPlanes[s->planenum].normal, texX, texY); for(j = 0; j < w->numpoints; j++) { dv = ds->verts + j; VectorCopy(w->p[j], dv->xyz); if(g_bBrushPrimit == BPRIMIT_OLDBRUSHES) { // calculate texture s/t dv->st[0] = s->vecs[0][3] + DotProduct(s->vecs[0], dv->xyz); dv->st[1] = s->vecs[1][3] + DotProduct(s->vecs[1], dv->xyz); dv->st[0] /= si->width; dv->st[1] /= si->height; } else { // calculate texture s/t from brush primitive texture matrix x = DotProduct(dv->xyz, texX); y = DotProduct(dv->xyz, texY); dv->st[0] = s->texMat[0][0] * x + s->texMat[0][1] * y + s->texMat[0][2]; dv->st[1] = s->texMat[1][0] * x + s->texMat[1][1] * y + s->texMat[1][2]; } if(dv->st[0] < mins[0]) { mins[0] = dv->st[0]; } if(dv->st[1] < mins[1]) { mins[1] = dv->st[1]; } // copy normal VectorCopy(mapPlanes[s->planenum].normal, dv->normal); } // adjust the texture coordinates to be as close to 0 as possible if(!si->globalTexture) { mins[0] = floor(mins[0]); mins[1] = floor(mins[1]); for(i = 0; i < w->numpoints; i++) { dv = ds->verts + i; dv->st[0] -= mins[0]; dv->st[1] -= mins[1]; } } return qtrue; }
/* ======================================================================================================================= ======================================================================================================================= */ void TextureLockTransformation_BrushPrimit(face_t *f) { idVec3D Orig, texS, texT; // axis base of initial plane // used by transformation algo idVec3D temp; int j; //idVec3D vRotate; // rotation vector idVec3D rOrig, rvecS, rvecT; // geometric transformation of (0,0) (1,0) (0,1) { initial plane axis base } idVec3 rNormal; idVec3D rtexS, rtexT; // axis base for the transformed plane idVec3D lOrig, lvecS, lvecT; // [2] are not used ( but usefull for debugging ) idVec3D M[3]; double det; idVec3D D[2]; // silence compiler warnings rOrig.Zero(); rvecS = rOrig; rvecT = rOrig; rNormal.x = rOrig.x; rNormal.y = rOrig.y; rNormal.z = rOrig.z; // compute plane axis base ComputeAxisBase(f->plane.Normal(), texS, texT); Orig.x = vec3_origin.x; Orig.y = vec3_origin.y; Orig.z = vec3_origin.z; // // 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 vRotate.x = vec3_origin.x; vRotate.y = vec3_origin.y; vRotate.z = vec3_origin.z; vRotate[txl_nAxis] = txl_fDeg; VectorRotate3Origin(Orig, vRotate, txl_vOrigin, rOrig); VectorRotate3Origin(texS, vRotate, txl_vOrigin, rvecS); VectorRotate3Origin(texT, vRotate, txl_vOrigin, rvecT); // compute normal of plane after rotation VectorRotate3(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, txl_matrix[j]); } } // compute rotated plane axis base ComputeAxisBase(rNormal, rtexS, rtexT); // compute S/T coordinates of the three points in rotated axis base ( in M matrix ) lOrig[0] = DotProduct(rOrig, rtexS); lOrig[1] = DotProduct(rOrig, rtexT); lvecS[0] = DotProduct(rvecS, rtexS); lvecS[1] = DotProduct(rvecS, rtexT); lvecT[0] = DotProduct(rvecT, rtexS); lvecT[1] = DotProduct(rvecT, rtexT); M[0][0] = lOrig[0]; M[1][0] = lOrig[1]; M[2][0] = 1.0f; M[0][1] = lvecS[0]; M[1][1] = lvecS[1]; M[2][1] = 1.0f; M[0][2] = lvecT[0]; M[1][2] = lvecT[1]; M[2][2] = 1.0f; // fill data vector D[0][0] = f->brushprimit_texdef.coords[0][2]; D[0][1] = f->brushprimit_texdef.coords[0][0] + f->brushprimit_texdef.coords[0][2]; D[0][2] = f->brushprimit_texdef.coords[0][1] + f->brushprimit_texdef.coords[0][2]; D[1][0] = f->brushprimit_texdef.coords[1][2]; D[1][1] = f->brushprimit_texdef.coords[1][0] + f->brushprimit_texdef.coords[1][2]; D[1][2] = f->brushprimit_texdef.coords[1][1] + f->brushprimit_texdef.coords[1][2]; // solve det = SarrusDet(M[0], M[1], M[2]); f->brushprimit_texdef.coords[0][0] = SarrusDet(D[0], M[1], M[2]) / det; f->brushprimit_texdef.coords[0][1] = SarrusDet(M[0], D[0], M[2]) / det; f->brushprimit_texdef.coords[0][2] = SarrusDet(M[0], M[1], D[0]) / det; f->brushprimit_texdef.coords[1][0] = SarrusDet(D[1], M[1], M[2]) / det; f->brushprimit_texdef.coords[1][1] = SarrusDet(M[0], D[1], M[2]) / det; f->brushprimit_texdef.coords[1][2] = SarrusDet(M[0], M[1], D[1]) / det; }
/* ======================================================================================================================= ======================================================================================================================= */ 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); }
static void ConvertBrush(FILE * f, int num, bspBrush_t * brush, vec3_t origin) { int i, j; bspBrushSide_t *side; side_t *buildSide; bspShader_t *shader; char *texture; bspPlane_t *plane; plane_t *buildPlane; vec3_t pts[3]; bspDrawVert_t *vert[3]; int valid; /* start brush */ fprintf(f, "\t// brush %d\n", num); fprintf(f, "\t{\n"); fprintf(f, "\tbrushDef\n"); fprintf(f, "\t{\n"); /* clear out build brush */ for(i = 0; i < buildBrush->numsides; i++) { buildSide = &buildBrush->sides[i]; if(buildSide->winding != NULL) { FreeWinding(buildSide->winding); buildSide->winding = NULL; } } buildBrush->numsides = 0; /* iterate through bsp brush sides */ for(i = 0; i < brush->numSides; i++) { /* get side */ side = &bspBrushSides[brush->firstSide + i]; /* get shader */ if(side->shaderNum < 0 || side->shaderNum >= numBSPShaders) continue; shader = &bspShaders[side->shaderNum]; if(!Q_stricmp(shader->shader, "default") || !Q_stricmp(shader->shader, "noshader")) continue; /* get plane */ plane = &bspPlanes[side->planeNum]; /* add build side */ buildSide = &buildBrush->sides[buildBrush->numsides]; buildBrush->numsides++; /* tag it */ buildSide->shaderInfo = ShaderInfoForShader(shader->shader); buildSide->planenum = side->planeNum; buildSide->winding = NULL; } /* make brush windings */ if(!CreateBrushWindings(buildBrush)) return; /* iterate through build brush sides */ for(i = 0; i < buildBrush->numsides; i++) { /* get build side */ buildSide = &buildBrush->sides[i]; /* get plane */ buildPlane = &mapplanes[buildSide->planenum]; /* dummy check */ if(buildSide->shaderInfo == NULL || buildSide->winding == NULL) continue; // st-texcoords -> texMat block // start out with dummy VectorSet(buildSide->texMat[0], 1 / 32.0, 0, 0); VectorSet(buildSide->texMat[1], 0, 1 / 32.0, 0); // find surface for this side (by brute force) // surface format: // - meshverts point in pairs of three into verts // - (triangles) // - find the triangle that has most in common with our side GetBestSurfaceTriangleMatchForBrushside(buildSide, vert); valid = 0; if(vert[0] && vert[1] && vert[2]) { int i; vec3_t texX, texY; vec3_t xy1I, xy1J, xy1K; vec2_t stI, stJ, stK; vec_t D, D0, D1, D2; ComputeAxisBase(buildPlane->normal, texX, texY); VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1); VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1); VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1); stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1]; stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1]; stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1]; // - solve linear equations: // - (x, y) := xyz . (texX, texY) // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2] // (for three vertices) D = Det3x3(xy1I[0], xy1I[1], 1, xy1J[0], xy1J[1], 1, xy1K[0], xy1K[1], 1); if(D != 0) { for(i = 0; i < 2; ++i) { D0 = Det3x3(stI[i], xy1I[1], 1, stJ[i], xy1J[1], 1, stK[i], xy1K[1], 1); D1 = Det3x3(xy1I[0], stI[i], 1, xy1J[0], stJ[i], 1, xy1K[0], stK[i], 1); D2 = Det3x3(xy1I[0], xy1I[1], stI[i], xy1J[0], xy1J[1], stJ[i], xy1K[0], xy1K[1], stK[i]); VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D); valid = 1; } } else fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n", buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], texX[0], texX[1], texX[2], texY[0], texY[1], texY[2], vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1], vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1], vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]); } else if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16)) fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader); /* get texture name */ if(!Q_strncasecmp(buildSide->shaderInfo->shader, "textures/", 9)) texture = buildSide->shaderInfo->shader + 9; else texture = buildSide->shaderInfo->shader; /* get plane points and offset by origin */ for(j = 0; j < 3; j++) { VectorAdd(buildSide->winding->p[j], origin, pts[j]); //% pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f ); //% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f ); //% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f ); } /* print brush side */ /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ fprintf(f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n", pts[0][0], pts[0][1], pts[0][2], pts[1][0], pts[1][1], pts[1][2], pts[2][0], pts[2][1], pts[2][2], buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2], buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2], texture, // DEBUG: valid ? 0 : C_DETAIL 0); // TODO write brush primitives format here } /* end brush */ fprintf(f, "\t}\n"); fprintf(f, "\t}\n\n"); }
// 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 ); }