JNR
laCollisionDomain.cpp
1 /*
2 
3 Jump'n'Run Engine
4 http://www.atanaslaskov.com/jnr/
5 
6 BSD LICENSE
7 Copyright (c) 2007-2013, Atanas Laskov
8 All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12 1. Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL ATANAS LASKOV BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 */
29 
30 //
31 // FILE: laCollisionDomain.cpp
32 //
33 // Copyright (C) 2007-2013 Atanas Laskov, <latanas@gmail.com>
34 //
35 #include "stdafx.h"
36 #include "Core.h"
37 
38 laCollisionDomain::laCollisionDomain(void)
39 {
40  _nLineCnt = 0;
41  _pNextDomain = NULL;
42 }
43 
44 /*laCollisionDomain::~laCollisionDomain(void)
45 {
46 }*/
47 
48 laPoint3 laCollisionDomain::normal(laPoint3 a, laPoint3 b, laPoint3 c)
49 {
50  laPoint3 v1 = a-b;
51  laPoint3 v2 = a-c;
52  laPoint3 normal;
53 
54  normal[0] = v1.y()*v2.z() - v1.z()*v2.y();
55  normal[1] = v1.z()*v2.x() - v1.x()*v2.z();
56  normal[2] = v1.x()*v2.y() - v1.y()*v2.x();
57 
58  double len = normal.lenght()*3.0;
59  normal = laPoint3(normal/len)*M_UNIT;
60 
61  return normal;
62 }
63 
64 // Remove empty domains in the chain
65 //
66 void laCollisionDomain::optimize()
67 {
68  laCollisionDomain *pNext = _pNextDomain;
69 
70  while( pNext && (pNext->countLines() == 0) )
71  pNext = pNext->nextDomain();
72  _pNextDomain = pNext;
73 
74  if(pNext) _pNextDomain->optimize();
75 }
76 
77 void laCollisionDomain::addLine(laPoint3 a, laPoint3 b, laPoint3 normal, rpgTrap* pTrap)
78 {
79  ASSERT( (_nLineCnt+1) < M_MAX_COLLISION_DOMAIN_SZ, "Collision domain exceeds maximal size" );
80 
81  laLine2 ln(a, b);
82 
83  _arLines[_nLineCnt] = ln;
84  _arNormals[_nLineCnt] = normal;
85  _arTrap[_nLineCnt] = pTrap;
86  _nLineCnt++;
87 }
88 
89 
90 void laCollisionDomain::addTriangle(const laPoint3 &a, const laPoint3 &b, const laPoint3 &c, rpgTrap* pTrap)
91 {
92  const double CollisionPathZ = M_UNIT/2.0;
93  const double SmallDistance = M_UNIT/20.0;
94 
95  laPoint3 arTrianglePoints[3];
96  int arSide[3];
97 
98  unsigned arLinePointIndexs[3];
99  unsigned nLinePoints=0;
100  unsigned i;
101 
102  arTrianglePoints[0] = _offset + a;
103  arTrianglePoints[1] = _offset + b;
104  arTrianglePoints[2] = _offset + c;
105 
106  //arTrianglePoints[0].snap(SmallDistance);
107  //arTrianglePoints[1].snap(SmallDistance);
108  //arTrianglePoints[2].snap(SmallDistance);
109 
110  //Analyse vertex positions in relation to the collision track
111  //
112  for(i=0; i<3; i++)
113  {
114  if( M_ABS(arTrianglePoints[i].z()-CollisionPathZ) <= SmallDistance ) //vertex on the collision track
115  {
116  arSide[i] = 0;
117  arLinePointIndexs[nLinePoints++] = i;
118  }
119  else if(arTrianglePoints[i].z() < CollisionPathZ) arSide[i] = -1; //vertex in the "negative" side
120  else arSide[i] = 1; //vertex in the "positive" side
121  }
122 
123  //If all vertex lie on the same side of the collision track there is no intersection so we ignore this triangle
124  if( M_ABS(arSide[0]+arSide[1]+arSide[2])==3 ) return;
125 
126  //If all vertex lie on the collision track itself this is some sort of invalid triangle
127  if( nLinePoints == 3 ) return;
128 
129  //If an edge lies on the collision track just add it
130  if(nLinePoints == 2){
131  addLine(arTrianglePoints[arLinePointIndexs[0]],
132  arTrianglePoints[arLinePointIndexs[1]],
133  normal(a,b,c), pTrap);
134  return;
135  }
136 
137  //If there is a single point of the triangle that lies on the collision track
138  if(nLinePoints==1)
139  {
140  //The two remaining points are on the same side ignore this triangle
141  if( (arSide[0]+arSide[1]+arSide[2]) !=0 ) return;
142 
143  //Otherwise, find the crossing of the edge between them with the collision track
144  if(arLinePointIndexs[0]==0)
145  {
146  arLinePointIndexs[1] = 1;
147  arLinePointIndexs[2] = 2;
148  }
149  else if(arLinePointIndexs[0]==1)
150  {
151  arLinePointIndexs[1] = 0;
152  arLinePointIndexs[2] = 2;
153  }
154  else if(arLinePointIndexs[0]==2)
155  {
156  arLinePointIndexs[1] = 0;
157  arLinePointIndexs[2] = 1;
158  }
159 
160  //Extract the edge end-points
161  laPoint3 track_pt = arTrianglePoints[arLinePointIndexs[0]];
162  laPoint3 pt1 = arTrianglePoints[arLinePointIndexs[1]];
163  laPoint3 pt2 = arTrianglePoints[arLinePointIndexs[2]];
164 
165  //The laLine2 class is 2D and it can not hanndle a 3D intersection. That's
166  //why we use two proections to achive the same result.
167 
168  //Build a XZ proection
169  laLine2 edge_xz(laPoint3(pt1.x(), pt1.z()), laPoint3(pt2.x(), pt2.z()));
170 
171  double k = edge_xz.getK_atY(CollisionPathZ); //this is really "GetKAtZ" because in this proection Y=>Z
172  double x = edge_xz.getX(k);
173 
174  //Build a YZ proection
175  laLine2 edge_yz(laPoint3(pt1.y(), pt1.z()), laPoint3(pt2.y(), pt2.z()));
176  k = edge_yz.getK_atY(CollisionPathZ); //this is really "GetKAtZ" bacause in this proection Y=>Z
177  double y = edge_yz.getX(k);
178 
179  //Add the line
180  addLine(track_pt, laPoint3(x, y), normal(a,b,c), pTrap);
181  return;
182  }
183 
184  //If we are here, then there are no points whatoever that lie
185  //near the collision track. In that case two of the points are
186  //together on one side and there is a single point on the other. The
187  //two edges that come out of that singe point intersect the collision
188  //path so we must identify them.
189 
190  //If 0 and 1 are on the same side
191  if( arSide[0]+arSide[1] != 0)
192  {
193  arLinePointIndexs[0] = 2; //then 2 is alone
194  arLinePointIndexs[1] = 0; //0 is an end-point of a crossing edge
195  arLinePointIndexs[2] = 1; //1 is an end-point of a crossing edge
196  }
197  //If 0 and 2 are on the same side
198  else if( arSide[0]+arSide[2] != 0)
199  {
200  arLinePointIndexs[0] = 1; //then 1 is alone
201  arLinePointIndexs[1] = 0; //0 is an end-point of a crossing edge
202  arLinePointIndexs[2] = 2; //2 is an end-point of a crossing edge
203  }
204  //If 1 and 2 are on the same side
205  else if( arSide[1]+arSide[2] != 0)
206  {
207  arLinePointIndexs[0] = 0; //then 0 is alone
208  arLinePointIndexs[1] = 1; //1 is an end-point of a crossing edge
209  arLinePointIndexs[2] = 2; //2 is an end-point of a crossing edge
210  }
211 
212  //Now that we know which is the lone vertex, we can proceed
213  //to finding the crossings at its edges
214 
215  //Extract the edge end-points
216  laPoint3 lone = arTrianglePoints[arLinePointIndexs[0]];
217  laPoint3 pt1 = arTrianglePoints[arLinePointIndexs[1]];
218  laPoint3 pt2 = arTrianglePoints[arLinePointIndexs[2]];
219 
220  //The laLine2 class is 2D and it cannot hanndle a 3D intersection;
221  //We use two 2D projections to achive the same result.
222 
223  //Build a XZ projection
224  laLine2 edge1_xz(laPoint3(lone.x(), lone.z()), laPoint3(pt1.x(), pt1.z()));
225  laLine2 edge2_xz(laPoint3(lone.x(), lone.z()), laPoint3(pt2.x(), pt2.z()));
226 
227  double k1 = edge1_xz.getK_atY(CollisionPathZ); //this is really "GetKAtZ" because in this proection Y=>Z
228  double k2 = edge2_xz.getK_atY(CollisionPathZ);
229 
230  double x1 = edge1_xz.getX(k1);
231  double x2 = edge2_xz.getX(k2);
232 
233  //Build a YZ projection
234  laLine2 edge1_yz(laPoint3(lone.y(), lone.z()), laPoint3(pt1.y(), pt1.z()));
235  laLine2 edge2_yz(laPoint3(lone.y(), lone.z()), laPoint3(pt2.y(), pt2.z()));
236 
237  k1 = edge1_yz.getK_atY(CollisionPathZ); //this is really "GetKAtZ" bacause in this proection Y=>Z
238  k2 = edge2_yz.getK_atY(CollisionPathZ);
239 
240  double y1 = edge1_yz.getX(k1);
241  double y2 = edge2_yz.getX(k2);
242 
243  //Add the line
244  addLine(laPoint3(x1, y1), laPoint3(x2, y2), normal(a,b,c), pTrap);
245 
246 }
247 
248 void laCollisionDomain::updateBounds()
249 {
250  _rectBounds.reset();
251  for(unsigned i=0; i<_nLineCnt; i++) _rectBounds.add( _arLines[i] );
252 }
253 
254 // Draw lines and normals in the domain
255 //
256 void laCollisionDomain::draw(laRenderer* r, laPoint3 ptBasePos)
257 {
258  //const double dCollisionPathZ = M_UNIT/2.0;
259 
260  /*r->modeLight(M_FALSE);
261  r->modeTexture(M_FALSE);
262  r->modeDepthBuffer(M_FALSE);*/
263 
264 
265  for(unsigned i=0; i<_nLineCnt; i++)
266  {
267  laLine2 ln(_arLines[i].origin - (laPoint2)_offset, _arLines[i].origin - (laPoint2)_offset + _arLines[i].vector);
268  laLine2 ln_normal(ln.origin + ln.vector*0.5, ln.origin + ln.vector*0.5 + _arNormals[i]*0.5);
269 
270  r->styleLine(2);
271  r->styleSet(laColor(255,0,0));
272  ln.draw(r, (laPoint2)ptBasePos);
273 
274  r->styleLine(1);
275  r->styleSet(laColor(255,0,0));
276  ln_normal.draw(r, (laPoint2)ptBasePos);
277  }
278 
279  /*r->modeLight(M_TRUE);
280  r->modeTexture(M_TRUE);
281  r->styleSet(laColor(255,255,255));
282  r->modeDepthBuffer(M_TRUE);*/
283 }
#define M_UNIT
Unit of 1 meter.
2D Point
Definition: laPoint_novec.h:41
void add(const laPoint2 &p)
Revert to "uninitialized" state.
Definition: laRect2.h:64
Trap Properties.
Definition: rpgTrap.h:42
2D line segment
Definition: laLine2.h:40
#define M_ABS(a)
Return abs(a)
Collision Domain.
Virtual interface for the Engine graphics renderer.
Definition: laRenderer.h:98