From 0819a13b05a9bcdd0ba2f5062be6d1a1a55a4cfc Mon Sep 17 00:00:00 2001 From: spog Date: Sat, 25 Mar 2006 19:50:29 +0000 Subject: [PATCH] fixed texture-fitting with rotated texture transforms git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@39 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- CHANGES | 1 + radiant/brush_primit.cpp | 220 ++++++++------------------------------- 2 files changed, 44 insertions(+), 177 deletions(-) diff --git a/CHANGES b/CHANGES index b7ce75a2..823233ea 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ SPoG - Fixed crash when resetting preferences after startup failure. - Fixed crash on next-leak-spot with build-monitoring enabled. - Fixed doom3/quake4 blended-decal rendering when toggling lighting mode. +- Fixed fit-texture with rotated texture transforms. 20/03/2006 SPoG diff --git a/radiant/brush_primit.cpp b/radiant/brush_primit.cpp index 87173284..b8cc5d38 100644 --- a/radiant/brush_primit.cpp +++ b/radiant/brush_primit.cpp @@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "texturelib.h" #include "math/matrix.h" #include "math/plane.h" +#include "math/aabb.h" #include "winding.h" #include "preferences.h" @@ -407,107 +408,16 @@ void AddPointToBounds(const Vector3& v, Vector3& mins, Vector3& maxs) } } -void Texdef_FitTexture(texdef_t& td, std::size_t width, std::size_t height, const Vector3& normal, const Winding& w, float s_repeat, float t_repeat) +template +inline BasicVector3 vector3_inverse(const BasicVector3& self) { - float temp; - float rot_width, rot_height; - float cosv,sinv; - float min_t, min_s, max_t, max_s; - float s,t; - Vector3 vecs[2]; - Vector3 coords[4]; - - Vector3 mins, maxs; - - if(s_repeat == 0) - s_repeat = 1; - if(t_repeat == 0) - t_repeat = 1; - - { - ClearBounds(mins, maxs); - for(Winding::const_iterator i = w.begin(); i != w.end(); ++i) - { - AddPointToBounds((*i).vertex, mins, maxs); - } - } - - // - // get the current angle - // - { - double ang = degrees_to_radians(td.rotate); - sinv = static_cast(sin(ang)); - cosv = static_cast(cos(ang)); - } - - // get natural texture axis - TextureAxisFromNormal(normal, vecs[0], vecs[1]); - - min_s = static_cast(vector3_dot(mins, vecs[0])); - min_t = static_cast(vector3_dot(mins, vecs[1])); - max_s = static_cast(vector3_dot(maxs, vecs[0])); - max_t = static_cast(vector3_dot(maxs, vecs[1])); - coords[0][0] = min_s; - coords[0][1] = min_t; - coords[1][0] = max_s; - coords[1][1] = min_t; - coords[2][0] = min_s; - coords[2][1] = max_t; - coords[3][0] = max_s; - coords[3][1] = max_t; - min_s = min_t = 99999; - max_s = max_t = -99999; - for (int i=0; i<4; i++) - { - s = cosv * coords[i][0] - sinv * coords[i][1]; - t = sinv * coords[i][0] + cosv * coords[i][1]; - if (i&1) - { - if (s > max_s) - { - max_s = s; - } - } - else - { - if (s < min_s) - { - min_s = s; - } - if (i<2) - { - if (t < min_t) - { - min_t = t; - } - } - else - { - if (t > max_t) - { - max_t = t; - } - } - } - } - rot_width = (max_s - min_s); - rot_height = (max_t - min_t); - td.scale[0] = -(rot_width/(static_cast(width) * s_repeat)); - td.scale[1] = -(rot_height/(static_cast(height) * t_repeat)); - - td.shift[0] = min_s/td.scale[0]; - temp = static_cast(float_to_integer(td.shift[0] / (static_cast(width) * s_repeat))); - temp = (temp+1)*static_cast(width) * s_repeat; - td.shift[0] = static_cast(float_to_integer(temp - td.shift[0]) % static_cast(static_cast(width) * s_repeat)); - - td.shift[1] = min_t/td.scale[1]; - temp = static_cast(float_to_integer(td.shift[1] / (static_cast(height) * t_repeat))); - temp = (temp+1)*(static_cast(height) * t_repeat); - td.shift[1] = static_cast(float_to_integer(temp - td.shift[1]) % static_cast(static_cast(height) * t_repeat)); + return BasicVector3( + Element(1.0 / self.x()), + Element(1.0 / self.y()), + Element(1.0 / self.z()) + ); } - // low level functions .. put in mathlib? #define BPMatCopy(a,b) {b[0][0] = a[0][0]; b[0][1] = a[0][1]; b[0][2] = a[0][2]; b[1][0] = a[1][0]; b[1][1] = a[1][1]; b[1][2] = a[1][2];} // apply a scale transformation to the BP matrix @@ -1192,81 +1102,6 @@ void BPTexdef_Construct(brushprimit_texdef_t& bp_td, std::size_t width, std::siz ConvertTexMatWithDimensions(bp_td.coords, 2, 2, bp_td.coords, width, height); } -//++timo FIXME quick'n dirty hack, doesn't care about current texture settings (angle) -// can be improved .. bug #107311 -void BPTexdef_FitTexture(brushprimit_texdef_t& bp_td, std::size_t width, std::size_t height, const Vector3& normal, const Winding& w, float s_repeat, float t_repeat) -{ - Vector3 BBoxSTMin, BBoxSTMax; - Vector3 M[3],D[2]; -// Vector3 N[2],Mf[2]; - brushprimit_texdef_t N; - Vector3 Mf[2]; - - //qtexture_t texture; - //texture.width = width; - //texture.height = height; - - - // we'll be working on a standardized texture size -// ConvertTexMatWithQTexture( &bp_td, &texture, &bp_td, 0 ); - // compute the BBox in ST coords - { - Winding tmp(w); - Texdef_EmitTextureCoordinates(TextureProjection(texdef_t(), bp_td, Vector3(0, 0, 0), Vector3(0, 0, 0)), width, height, tmp, normal, g_matrix4_identity); - - ClearBounds( BBoxSTMin, BBoxSTMax ); - for(Winding::const_iterator i = tmp.begin(); i != tmp.end(); ++i) - { - // AddPointToBounds in 2D on (S,T) coordinates - for(int j=0 ; j<2 ; j++) - { - float val = (*i).texcoord[j]; - 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,t_repeat) 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] = s_repeat; D[0][2] = 0.0f; - D[1][0] = 0.0f; D[1][1] = 0.0f; D[1][2] = t_repeat; - 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')=(s_repeat,0) C(S',T')=(0,t_repeat) - // 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])/s_repeat, 0.0f, BBoxSTMin[0] ); - VectorSet( N[1], 0.0f, (BBoxSTMax[1]-BBoxSTMin[1])/t_repeat, BBoxSTMin[1] ); -#endif - - // the final matrix is the product (Mf stands for Mfit) - Mf[0][0] = N.coords[0][0] * bp_td.coords[0][0] + N.coords[0][1] * bp_td.coords[1][0]; - Mf[0][1] = N.coords[0][0] * bp_td.coords[0][1] + N.coords[0][1] * bp_td.coords[1][1]; - Mf[0][2] = N.coords[0][0] * bp_td.coords[0][2] + N.coords[0][1] * bp_td.coords[1][2] + N.coords[0][2]; - Mf[1][0] = N.coords[1][0] * bp_td.coords[0][0] + N.coords[1][1] * bp_td.coords[1][0]; - Mf[1][1] = N.coords[1][0] * bp_td.coords[0][1] + N.coords[1][1] * bp_td.coords[1][1]; - Mf[1][2] = N.coords[1][0] * bp_td.coords[0][2] + N.coords[1][1] * bp_td.coords[1][2] + N.coords[1][2]; - // copy back - bp_td.coords[0][0] = Mf[0][0]; - bp_td.coords[0][1] = Mf[0][1]; - bp_td.coords[0][2] = Mf[0][2]; - bp_td.coords[1][0] = Mf[1][0]; - bp_td.coords[1][1] = Mf[1][1]; - bp_td.coords[1][2] = Mf[1][2]; - // handle the texture size -// ConvertTexMatWithQTexture( &bp_td, 0, &bp_td, &texture ); -} - - - void Texdef_Assign(TextureProjection& projection, const TextureProjection& other) { if (g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES) @@ -1322,14 +1157,45 @@ void Texdef_Rotate(TextureProjection& projection, float angle) void Texdef_FitTexture(TextureProjection& projection, std::size_t width, std::size_t height, const Vector3& normal, const Winding& w, float s_repeat, float t_repeat) { - if (g_bp_globals.m_texdefTypeId == TEXDEFTYPEID_BRUSHPRIMITIVES) + if(w.numpoints < 3) + { + return; + } + + Matrix4 st2tex; + Texdef_toTransform(projection, (float)width, (float)height, st2tex); + + // the current texture transform + Matrix4 local2tex = st2tex; { - BPTexdef_FitTexture(projection.m_brushprimit_texdef, width, height, normal, w, s_repeat, t_repeat); + Matrix4 xyz2st; + Texdef_basisForNormal(projection, normal, xyz2st); + matrix4_multiply_by_matrix4(local2tex, xyz2st); } - else + + // the bounds of the current texture transform + AABB bounds; + for(Winding::const_iterator i = w.begin(); i != w.end(); ++i) { - Texdef_FitTexture(projection.m_texdef, width, height, normal, w, s_repeat, t_repeat); + Vector3 texcoord = matrix4_transformed_point(local2tex, (*i).vertex); + aabb_extend_by_point_safe(bounds, texcoord); } + bounds.origin.z() = 0; + bounds.extents.z() = 1; + + // the bounds of a perfectly fitted texture transform + AABB perfect(Vector3(s_repeat * 0.5, t_repeat * 0.5, 0), Vector3(s_repeat * 0.5, t_repeat * 0.5, 1)); + + // the difference between the current texture transform and the perfectly fitted transform + Matrix4 matrix(matrix4_translation_for_vec3(bounds.origin - perfect.origin)); + matrix4_pivoted_scale_by_vec3(matrix, bounds.extents / perfect.extents, perfect.origin); + matrix4_affine_invert(matrix); + + // apply the difference to the current texture transform + matrix4_premultiply_by_matrix4(st2tex, matrix); + + Texdef_fromTransform(projection, (float)width, (float)height, st2tex); + Texdef_normalise(projection, (float)width, (float)height); } float Texdef_getDefaultTextureScale() -- 2.39.2