Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
segmentcell.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 by Kapoulkine Arseny
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public
15  License along with this library; if not, write to the Free
16  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 
21 {
22 private:
23  int sign (float val)
24  {
25  return val > 0 ? 1 : val < 0 ? -1 : 0;
26  }
27 
28  iTerrainCell* cell;
29  const csVector3& start;
30  const csVector3& end;
31 
32  const csVector2& pos;
33  const csVector3& size;
34 
35  float scale_u, scale_v;
36 
37  float u0, v0, h0;
38  float u1, v1, h1;
39  float du, dv, dh;
40  float oneOverdu, oneOverdv;
41  float eu, ev;
42  float dp, oneOverdp, ep;
43 
44  float t, h, cell_height;
45 
46  unsigned int width, height;
47 
48  bool firsttime, vertical, verticalhit;
49 
50 public:
51  csTerrainSegmentCellCollider (iTerrainCell* cell, const csVector3&
52  start, const csVector3& end)
53  : start(start), end(end), pos(cell->GetPosition ()), size(cell->GetSize ()),
54  vertical (false), verticalhit (false)
55  {
56  // Constants
57  const float rootOf2 = 1.414213f;
58  const float halfRoot2 = rootOf2 / 2;
59 
60  this->cell = cell;
61 
62  width = cell->GetGridWidth ();
63  height = cell->GetGridHeight ();
64 
65  scale_u = size.x / (width - 1);
66  scale_v = size.z / (height - 1);
67 
68  // Offset from grid 0,0
69  const csVector2 gridOffsetStart = csVector2(start.x - pos.x,
70  -(start.z - (pos.y + size.z)));
71  const csVector2 gridOffsetEnd = csVector2(end.x - pos.x,
72  -(end.z - (pos.y + size.z)));
73 
74  // U, V and height of segment start in cell space
75  u0 = (gridOffsetStart.x) / scale_u;
76  v0 = (gridOffsetStart.y) / scale_v;
77  h0 = start.y;
78 
79  // U, V and height of segment end in cell space
80  u1 = (gridOffsetEnd.x) / scale_u;
81  v1 = (gridOffsetEnd.y) / scale_v;
82  h1 = end.y;
83 
84  // Compute differences for ray (lengths along axes) and their inverse
85  du = u1 - u0;
86  dv = v1 - v0;
87  dh = h1 - h0;
88 
89  // vertical case
90  if (du == 0 && dv == 0)
91  {
92  vertical = true;
93 
94  float height = cell->GetHeight (gridOffsetStart);
95  if (csMin(h0, h1) <= height &&
96  csMax(h0, h1) >= height)
97  {
98  verticalhit = true;
99  }
100  }
101 
102  if (fabs (du) < SMALL_EPSILON) du = SMALL_EPSILON;
103  if (fabs (dv) < SMALL_EPSILON) dv = SMALL_EPSILON;
104 
105  oneOverdu = 1 / du;
106  oneOverdv = 1 / dv;
107 
108  // Distance to intersection with u/v axes
109  eu = u0 - floor(u0);
110  ev = v0 - floor(v0);
111 
112  // Differences and distance to intersection with diagonal
113  dp = (du + dv) / rootOf2;
114 
115  if (fabs (dp) < SMALL_EPSILON) dp = SMALL_EPSILON;
116 
117  oneOverdp = 1 / dp;
118  ep = fabs(dp) * (1 - eu - ev) / (dv + du); // line-line intersection
119 
120  // Fixup for positive directions
121  if (du > 0) eu = 1 - eu;
122  if (dv > 0) ev = 1 - ev;
123  if (ep < 0) ep += halfRoot2;
124 
125  // Stepping variables
126  t = 0;
127  h = h0;
128  cell_height = cell->GetHeight (gridOffsetStart);
129 
130  firsttime = true;
131  }
132 
133  // 0 - nothing happened
134  // 1 - collision
135  // -1 - loop stop
136  int GetIntersection (csVector3& result, csVector2& cell_result)
137  {
138  // Constants
139  const float rootOf2 = 1.414213f;
140  const float halfRoot2 = rootOf2 / 2;
141 
142  if (t < 0 || t >= 1) return -1;
143  if (!(t < 0) && !(t >= 0)) return -1;
144 
145  float r_h0 = h;
146  float tstep = 0;
147 
148  if (vertical)
149  {
150  if (verticalhit && firsttime)
151  {
152  firsttime = false;
153 
154  cell_result.x = u0;
155  cell_result.y = v0;
156 
157  result.x = pos.x + cell_result.x * scale_u;
158  result.y = cell_height;
159  result.z = pos.y + height - cell_result.y * scale_v;
160 
161  return 1;
162  }
163  else
164  {
165  return -1;
166  }
167  }
168 
169  if (!firsttime)
170  {
171  float tToU = eu * fabs (oneOverdu); // Time to reach U intersection
172  float tToV = ev * fabs (oneOverdv); // Time to reach V intersection
173  float tToP = ep * fabs (oneOverdp); // Time to reach P intersection
174 
175  if (tToU <= tToV && tToU <= tToP)
176  {
177  // U intersection first
178  if (t + tToU > 1) tToU = 1 - t;
179 
180  tstep = tToU;
181  t += tToU;
182 
183  // Update distances
184  eu = 0;
185  ev -= fabs(dv) * tToU;
186  ep -= fabs(dp) * tToU;
187 
188  // Update height
189  h += dh * tToU;
190  }
191  else if (tToV <= tToU && tToV <= tToP)
192  {
193  // V intersection first
194  if (t + tToV > 1) tToV = 1 - t;
195 
196  tstep = tToV;
197  t += tToV;
198 
199  // Update distances
200  eu -= fabs(du) * tToV;
201  ev = 0;
202  ep -= fabs(dp) * tToV;
203 
204  // Update height
205  h += dh * tToV;
206  }
207  else
208  {
209  // P intersection first
210  if (t + tToP > 1) tToP = 1 - t;
211 
212  tstep = tToP;
213  t += tToP;
214 
215  // Update distances
216  eu -= fabs(du) * tToP;
217  ev -= fabs(dv) * tToP;
218  ep = 0;
219 
220  // Update height
221  h += dh * tToP;
222  }
223 
224  // Wrap around
225  if (eu <= 0) eu = 1;
226  if (ev <= 0) ev = 1;
227  if (ep <= 0) ep = halfRoot2;
228  }
229 
230  firsttime = false;
231 
232  // Check for intersection
233  float r_h1 = h;
234  float h_h0 = cell_height;
235 
236  csVector2 uv = csVector2 ((u0 + du * t) * scale_u,
237  (v0 + dv * t) * scale_v);
238  float h_h1 = cell->GetHeight (uv);
239 
240  // Remember height value
241  cell_height = h_h1;
242 
243  // Check intersection
244  int cmp_h0 = sign (r_h0 - h_h0);
245  int cmp_h1 = sign (r_h1 - h_h1);
246 
247  if (cmp_h0 * cmp_h1 == -1 || fabs (r_h1 - h_h1) < EPSILON)
248  {
249  float correct_t = t;
250 
251  if (cmp_h0 * cmp_h1 == -1)
252  {
253  // A B C
254  // (vertex) ------(intersection)------- (vertex)
255  // AC = tstep (in terms of t), we have to subtract
256  // BC from correct_t. AB / BC equals the height ratio
257  float coeff = fabs(r_h0 - h_h0) / fabs(r_h1 - h_h1);
258 
259  // AB / BC = coeff
260  // AB + BC = tstep
261  // AB = coeff * BC
262  // BC * (coeff + 1) = tstep
263 
264  correct_t -= tstep / (coeff + 1);
265  }
266 
267  cell_result.x = u0 + du * correct_t;
268  cell_result.y = v0 + dv * correct_t;
269 
270  result.x = pos.x + cell_result.x * scale_u;
271  result.y = h0 + dh * correct_t;
272  result.z = pos.y + height - cell_result.y * scale_v;
273 
274  return (cell_result.x >=0 && cell_result.x <= width - 1 &&
275  cell_result.y >=0 && cell_result.y <= height - 1);
276  }
277 
278  return 0;
279  }
280 };
281