BillboardSample.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include "BillboardSample.h"
  2. #include "Grid.h"
  3. #include "SamplesGame.h"
  4. #if defined(ADD_SAMPLE)
  5. ADD_SAMPLE("Graphics", "Billboards", BillboardSample, 12);
  6. #endif
  7. static const unsigned int MOVE_FORWARD = 1;
  8. static const unsigned int MOVE_BACKWARD = 2;
  9. static const unsigned int MOVE_LEFT = 4;
  10. static const unsigned int MOVE_RIGHT = 8;
  11. static const unsigned int MOVE_UP = 16;
  12. static const unsigned int MOVE_DOWN = 32;
  13. static const float MOVE_SPEED = 1.0f;
  14. static const float UP_DOWN_SPEED = 1.0f;
  15. static const float GROUND_WIDTH = 4.0f;
  16. static const float GROUND_HEIGHT = 4.0f;
  17. static const float GROUND_REPEAT_TEXTURE = 30.0f;
  18. static const float BILLBOARD_WIDTH = 0.5f;
  19. static const float BILLBOARD_HEIGHT = 0.5f;
  20. static const unsigned int BILLBOARD_COUNT = 300;
  21. BillboardSample::BillboardSample()
  22. : _font(NULL), _scene(NULL), _ground(NULL), _gamepad(NULL), _moveFlags(0), _prevX(0), _prevY(0), _buttonPressed(false)
  23. {
  24. }
  25. void BillboardSample::initialize()
  26. {
  27. setMultiTouch(true);
  28. // Create the font and scene
  29. _font = Font::create("res/common/arial.gpb");
  30. _scene = Scene::create();
  31. // Initialize the camera
  32. _camera.initialize(0.1f, 100, 45);
  33. _camera.setPosition(Vector3(0, BILLBOARD_HEIGHT * 1.5f, GROUND_WIDTH / 2.0f));
  34. _camera.rotate(0.0f, -MATH_DEG_TO_RAD(10));
  35. _scene->addNode(_camera.getRootNode());
  36. _scene->setActiveCamera(_camera.getCamera());
  37. // Load the ground
  38. loadGround();
  39. // Load billboards
  40. loadBillboards();
  41. _gamepad = getGamepad(0);
  42. // This is needed because the virtual gamepad is shared between all samples.
  43. // SamplesGame always ensures the virtual gamepad is disabled when a sample is exited.
  44. if (_gamepad && _gamepad->isVirtual())
  45. _gamepad->getForm()->setEnabled(true);
  46. }
  47. void BillboardSample::finalize()
  48. {
  49. for (std::vector<Node*>::iterator it = _billboards.begin(); it != _billboards.end(); ++it)
  50. {
  51. Node* node = *it;
  52. node->release();
  53. }
  54. _billboards.clear();
  55. SAFE_RELEASE(_scene);
  56. SAFE_RELEASE(_font);
  57. SAFE_RELEASE(_ground);
  58. }
  59. void BillboardSample::update(float elapsedTime)
  60. {
  61. float time = (float)elapsedTime / 1000.0f;
  62. if (_gamepad->isButtonDown(Gamepad::BUTTON_A))
  63. _moveFlags |= MOVE_DOWN;
  64. else
  65. _moveFlags &= ~MOVE_DOWN;
  66. if (_gamepad->isButtonDown(Gamepad::BUTTON_B))
  67. _moveFlags |= MOVE_UP;
  68. else
  69. _moveFlags &= ~MOVE_UP;
  70. Vector2 move;
  71. if (_moveFlags != 0)
  72. {
  73. // Forward motion
  74. if (_moveFlags & MOVE_FORWARD)
  75. {
  76. move.y = 1;
  77. }
  78. else if (_moveFlags & MOVE_BACKWARD)
  79. {
  80. move.y = -1;
  81. }
  82. // Strafing
  83. if (_moveFlags & MOVE_LEFT)
  84. {
  85. move.x = 1;
  86. }
  87. else if (_moveFlags & MOVE_RIGHT)
  88. {
  89. move.x = -1;
  90. }
  91. move.normalize();
  92. // Up and down
  93. if (_moveFlags & MOVE_UP)
  94. {
  95. _camera.moveUp(time * UP_DOWN_SPEED);
  96. }
  97. else if (_moveFlags & MOVE_DOWN)
  98. {
  99. _camera.moveDown(time * UP_DOWN_SPEED);
  100. }
  101. }
  102. else if (_gamepad->getJoystickCount() > 0)
  103. {
  104. _gamepad->getJoystickValues(0, &move);
  105. move.x = -move.x;
  106. }
  107. if (_gamepad->getJoystickCount() > 1)
  108. {
  109. Vector2 joy2;
  110. _gamepad->getJoystickValues(1, &joy2);
  111. _camera.rotate(MATH_DEG_TO_RAD(joy2.x * 2.0f), MATH_DEG_TO_RAD(joy2.y * 2.0f));
  112. }
  113. if (!move.isZero())
  114. {
  115. move.scale(time * MOVE_SPEED);
  116. _camera.moveForward(move.y);
  117. _camera.moveLeft(move.x);
  118. }
  119. }
  120. void BillboardSample::render(float elapsedTime)
  121. {
  122. // Clear the color and depth buffers
  123. clear(CLEAR_COLOR_DEPTH, Vector4::fromColor(0x355D90FF), 1.0f, 0);
  124. // Draw the ground
  125. _ground->draw();
  126. // Get the scene camera
  127. Camera* camera = _scene->getActiveCamera();
  128. for (unsigned int i = 0; i < BILLBOARD_COUNT; i++)
  129. {
  130. Node* node = _billboards[i];
  131. // Rotate the node x/z to face the camera
  132. Matrix m;
  133. Matrix::createBillboard(node->getTranslationWorld(), camera->getNode()->getTranslationWorld(), camera->getNode()->getUpVectorWorld(), &m);
  134. Quaternion q;
  135. m.getRotation(&q);
  136. node->setRotation(q);
  137. if (node->getBoundingSphere().intersects(camera->getFrustum()))
  138. node->getModel()->draw();
  139. }
  140. // draw the gamepad
  141. _gamepad->draw();
  142. // draw the frame rate
  143. drawFrameRate(_font, Vector4::one(), 5, 1, getFrameRate());
  144. }
  145. void BillboardSample::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  146. {
  147. switch (evt)
  148. {
  149. case Touch::TOUCH_PRESS:
  150. if (x < 75 && y < 50)
  151. {
  152. // Toggle Vsync if the user touches the top left corner
  153. setVsync(!isVsync());
  154. }
  155. _prevX = x;
  156. _prevY = y;
  157. break;
  158. case Touch::TOUCH_RELEASE:
  159. _prevX = 0;
  160. _prevY = 0;
  161. break;
  162. case Touch::TOUCH_MOVE:
  163. {
  164. int deltaX = x - _prevX;
  165. int deltaY = y - _prevY;
  166. _prevX = x;
  167. _prevY = y;
  168. float pitch = -MATH_DEG_TO_RAD(deltaY * 0.5f);
  169. float yaw = MATH_DEG_TO_RAD(deltaX * 0.5f);
  170. _camera.rotate(yaw, pitch);
  171. break;
  172. }
  173. };
  174. }
  175. void BillboardSample::keyEvent(Keyboard::KeyEvent evt, int key)
  176. {
  177. if (evt == Keyboard::KEY_PRESS)
  178. {
  179. switch (key)
  180. {
  181. case Keyboard::KEY_W:
  182. _moveFlags |= MOVE_FORWARD;
  183. break;
  184. case Keyboard::KEY_S:
  185. _moveFlags |= MOVE_BACKWARD;
  186. break;
  187. case Keyboard::KEY_A:
  188. _moveFlags |= MOVE_LEFT;
  189. break;
  190. case Keyboard::KEY_D:
  191. _moveFlags |= MOVE_RIGHT;
  192. break;
  193. case Keyboard::KEY_Q:
  194. _moveFlags |= MOVE_DOWN;
  195. break;
  196. case Keyboard::KEY_E:
  197. _moveFlags |= MOVE_UP;
  198. break;
  199. case Keyboard::KEY_PG_UP:
  200. _camera.rotate(0, MATH_PIOVER4);
  201. break;
  202. case Keyboard::KEY_PG_DOWN:
  203. _camera.rotate(0, -MATH_PIOVER4);
  204. break;
  205. case Keyboard::KEY_ONE:
  206. case Keyboard::KEY_SPACE:
  207. break;
  208. }
  209. }
  210. else if (evt == Keyboard::KEY_RELEASE)
  211. {
  212. switch (key)
  213. {
  214. case Keyboard::KEY_W:
  215. _moveFlags &= ~MOVE_FORWARD;
  216. break;
  217. case Keyboard::KEY_S:
  218. _moveFlags &= ~MOVE_BACKWARD;
  219. break;
  220. case Keyboard::KEY_A:
  221. _moveFlags &= ~MOVE_LEFT;
  222. break;
  223. case Keyboard::KEY_D:
  224. _moveFlags &= ~MOVE_RIGHT;
  225. break;
  226. case Keyboard::KEY_Q:
  227. _moveFlags &= ~MOVE_DOWN;
  228. break;
  229. case Keyboard::KEY_E:
  230. _moveFlags &= ~MOVE_UP;
  231. break;
  232. }
  233. }
  234. }
  235. bool BillboardSample::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  236. {
  237. switch (evt)
  238. {
  239. case Mouse::MOUSE_WHEEL:
  240. _camera.moveForward(wheelDelta * MOVE_SPEED / 4.0f );
  241. return true;
  242. }
  243. return false;
  244. }
  245. void BillboardSample::loadGround()
  246. {
  247. // Just a basic plane for this sample
  248. Mesh* mesh = Mesh::createQuad(-(GROUND_WIDTH / 2.0f), -(GROUND_HEIGHT / 2.0f), GROUND_WIDTH, GROUND_HEIGHT);
  249. Node* node = Node::create();
  250. _ground = Model::create(mesh);
  251. SAFE_RELEASE(mesh);
  252. node->setModel(_ground);
  253. _scene->addNode(node);
  254. node->rotateX(MATH_DEG_TO_RAD(90));
  255. Effect* effect = Effect::createFromFile("res/shaders/textured-unlit.vert", "res/shaders/textured-unlit.frag", "TEXTURE_REPEAT");
  256. Material* material = Material::create(effect);
  257. material->getStateBlock()->setDepthTest(true);
  258. material->getStateBlock()->setBlend(false);
  259. Texture::Sampler* sampler = material->getParameter("u_diffuseTexture")->setValue("res/png/dirt.png", true);
  260. sampler->setFilterMode(Texture::LINEAR_MIPMAP_LINEAR, Texture::LINEAR);
  261. material->getParameter("u_textureRepeat")->setValue(Vector2(GROUND_REPEAT_TEXTURE, GROUND_REPEAT_TEXTURE));
  262. material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
  263. _ground->setMaterial(material);
  264. SAFE_RELEASE(material);
  265. SAFE_RELEASE(effect)
  266. SAFE_RELEASE(node);
  267. }
  268. void BillboardSample::loadBillboards()
  269. {
  270. Mesh* mesh = Mesh::createQuad(-(BILLBOARD_WIDTH / 2.0f), -(BILLBOARD_HEIGHT / 2.0f), BILLBOARD_WIDTH, BILLBOARD_HEIGHT);
  271. mesh->setBoundingSphere(BoundingSphere(Vector3::zero(), BILLBOARD_HEIGHT));
  272. Effect* effect = Effect::createFromFile("res/shaders/textured-unlit.vert", "res/shaders/textured-unlit.frag", "TEXTURE_DISCARD_ALPHA");
  273. // Create the model and node and bind the material
  274. for ( unsigned int i = 0; i < BILLBOARD_COUNT; i++ )
  275. {
  276. Node* node = Node::create();
  277. Model* model = Model::create(mesh);
  278. node->setModel(model);
  279. _scene->addNode(node);
  280. Material* material = Material::create(effect);
  281. material->getStateBlock()->setDepthTest(true);
  282. material->getStateBlock()->setBlend(false);
  283. material->getParameter("u_diffuseTexture")->setValue("res/png/grass.png" , true);
  284. material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
  285. model->setMaterial(material);
  286. SAFE_RELEASE(model);
  287. SAFE_RELEASE(material);
  288. // Randomly postiion within the domain
  289. float tx = MATH_RANDOM_0_1() * GROUND_WIDTH - (GROUND_WIDTH / 2.0f);
  290. float tz = MATH_RANDOM_0_1() * GROUND_HEIGHT - (GROUND_HEIGHT / 2.0f);
  291. node->translate(tx, (BILLBOARD_HEIGHT / 2.0f), tz);
  292. _billboards.push_back(node);
  293. }
  294. SAFE_RELEASE(effect);
  295. SAFE_RELEASE(mesh);
  296. }
  297. void BillboardSample::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad)
  298. {
  299. switch(evt)
  300. {
  301. case Gamepad::CONNECTED_EVENT:
  302. case Gamepad::DISCONNECTED_EVENT:
  303. _gamepad = getGamepad(0);
  304. // This is needed because the virtual gamepad is shared between all samples.
  305. // SamplesGame always ensures the virtual gamepad is disabled when a sample is exited.
  306. if (_gamepad && _gamepad->isVirtual())
  307. _gamepad->getForm()->setEnabled(true);
  308. break;
  309. }
  310. }