Application.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "AnimatedModel.h"
  25. #include "Animation.h"
  26. #include "AnimationState.h"
  27. #include "Audio.h"
  28. #include "Application.h"
  29. #include "BillboardSet.h"
  30. #include "Button.h"
  31. #include "CheckBox.h"
  32. #include "CollisionShape.h"
  33. #include "Cursor.h"
  34. #include "CustomObject.h"
  35. #include "DebugHud.h"
  36. #include "DebugRenderer.h"
  37. #include "Engine.h"
  38. #include "EngineEvents.h"
  39. #include "Exception.h"
  40. #include "File.h"
  41. #include "Font.h"
  42. #include "Geometry.h"
  43. #include "IndexBuffer.h"
  44. #include "Input.h"
  45. #include "InstancedModel.h"
  46. #include "Joint.h"
  47. #include "Light.h"
  48. #include "Log.h"
  49. #include "Material.h"
  50. #include "Mod.h"
  51. #include "OcclusionBuffer.h"
  52. #include "Octree.h"
  53. #include "OctreeQuery.h"
  54. #include "PhysicsEvents.h"
  55. #include "PhysicsWorld.h"
  56. #include "Pipeline.h"
  57. #include "ParticleEmitter.h"
  58. #include "Profiler.h"
  59. #include "Renderer.h"
  60. #include "RendererImpl.h"
  61. #include "ResourceCache.h"
  62. #include "RigidBody.h"
  63. #include "Scene.h"
  64. #include "Skybox.h"
  65. #include "StaticModel.h"
  66. #include "Text.h"
  67. #include "StringUtils.h"
  68. #include "Texture2D.h"
  69. #include "UI.h"
  70. #include "UIEvents.h"
  71. #include "VertexBuffer.h"
  72. #include "Window.h"
  73. #include "XM.h"
  74. #include "XMLFile.h"
  75. #include "Zone.h"
  76. #include "DebugNew.h"
  77. void calculateTangents(float* vertexData, unsigned vertexCount, const unsigned short* indexData, unsigned indexCount);
  78. float vertexData[] =
  79. {
  80. // Side 1
  81. -1, 1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0,
  82. 1, 1, -1, 0, 0, -1, 1, 0, 0, 0, 0, 0,
  83. 1, -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0,
  84. -1, -1, -1, 0, 0, -1, 0, 1, 0, 0, 0, 0,
  85. // Side 2
  86. 1, 1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  87. 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
  88. 1, -1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0,
  89. 1, -1, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
  90. // Side 3
  91. 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
  92. -1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
  93. -1, -1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0,
  94. 1, -1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0,
  95. // Side 4
  96. -1, 1, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
  97. -1, 1, -1, -1, 0, 0, 1, 0, 0, 0, 0, 0,
  98. -1, -1, -1, -1, 0, 0, 1, 1, 0, 0, 0, 0,
  99. -1, -1, 1, -1, 0, 0, 0, 1, 0, 0, 0, 0,
  100. // Side 5
  101. -1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
  102. 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
  103. 1, 1, -1, 0, 1, 0, 1, 1, 0, 0, 0, 0,
  104. -1, 1, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
  105. // Side 6
  106. -1, -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0,
  107. 1, -1, -1, 0, -1, 0, 1, 0, 0, 0, 0, 0,
  108. 1, -1, 1, 0, -1, 0, 1, 1, 0, 0, 0, 0,
  109. -1, -1, 1, 0, -1, 0, 0, 1, 0, 0, 0, 0
  110. };
  111. const unsigned short indexData[] =
  112. {
  113. 0, 1, 2,
  114. 2, 3, 0,
  115. 4, 5, 6,
  116. 6, 7, 4,
  117. 8, 9, 10,
  118. 10, 11, 8,
  119. 12, 13, 14,
  120. 14, 15, 12,
  121. 16, 17, 18,
  122. 18, 19, 16,
  123. 20, 21, 22,
  124. 22, 23, 20
  125. };
  126. float objectangle = 0;
  127. float yaw = 0;
  128. float pitch = 0;
  129. bool paused = true;
  130. int texturequality = 2;
  131. int materialquality = 2;
  132. int fallbacklevel = 0;
  133. int shadowmapsize = 1024;
  134. bool hiresshadowmap = false;
  135. int texturefilter = 2;
  136. bool usespecular = true;
  137. int drawdebug = 0;
  138. bool drawshadows = true;
  139. bool attach = true;
  140. bool useocclusion = true;
  141. bool shadowfocus = true;
  142. static const int NUM_OBJECTS = 250;
  143. static const int NUM_LIGHTS = 20;
  144. static const int NUM_INSTANCENODES = 20;
  145. static const int NUM_INSTANCES = 50;
  146. static const int NUM_BILLBOARDNODES = 20;
  147. static const int NUM_BILLBOARDS = 15;
  148. Application::Application(const std::vector<std::string>& arguments) :
  149. mArguments(arguments)
  150. {
  151. subscribeToEvent(EVENT_UPDATE, EVENT_HANDLER(Application, handleUpdate));
  152. subscribeToEvent(EVENT_POSTRENDERUPDATE, EVENT_HANDLER(Application, handlePostRenderUpdate));
  153. subscribeToEvent(EVENT_MOUSEMOVE, EVENT_HANDLER(Application, handleMouseMove));
  154. subscribeToEvent(EVENT_MOUSEBUTTONDOWN, EVENT_HANDLER(Application, handleMouseButtonDown));
  155. subscribeToEvent(EVENT_MOUSEBUTTONUP, EVENT_HANDLER(Application, handleMouseButtonUp));
  156. }
  157. Application::~Application()
  158. {
  159. if (mEngine)
  160. {
  161. mEngine->dumpResources();
  162. mEngine->dumpProfilingData();
  163. }
  164. }
  165. void Application::run()
  166. {
  167. init();
  168. while (!mEngine->isExiting())
  169. mEngine->runFrame(mScene, mCameraEntity->getComponent<Camera>());
  170. }
  171. void Application::init()
  172. {
  173. mEngine = new Engine("Test.log");
  174. mEngine->init("Urho3D Test", mArguments);
  175. PROFILE(App_Init);
  176. mCache = mEngine->getResourceCache();
  177. mCache->addResourcePath(getSystemFontDirectory());
  178. Renderer* renderer = mEngine->getRenderer();
  179. UI* ui = mEngine->getUI();
  180. UIElement* uiRoot = ui->getRootElement();
  181. XMLFile* uiSetup = mCache->getResource<XMLFile>("UI/UI.xml");
  182. Cursor* cursor = new Cursor("Cursor");
  183. cursor->loadParameters(uiSetup, "Cursor", mCache);
  184. cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
  185. ui->setCursor(cursor);
  186. //Button* button = new Button("TestButton");
  187. //button->loadParameters(uiSetup, "Button", mCache);
  188. //Text* text = new Text("TEST");
  189. //text->setFont(mCache->getResource<Font>("cour.ttf"), 12);
  190. //button->setLabel(text);
  191. //button->setAlignment(HA_CENTER, VA_CENTER);
  192. //button->setSize(100, 40);
  193. //uiRoot->addChild(button);
  194. //
  195. //for (unsigned i = 0; i < 4; ++i)
  196. //{
  197. // CheckBox* checkBox = new CheckBox("TestCheckBox" + toString(i));
  198. // checkBox->loadParameters(uiSetup, "CheckBox", mCache);
  199. // checkBox->setPosition(renderer->getWidth() / 3, renderer->getHeight() / 3 + 32 * i);
  200. // uiRoot->addChild(checkBox);
  201. //}
  202. mScene = mEngine->createScene();
  203. PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
  204. world->setGravity(Vector3(0.0f, -9.81f, 0.0f));
  205. world->setFps(100);
  206. world->setLinearRestThreshold(0.1f);
  207. world->setAngularRestThreshold(0.1f);
  208. world->setContactSurfaceLayer(0.001f);
  209. DebugHud* debugHud = mEngine->createDebugHud();
  210. debugHud->setFont(mCache->getResource<Font>("cour.ttf"), 12);
  211. debugHud->setMode(DEBUGHUD_SHOW_STATS | DEBUGHUD_SHOW_MODE);
  212. mCameraEntity = mScene->createEntity();
  213. Camera* camera = mCameraEntity->createComponent<Camera>();
  214. camera->setPosition(Vector3(-50.0f, 2.0f, -50.0f));
  215. camera->setAspectRatio((float)renderer->getWidth() / (float)renderer->getHeight());
  216. calculateTangents(vertexData, 24, indexData, 36);
  217. SharedPtr<VertexBuffer> vb(new VertexBuffer(renderer, false));
  218. vb->setSize(24, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
  219. vb->setData(vertexData);
  220. SharedPtr<IndexBuffer> ib(new IndexBuffer(renderer, false));
  221. ib->setSize(36, false);
  222. ib->setData(indexData);
  223. SharedPtr<Geometry> g(new Geometry());
  224. g->setVertexBuffer(0, vb);
  225. g->setIndexBuffer(ib);
  226. g->setDrawRange(TRIANGLE_LIST, 0, ib->getIndexCount());
  227. SharedPtr<Model> box(new Model(renderer, "Models/Box.mdl"));
  228. box->setNumGeometries(1);
  229. box->setNumGeometryLodLevels(0, 1);
  230. box->setGeometry(0, 0, g);
  231. box->setBoundingBox(BoundingBox(-1.0f, 1.0f));
  232. mCache->addManualResource(box);
  233. createScene();
  234. Entity* sun = mScene->createEntity();
  235. Light* sunLight = sun->createComponent<Light>();
  236. sunLight->setLightType(LIGHT_DIRECTIONAL);
  237. sunLight->setDirection(Vector3(0.5f, -1.0f, 0.5f));
  238. sunLight->setColor(Color(0.2f, 0.2f, 0.2f));
  239. sunLight->setSpecularIntensity(1.0);
  240. //sunLight->setCastShadows(true);
  241. //sunLight->setShadowCascade(CascadeParameters(3, 0.95f, 0.2f, 500.0f));
  242. Light* cameraLight = mCameraEntity->createComponent<Light>();
  243. cameraLight->setLightType(LIGHT_SPOT);
  244. cameraLight->setDirection(Vector3(0.0f, 0.0f, 1.0f));
  245. cameraLight->setRange(50.0f);
  246. cameraLight->setColor(Color(2.0f, 2.0f, 2.0f));
  247. cameraLight->setSpecularIntensity(2.0f);
  248. cameraLight->setCastShadows(true);
  249. cameraLight->setShadowResolution(0.5f);
  250. cameraLight->setShadowFocus(FocusParameters(false, false, false, 0.5f, 3.0f));
  251. cameraLight->setRampTexture(mCache->getResource<Texture2D>("Textures/RampWide.png"));
  252. cameraLight->setSpotTexture(mCache->getResource<Texture2D>("Textures/SpotWide.png"));
  253. camera->addChild(cameraLight);
  254. }
  255. void Application::createScene()
  256. {
  257. PROFILE(App_CreateScene);
  258. Octree* octree = mScene->getExtension<Octree>();
  259. PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
  260. // Create a zone to control the ambient lighting
  261. Zone* zone = new Zone(octree);
  262. zone->setBoundingBox(BoundingBox(-1000.0f, 1000.0f));
  263. zone->setAmbientColor(Color(0.1f, 0.1f, 0.1f));
  264. Entity* newEntity = mScene->createEntity();
  265. newEntity->addComponent(zone);
  266. // Create the "floor"
  267. for (int y = -5; y <= 5; y++)
  268. {
  269. for (int x = -5; x <= 5; x++)
  270. {
  271. RigidBody* body = new RigidBody(world);
  272. body->setPosition(Vector3(x * 20.5f, -0.5f, y * 20.5f));
  273. body->setScale(Vector3(10.0f, 0.5f, 10.0f));
  274. body->setCollisionShape(mCache->getResource<CollisionShape>("Physics/Box.xml"));
  275. body->setCollisionGroup(2);
  276. body->setCollisionMask(1);
  277. StaticModel* object = new StaticModel(octree);
  278. object->setModel(mCache->getResource<Model>("Models/Box.mdl"));
  279. object->setMaterial(mCache->getResource<Material>("Materials/Test.xml"));
  280. body->addChild(object);
  281. Entity* newEntity = mScene->createEntity();
  282. newEntity->addComponent(body);
  283. newEntity->addComponent(object);
  284. }
  285. }
  286. // Create 2 occluder walls
  287. for (int x = 0; x < 2; x++)
  288. {
  289. RigidBody* body = new RigidBody(world);
  290. body->setPosition(Vector3(0.0f, 5.0f, 0.0f));
  291. body->setRotation(Quaternion(x * 90.0f, Vector3::sUp));
  292. body->setScale(Vector3(112.0f, 5.0f, 0.5f));
  293. body->setCollisionShape(mCache->getResource<CollisionShape>("Physics/Box.xml"));
  294. body->setCollisionGroup(2);
  295. body->setCollisionMask(1);
  296. StaticModel* object = new StaticModel(octree);
  297. object->setModel(mCache->getResource<Model>("Models/Box.mdl"));
  298. object->setMaterial(mCache->getResource<Material>("Materials/Test.xml"));
  299. object->setCastShadows(true);
  300. object->setOccluder(true);
  301. body->addChild(object);
  302. Entity* newEntity = mScene->createEntity();
  303. newEntity->addComponent(body);
  304. newEntity->addComponent(object);
  305. }
  306. // Create static mushroom with physics
  307. {
  308. RigidBody* body = new RigidBody(world);
  309. body->setPosition(Vector3(50.0f, 0.0f, 50.0f));
  310. body->setScale(10.0f);
  311. body->setCollisionShape(mCache->getResource<CollisionShape>("Physics/Mushroom.xml"));
  312. body->setCollisionGroup(2);
  313. body->setCollisionMask(1);
  314. StaticModel* object = new StaticModel(octree);
  315. object->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
  316. object->setMaterial(mCache->getResource<Material>("Materials/Mushroom.xml"));
  317. object->setCastShadows(true);
  318. object->setOccluder(true);
  319. body->addChild(object);
  320. Entity* newEntity = mScene->createEntity();
  321. newEntity->addComponent(body);
  322. newEntity->addComponent(object);
  323. }
  324. // Create instanced mushrooms
  325. for (unsigned j = 0; j < NUM_INSTANCENODES; ++j)
  326. {
  327. InstancedModel* instanced = new InstancedModel(octree);
  328. instanced->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
  329. instanced->setMaterial(mCache->getResource<Material>("Materials/Mushroom.xml"));
  330. instanced->setPosition(Vector3(random() * 160.0f - 80.0f, 0.0f, random() * 160.0f - 80.0f));
  331. instanced->setCastShadows(true);
  332. instanced->setNumInstances(50);
  333. std::vector<Instance>& instances = instanced->getInstances();
  334. for (unsigned i = 0; i < NUM_INSTANCES; ++i)
  335. {
  336. Vector3 position(random() * 20.0f - 10.0f, 0.0f, random() * 20.0f - 10.0f);
  337. float angle = random() * 360.0f;
  338. float size = 1.0f + random() * 2.0f;
  339. instances[i].mPosition = position;
  340. instances[i].mRotation = Quaternion(angle, Vector3::sUp);
  341. instances[i].mScale = Vector3(size, size, size);
  342. }
  343. instanced->updated();
  344. Entity* newEntity = mScene->createEntity();
  345. newEntity->addComponent(instanced);
  346. }
  347. // Create animated models
  348. for (unsigned i = 0; i < NUM_OBJECTS; ++i)
  349. {
  350. AnimatedModel* object = new AnimatedModel(octree);
  351. Vector3 position(random() * 180.0f - 90.0f, 0.0f, random() * 180.0f - 90.0f);
  352. float angle = random() * 360.0f;
  353. object->setPosition(position);
  354. object->setRotation(Quaternion(angle, Vector3::sUp));
  355. object->setCastShadows(true);
  356. object->setScale(1.0f + random() * 0.25f);
  357. object->setModel(mCache->getResource<Model>("Models/Jack.mdl"));
  358. object->setMaterial(mCache->getResource<Material>("Materials/Jack.xml"));
  359. object->setShadowDistance(200.0f);
  360. object->setDrawDistance(300.0f);
  361. AnimationState* anim = object->addAnimationState(mCache->getResource<Animation>("Models/Jack_Walk.ani"));
  362. if (anim)
  363. {
  364. anim->setUseNlerp(true);
  365. anim->setLooped(true);
  366. anim->setWeight(1.0f);
  367. }
  368. Entity* newEntity = mScene->createEntity();
  369. newEntity->addComponent(object);
  370. mAnimatingObjects.push_back(newEntity);
  371. }
  372. // Create floating smoke clouds
  373. for (unsigned b = 0; b < NUM_BILLBOARDNODES; ++b)
  374. {
  375. BillboardSet* billboard = new BillboardSet(octree);
  376. billboard->setNumBillboards(NUM_BILLBOARDS);
  377. billboard->setPosition(Vector3(random() * 200.0f - 100.0f, random() * 15.0f + 5.0f, random() * 200.0f - 100.0f));
  378. billboard->setMaterial(mCache->getResource<Material>("Materials/LitSmoke.xml"));
  379. billboard->setBillboardsSorted(true);
  380. std::vector<Billboard>& bb = billboard->getBillboards();
  381. for (unsigned i = 0; i < NUM_BILLBOARDS; ++i)
  382. {
  383. bb[i].mPosition = Vector3(random() * 15.0f - 7.5f, random() * 8.0f - 4.0f, random() * 15.0f - 7.5f);
  384. bb[i].mSize = Vector2(random() * 2.0f + 3.0f, random() * 2.0f + 3.0f);
  385. bb[i].mRotation = random() * 360.0f;
  386. bb[i].mEnabled = true;
  387. }
  388. billboard->updated();
  389. Entity* newEntity = mScene->createEntity();
  390. newEntity->addComponent(billboard);
  391. mBillboards.push_back(newEntity);
  392. }
  393. // Create lights
  394. for (unsigned i = 0; i < NUM_LIGHTS; ++i)
  395. {
  396. Light* light = new Light(octree);
  397. Vector3 position(
  398. random() * 150.0f - 75.0f,
  399. random() * 30.0f + 30.0f,
  400. random() * 150.0f - 75.0f
  401. );
  402. Color color(
  403. (rand() & 1) * 0.5f + 0.5f,
  404. (rand() & 1) * 0.5f + 0.5f,
  405. (rand() & 1) * 0.5f + 0.5f
  406. );
  407. if ((color.mR == 0.5f) && (color.mG == 0.5f) && (color.mB == 0.5f))
  408. color = Color(1.0f, 1.0f, 1.0f);
  409. float angle = random() * 360.0f;
  410. light->setPosition(position);
  411. light->setDirection(Vector3(sinf(angle * M_DEGTORAD), -1.0f, cosf(angle * M_DEGTORAD)));
  412. light->setLightType(LIGHT_SPOT);
  413. light->setRange(75.0f);
  414. light->setRampTexture(mCache->getResource<Texture2D>("Textures/RampExtreme.png"));
  415. light->setFov(15.0f);
  416. light->setColor(color);
  417. light->setSpecularIntensity(1.0f);
  418. light->setCastShadows(true);
  419. light->setShadowBias(BiasParameters(0.00002f, 0.0f));
  420. light->setShadowResolution(0.5f);
  421. // The spot lights will not have anything near them, so move the near plane of the shadow camera farther
  422. // for better shadow depth resolution
  423. light->setShadowNearFarRatio(0.01f);
  424. Entity* newEntity = mScene->createEntity();
  425. newEntity->addComponent(light);
  426. mLights.push_back(newEntity);
  427. }
  428. }
  429. void Application::handleUpdate(StringHash eventType, VariantMap& eventData)
  430. {
  431. using namespace Update;
  432. float timeStep = eventData[P_TIMESTEP].getFloat();
  433. if (!paused)
  434. {
  435. objectangle += 10.0f * timeStep;
  436. for (unsigned i = 0; i < mLights.size(); ++i)
  437. {
  438. Light* light = mLights[i]->getComponent<Light>();
  439. light->setRotation(Quaternion(0, objectangle * 2, 0));
  440. }
  441. for (unsigned i = 0; i < mAnimatingObjects.size(); ++i)
  442. {
  443. AnimatedModel* model = mAnimatingObjects[i]->getComponent<AnimatedModel>();
  444. const std::vector<AnimationState*>& anims = model->getAnimationStates();
  445. for (unsigned j = 0; j < anims.size(); ++j)
  446. anims[j]->addTime(timeStep);
  447. }
  448. for (unsigned i = 0; i < mBillboards.size(); ++i)
  449. {
  450. BillboardSet* billboard = mBillboards[i]->getComponent<BillboardSet>();
  451. std::vector<Billboard>& bb = billboard->getBillboards();
  452. for (unsigned j = 0; j < bb.size(); ++j)
  453. bb[j].mRotation += 50.0f * timeStep;
  454. billboard->updated();
  455. }
  456. }
  457. Input* input = mEngine->getInput();
  458. float speedMultiplier = 1.0f;
  459. if (input->getKeyDown(KEY_SHIFT))
  460. speedMultiplier = 5.0f;
  461. if (input->getKeyDown(KEY_CONTROL))
  462. speedMultiplier = 0.1f;
  463. if (input->getKeyDown('W'))
  464. mCameraEntity->getComponent<Camera>()->translateRelative(Vector3(0.0f,0.0f,10.0f) * timeStep * speedMultiplier);
  465. if (input->getKeyDown('S'))
  466. mCameraEntity->getComponent<Camera>()->translateRelative(Vector3(0.0f,0.0f,-10.0f) * timeStep * speedMultiplier);
  467. if (input->getKeyDown('A'))
  468. mCameraEntity->getComponent<Camera>()->translateRelative(Vector3(-10.0f,0.0f,0.0f) * timeStep * speedMultiplier);
  469. if (input->getKeyDown('D'))
  470. mCameraEntity->getComponent<Camera>()->translateRelative(Vector3(10.0f,0.0f,0.0f) * timeStep * speedMultiplier);
  471. if (input->getKeyPress('1'))
  472. {
  473. Renderer* renderer = mEngine->getRenderer();
  474. int nextRenderMode = renderer->getRenderMode();
  475. if (input->getKeyDown(KEY_SHIFT))
  476. {
  477. --nextRenderMode;
  478. if (nextRenderMode < 0)
  479. nextRenderMode = 2;
  480. }
  481. else
  482. {
  483. ++nextRenderMode;
  484. if (nextRenderMode > 2)
  485. nextRenderMode = 0;
  486. }
  487. renderer->setMode((RenderMode)nextRenderMode, renderer->getWidth(), renderer->getHeight(), renderer->getFullscreen(),
  488. renderer->getVsync(), renderer->getMultiSample());
  489. }
  490. if (input->getKeyPress('2'))
  491. {
  492. texturequality++;
  493. if (texturequality > 2)
  494. texturequality = 0;
  495. mEngine->getPipeline()->setTextureQuality(texturequality);
  496. }
  497. if (input->getKeyPress('3'))
  498. {
  499. materialquality++;
  500. if (materialquality > 2)
  501. materialquality = 0;
  502. mEngine->getPipeline()->setMaterialQuality(materialquality);
  503. }
  504. if (input->getKeyPress('4'))
  505. {
  506. usespecular = !usespecular;
  507. mEngine->getPipeline()->setSpecularLighting(usespecular);
  508. }
  509. if (input->getKeyPress('5'))
  510. {
  511. drawshadows = !drawshadows;
  512. mEngine->getPipeline()->setDrawShadows(drawshadows);
  513. }
  514. if (input->getKeyPress('6'))
  515. {
  516. shadowmapsize *= 2;
  517. if (shadowmapsize > 2048)
  518. shadowmapsize = 512;
  519. mEngine->getPipeline()->setShadowMapSize(shadowmapsize);
  520. }
  521. if (input->getKeyPress('7'))
  522. {
  523. hiresshadowmap = !hiresshadowmap;
  524. mEngine->getPipeline()->setShadowMapHiresDepth(hiresshadowmap);
  525. }
  526. if (input->getKeyPress('8'))
  527. {
  528. useocclusion = !useocclusion;
  529. mEngine->getPipeline()->setMaxOccluderTriangles(useocclusion ? 5000 : 0);
  530. }
  531. if (input->getKeyPress('L'))
  532. {
  533. Light* cameraLight = mCameraEntity->getComponent<Light>();
  534. attach = !attach;
  535. if (attach)
  536. {
  537. cameraLight->setPosition(Vector3::sZero);
  538. cameraLight->setRotation(Quaternion::sIdentity);
  539. mCameraEntity->getComponent<Camera>()->addChild(cameraLight);
  540. }
  541. else
  542. {
  543. // Detach child and set world transform to match what it was before detach
  544. mCameraEntity->getComponent<Camera>()->removeChild(cameraLight, true);
  545. }
  546. }
  547. if (input->getKeyPress(' '))
  548. {
  549. drawdebug++;
  550. if (drawdebug > 2) drawdebug = 0;
  551. mEngine->setDebugDrawMode(drawdebug);
  552. }
  553. if (input->getKeyPress('P'))
  554. {
  555. paused = !paused;
  556. }
  557. if (input->getKeyPress('C'))
  558. {
  559. Camera* camera = mCameraEntity->getComponent<Camera>();
  560. camera->setOrthographic(!camera->isOrthographic());
  561. }
  562. if (input->getKeyPress('O'))
  563. {
  564. if (!mOcclusionDebugImage)
  565. {
  566. try
  567. {
  568. Renderer* renderer = mEngine->getRenderer();
  569. UIElement* uiRoot = mEngine->getUIRoot();
  570. mOcclusionDebugTexture = new Texture2D(renderer, TEXTURE_DYNAMIC);
  571. mOcclusionDebugTexture->setNumLevels(1);
  572. mOcclusionDebugTexture->setSize(256, 256, D3DFMT_R32F);
  573. mOcclusionDebugImage = new BorderImage();
  574. mOcclusionDebugImage->setSize(256, 256);
  575. mOcclusionDebugImage->setTexture(mOcclusionDebugTexture);
  576. mOcclusionDebugImage->setAlignment(HA_RIGHT, VA_BOTTOM);
  577. uiRoot->addChild(mOcclusionDebugImage);
  578. }
  579. catch (...)
  580. {
  581. }
  582. }
  583. else
  584. {
  585. mOcclusionDebugImage->setVisible(!mOcclusionDebugImage->isVisible());
  586. }
  587. }
  588. if (input->getKeyPress('T'))
  589. mEngine->getDebugHud()->toggle(DEBUGHUD_SHOW_PROFILER);
  590. if (input->getKeyPress('F'))
  591. {
  592. Pipeline* pipeline = mEngine->getPipeline();
  593. EdgeFilterParameters params = pipeline->getEdgeFilter();
  594. if (params.mMaxFilter > 0.0f)
  595. params.mMaxFilter = 0.0f;
  596. else
  597. params.mMaxFilter = 1.0f;
  598. pipeline->setEdgeFilter(params);
  599. }
  600. if (input->getKeyPress(KEY_ESCAPE))
  601. mEngine->exit();
  602. }
  603. void Application::handlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
  604. {
  605. using namespace PostRenderUpdate;
  606. float timeStep = eventData[P_TIMESTEP].getFloat();
  607. // Test world raycast
  608. Camera* camera = mCameraEntity->getComponent<Camera>();
  609. UI* ui = mEngine->getUI();
  610. Renderer* renderer = mEngine->getRenderer();
  611. DebugRenderer* debug = mEngine->getDebugRenderer();
  612. if (camera)
  613. {
  614. IntVector2 pos = ui->getCursorPosition();
  615. if (!ui->getElementAt(pos))
  616. {
  617. Ray cameraRay = camera->getScreenRay(((float)pos.mX) / renderer->getWidth(), ((float)pos.mY) / renderer->getHeight());
  618. std::vector<RayQueryResult> result;
  619. RayOctreeQuery query(cameraRay, result, NODE_GEOMETRY, NODE_BILLBOARDSET, false, false, 250.0f, RAY_TRIANGLE);
  620. mScene->getExtension<Octree>()->getNodes(query);
  621. if (result.size())
  622. {
  623. VolumeNode* node = result[0].mNode;
  624. Vector3 rayHitPos = cameraRay.mOrigin + query.mResult[0].mDistance * cameraRay.mDirection;
  625. debug->addBoundingBox(BoundingBox(-0.01f, 0.01f), Matrix4x3(rayHitPos, Quaternion::sIdentity, Vector3::sUnity), Color(1.0f, 1.0f, 1.0f));
  626. // Check for sub-object results (node-specific)
  627. if (result[0].mSubObject < M_MAX_UNSIGNED)
  628. {
  629. // Bone
  630. if (node->getNodeFlags() & NODE_ANIMATEDMODEL)
  631. {
  632. AnimatedModel* anim = static_cast<AnimatedModel*>(node);
  633. Bone* bone = anim->getSkeleton().getBone(result[0].mSubObject);
  634. debug->addBoundingBox(bone->getBoundingBox(), bone->getWorldTransform(), Color(1.0f, 1.0f, 1.0f));
  635. }
  636. // Instance
  637. else if (node->getNodeFlags() & NODE_INSTANCEDMODEL)
  638. {
  639. InstancedModel* instanced = static_cast<InstancedModel*>(node);
  640. Instance* instance = instanced->getInstance(result[0].mSubObject);
  641. Matrix4x3 transform(instance->mPosition, instance->mRotation, instance->mScale);
  642. if (instanced->getInstancesRelative())
  643. transform = instanced->getWorldTransform() * transform;
  644. debug->addBoundingBox(instanced->getBoundingBox().getTransformed(transform), Color(1.0f, 1.0f, 1.0f));
  645. }
  646. // Custom object subgeometry
  647. else if (node->getNodeFlags() & NODE_CUSTOMOBJECT)
  648. {
  649. CustomObject* custom = static_cast<CustomObject*>(node);
  650. const CustomGeometry* geom = custom->getGeometry(result[0].mSubObject);
  651. debug->addBoundingBox(geom->mBoundingBox.getTransformed(custom->getWorldTransform()), Color(1.0f, 1.0f, 1.0f));
  652. }
  653. }
  654. else
  655. debug->addBoundingBox(node->getWorldBoundingBox(), Color(1.0f, 1.0f, 1.0f));
  656. }
  657. }
  658. }
  659. // Update occlusion debug texture if visible
  660. if ((mOcclusionDebugImage) && (mOcclusionDebugImage->isVisible()))
  661. {
  662. PROFILE(App_UpdateOcclusionDebugTextures);
  663. static const float INV_Z_SCALE = 1.0f / (OCCLUSION_Z_SCALE);
  664. // Dump occlusion depth buffer to debug texture
  665. // Get an occlusion buffer matching the aspect ratio, it should be the main view occlusion buffer
  666. const OcclusionBuffer* buffer = mEngine->getPipeline()->getOcclusionBuffer(camera->getAspectRatio());
  667. if (buffer)
  668. {
  669. int width = buffer->getWidth();
  670. int height = buffer->getHeight();
  671. if (buffer->getBuffer())
  672. {
  673. mOcclusionDebugTexture->setSize(width, height, D3DFMT_R32F);
  674. mOcclusionDebugImage->setSize(width, height);
  675. mOcclusionDebugImage->setFullImageRect();
  676. D3DLOCKED_RECT hwRect;
  677. mOcclusionDebugTexture->lock(0, 0, &hwRect);
  678. for (int y = 0; y < height; ++y)
  679. {
  680. float* dest = (float*)(((unsigned char*)hwRect.pBits) + y * hwRect.Pitch);
  681. int* src = buffer->getBuffer() + y * width;
  682. for (int x = 0; x < width; ++x)
  683. {
  684. float depth = src[x] * INV_Z_SCALE;
  685. dest[x] = depth * 0.5f;
  686. }
  687. }
  688. mOcclusionDebugTexture->unlock();
  689. }
  690. }
  691. }
  692. }
  693. void Application::handleMouseButtonDown(StringHash eventType, VariantMap& eventData)
  694. {
  695. using namespace MouseButtonDown;
  696. int button = eventData[P_BUTTON].getInt();
  697. if (button == MOUSEB_RIGHT)
  698. {
  699. UIElement* cursor = mEngine->getUICursor();
  700. if (cursor)
  701. cursor->setVisible(false);
  702. }
  703. UI* ui = mEngine->getUI();
  704. if ((button == MOUSEB_LEFT) && (!ui->getElementAt(ui->getCursorPosition())))
  705. {
  706. // Test creating a new physics object
  707. if (mCameraEntity)
  708. {
  709. Camera* camera = mCameraEntity->getComponent<Camera>();
  710. Octree* octree = mScene->getExtension<Octree>();
  711. PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
  712. Entity* newEntity = mScene->createEntity();
  713. RigidBody* body = new RigidBody(world);
  714. body->setMode(PHYS_DYNAMIC);
  715. body->setPosition(camera->getPosition());
  716. body->setRotation(camera->getRotation());
  717. body->setScale(0.1f);
  718. body->setFriction(1.0f);
  719. body->setAngularMaxVelocity(500.0f);
  720. body->setCollisionShape(mCache->getResource<CollisionShape>("Physics/Box.xml"));
  721. body->setCollisionGroup(1);
  722. body->setCollisionMask(3);
  723. body->setLinearVelocity(camera->getUpVector() + camera->getForwardVector() * 10.0f);
  724. StaticModel* object = new StaticModel(octree);
  725. object->setModel(mCache->getResource<Model>("Models/Box.mdl"));
  726. object->setMaterial(mCache->getResource<Material>("Materials/Test.xml"));
  727. object->setCastShadows(true);
  728. object->setShadowDistance(75.0f);
  729. object->setDrawDistance(100.0f);
  730. body->addChild(object);
  731. newEntity->addComponent(body);
  732. newEntity->addComponent(object);
  733. }
  734. }
  735. }
  736. void Application::handleMouseButtonUp(StringHash eventType, VariantMap& eventData)
  737. {
  738. using namespace MouseButtonDown;
  739. if (eventData[P_BUTTON].getInt() == MOUSEB_RIGHT)
  740. {
  741. UIElement* cursor = mEngine->getUICursor();
  742. if (cursor)
  743. cursor->setVisible(true);
  744. }
  745. }
  746. void Application::handleMouseMove(StringHash eventType, VariantMap& eventData)
  747. {
  748. using namespace MouseMove;
  749. if (eventData[P_BUTTONS].getInt() & MOUSEB_RIGHT)
  750. {
  751. int mousedx = eventData[P_X].getInt();
  752. int mousedy = eventData[P_Y].getInt();
  753. yaw += mousedx / 10.0f;
  754. pitch += mousedy / 10.0f;
  755. if (pitch < -90.0f)
  756. pitch = -90.0f;
  757. if (pitch > 90.0f)
  758. pitch = 90.0f;
  759. if (mCameraEntity)
  760. mCameraEntity->getComponent<Camera>()->setRotation(Quaternion(yaw, Vector3::sUp) * Quaternion(pitch, Vector3::sRight));
  761. }
  762. }
  763. void calculateTangents(float* vertexData, unsigned vertexCount, const unsigned short* indexData, unsigned indexCount)
  764. {
  765. // Tangent generation from
  766. // http://www.terathon.com/code/tangent.html
  767. static const int V_OFS = 0;
  768. static const int N_OFS = 3;
  769. static const int UV_OFS = 6;
  770. static const int T_OFS = 8;
  771. static const int V_SIZE = 12;
  772. Vector3 *tan1 = new Vector3[vertexCount * 2];
  773. Vector3 *tan2 = tan1 + vertexCount;
  774. memset(tan1, 0, sizeof(Vector3) * vertexCount * 2);
  775. for (unsigned a = 0; a < indexCount; a += 3)
  776. {
  777. unsigned short i1 = indexData[a+0];
  778. unsigned short i2 = indexData[a+1];
  779. unsigned short i3 = indexData[a+2];
  780. const Vector3 v1 = Vector3(&vertexData[i1 * V_SIZE + V_OFS]);
  781. const Vector3 v2 = Vector3(&vertexData[i2 * V_SIZE + V_OFS]);
  782. const Vector3 v3 = Vector3 (&vertexData[i3 * V_SIZE + V_OFS]);
  783. const Vector2 w1 = Vector2(&vertexData[i1 * V_SIZE + UV_OFS]);
  784. const Vector2 w2 = Vector2(&vertexData[i2 * V_SIZE + UV_OFS]);
  785. const Vector2 w3 = Vector2(&vertexData[i3 * V_SIZE + UV_OFS]);
  786. float x1 = v2.mX - v1.mX;
  787. float x2 = v3.mX - v1.mX;
  788. float y1 = v2.mY - v1.mY;
  789. float y2 = v3.mY - v1.mY;
  790. float z1 = v2.mZ - v1.mZ;
  791. float z2 = v3.mZ - v1.mZ;
  792. float s1 = w2.mX - w1.mX;
  793. float s2 = w3.mX - w1.mX;
  794. float t1 = w2.mY - w1.mY;
  795. float t2 = w3.mY - w1.mY;
  796. float r = 1.0f / (s1 * t2 - s2 * t1);
  797. Vector3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
  798. (t2 * z1 - t1 * z2) * r);
  799. Vector3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
  800. (s1 * z2 - s2 * z1) * r);
  801. tan1[i1] += sdir;
  802. tan1[i2] += sdir;
  803. tan1[i3] += sdir;
  804. tan2[i1] += tdir;
  805. tan2[i2] += tdir;
  806. tan2[i3] += tdir;
  807. }
  808. for (unsigned a = 0; a < vertexCount; a++)
  809. {
  810. const Vector3 n = Vector3(&vertexData[a * V_SIZE + N_OFS]);
  811. const Vector3 t = Vector3(tan1[a]);
  812. Vector3 xyz;
  813. float w;
  814. // Gram-Schmidt orthogonalize
  815. xyz = (t - n * n.dotProduct(t)).getNormalized();
  816. // Calculate handedness
  817. w = n.crossProduct(t).dotProduct(tan2[a]) < 0.0f ? -1.0f : 1.0f;
  818. vertexData[a * V_SIZE + T_OFS] = xyz.mX;
  819. vertexData[a * V_SIZE + T_OFS + 1] = xyz.mY;
  820. vertexData[a * V_SIZE + T_OFS + 2] = xyz.mZ;
  821. vertexData[a * V_SIZE + T_OFS + 3] = w;
  822. }
  823. delete[] tan1;
  824. }