Waypoint.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. /******************************************************************************/
  6. #define CC4_WAYPOINT CC4('W','P','N','T')
  7. /******************************************************************************/
  8. Cache<Waypoint> Waypoints("Waypoint");
  9. /******************************************************************************/
  10. // MANAGE
  11. /******************************************************************************/
  12. void Waypoint::zero()
  13. {
  14. loop_mode=SINGLE;
  15. }
  16. Waypoint::Waypoint() {zero();}
  17. Waypoint& Waypoint::del()
  18. {
  19. points.del();
  20. zero();
  21. return T;
  22. }
  23. /******************************************************************************/
  24. // GET / SET
  25. /******************************************************************************/
  26. Flt Waypoint::length()C
  27. {
  28. if(points.elms()<=1)return 0;
  29. switch(loop_mode)
  30. {
  31. case LOOP : return points.last().total_length + Dist(points.first().pos, points.last().pos);
  32. case PING_PONG: return points.last().total_length*2;
  33. default : return points.last().total_length ; // SINGLE
  34. }
  35. }
  36. /******************************************************************************/
  37. Vec Waypoint::pos(Flt x, Bool smooth)C
  38. {
  39. switch(points.elms())
  40. {
  41. case 0: return 0;
  42. case 1: return points.first().pos;
  43. default:
  44. {
  45. switch(loop_mode)
  46. {
  47. case LOOP:
  48. {
  49. x=Frac(x, length());
  50. // binary search
  51. Int l=0, r=points.elms(); for(; l<r; ){Int mid=UInt(l+r)/2; if(x<points[mid].total_length)r=mid;else l=mid+1;}
  52. if( l!=points.elms())
  53. {
  54. C Point &from=points[l-1],
  55. &to =points[l ];
  56. Flt dl =to.total_length-from.total_length; if(!dl)return from.pos;
  57. Flt s =(x-from.total_length)/dl;
  58. if(!smooth)return Lerp ( from.pos, to.pos, s);
  59. return Lerp4(points[Mod(l-2, points.elms())].pos, from.pos, to.pos, points[Mod(l+1, points.elms())].pos, s);
  60. }
  61. else // on the last virtual edge (last->first)
  62. {
  63. C Point &from=points.last (),
  64. &to =points.first();
  65. Flt dl =Dist(from.pos,to.pos); if(!dl)return from.pos;
  66. Flt s =(x-from.total_length)/dl;
  67. if(!smooth)return Lerp ( from.pos, to.pos, s);
  68. return Lerp4(points[Mod(points.elms()-2, points.elms())].pos, from.pos, to.pos, points[Mod(1, points.elms())].pos, s);
  69. }
  70. }break;
  71. case PING_PONG:
  72. {
  73. Flt length=T.length();
  74. x=Frac(x, length); if(x>length*0.5f)x=length-x;
  75. // binary search
  76. Int l=0, r=points.elms(); for(; l<r; ){Int mid=UInt(l+r)/2; if(x<points[mid].total_length)r=mid;else l=mid+1;}
  77. C Point &from=points[l-1],
  78. &to =points[l ];
  79. Flt dl =to.total_length-from.total_length; if(!dl)return from.pos;
  80. Flt s =(x-from.total_length)/dl;
  81. if(!smooth)return Lerp ( from.pos, to.pos, s);
  82. return Lerp4(points[Mod(l-2, points.elms())].pos, from.pos, to.pos, points[Mod(l+1, points.elms())].pos, s);
  83. }break;
  84. default: // SINGLE
  85. {
  86. if(x<= 0)return points.first().pos;
  87. if(x>=length())return points.last ().pos;
  88. // binary search
  89. Int l=0, r=points.elms(); for(; l<r; ){Int mid=UInt(l+r)/2; if(x<points[mid].total_length)r=mid;else l=mid+1;}
  90. C Point &from=points[l-1],
  91. &to =points[l ];
  92. Flt dl =to.total_length-from.total_length; if(!dl)return from.pos;
  93. Flt s =(x-from.total_length)/dl;
  94. if(!smooth)return Lerp ( from.pos, to.pos, s);
  95. return Lerp4(points[Max(l-2, 0)].pos, from.pos, to.pos, points[Min(l+1, points.elms()-1)].pos, s);
  96. }break;
  97. }
  98. }break;
  99. }
  100. }
  101. /******************************************************************************/
  102. // OPERATIONS
  103. /******************************************************************************/
  104. void Waypoint::New(C Vec &pos)
  105. {
  106. points.New().pos=pos;
  107. updateTotalLengths();
  108. }
  109. void Waypoint::New(Int i, C Vec &pos)
  110. {
  111. points.NewAt(i).pos=pos;
  112. updateTotalLengths();
  113. }
  114. Waypoint& Waypoint::remove(Int i)
  115. {
  116. if(InRange(i, points))
  117. {
  118. points.remove(i, true);
  119. updateTotalLengths();
  120. }
  121. return T;
  122. }
  123. /******************************************************************************/
  124. Waypoint& Waypoint::rol () {points. rotateOrder(-1); return updateTotalLengths();}
  125. Waypoint& Waypoint::ror () {points. rotateOrder( 1); return updateTotalLengths();}
  126. Waypoint& Waypoint::reverse() {points.reverseOrder( ); return updateTotalLengths();}
  127. /******************************************************************************/
  128. Waypoint& Waypoint::updateTotalLengths()
  129. {
  130. if(points.elms())
  131. {
  132. Flt length=points[0].total_length=0;
  133. for(Int i=1; i<points.elms(); i++)
  134. {
  135. length+=Dist(points[i-1].pos, points[i].pos);
  136. points[i].total_length=length;
  137. }
  138. }
  139. return T;
  140. }
  141. /******************************************************************************/
  142. // DRAW
  143. /******************************************************************************/
  144. static void DrawPoint(C Vec &pos, Flt radius)
  145. {
  146. #define N 8
  147. Vec2 prev(radius, 0);
  148. REP(N)
  149. {
  150. Vec2 next; CosSin(next.x, next.y, i*(PI2/N)); next*=radius;
  151. VI.line(pos+prev. xy0(), pos+next. xy0());
  152. VI.line(pos+prev._0yx(), pos+next._0yx());
  153. prev=next;
  154. }
  155. }
  156. void Waypoint::draw(C Color &point_color, C Color &edge_color, Flt point_radius, Int edge_steps)C
  157. {
  158. if(edge_color.a)
  159. {
  160. const Flt step=1.0f/edge_steps;
  161. const Vec up(0, point_radius, 0);
  162. VI.color(edge_color);
  163. REP(points.elms()-1)
  164. {
  165. C Point &a=points[i ],
  166. &b=points[i+1];
  167. if(edge_steps>1)
  168. {
  169. Vec cur=b.pos; const Flt s=(b.total_length-a.total_length)*step;
  170. REP(edge_steps)
  171. {
  172. Vec next=pos(a.total_length+i*s, true);
  173. VI.line(cur-up, next-up);
  174. VI.line(cur+up, next+up);
  175. cur=next;
  176. }
  177. }else
  178. {
  179. VI.line(a.pos-up, b.pos-up);
  180. VI.line(a.pos+up, b.pos+up);
  181. }
  182. }
  183. if(loop_mode==LOOP && points.elms()>=3)
  184. {
  185. C Point &a=points.last (),
  186. &b=points.first();
  187. if(edge_steps>1)
  188. {
  189. Vec cur=b.pos; const Flt s=(length()-a.total_length)*step;
  190. REP(edge_steps)
  191. {
  192. Vec next=pos(a.total_length+i*s, true);
  193. VI.line(cur-up, next-up);
  194. VI.line(cur+up, next+up);
  195. cur=next;
  196. }
  197. }else
  198. {
  199. VI.line(a.pos-up, b.pos-up);
  200. VI.line(a.pos+up, b.pos+up);
  201. }
  202. }
  203. VI.end();
  204. }
  205. if(point_color.a && point_radius>EPS)
  206. {
  207. VI.color(point_color); REPA(points)DrawPoint(points[i].pos, point_radius);
  208. VI.end ( );
  209. }
  210. }
  211. void DrawWaypoint(C Vec &pos, C Color &color, Flt radius)
  212. {
  213. if(color.a)
  214. {
  215. VI.color(color); DrawPoint(pos, radius);
  216. VI.end ( );
  217. }
  218. }
  219. /******************************************************************************/
  220. // IO
  221. /******************************************************************************/
  222. Bool Waypoint::saveData(File &f)C
  223. {
  224. f.cmpUIntV(0); // version
  225. if(points._saveRaw(f))
  226. {
  227. f.putByte(loop_mode);
  228. return f.ok();
  229. }
  230. return false;
  231. }
  232. Bool Waypoint::loadData(File &f)
  233. {
  234. switch(f.decUIntV()) // version
  235. {
  236. case 0: if(points._loadRaw(f))
  237. {
  238. loop_mode=LOOP_MODE(f.getByte());
  239. if(f.ok())return true;
  240. }break;
  241. }
  242. del(); return false;
  243. }
  244. /******************************************************************************/
  245. Bool Waypoint::save(File &f)C
  246. {
  247. f.putUInt(CC4_WAYPOINT);
  248. return saveData(f);
  249. }
  250. Bool Waypoint::load(File &f)
  251. {
  252. if(f.getUInt()==CC4_WAYPOINT)return loadData(f);
  253. del(); return false;
  254. }
  255. /******************************************************************************/
  256. Bool Waypoint::save(C Str &name)C
  257. {
  258. File f; if(f.writeTry(name)){if(save(f) && f.flush())return true; f.del(); FDelFile(name);}
  259. return false;
  260. }
  261. Bool Waypoint::load(C Str &name)
  262. {
  263. File f; if(f.readTry(name))return load(f);
  264. del(); return false;
  265. }
  266. /******************************************************************************/
  267. }}
  268. /******************************************************************************/