Skyscraper 2.0
texmap.cpp
Go to the documentation of this file.
1/*
2 This code was originally part of Crystal Space
3 Available at http://www.crystalspace3d.org
4 Copyright (C) 1998-2005 by Jorrit Tyberghein
5 Modifications Copyright (C)2010 Ryan Thoryk
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library 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 GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with this library; if not, write to the Free
19 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include <math.h>
23#include "globals.h"
24#include "sbs.h"
25#include "polygon.h"
26#include "texture.h"
27#include "utility.h"
28
29namespace SBS {
30
31#undef EPSILON
32#define EPSILON 0.001f
33#undef SMALL_EPSILON
34#define SMALL_EPSILON 0.000001f
35
36bool TextureManager::ComputeTextureMap(Matrix3 &t_matrix, Vector3 &t_vector, PolyArray &vertices, const Vector3 &p1, const Vector3 &p2, const Vector3 &p3, Real tw, Real th)
37{
38 //this is modified code from the Crystal Space thingmesh system (SetTextureSpace function),
39 //from the "plugins/mesh/thing/object/polygon.cpp" file.
40
41 //given an array of vertices, this returns the texture transformation matrix and vector
42
43 //original description:
44 // Set the texture space transformation given three vertices and
45 // their uv coordinates.
46 //
47 // Some explanation. We have three points for
48 // which we know the uv coordinates. This gives:
49 // P1 -> UV1
50 // P2 -> UV2
51 // P3 -> UV3
52 // P1, P2, and P3 are on the same plane so we can write:
53 // P = P1 + lambda * (P2-P1) + mu * (P3-P1)
54 // For the same lambda and mu we can write:
55 // UV = UV1 + lambda * (UV2-UV1) + mu * (UV3-UV1)
56 // What we want is Po, Pu, and Pv (also on the same
57 // plane) so that the following uv coordinates apply:
58 // Po -> 0,0
59 // Pu -> 1,0
60 // Pv -> 0,1
61 // The UV equation can be written as follows:
62 // U = U1 + lambda * (U2-U1) + mu * (U3-U1)
63 // V = V1 + lambda * (V2-V1) + mu * (V3-V1)
64 // This is a matrix equation (2x2 matrix):
65 // UV = UV1 + M * PL
66 // We have UV in this case and we need PL so we
67 // need to invert this equation:
68 // (1/M) * (UV - UV1) = PL
69
70 //get stored UV mappings and adjust according to width and height
71 Vector2 uv1, uv2, uv3;
72 uv1.x = MapUV[0].x * tw;
73 uv1.y = MapUV[0].y * th;
74 uv2.x = MapUV[1].x * tw;
75 uv2.y = MapUV[1].y * th;
76 uv3.x = MapUV[2].x * tw;
77 uv3.y = MapUV[2].y * th;
78
79 //set up 2D matrix
80 Real m11, m12, m21, m22;
81 m11 = uv2.x - uv1.x;
82 m12 = uv3.x - uv1.x;
83 m21 = uv2.y - uv1.y;
84 m22 = uv3.y - uv1.y;
85
86 //compute determinant of matrix
87 Real det = m11 * m22 - m12 * m21;
88
89 if (std::abs(det) < SMALL_EPSILON)
90 return ReportError("ComputeTextureMap: Bad UV coordinates");
91 else
92 {
93 //invert matrix
94 Real inv_det = 1 / (m11 * m22 - m12 * m21);
95 Real tmp1, tmp2, tmp3, tmp4;
96 tmp1 = m11;
97 tmp2 = m12;
98 tmp3 = m21;
99 tmp4 = m22;
100
101 m11 = tmp4 * inv_det;
102 m12 = -tmp2 * inv_det;
103 m21 = -tmp3 * inv_det;
104 m22 = tmp1 * inv_det;
105 }
106
107 Vector2 pl;
108 Vector3 po, pu, pv;
109
110 // For (0,0) and Po
111 Vector2 v = Vector2(0, 0) - uv1;
112 pl = Vector2(m11 * v.x + m12 * v.y, m21 * v.x + m22 * v.y);
113 po = p1 + pl.x * (p2 - p1) + pl.y * (p3 - p1);
114 po = Round(po, 7); //round result to prevent precision errors
115
116 // For (1,0) and Pu
117 v = Vector2(1, 0) - uv1;
118 pl = Vector2(m11 * v.x + m12 * v.y, m21 * v.x + m22 * v.y);
119 pu = p1 + pl.x * (p2 - p1) + pl.y * (p3 - p1);
120 pu = Round(pu, 7); //round result to prevent precision errors
121
122 // For (0,1) and Pv
123 v = Vector2(0, 1) - uv1;
124 pl = Vector2(m11 * v.x + m12 * v.y, m21 * v.x + m22 * v.y);
125 pv = p1 + pl.x * (p2 - p1) + pl.y * (p3 - p1);
126 pv = Round(pv, 7); //round result to prevent precision errors
127
128 //compute norms of vectors
129 Vector3 len1 = pu - po;
130 Vector3 len2 = pv - po;
131 Real len1f = sqrt(len1.x * len1.x + len1.y * len1.y + len1.z * len1.z);
132 Real len2f = sqrt(len2.x * len2.x + len2.y * len2.y + len2.z * len2.z);
133
134 return ComputeTextureSpace(t_matrix, t_vector, po, pu, len1f, pv, len2f);
135}
136
137bool TextureManager::ComputeTextureSpace(Matrix3 &m, Vector3 &v, const Vector3 &v_orig, const Vector3 &v1, Real len1, const Vector3 &v2, Real len2)
138{
139 //originally from Crystal Space's libs/csgeom/textrans.cpp file
140
157 Real d = v_orig.squaredDistance(v1);
158 //get inverse square of d
159 Real invl1 = 1 / sqrt(d);
160
161 d = v_orig.squaredDistance(v2);
162 //get inverse square of d
163 Real invl2 = (d) ? 1 / sqrt(d) : 0;
164
165 Vector3 v_u = (v1 - v_orig) * len1 * invl1;
166 Vector3 v_v = (v2 - v_orig) * len2 * invl2;
167 Vector3 v_w = v_u.crossProduct(v_v);
168
169 m[0][0] = v_u.x;
170 m[0][1] = v_v.x;
171 m[0][2] = v_w.x;
172 m[1][0] = v_u.y;
173 m[1][1] = v_v.y;
174 m[1][2] = v_w.y;
175 m[2][0] = v_u.z;
176 m[2][1] = v_v.z;
177 m[2][2] = v_w.z;
178
179 v = v_orig;
180
181 Real det = m.Determinant();
182 /*if (std::abs(det) < SMALL_EPSILON)
183 {
184 //m = m.IDENTITY;
185 //return ReportError("Error computing texture space");
186
187 //alternate matrix inversion method
188 //(standard inversion breaks when using small numbers)
189 if (v_u.x == 0)
190 m[0][0] = 0;
191 else
192 m[0][0] = 1 / v_u.x;
193
194 if (v_v.x == 0)
195 m[0][1] = 0;
196 else
197 m[0][1] = 1 / v_v.x;
198
199 if (v_w.x == 0)
200 m[0][2] = 0;
201 else
202 m[0][2] = 1 / v_w.x;
203
204 if (v_u.y == 0)
205 m[1][0] = 0;
206 else
207 m[1][0] = 1 / v_u.y;
208
209 if (v_v.y == 0)
210 m[1][1] = 0;
211 else
212 m[1][1] = 1 / v_v.y;
213
214 if (v_w.y == 0)
215 m[1][2] = 0;
216 else
217 m[1][2] = 1 / v_w.y;
218
219 if (v_u.z == 0)
220 m[2][0] = 0;
221 else
222 m[2][0] = 1 / v_u.z;
223
224 if (v_v.z == 0)
225 m[2][1] = 0;
226 else
227 m[2][1] = 1 / v_v.z;
228
229 if (v_w.z == 0)
230 m[2][2] = 0;
231 else
232 m[2][2] = 1 / v_w.z;
233 }
234 else*/
235 m = m.Inverse(1e-10f); //standard inversion
236
237 return true;
238}
239
240void Utility::SplitWithPlane(int axis, PolyArray &orig, PolyArray &poly1, PolyArray &poly2, Real value)
241{
242 //from Crystal Space libs/csgeom/poly3d.cpp
243 //axis is 0 for X, 1 for Y, 2 for Z
244 //splits the "orig" polygon on the desired plane into two resulting polygons
245
246 poly1.clear();
247 poly2.clear();
248
249 //preallocate memory for a worst-case scenario
250 poly1.reserve(orig.size());
251 poly2.reserve(orig.size());
252
253 Vector3 ptB;
254 Real sideA = 0, sideB = 0;
255 Vector3 ptA = orig[orig.size() - 1];
256
257 if (axis == 0)
258 sideA = ptA.x - value;
259 if (axis == 1)
260 sideA = ptA.y - value;
261 if (axis == 2)
262 sideA = ptA.z - value;
263
264 if (std::abs(sideA) < SMALL_EPSILON)
265 sideA = 0;
266
267 for (int i = -1; ++i < (int)orig.size();)
268 {
269 ptB = orig[i];
270 if (axis == 0)
271 sideB = ptB.x - value;
272 if (axis == 1)
273 sideB = ptB.y - value;
274 if (axis == 2)
275 sideB = ptB.z - value;
276
277 if (std::abs(sideB) < SMALL_EPSILON)
278 sideB = 0;
279
280 if (sideB > 0)
281 {
282 if (sideA < 0)
283 {
284 // Compute the intersection point of the line
285 // from point A to point B with the partition
286 // plane. This is a simple ray-plane intersection.
287
288 Vector3 v = ptB;
289 v -= ptA;
290
291 Real sect = 0;
292 if (axis == 0)
293 sect = -(ptA.x - value) / v.x;
294 if (axis == 1)
295 sect = -(ptA.y - value) / v.y;
296 if (axis == 2)
297 sect = -(ptA.z - value) / v.z;
298 v *= sect;
299 v += ptA;
300 poly1.emplace_back(v);
301 poly2.emplace_back(v);
302 }
303
304 poly2.emplace_back(ptB);
305 }
306 else if (sideB < 0)
307 {
308 if (sideA > 0)
309 {
310 // Compute the intersection point of the line
311 // from point A to point B with the partition
312 // plane. This is a simple ray-plane intersection.
313
314 Vector3 v = ptB;
315 v -= ptA;
316
317 Real sect = 0;
318 if (axis == 0)
319 sect = -(ptA.x - value) / v.x;
320 if (axis == 1)
321 sect = -(ptA.y - value) / v.y;
322 if (axis == 2)
323 sect = -(ptA.z - value) / v.z;
324 v *= sect;
325 v += ptA;
326 poly1.emplace_back(v);
327 poly2.emplace_back(v);
328 }
329
330 poly1.emplace_back(ptB);
331 }
332 else
333 {
334 poly1.emplace_back(ptB);
335 poly2.emplace_back(ptB);
336 }
337
338 ptA = ptB;
339 sideA = sideB;
340 }
341}
342
344{
345 //from Crystal Space libs/csgeom/poly3d.cpp
346 //calculate polygon normal
347
348 float ayz = 0;
349 float azx = 0;
350 float axy = 0;
351 size_t i, i1;
352 float x1, y1, z1, x, y, z;
353
354 i1 = vertices.size() - 1;
355 x1 = (float)vertices[i1].x;
356 y1 = (float)vertices[i1].y;
357 z1 = (float)vertices[i1].z;
358 for (i = 0; i < vertices.size(); i++)
359 {
360 x = (float)vertices[i].x;
361 y = (float)vertices[i].y;
362 z = (float)vertices[i].z;
363 ayz += (z1 + z) * (y - y1);
364 azx += (x1 + x) * (z - z1);
365 axy += (y1 + y) * (x - x1);
366 x1 = x;
367 y1 = y;
368 z1 = z;
369 }
370
371 float sqd = ayz * ayz + azx * azx + axy * axy;
372 float invd;
373 if (sqd < SMALL_EPSILON)
374 invd = 1.0f / SMALL_EPSILON;
375 else
376 invd = 1.0f / sqrt(sqd);
377 Vector3 norm;
378 norm.x = ayz * invd;
379 norm.y = azx * invd;
380 norm.z = axy * invd;
381 D = -norm.x * vertices[0].x - norm.y * vertices[0].y - norm.z * vertices[0].z;
382 return norm;
383}
384
385bool Polygon::IntersectRay(const Vector3 &start, const Vector3 &end)
386{
387 //from Crystal Space plugins/mesh/thing/object/polygon.cpp
388
397 // First we do backface culling on the polygon with respect to
398 // the starting point of the beam.
399
401
402 Real dot1 = plane.d + plane.normal.x * start.x + plane.normal.y * start.y + plane.normal.z * start.z;
403 if (dot1 > 0)
404 return false;
405
406 // If this vector is perpendicular to the plane of the polygon we
407 // need to catch this case here.
408 Real dot2 = plane.d + plane.normal.x * end.x + plane.normal.y * end.y + plane.normal.z * end.z;
409 if (std::abs(dot1 - dot2) < SMALL_EPSILON)
410 return false;
411
412 // Now we generate a plane between the starting point of the ray and
413 // every edge of the polygon. With the plane normal of that plane we
414 // can then check if the end of the ray is on the same side for all
415 // these planes.
416 Vector3 normal;
417 Vector3 relend = end;
418 relend -= start;
419
420 Vector3 pos = sbs->ToRemote(mesh->GetPosition(), true, false);
421
422 for (size_t index = 0; index < geometry.size(); index++)
423 {
424 size_t i1 = geometry[index].size() - 1;
425 for (size_t i = 0; i < geometry[index].size(); i++)
426 {
427 Vector3 v = sbs->ToLocal(geometry[index][i1].vertex, false, true);
428 Vector3 vertex = pos + v;
429 Vector3 start2 = start - vertex;
430 normal = start2.crossProduct(start - vertex);
431 if ((relend.x * normal.x + relend.y * normal.y + relend.z * normal.z > 0))
432 continue;
433 i1 = i;
434 }
435 }
436
437 return true;
438}
439
440bool Polygon::IntersectSegment(const Vector3 &start, const Vector3 &end, Vector3 &isect, Real *pr, Vector3 &normal)
441{
442 //from Crystal Space plugins/mesh/thing/object/polygon.cpp
443
444 //positions need to be in remote (Ogre) values
445
451 if (!IntersectRay(start, end))
452 return false;
453
454 return IntersectSegmentPlane(start, end, isect, pr, normal);
455}
456
457bool Polygon::IntersectSegmentPlane(const Vector3 &start, const Vector3 &end, Vector3 &isect, Real *pr, Vector3 &normal)
458{
459 //from Crystal Space plugins/mesh/thing/object/polygon.cpp
460
466 // So now we have the plane equation of the polygon:
467 // A*x + B*y + C*z + D = 0
468 //
469 // We also have the parameter line equations of the ray
470 // going through 'start' and 'end':
471 // x = r*(x2-x1)+x1
472 // y = r*(y2-y1)+y1
473 // z = r*(z2-z1)+z1
474 //
475 // => A*(r*(x2-x1)+x1) + B*(r*(y2-y1)+y1) + C*(r*(z2-z1)+z1) + D = 0
476 // Set *pr to -1 to indicate error if we return false now.
477 if (pr)
478 *pr = -1;
479
481
482 Real denom = plane.normal.x * (end.x - start.x) +
483 plane.normal.y * (end.y - start.y) +
484 plane.normal.z * (end.z - start.z);
485
486 if (std::abs(denom) < SMALL_EPSILON)
487 return false; // Lines are parallel
488
489 Real num = -(plane.normal.x * start.x +
490 plane.normal.y * start.y +
491 plane.normal.z * start.z +
492 plane.d);
493 Real r = num / denom;
494
495 // Calculate 'r' and 'isect' even if the intersection point is
496 // not on the segment. That way we can use this function for testing
497 // with rays as well.
498 if (pr)
499 *pr = r;
500
501 isect.x = r * (end.x - start.x) + start.x;
502 isect.y = r * (end.y - start.y) + start.y;
503 isect.z = r * (end.z - start.z) + start.z;
504
505 // If r is not in [0,1] the intersection point is not on the segment.
506 if (r < 0 /*-SMALL_EPSILON*/ || r > 1)
507 return false;
508
509 normal = plane.normal;
510 return true;
511}
512
513}
virtual bool ReportError(const std::string &message)
Definition object.cpp:84
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:321
bool IntersectSegmentPlane(const Vector3 &start, const Vector3 &end, Vector3 &isect, Real *pr, Vector3 &normal)
Definition texmap.cpp:457
bool IntersectRay(const Vector3 &start, const Vector3 &end)
Definition texmap.cpp:385
GeometrySet geometry
Definition polygon.h:47
bool IntersectSegment(const Vector3 &start, const Vector3 &end, Vector3 &isect, Real *pr, Vector3 &normal)
Definition texmap.cpp:440
MeshObject * mesh
Definition polygon.h:46
Plane GetAbsolutePlane()
Definition polygon.cpp:99
Plane plane
Definition polygon.h:50
Real ToLocal(Real remote_value)
Definition sbs.cpp:2367
Real ToRemote(Real local_value)
Definition sbs.cpp:2407
bool ComputeTextureSpace(Matrix3 &m, Vector3 &v, const Vector3 &v_orig, const Vector3 &v1, Real len1, const Vector3 &v2, Real len2)
Definition texmap.cpp:137
bool ComputeTextureMap(Matrix3 &t_matrix, Vector3 &t_vector, PolyArray &vertices, const Vector3 &p1, const Vector3 &p2, const Vector3 &p3, Real tw, Real th)
Definition texmap.cpp:36
std::vector< Vector2 > MapUV
Definition texture.h:139
void SplitWithPlane(int axis, PolyArray &orig, PolyArray &poly1, PolyArray &poly2, Real value)
Definition texmap.cpp:240
Vector3 ComputeNormal(PolyArray &vertices, Real &D)
Definition texmap.cpp:343
Ogre::Matrix3 Matrix3
Definition globals.h:64
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
Ogre::Plane Plane
Definition globals.h:65
Ogre::Vector2 Vector2
Definition globals.h:59
std::vector< Vector3 > PolyArray
Definition sbs.h:118
float Round(float number, int decimal_places)
Definition globals.cpp:346
#define SMALL_EPSILON
Definition texmap.cpp:34