bacwar.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #include "metaballs.h"
  2. #include "game.h"
  3. #include <QTime>
  4. // for readability, the screen and texture sizes are hard-coded
  5. const float SCREEN_WIDTH=640.0f;
  6. const float SCREEN_HEIGHT=360.0f;
  7. VGPath path;
  8. VGPaint paint;
  9. // images
  10. VGuint bgImage;
  11. VGuint centerImage;
  12. VGuint capsuleImage;
  13. // temp buffer for transformed path coordinates
  14. VGubyte moveTo=VG_MOVE_TO_ABS;
  15. VGubyte lineTo=VG_LINE_TO_ABS;
  16. VGubyte closePath=VG_CLOSE_PATH;
  17. /** walltime */
  18. float t;
  19. int frames=0;
  20. #define BALL_COUNT 16
  21. Ball *balls = 0;
  22. MetaballSystem *mbs;
  23. VGPath blobs[BALL_COUNT];
  24. QVector2D capsulePosition; // where is the medical capsule laying
  25. float capsulePower;
  26. /**
  27. * Loads a PNG file and creates VGImage using the 32bit image data.
  28. */
  29. VGImage loadVGImage(QString filename)
  30. {
  31. QImage texture;
  32. if(!texture.load(filename))
  33. {
  34. qDebug("loadVGImage cannot load '%s'", filename);
  35. return VG_INVALID_HANDLE;
  36. }
  37. int w=texture.width();
  38. int h=texture.height();
  39. if (w<1 || h<1) return VG_INVALID_HANDLE;
  40. VGImage image = vgCreateImage(VG_sARGB_8888, w, h, VG_IMAGE_QUALITY_FASTER);
  41. if(image==VG_INVALID_HANDLE)
  42. {
  43. VGErrorCode err = vgGetError();
  44. qDebug("loadVGImage error 0x%x", err);
  45. }
  46. vgImageSubData(image, (QRgb*)texture.bits(), w*4, VG_sARGB_8888, 0, 0, w, h);
  47. return image;
  48. }
  49. /**
  50. *
  51. * Initialize the game. This is called once when the application is starting up.
  52. *
  53. */
  54. void game_init()
  55. {
  56. capsulePower = -1.0f; // capsule is not on the table
  57. // Create the balls
  58. balls = new Ball[ BALL_COUNT ];
  59. // Initialize the balls
  60. for (int f=0; f<BALL_COUNT; f++) {
  61. balls[f].pos = QVector2D( (rand() & 255) * SCREEN_WIDTH / 255.0f,(rand() & 255) * SCREEN_HEIGHT / 255.0f);
  62. balls[f].size = 2+(rand() & 3);
  63. }
  64. // Create metaballsystem to control the balls.
  65. mbs = new MetaballSystem( BALL_COUNT, balls, 2.0, 4*0.0015);
  66. }
  67. /**
  68. *
  69. * Destroy everything. Will be called when the application is about to exit.
  70. *
  71. */
  72. void game_destroy()
  73. {
  74. delete mbs; mbs = 0;
  75. delete [] balls; balls = 0;
  76. }
  77. /**
  78. *
  79. * Called after init. And everytime we are coming back from background.
  80. *
  81. */
  82. void game_prepare()
  83. {
  84. vgSeti(VG_FILL_RULE, VG_NON_ZERO);
  85. bgImage = loadVGImage(":/images/bg.png");
  86. centerImage = loadVGImage(":/images/center.png");
  87. capsuleImage = loadVGImage(":/images/capsule.png");
  88. paint = vgCreatePaint();
  89. vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
  90. vgSetColor(paint, 0xff00ffff);
  91. path=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
  92. vguRect(path, 0, 0, 4, 4);
  93. for(int i=0;i<mbs->ballCount;i++)
  94. {
  95. blobs[i]=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
  96. }
  97. }
  98. /**
  99. *
  100. * Called before destroy. And everytime we are going to background.
  101. *
  102. */
  103. void game_release()
  104. {
  105. vgDestroyImage( bgImage ); bgImage = VG_INVALID_HANDLE;
  106. vgDestroyImage( centerImage ); centerImage = VG_INVALID_HANDLE;
  107. vgDestroyImage( capsuleImage ); capsuleImage = VG_INVALID_HANDLE;
  108. vgDestroyPath(path);
  109. vgDestroyPaint(paint);
  110. for(int i=0;i<mbs->ballCount;i++)
  111. {
  112. vgDestroyPath(blobs[i]);
  113. }
  114. }
  115. /**
  116. *
  117. * Update. Walltime is the seconds we have been running
  118. *
  119. */
  120. void game_update(float walltime)
  121. {
  122. float frameTime = walltime-t;
  123. if (frameTime>0.1f) frameTime = 0.1f;
  124. t=walltime;
  125. QVector2D expos,temp;
  126. // Update the capsule
  127. if (capsulePower>=0.0f) {
  128. for (int f=0; f<BALL_COUNT; f++) {
  129. temp = balls[f].pos - capsulePosition;
  130. float invpower = QVector2D::dotProduct(temp, temp)*0.3f;
  131. invpower = (10000.0f / (invpower+1.0f)) * frameTime * capsulePower;
  132. if (invpower>1.0f) invpower = 1.0f;
  133. if (balls[f].size>1.0f) {
  134. balls[f].size -= (balls[f].size-1.0f) * invpower * 0.1f;
  135. }
  136. //if (invpower>10.0f) balls[f].size -= 2;
  137. //if (balls[f].size<1.0f) balls[f].size = 1.0f;
  138. balls[f].dir += temp*invpower;
  139. }
  140. }
  141. // Update the balls.
  142. for (int f=0; f<mbs->ballCount; f++) {
  143. Ball &b = mbs->balls[f];
  144. // gravity to other balls.
  145. for (int g=0; g<mbs->ballCount; g++)
  146. if (f!=g) {
  147. Ball &b2 = mbs->balls[g];
  148. temp = b2.pos - b.pos;
  149. float invpower = QVector2D::dotProduct(temp,temp)*0.05f;
  150. //if (invpower<2.0f) invpower = 2.0f;
  151. temp *= (2000.0f / (invpower*invpower+1.0f))*frameTime;
  152. b.dir += temp;
  153. b2.dir -= temp;
  154. }
  155. // Some random movement
  156. b.dir += QVector2D( (float)(rand() & 255)/255.0f-0.5f, (float)(rand() & 255)/255.0f-0.5f ) * frameTime * 500.0f;
  157. b.size += (10.0f - b.size) * frameTime * 0.05f;
  158. expos = b.pos;
  159. temp = (b.dir * frameTime);
  160. b.pos += temp;
  161. b.dir -= temp;
  162. // bound checking
  163. if (b.pos.x() < 0 || b.pos.x() > SCREEN_WIDTH) {b.dir.setX( -b.dir.x() ); b.pos = expos; }
  164. if (b.pos.y() < 0 || b.pos.y() > SCREEN_HEIGHT) {b.dir.setY( -b.dir.y() ); b.pos = expos; }
  165. }
  166. }
  167. void debug_point(float x, float y, int color)
  168. {
  169. vgLoadIdentity();
  170. vgTranslate(x, y);
  171. vgSetColor(paint, color);
  172. vgSetPaint(paint, VG_FILL_PATH | VG_STROKE_PATH);
  173. vgDrawPath(path, VG_FILL_PATH | VG_STROKE_PATH);
  174. vgLoadIdentity();
  175. }
  176. void draw_balls()
  177. {
  178. float step = 10;
  179. /*
  180. # First, track the border for all balls and store
  181. # it to pos0 and edgePos. The latter will move along the border,
  182. # pos0 stays at the initial coordinates.
  183. */
  184. for(int i=0;i<mbs->ballCount;i++)
  185. {
  186. Ball &b = mbs->balls[i];
  187. //b.pos = QVector2D(sin(t*.2+i*7.1)*200+320,cos(i*4.1+t*.3)*150+180);
  188. QVector2D p=b.pos;
  189. b.pos0 = mbs->trackTheBorder(b.pos+QVector2D(0,1));
  190. b.edgePos = b.pos0;
  191. b.tracking = true;
  192. b.sharedBall=-1;
  193. b.verticeCount=0;
  194. vgClearPath(blobs[i], VG_PATH_CAPABILITY_APPEND_TO);
  195. p=b.pos0;
  196. float xy[2]={p.x(), SCREEN_HEIGHT-p.y()};
  197. #if 0
  198. debug_point(xy[0], xy[1], 0xff0000ff);
  199. #endif
  200. // vgAppendPathData(blobs[i], 1, &moveTo, xy);
  201. b.commands[b.verticeCount]=VG_MOVE_TO_ABS;
  202. b.vertices[b.verticeCount*2]=xy[0];
  203. b.vertices[b.verticeCount*2+1]=xy[1];
  204. b.verticeCount++;
  205. }
  206. for(int i=0;i<mbs->ballCount;i++)
  207. {
  208. for(int c=0;c<100;c++)
  209. {
  210. Ball &ball = mbs->balls[i];
  211. if(!ball.tracking)
  212. {
  213. continue;
  214. }
  215. //# walk along the tangent, using chosen differential method
  216. ball.edgePos = mbs->rungeKutta2Tangent(ball.edgePos, step);
  217. //# correction step towards the border
  218. mbs->stepOnceTowardsBorder(ball.edgePos);
  219. //# check if we've gone a full circle or hit some other
  220. //# edge tracker
  221. int otherball=-1;
  222. for(int j=0;j<mbs->ballCount;j++)
  223. {
  224. Ball &ob = mbs->balls[j];
  225. if((i!=j || c>3) && (ob.pos0-ball.edgePos).lengthSquared()<step*step)
  226. {
  227. ball.tracking=false;
  228. otherball=j;
  229. }
  230. }
  231. QVector2D p=ball.edgePos;
  232. float xy[2]={p.x(), SCREEN_HEIGHT-p.y()};
  233. ball.commands[ball.verticeCount]=VG_LINE_TO_ABS;
  234. ball.vertices[ball.verticeCount*2]=xy[0];
  235. ball.vertices[ball.verticeCount*2+1]=xy[1];
  236. ball.verticeCount++;
  237. if(otherball!=-1)
  238. {
  239. QVector2D p=balls[otherball].pos0;
  240. float xy[2]={p.x(), SCREEN_HEIGHT-p.y()};
  241. ball.commands[ball.verticeCount]=VG_LINE_TO_ABS;
  242. ball.vertices[ball.verticeCount*2]=xy[0];
  243. ball.vertices[ball.verticeCount*2+1]=xy[1];
  244. ball.verticeCount++;
  245. }
  246. }
  247. vgLoadIdentity();
  248. vgAppendPathData(blobs[i], mbs->balls[i].verticeCount, mbs->balls[i].commands, mbs->balls[i].vertices);
  249. //vgSetColor(paint, 0xFFFFFF7F);
  250. vgSetColor(paint, 0x0000007F);
  251. vgSetPaint(paint, VG_FILL_PATH | VG_STROKE_PATH);
  252. vgDrawPath(blobs[i], 0*VG_FILL_PATH | VG_STROKE_PATH);
  253. }
  254. }
  255. /**
  256. *
  257. * Render everything.
  258. *
  259. */
  260. void game_render()
  261. {
  262. // Draw the background
  263. vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
  264. vgLoadIdentity();
  265. vgScale(SCREEN_WIDTH/512.0f, SCREEN_HEIGHT/512.0f );
  266. vgDrawImage( bgImage );
  267. // Draw the centers.
  268. vgScale(1,1);
  269. for(int i=0;i<mbs->ballCount;i++)
  270. {
  271. vgLoadIdentity();
  272. QVector2D p=mbs->balls[i].pos;
  273. float scale = 0.3f + mbs->balls[i].size * 0.15f;
  274. vgTranslate(p.x()-64 * scale, SCREEN_HEIGHT-p.y()-64 * scale);
  275. vgScale(scale,scale );
  276. vgDrawImage( centerImage );
  277. }
  278. // Render the capsule
  279. if (capsulePower>=0.0f) {
  280. vgScale(1,1);
  281. vgLoadIdentity();
  282. float scale = -0.6f;
  283. vgTranslate(capsulePosition.x()-64 * scale, SCREEN_HEIGHT-capsulePosition.y()-64 * scale);
  284. vgScale(scale,scale );
  285. vgDrawImage( capsuleImage );
  286. }
  287. // center to screen
  288. vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
  289. frames++;
  290. vgSetPaint(paint, VG_STROKE_PATH);
  291. vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
  292. vgSetf(VG_STROKE_LINE_WIDTH, 8);
  293. draw_balls();
  294. }
  295. void game_event(int type, float x, float y, float z)
  296. {
  297. capsulePosition = QVector2D( x,y );
  298. switch (type) {
  299. defualt:
  300. case Qt::TouchPointPressed:
  301. capsulePower = 1.0f;
  302. break;
  303. case Qt::TouchPointReleased:
  304. capsulePower = -1.0f;
  305. }
  306. }