xoreos  0.0.5
trigger.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include "glm/gtc/type_ptr.hpp"
26 #include "glm/gtx/intersect.hpp"
27 
28 #include "src/aurora/gff3file.h"
29 #include "src/aurora/resman.h"
30 
32 
33 const float kEpsilon = 1.0e-5; // Negligible distance in game space
34 
35 namespace Engines {
36 
38  : Renderable(Graphics::kRenderableTypeObject),
39  _visible(false), _prepared(false) {
40 
41 }
42 
43 void Trigger::setVisible(bool visible) {
44  _visible = visible;
45 }
46 
47 /*
48  * Return true if the (x, y) coordinates are located within
49  * the horizontal projection of this closed polygon.
50  */
51 bool Trigger::contains(float x, float y) const {
52  // Must have a surface defined
53  size_t vertexCount = _geometry.size();
54  if (vertexCount < 3)
55  return false;
56 
57  // Check the container data
58  assert(_prepared);
59 
60  // Check if point is in bounding box
61  if (!_boundingbox.isIn(x, y))
62  return false;
63 
64  // Initialization
65  std::vector<glm::vec3>::const_iterator it1, it2;
66  std::vector<SlopeData>::const_iterator it3;
67  int count = 0;
68 
69  // Set first iterator to the last vertex
70  it1 = _geometry.end();
71  it1--;
72 
73  // Cycle through the vertices, counting the number of ray intersections
74  for (it2 = _geometry.begin(), it3 = _sides.begin(); it2 != _geometry.end(); ++it2, ++it3) {
75  // Check for a ray intersection
76  if (isRayIntersect(x, y, it1->x, it1->y, it2->x, it2->y, it3->m, it3->isVert))
77  count++;
78 
79  // Store for the next loop
80  it1 = it2;
81  }
82 
83  // Ray-casting algorithm
84  return (count % 2) ? true : false;
85 }
86 
88 
89 }
90 
93  return;
94 
95  size_t vertexCount = _geometry.size();
96  if (vertexCount < 3)
97  return;
98 
99  // Semi-transparent blue hue
100  glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
101  glBegin(GL_TRIANGLES);
102 
103  for (size_t i = 2; i < vertexCount; ++i) {
104  glVertex3fv(glm::value_ptr(_geometry[0]));
105  glVertex3fv(glm::value_ptr(_geometry[i - 1]));
106  glVertex3fv(glm::value_ptr(_geometry[i]));
107  }
108 
109  glEnd();
110  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
111 }
112 
113 /*
114  * Prepare internal data for the contains(x, y) call.
115  * Run this after the _geometry data is loaded.
116  */
118  std::vector<glm::vec3>::iterator it;
119 
120  // Add vertices to the bounding box
121  for (it = _geometry.begin(); it != _geometry.end(); ++it)
122  _boundingbox.add(it->x, it->y, it->z);
123  //
124  // Initialization
125  std::vector<glm::vec3>::iterator it1, it2;
126  _sides.clear();
127 
128  // Set first iterator to the last vertex
129  it1 = _geometry.end();
130  it1--;
131 
132  // Precompute the slopes of the sides
133  for (it2 = _geometry.begin(); it2 != _geometry.end(); ++it2) {
134  float dx = it2->x - it1->x;
135  float dy = it2->y - it1->y;
136  SlopeData data;
137 
138  // Check if this is a (near) vertical side
139  if ((dx > kEpsilon) || (dx < -kEpsilon)) {
140  data.m = dy / dx;
141  data.isVert = false;
142  } else {
143  data.m = 0.0f;
144  data.isVert = true;
145  }
146 
147  // Add the data to the vector
148  _sides.push_back(data);
149 
150  // Store for the next loop
151  it1 = it2;
152  }
153 
154  // Flag as processed
155  _prepared = true;
156 }
157 
158 /*
159  * Return true if a ray extending from (x, y) to (x, infinity)
160  * intersects the line segment from (x1, y1) to (x2, y2).
161  */
162 bool Trigger::isRayIntersect(float x, float y,
163  float x1, float y1,
164  float x2, float y2,
165  float m, bool isVert) const {
166 
167  // Check if y is below max of y1 and y2
168  if ((y > y1) && (y > y2))
169  return false;
170 
171  // On a vertex alignment, add an offset
172  float x0 = x;
173  if ((x0 == x1) || (x0 == x2)) {
174  x0 = x0 + kEpsilon;
175  }
176 
177  // Check if x0 is in [x1, x2]
178  if (x1 < x2) {
179  if ((x0 < x1) || (x0 > x2))
180  return false;
181  } else {
182  if ((x0 < x2) || (x0 > x1))
183  return false;
184  }
185 
186  // Check if line segment is vertical
187  if (isVert) {
188  return true;
189  } else {
190  float yint = m * (x0 - x1) + y1;
191 
192  // Is the point above the line?
193  if (!(y > yint))
194  return true;
195  }
196 
197  return false;
198 }
199 
200 } // End of namespace Engines
Handling version V3.2/V3.3 of BioWare&#39;s GFFs (generic file format).
bool isIn(float x, float y) const
Only render transparent parts.
Definition: types.h:99
bool isRayIntersect(float x, float y, float x1, float y1, float x2, float y2, float m, bool isVert) const
Definition: trigger.cpp:162
bool _prepared
Definition: trigger.h:60
const float kEpsilon
Definition: trigger.cpp:33
RenderPass
Definition: types.h:97
Generic trigger.
std::vector< SlopeData > _sides
Definition: trigger.h:62
Common::BoundingBox _boundingbox
Definition: trigger.h:61
void add(float x, float y, float z)
void render(Graphics::RenderPass pass)
Render the object.
Definition: trigger.cpp:91
void setVisible(bool visible)
Definition: trigger.cpp:43
std::vector< glm::vec3 > _geometry
Definition: trigger.h:50
#define pass
Definition: fft.cpp:257
The global resource manager for Aurora resources.
void calculateDistance()
Calculate the object&#39;s distance.
Definition: trigger.cpp:87
bool contains(float x, float y) const
Definition: trigger.cpp:51