Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Render.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "Render.h"
21 
22 #include "graphics/Overlay.h"
23 #include "graphics/Terrain.h"
26 #include "maths/MathUtil.h"
27 #include "maths/Quaternion.h"
28 #include "maths/Vector2D.h"
29 #include "ps/Profile.h"
34 
35 void SimRender::ConstructLineOnGround(const CSimContext& context, const std::vector<float>& xz,
36  SOverlayLine& overlay, bool floating, float heightOffset)
37 {
38  PROFILE("ConstructLineOnGround");
39 
40  overlay.m_Coords.clear();
41 
42  CmpPtr<ICmpTerrain> cmpTerrain(context, SYSTEM_ENTITY);
43  if (!cmpTerrain)
44  return;
45 
46  if (xz.size() < 2)
47  return;
48 
49  float water = 0.f;
50  if (floating)
51  {
52  CmpPtr<ICmpWaterManager> cmpWaterManager(context, SYSTEM_ENTITY);
53  if (cmpWaterManager)
54  water = cmpWaterManager->GetExactWaterLevel(xz[0], xz[1]);
55  }
56 
57  overlay.m_Coords.reserve(xz.size()/2 * 3);
58 
59  for (size_t i = 0; i < xz.size(); i += 2)
60  {
61  float px = xz[i];
62  float pz = xz[i+1];
63  float py = std::max(water, cmpTerrain->GetExactGroundLevel(px, pz)) + heightOffset;
64  overlay.m_Coords.push_back(px);
65  overlay.m_Coords.push_back(py);
66  overlay.m_Coords.push_back(pz);
67  }
68 }
69 
70 void SimRender::ConstructCircleOnGround(const CSimContext& context, float x, float z, float radius,
71  SOverlayLine& overlay, bool floating, float heightOffset)
72 {
73  overlay.m_Coords.clear();
74 
75  CmpPtr<ICmpTerrain> cmpTerrain(context, SYSTEM_ENTITY);
76  if (!cmpTerrain)
77  return;
78 
79  float water = 0.f;
80  if (floating)
81  {
82  CmpPtr<ICmpWaterManager> cmpWaterManager(context, SYSTEM_ENTITY);
83  if (cmpWaterManager)
84  water = cmpWaterManager->GetExactWaterLevel(x, z);
85  }
86 
87  // Adapt the circle resolution to look reasonable for small and largeish radiuses
88  size_t numPoints = clamp((size_t)(radius*4.0f), (size_t)12, (size_t)48);
89 
90  overlay.m_Coords.reserve((numPoints + 1) * 3);
91 
92  for (size_t i = 0; i <= numPoints; ++i) // use '<=' so it's a closed loop
93  {
94  float a = (float)i * 2 * (float)M_PI / (float)numPoints;
95  float px = x + radius * sinf(a);
96  float pz = z + radius * cosf(a);
97  float py = std::max(water, cmpTerrain->GetExactGroundLevel(px, pz)) + heightOffset;
98  overlay.m_Coords.push_back(px);
99  overlay.m_Coords.push_back(py);
100  overlay.m_Coords.push_back(pz);
101  }
102 }
103 
104 // This method splits up a straight line into a number of line segments each having a length ~= TERRAIN_TILE_SIZE
105 static void SplitLine(std::vector<std::pair<float, float> >& coords, float x1, float y1, float x2, float y2)
106 {
107  float length = sqrtf(SQR(x1 - x2) + SQR(y1 - y2));
108  size_t pieces = ((int)length) / TERRAIN_TILE_SIZE;
109  if (pieces > 0)
110  {
111  float xPieceLength = (x1 - x2) / (float)pieces;
112  float yPieceLength = (y1 - y2) / (float)pieces;
113  for (size_t i = 1; i <= (pieces - 1); ++i)
114  {
115  coords.push_back(std::make_pair(x1 - (xPieceLength * (float)i), y1 - (yPieceLength * (float)i)));
116  }
117  }
118  coords.push_back(std::make_pair(x2, y2));
119 }
120 
121 void SimRender::ConstructSquareOnGround(const CSimContext& context, float x, float z, float w, float h, float a,
122  SOverlayLine& overlay, bool floating, float heightOffset)
123 {
124  overlay.m_Coords.clear();
125 
126  CmpPtr<ICmpTerrain> cmpTerrain(context, SYSTEM_ENTITY);
127  if (!cmpTerrain)
128  return;
129 
130  float water = 0.f;
131  if (floating)
132  {
133  CmpPtr<ICmpWaterManager> cmpWaterManager(context, SYSTEM_ENTITY);
134  if (cmpWaterManager)
135  water = cmpWaterManager->GetExactWaterLevel(x, z);
136  }
137 
138  float c = cosf(a);
139  float s = sinf(a);
140 
141  std::vector<std::pair<float, float> > coords;
142 
143  // Add the first vertex, since SplitLine will be adding only the second end-point of the each line to
144  // the coordinates list. We don't have to worry about the other lines, since the end-point of one line
145  // will be the starting point of the next
146  coords.push_back(std::make_pair(x - w/2*c + h/2*s, z + w/2*s + h/2*c));
147 
148  SplitLine(coords, x - w/2*c + h/2*s, z + w/2*s + h/2*c, x - w/2*c - h/2*s, z + w/2*s - h/2*c);
149  SplitLine(coords, x - w/2*c - h/2*s, z + w/2*s - h/2*c, x + w/2*c - h/2*s, z - w/2*s - h/2*c);
150  SplitLine(coords, x + w/2*c - h/2*s, z - w/2*s - h/2*c, x + w/2*c + h/2*s, z - w/2*s + h/2*c);
151  SplitLine(coords, x + w/2*c + h/2*s, z - w/2*s + h/2*c, x - w/2*c + h/2*s, z + w/2*s + h/2*c);
152 
153  overlay.m_Coords.reserve(coords.size() * 3);
154 
155  for (size_t i = 0; i < coords.size(); ++i)
156  {
157  float px = coords[i].first;
158  float pz = coords[i].second;
159  float py = std::max(water, cmpTerrain->GetExactGroundLevel(px, pz)) + heightOffset;
160  overlay.m_Coords.push_back(px);
161  overlay.m_Coords.push_back(py);
162  overlay.m_Coords.push_back(pz);
163  }
164 }
165 
167 {
168  overlayLine.m_Coords.clear();
169 
170  if (bound.IsEmpty())
171  return;
172 
173  const CVector3D& pMin = bound[0];
174  const CVector3D& pMax = bound[1];
175 
176  // floor square
177  overlayLine.PushCoords(pMin.X, pMin.Y, pMin.Z);
178  overlayLine.PushCoords(pMax.X, pMin.Y, pMin.Z);
179  overlayLine.PushCoords(pMax.X, pMin.Y, pMax.Z);
180  overlayLine.PushCoords(pMin.X, pMin.Y, pMax.Z);
181  overlayLine.PushCoords(pMin.X, pMin.Y, pMin.Z);
182  // roof square
183  overlayLine.PushCoords(pMin.X, pMax.Y, pMin.Z);
184  overlayLine.PushCoords(pMax.X, pMax.Y, pMin.Z);
185  overlayLine.PushCoords(pMax.X, pMax.Y, pMax.Z);
186  overlayLine.PushCoords(pMin.X, pMax.Y, pMax.Z);
187  overlayLine.PushCoords(pMin.X, pMax.Y, pMin.Z);
188 }
189 
191 {
192  overlayLine.m_Coords.clear();
193 
194  if (box.IsEmpty())
195  return;
196 
197  CVector3D corners[8];
198  box.GetCorner(-1, -1, -1, corners[0]);
199  box.GetCorner( 1, -1, -1, corners[1]);
200  box.GetCorner( 1, -1, 1, corners[2]);
201  box.GetCorner(-1, -1, 1, corners[3]);
202  box.GetCorner(-1, 1, -1, corners[4]);
203  box.GetCorner( 1, 1, -1, corners[5]);
204  box.GetCorner( 1, 1, 1, corners[6]);
205  box.GetCorner(-1, 1, 1, corners[7]);
206 
207  overlayLine.PushCoords(corners[0]);
208  overlayLine.PushCoords(corners[1]);
209  overlayLine.PushCoords(corners[2]);
210  overlayLine.PushCoords(corners[3]);
211  overlayLine.PushCoords(corners[0]);
212 
213  overlayLine.PushCoords(corners[4]);
214  overlayLine.PushCoords(corners[5]);
215  overlayLine.PushCoords(corners[6]);
216  overlayLine.PushCoords(corners[7]);
217  overlayLine.PushCoords(corners[4]);
218 }
219 
220 void SimRender::ConstructGimbal(const CVector3D& center, float radius, SOverlayLine& out, size_t numSteps)
221 {
222  ENSURE(numSteps > 0 && numSteps % 4 == 0); // must be a positive multiple of 4
223 
224  out.m_Coords.clear();
225 
226  size_t fullCircleSteps = numSteps;
227  const float angleIncrement = 2.f*M_PI/fullCircleSteps;
228 
229  const CVector3D X_UNIT(1, 0, 0);
230  const CVector3D Y_UNIT(0, 1, 0);
231  const CVector3D Z_UNIT(0, 0, 1);
232  CVector3D rotationVector(0, 0, radius); // directional vector based in the center that we will be rotating to get the gimbal points
233 
234  // first draw a quarter of XZ gimbal; then complete the XY gimbal; then continue the XZ gimbal and finally add the YZ gimbal
235  // (that way we can keep a single continuous line)
236 
237  // -- XZ GIMBAL (PART 1/2) -----------------------------------------------
238 
239  CQuaternion xzRotation;
240  xzRotation.FromAxisAngle(Y_UNIT, angleIncrement);
241 
242  for (size_t i = 0; i < fullCircleSteps/4; ++i) // complete only a quarter of the way
243  {
244  out.PushCoords(center + rotationVector);
245  rotationVector = xzRotation.Rotate(rotationVector);
246  }
247 
248  // -- XY GIMBAL ----------------------------------------------------------
249 
250  // now complete the XY gimbal while the XZ gimbal is interrupted
251  CQuaternion xyRotation;
252  xyRotation.FromAxisAngle(Z_UNIT, angleIncrement);
253 
254  for (size_t i = 0; i < fullCircleSteps; ++i) // note the <; the last point of the XY gimbal isn't added, because the XZ gimbal will add it
255  {
256  out.PushCoords(center + rotationVector);
257  rotationVector = xyRotation.Rotate(rotationVector);
258  }
259 
260  // -- XZ GIMBAL (PART 2/2) -----------------------------------------------
261 
262  // resume the XZ gimbal to completion
263  for (size_t i = fullCircleSteps/4; i < fullCircleSteps; ++i) // exclude the last point of the circle so the YZ gimbal can add it
264  {
265  out.PushCoords(center + rotationVector);
266  rotationVector = xzRotation.Rotate(rotationVector);
267  }
268 
269  // -- YZ GIMBAL ----------------------------------------------------------
270 
271  CQuaternion yzRotation;
272  yzRotation.FromAxisAngle(X_UNIT, angleIncrement);
273 
274  for (size_t i = 0; i <= fullCircleSteps; ++i)
275  {
276  out.PushCoords(center + rotationVector);
277  rotationVector = yzRotation.Rotate(rotationVector);
278  }
279 }
280 
282 {
283  outX.m_Coords.clear();
284  outY.m_Coords.clear();
285  outZ.m_Coords.clear();
286 
287  outX.m_Color = CColor(1, 0, 0, .5f); // X axis; red
288  outY.m_Color = CColor(0, 1, 0, .5f); // Y axis; green
289  outZ.m_Color = CColor(0, 0, 1, .5f); // Z axis; blue
290 
291  outX.m_Thickness = 2;
292  outY.m_Thickness = 2;
293  outZ.m_Thickness = 2;
294 
295  CVector3D origin = coordSystem.GetTranslation();
296  outX.PushCoords(origin);
297  outY.PushCoords(origin);
298  outZ.PushCoords(origin);
299 
300  outX.PushCoords(origin + CVector3D(coordSystem(0,0), coordSystem(1,0), coordSystem(2,0)));
301  outY.PushCoords(origin + CVector3D(coordSystem(0,1), coordSystem(1,1), coordSystem(2,1)));
302  outZ.PushCoords(origin + CVector3D(coordSystem(0,2), coordSystem(1,2), coordSystem(2,2)));
303 }
304 
305 void SimRender::SmoothPointsAverage(std::vector<CVector2D>& points, bool closed)
306 {
307  PROFILE("SmoothPointsAverage");
308 
309  size_t n = points.size();
310  if (n < 2)
311  return; // avoid out-of-bounds array accesses, and leave the points unchanged
312 
313  std::vector<CVector2D> newPoints;
314  newPoints.resize(points.size());
315 
316  // Handle the end points appropriately
317  if (closed)
318  {
319  newPoints[0] = (points[n-1] + points[0] + points[1]) / 3.f;
320  newPoints[n-1] = (points[n-2] + points[n-1] + points[0]) / 3.f;
321  }
322  else
323  {
324  newPoints[0] = points[0];
325  newPoints[n-1] = points[n-1];
326  }
327 
328  // Average all the intermediate points
329  for (size_t i = 1; i < n-1; ++i)
330  newPoints[i] = (points[i-1] + points[i] + points[i+1]) / 3.f;
331 
332  points.swap(newPoints);
333 }
334 
335 static CVector2D EvaluateSpline(float t, CVector2D a0, CVector2D a1, CVector2D a2, CVector2D a3, float offset)
336 {
337  // Compute position on spline
338  CVector2D p = a0*(t*t*t) + a1*(t*t) + a2*t + a3;
339 
340  // Compute unit-vector direction of spline
341  CVector2D dp = (a0*(3*t*t) + a1*(2*t) + a2).Normalized();
342 
343  // Offset position perpendicularly
344  return p + CVector2D(dp.Y*-offset, dp.X*offset);
345 }
346 
347 void SimRender::InterpolatePointsRNS(std::vector<CVector2D>& points, bool closed, float offset, int segmentSamples /* = 4 */)
348 {
349  PROFILE("InterpolatePointsRNS");
350  ENSURE(segmentSamples > 0);
351 
352  std::vector<CVector2D> newPoints;
353 
354  // (This does some redundant computations for adjacent vertices,
355  // but it's fairly fast (<1ms typically) so we don't worry about it yet)
356 
357  // TODO: Instead of doing a fixed number of line segments between each
358  // control point, it should probably be somewhat adaptive to get a nicer
359  // curve with fewer points
360 
361  size_t n = points.size();
362 
363  if (closed)
364  {
365  if (n < 1)
366  return; // we need at least a single point to not crash
367  }
368  else
369  {
370  if (n < 2)
371  return; // in non-closed mode, we need at least n=2 to not crash
372  }
373 
374  size_t imax = closed ? n : n-1;
375  newPoints.reserve(imax*segmentSamples);
376 
377  // these are primarily used inside the loop, but for open paths we need them outside the loop once to compute the last point
378  CVector2D a0;
379  CVector2D a1;
380  CVector2D a2;
381  CVector2D a3;
382 
383  for (size_t i = 0; i < imax; ++i)
384  {
385  // Get the relevant points for this spline segment; each step interpolates the segment between p1 and p2; p0 and p3 are the points
386  // before p1 and after p2, respectively; they're needed to compute tangents and whatnot.
387  CVector2D p0; // normally points[(i-1+n)%n], but it's a bit more complicated due to open/closed paths -- see below
388  CVector2D p1 = points[i];
389  CVector2D p2 = points[(i+1)%n];
390  CVector2D p3; // normally points[(i+2)%n], but it's a bit more complicated due to open/closed paths -- see below
391 
392  if (!closed && (i == 0))
393  // p0's point index is out of bounds, and we can't wrap around because we're in non-closed mode -- create an artificial point
394  // that extends p1 -> p0 (i.e. the first segment's direction)
395  p0 = points[0] + (points[0] - points[1]);
396  else
397  // standard wrap-around case
398  p0 = points[(i-1+n)%n]; // careful; don't use (i-1)%n here, as the result is machine-dependent for negative operands (e.g. if i==0, the result could be either -1 or n-1)
399 
400 
401  if (!closed && (i == n-2))
402  // p3's point index is out of bounds; create an artificial point that extends p_(n-2) -> p_(n-1) (i.e. the last segment's direction)
403  // (note that p2's index should not be out of bounds, because in non-closed mode imax is reduced by 1)
404  p3 = points[n-1] + (points[n-1] - points[n-2]);
405  else
406  // standard wrap-around case
407  p3 = points[(i+2)%n];
408 
409 
410  // Do the RNS computation (based on GPG4 "Nonuniform Splines")
411  float l1 = (p2 - p1).Length(); // length of spline segment (i)..(i+1)
412  CVector2D s0 = (p1 - p0).Normalized(); // unit vector of spline segment (i-1)..(i)
413  CVector2D s1 = (p2 - p1).Normalized(); // unit vector of spline segment (i)..(i+1)
414  CVector2D s2 = (p3 - p2).Normalized(); // unit vector of spline segment (i+1)..(i+2)
415  CVector2D v1 = (s0 + s1).Normalized() * l1; // spline velocity at i
416  CVector2D v2 = (s1 + s2).Normalized() * l1; // spline velocity at i+1
417 
418  // Compute standard cubic spline parameters
419  a0 = p1*2 + p2*-2 + v1 + v2;
420  a1 = p1*-3 + p2*3 + v1*-2 + v2*-1;
421  a2 = v1;
422  a3 = p1;
423 
424  // Interpolate at regular points across the interval
425  for (int sample = 0; sample < segmentSamples; sample++)
426  newPoints.push_back(EvaluateSpline(sample/((float) segmentSamples), a0, a1, a2, a3, offset));
427 
428  }
429 
430  if (!closed)
431  // if the path is open, we should take care to include the last control point
432  // NOTE: we can't just do push_back(points[n-1]) here because that ignores the offset
433  newPoints.push_back(EvaluateSpline(1.f, a0, a1, a2, a3, offset));
434 
435  points.swap(newPoints);
436 }
437 
438 void SimRender::ConstructDashedLine(const std::vector<CVector2D>& keyPoints, SDashedLine& dashedLineOut, const float dashLength, const float blankLength)
439 {
440  // sanity checks
441  if (dashLength <= 0)
442  return;
443 
444  if (blankLength <= 0)
445  return;
446 
447  if (keyPoints.size() < 2)
448  return;
449 
450  dashedLineOut.m_Points.clear();
451  dashedLineOut.m_StartIndices.clear();
452 
453  // walk the line, counting the total length so far at each node point. When the length exceeds dashLength, cut the last segment at the
454  // required length and continue for blankLength along the line to start a new dash segment.
455 
456  // TODO: we should probably extend this function to also allow for closed lines. I was thinking of slightly scaling the dash/blank length
457  // so that it fits the length of the curve, but that requires knowing the length of the curve upfront which is sort of expensive to compute
458  // (O(n) and lots of square roots).
459 
460  bool buildingDash = true; // true if we're building a dash, false if a blank
461  float curDashLength = 0; // builds up the current dash/blank's length as we walk through the line nodes
462  CVector2D dashLastPoint = keyPoints[0]; // last point of the current dash/blank being built.
463 
464  // register the first starting node of the first dash
465  dashedLineOut.m_Points.push_back(keyPoints[0]);
466  dashedLineOut.m_StartIndices.push_back(0);
467 
468  // index of the next key point on the path. Must always point to a node that is further along the path than dashLastPoint, so we can
469  // properly take a direction vector along the path.
470  size_t i = 0;
471 
472  while(i < keyPoints.size() - 1)
473  {
474  // get length of this segment
475  CVector2D segmentVector = keyPoints[i + 1] - dashLastPoint; // vector from our current point along the path to nextNode
476  float segmentLength = segmentVector.Length();
477 
478  float targetLength = (buildingDash ? dashLength : blankLength);
479  if (curDashLength + segmentLength > targetLength)
480  {
481  // segment is longer than the dash length we still have to go, so we'll need to cut it; create a cut point along the segment
482  // line that is of just the required length to complete the dash, then make it the base point for the next dash/blank.
483  float cutLength = targetLength - curDashLength;
484  CVector2D cutPoint = dashLastPoint + (segmentVector.Normalized() * cutLength);
485 
486  // start a new dash or blank in the next iteration
487  curDashLength = 0;
488  buildingDash = !buildingDash; // flip from dash to blank and vice-versa
489  dashLastPoint = cutPoint;
490 
491  // don't increment i, we haven't fully traversed this segment yet so we still need to use the same point to take the
492  // direction vector with in the next iteration
493 
494  // this cut point is either the end of the current dash or the beginning of a new dash; either way, we're gonna need it
495  // in the points array.
496  dashedLineOut.m_Points.push_back(cutPoint);
497 
498  if (buildingDash)
499  {
500  // if we're gonna be building a new dash, then cutPoint is now the base point of that new dash, so let's register its
501  // index as a start index of a dash.
502  dashedLineOut.m_StartIndices.push_back(dashedLineOut.m_Points.size() - 1);
503  }
504 
505  }
506  else
507  {
508  // the segment from lastDashPoint to keyPoints[i+1] doesn't suffice to complete the dash, so we need to add keyPoints[i+1]
509  // to this dash's points and continue from there
510 
511  if (buildingDash)
512  // still building the dash, add it to the output (we don't need to store the blanks)
513  dashedLineOut.m_Points.push_back(keyPoints[i+1]);
514 
515  curDashLength += segmentLength;
516  dashLastPoint = keyPoints[i+1];
517  i++;
518 
519  }
520 
521  }
522 
523 }
524 
525 void SimRender::AngularStepFromChordLen(const float maxChordLength, const float radius, float& out_stepAngle, unsigned& out_numSteps)
526 {
527  float maxAngle = Geometry::ChordToCentralAngle(maxChordLength, radius);
528  out_numSteps = ceilf(float(2*M_PI)/maxAngle);
529  out_stepAngle = float(2*M_PI)/out_numSteps;
530 }
531 
532 // TODO: this serves a similar purpose to SplitLine above, but is more general. Also, SplitLine seems to be implemented more
533 // efficiently, might be nice to take some cues from it
534 void SimRender::SubdividePoints(std::vector<CVector2D>& points, float maxSegmentLength, bool closed)
535 {
536  size_t numControlPoints = points.size();
537  if (numControlPoints < 2)
538  return;
539 
540  ENSURE(maxSegmentLength > 0);
541 
542  size_t endIndex = numControlPoints;
543  if (!closed && numControlPoints > 2)
544  endIndex--;
545 
546  std::vector<CVector2D> newPoints;
547 
548  for (size_t i = 0; i < endIndex; i++)
549  {
550  const CVector2D& curPoint = points[i];
551  const CVector2D& nextPoint = points[(i+1) % numControlPoints];
552  const CVector2D line(nextPoint - curPoint);
553  CVector2D lineDirection = line.Normalized();
554 
555  // include control point i + a list of intermediate points between i and i + 1 (excluding i+1 itself)
556  newPoints.push_back(curPoint);
557 
558  // calculate how many intermediate points are needed so that each segment is of length <= maxSegmentLength
559  float lineLength = line.Length();
560  size_t numSegments = (size_t) ceilf(lineLength / maxSegmentLength);
561  float segmentLength = lineLength / numSegments;
562 
563  for (size_t s = 1; s < numSegments; ++s) // start at one, we already included curPoint
564  {
565  newPoints.push_back(curPoint + lineDirection * (s * segmentLength));
566  }
567  }
568 
569  points.swap(newPoints);
570 }
#define M_PI
Definition: wposix.h:64
Line-based overlay, with world-space coordinates, rendered in the world potentially behind other obje...
Definition: Overlay.h:36
float X
Definition: Vector2D.h:157
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
Definition: Overlay.h:34
virtual float GetExactGroundLevel(float x, float z)=0
void ConstructDashedLine(const std::vector< CVector2D > &linePoints, SDashedLine &dashedLineOut, const float dashLength, const float blankLength)
Creates a dashed line from the given line, dash length, and blank space between.
Definition: Render.cpp:438
static void out(const wchar_t *fmt,...)
Definition: wdbg_sym.cpp:419
void InterpolatePointsRNS(std::vector< CVector2D > &points, bool closed, float offset, int segmentSamples=4)
Updates the given points to include intermediate points interpolating between the original control po...
Definition: Render.cpp:347
static CVector2D EvaluateSpline(float t, CVector2D a0, CVector2D a1, CVector2D a2, CVector2D a3, float offset)
Definition: Render.cpp:335
CVector3D Rotate(const CVector3D &vec) const
Definition: Quaternion.cpp:300
#define SQR(x)
Definition: MathUtil.h:23
Contains pointers to various &#39;global&#39; objects that are needed by the simulation code, to allow easy access without using real (evil) global variables.
Definition: SimContext.h:32
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:44
std::vector< float > m_Coords
Definition: Overlay.h:41
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void ConstructCircleOnGround(const CSimContext &context, float x, float z, float radius, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line as a circle with given center and radius, conforming to terrain.
Definition: Render.cpp:70
float X
Definition: Vector3D.h:31
void ConstructLineOnGround(const CSimContext &context, const std::vector< float > &xz, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line from given points, conforming to terrain.
Definition: Render.cpp:35
CVector2D Normalized() const
Definition: Vector2D.h:124
void SubdividePoints(std::vector< CVector2D > &points, float maxSegmentLength, bool closed)
Subdivides a list of points into segments of maximum length maxSegmentLength that are of equal size b...
Definition: Render.cpp:534
void PushCoords(const CVector3D &v)
Definition: Overlay.h:44
float Y
Definition: Vector3D.h:31
void AngularStepFromChordLen(const float maxChordLength, const float radius, float &out_stepAngle, unsigned &out_numSteps)
Computes angular step parameters out_stepAngle and out_numSteps, given a maxChordLength on a circle o...
Definition: Render.cpp:525
virtual float GetExactWaterLevel(float x, float z)=0
Get the current water level at the given point.
std::vector< CVector2D > m_Points
Packed array of consecutive dashes&#39; points. Use m_StartIndices to navigate it.
Definition: Render.h:39
float Length() const
Definition: Vector2D.h:112
#define PROFILE(name)
Definition: Profile.h:195
std::vector< size_t > m_StartIndices
Start indices in m_Points of each dash.
Definition: Render.h:46
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
float Y
Definition: Vector2D.h:157
Helper functions related to rendering.
static void SplitLine(std::vector< std::pair< float, float > > &coords, float x1, float y1, float x2, float y2)
Definition: Render.cpp:105
u8 m_Thickness
Definition: Overlay.h:42
void ConstructSquareOnGround(const CSimContext &context, float x, float z, float w, float h, float a, SOverlayLine &overlay, bool floating, float heightOffset=0.25f)
Constructs overlay line as rectangle with given center and dimensions, conforming to terrain...
Definition: Render.cpp:121
void GetCorner(int u, int v, int w, CVector3D &out) const
Returns the corner at coordinate (u, v, w).
void SmoothPointsAverage(std::vector< CVector2D > &points, bool closed)
Updates the given points so each point is averaged with its neighbours, resulting in a somewhat smoot...
Definition: Render.cpp:305
float Z
Definition: Vector3D.h:31
void FromAxisAngle(const CVector3D &axis, float angle)
Definition: Quaternion.cpp:260
float ChordToCentralAngle(const float chordLength, const float radius)
Given a circle of radius radius, and a chord of length chordLength on this circle, computes the central angle formed by connecting the chord&#39;s endpoints to the center of the circle.
Definition: Geometry.cpp:48
void ConstructAxesMarker(const CMatrix3D &coordSystem, SOverlayLine &outX, SOverlayLine &outY, SOverlayLine &outZ)
Constructs 3D axis marker overlay lines for the given coordinate system.
Definition: Render.cpp:281
CColor m_Color
Definition: Overlay.h:40
CVector3D GetTranslation() const
Definition: Matrix3D.cpp:195
static float Length(const SVec3 v)
Definition: mikktspace.cpp:112
void ConstructBoxOutline(const CBoundingBoxOriented &box, SOverlayLine &overlayLine)
Constructs a solid outline of an arbitrarily-aligned bounding box.
Definition: Render.cpp:190
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
void ConstructGimbal(const CVector3D &center, float radius, SOverlayLine &out, size_t numSteps=16)
Constructs a simple gimbal outline with the given radius and center.
Definition: Render.cpp:220
Helper functions related to geometry algorithms.