1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #ifndef INCLUDED_TEXTURELIB_H
23 #define INCLUDED_TEXTURELIB_H
24
25 #include "debugging/debugging.h"
26 #include "math/Vector3.h"
27 #include "math/matrix.h"
28 #include "math/Plane3.h"
29
30 typedef Vector3 Colour3;
31 typedef unsigned int GLuint;
32 class LoadImageCallback;
33 class Image;
34
35 enum ProjectionAxis
36 {
37 eProjectionAxisX = 0, eProjectionAxisY = 1, eProjectionAxisZ = 2
38 };
39
40 // describes a GL texture
41 class GLTexture
42 {
43 private:
44
45 /**
46 * @brief This function does the actual processing of raw RGBA data into a GL texture.
47 * @note It will also resample to power-of-two dimensions, generate the mipmaps and adjust gamma.
48 */
49 void LoadTextureRGBA (Image& image);
50
51 const std::string name;
52
53 public:
54 GLTexture (const LoadImageCallback& load, const std::string& name);
55
56 void realise ();
57 void unrealise ();
58
59 const std::string& getName () const;
60
61 const LoadImageCallback& load;
62 std::size_t width, height;
63 GLuint texture_number; // gl bind number
64 Colour3 color; // for flat shade mode
65 int surfaceFlags, contentFlags, value;
66 bool hasAlpha;
67 };
68
matrix4_rotation_for_vector3(const Vector3 & x,const Vector3 & y,const Vector3 & z)69 inline Matrix4 matrix4_rotation_for_vector3 (const Vector3& x, const Vector3& y, const Vector3& z)
70 {
71 return Matrix4(x.x(), x.y(), x.z(), 0, y.x(), y.y(), y.z(), 0, z.x(), z.y(), z.z(), 0, 0, 0, 0, 1);
72 }
73
matrix4_swap_axes(const Vector3 & from,const Vector3 & to)74 inline Matrix4 matrix4_swap_axes (const Vector3& from, const Vector3& to)
75 {
76 if (from.x() != 0 && to.y() != 0) {
77 return matrix4_rotation_for_vector3(to, from, g_vector3_axis_z);
78 }
79
80 if (from.x() != 0 && to.z() != 0) {
81 return matrix4_rotation_for_vector3(to, g_vector3_axis_y, from);
82 }
83
84 if (from.y() != 0 && to.z() != 0) {
85 return matrix4_rotation_for_vector3(g_vector3_axis_x, to, from);
86 }
87
88 if (from.y() != 0 && to.x() != 0) {
89 return matrix4_rotation_for_vector3(from, to, g_vector3_axis_z);
90 }
91
92 if (from.z() != 0 && to.x() != 0) {
93 return matrix4_rotation_for_vector3(from, g_vector3_axis_y, to);
94 }
95
96 if (from.z() != 0 && to.y() != 0) {
97 return matrix4_rotation_for_vector3(g_vector3_axis_x, from, to);
98 }
99
100 ERROR_MESSAGE("unhandled axis swap case");
101
102 return Matrix4::getIdentity();
103 }
104
matrix4_reflection_for_plane(const Plane3 & plane)105 inline Matrix4 matrix4_reflection_for_plane (const Plane3& plane)
106 {
107 return Matrix4::byColumns(1 - (2 * plane.normal().x() * plane.normal().x()), -2 * plane.normal().x()
108 * plane.normal().y(), -2 * plane.normal().x() * plane.normal().z(), 0, -2 * plane.normal().y()
109 * plane.normal().x(), 1 - (2 * plane.normal().y() * plane.normal().y()), -2 * plane.normal().y()
110 * plane.normal().z(), 0, -2 * plane.normal().z() * plane.normal().x(), -2 * plane.normal().z()
111 * plane.normal().y(), 1 - (2 * plane.normal().z() * plane.normal().z()), 0, -2 * plane.dist()
112 * plane.normal().x(), -2 * plane.dist() * plane.normal().y(), -2 * plane.dist() * plane.normal().z(), 1);
113 }
114
matrix4_reflection_for_plane45(const Plane3 & plane,const Vector3 & from,const Vector3 & to)115 inline Matrix4 matrix4_reflection_for_plane45 (const Plane3& plane, const Vector3& from, const Vector3& to)
116 {
117 Vector3 first = from;
118 Vector3 second = to;
119
120 if ((from.dot(plane.normal()) > 0) == (to.dot(plane.normal()) > 0)) {
121 first = -first;
122 second = -second;
123 }
124
125 Matrix4 swap = matrix4_swap_axes(first, second);
126
127 //Matrix4 tmp = matrix4_reflection_for_plane(plane);
128
129 swap.tx() = -(-2 * plane.normal().x() * plane.dist());
130 swap.ty() = -(-2 * plane.normal().y() * plane.dist());
131 swap.tz() = -(-2 * plane.normal().z() * plane.dist());
132
133 return swap;
134 }
135
136 const float ProjectionAxisEpsilon = static_cast<float> (0.0001);
137
projectionaxis_better(float axis,float other)138 inline bool projectionaxis_better (float axis, float other)
139 {
140 return fabs(axis) > fabs(other) + ProjectionAxisEpsilon;
141 }
142
143 /// \brief Texture axis precedence: Z > X > Y
projectionaxis_for_normal(const Vector3 & normal)144 inline ProjectionAxis projectionaxis_for_normal (const Vector3& normal)
145 {
146 return (projectionaxis_better(normal[eProjectionAxisY], normal[eProjectionAxisX])) ? (projectionaxis_better(
147 normal[eProjectionAxisY], normal[eProjectionAxisZ])) ? eProjectionAxisY : eProjectionAxisZ
148 : (projectionaxis_better(normal[eProjectionAxisX], normal[eProjectionAxisZ])) ? eProjectionAxisX
149 : eProjectionAxisZ;
150 }
151
152 /*!
153 \brief Construct a transform from XYZ space to ST space (3d to 2d).
154 This will be one of three axis-aligned spaces, depending on the surface normal.
155 NOTE: could also be done by swapping values.
156 */
Normal_GetTransform(const Vector3 & normal,Matrix4 & transform)157 inline void Normal_GetTransform (const Vector3& normal, Matrix4& transform)
158 {
159 switch (projectionaxis_for_normal(normal)) {
160 case eProjectionAxisZ:
161 transform[0] = 1;
162 transform[1] = 0;
163 transform[2] = 0;
164
165 transform[4] = 0;
166 transform[5] = 1;
167 transform[6] = 0;
168
169 transform[8] = 0;
170 transform[9] = 0;
171 transform[10] = 1;
172 break;
173 case eProjectionAxisY:
174 transform[0] = 1;
175 transform[1] = 0;
176 transform[2] = 0;
177
178 transform[4] = 0;
179 transform[5] = 0;
180 transform[6] = -1;
181
182 transform[8] = 0;
183 transform[9] = 1;
184 transform[10] = 0;
185 break;
186 case eProjectionAxisX:
187 transform[0] = 0;
188 transform[1] = 0;
189 transform[2] = 1;
190
191 transform[4] = 1;
192 transform[5] = 0;
193 transform[6] = 0;
194
195 transform[8] = 0;
196 transform[9] = 1;
197 transform[10] = 0;
198 break;
199 }
200 transform[3] = transform[7] = transform[11] = transform[12] = transform[13] = transform[14] = 0;
201 transform[15] = 1;
202 }
203
204 /* greebo: This method calculates the normalised basis vectors of the texture plane as defined by <normal>
205 *
206 * If the normal vector points to the z-direction, the basis vectors are part
207 * of the xy-plane: texS = <0,1,0> and texT = <1,0,0>
208 *
209 * If normal vector points to the negative z-direction, the above case applies, but with
210 * the x-direction inversed: texS = <0,1,0> and texT = <-1,0,0> (note the minus)
211 *
212 * If none of the two above cases apply, the basis is calculated via cross products
213 * that result in vectors perpendicular to <normal>. These lie within the plane
214 * that is defined by the normal vector itself.
215 *
216 * Note: the vector <normal> MUST be normalised for this to function correctly.
217 */
ComputeAxisBase(const Vector3 & normal,Vector3 & texS,Vector3 & texT)218 inline void ComputeAxisBase (const Vector3& normal, Vector3& texS, Vector3& texT)
219 {
220 const Vector3 up(0, 0, 1);
221 const Vector3 down(0, 0, -1);
222
223 if (vector3_equal_epsilon(normal, up, float(1e-6))) {
224 texS = Vector3(0, 1, 0);
225 texT = Vector3(1, 0, 0);
226 } else if (vector3_equal_epsilon(normal, down, float(1e-6))) {
227 texS = Vector3(0, 1, 0);
228 texT = Vector3(-1, 0, 0);
229 } else {
230 texS = normal.crossProduct(up).getNormalised();
231 texT = normal.crossProduct(texS).getNormalised();
232 texS = -texS;
233 }
234 }
235
236 // greebo: Helper function
237 // handles degenerate cases, just in case library atan2 doesn't
arctangent_yx(double y,double x)238 inline double arctangent_yx (double y, double x)
239 {
240 if (fabs(x) > 1.0E-6) {
241 return atan2(y, x);
242 } else if (y > 0) {
243 return c_half_pi;
244 } else {
245 return -c_half_pi;
246 }
247 }
248
249 #endif
250