Sample.as 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // Common sample initialization as a framework for all samples.
  2. // - Create Urho3D logo at screen;
  3. // - Set custom window title and icon;
  4. // - Create Console and Debug HUD, and use F1 and F2 key to toggle them;
  5. // - Toggle rendering options from the keys 1-8;
  6. // - Take screenshots with key 9;
  7. // - Handle Esc key down to hide Console or exit application;
  8. // - Init touch input on mobile platform using screen joysticks (patched for each individual sample)
  9. Sprite@ logoSprite;
  10. Scene@ scene_;
  11. uint screenJoystickIndex = M_MAX_UNSIGNED; // Screen joystick index for navigational controls (mobile platforms only)
  12. uint screenJoystickSettingsIndex = M_MAX_UNSIGNED; // Screen joystick index for settings (mobile platforms only)
  13. bool touchEnabled = false; // Flag to indicate whether touch input has been enabled
  14. bool paused = false; // Pause flag
  15. bool drawDebug = false; // Draw debug geometry flag
  16. Node@ cameraNode; // Camera scene node
  17. float yaw = 0.0f; // Camera yaw angle
  18. float pitch = 0.0f; // Camera pitch angle
  19. const float TOUCH_SENSITIVITY = 2;
  20. void SampleStart()
  21. {
  22. if (GetPlatform() == "Android" || GetPlatform() == "iOS" || input.touchEmulation)
  23. // On mobile platform, enable touch by adding a screen joystick
  24. InitTouchInput();
  25. else if (input.numJoysticks == 0)
  26. // On desktop platform, do not detect touch when we already got a joystick
  27. SubscribeToEvent("TouchBegin", "HandleTouchBegin");
  28. // Create logo
  29. CreateLogo();
  30. // Set custom window Title & Icon
  31. SetWindowTitleAndIcon();
  32. // Create console and debug HUD
  33. CreateConsoleAndDebugHud();
  34. // Subscribe key down event
  35. SubscribeToEvent("KeyDown", "HandleKeyDown");
  36. // Subscribe scene update event
  37. SubscribeToEvent("SceneUpdate", "HandleSceneUpdate");
  38. }
  39. void InitTouchInput()
  40. {
  41. touchEnabled = true;
  42. XMLFile@ layout = cache.GetResource("XMLFile", "UI/ScreenJoystick_Samples.xml");
  43. if (!patchInstructions.empty)
  44. {
  45. // Patch the screen joystick layout further on demand
  46. XMLFile@ patchFile = XMLFile();
  47. if (patchFile.FromString(patchInstructions))
  48. layout.Patch(patchFile);
  49. }
  50. screenJoystickIndex = input.AddScreenJoystick(layout, cache.GetResource("XMLFile", "UI/DefaultStyle.xml"));
  51. input.screenJoystickVisible[0] = true;
  52. }
  53. void SetLogoVisible(bool enable)
  54. {
  55. if (logoSprite !is null)
  56. logoSprite.visible = enable;
  57. }
  58. void CreateLogo()
  59. {
  60. // Get logo texture
  61. Texture2D@ logoTexture = cache.GetResource("Texture2D", "Textures/LogoLarge.png");
  62. if (logoTexture is null)
  63. return;
  64. // Create logo sprite and add to the UI layout
  65. logoSprite = ui.root.CreateChild("Sprite");
  66. // Set logo sprite texture
  67. logoSprite.texture = logoTexture;
  68. int textureWidth = logoTexture.width;
  69. int textureHeight = logoTexture.height;
  70. // Set logo sprite scale
  71. logoSprite.SetScale(256.0f / textureWidth);
  72. // Set logo sprite size
  73. logoSprite.SetSize(textureWidth, textureHeight);
  74. // Set logo sprite hot spot
  75. logoSprite.SetHotSpot(0, textureHeight);
  76. // Set logo sprite alignment
  77. logoSprite.SetAlignment(HA_LEFT, VA_BOTTOM);
  78. // Make logo not fully opaque to show the scene underneath
  79. logoSprite.opacity = 0.75f;
  80. // Set a low priority for the logo so that other UI elements can be drawn on top
  81. logoSprite.priority = -100;
  82. }
  83. void SetWindowTitleAndIcon()
  84. {
  85. Image@ icon = cache.GetResource("Image", "Textures/UrhoIcon.png");
  86. graphics.windowIcon = icon;
  87. graphics.windowTitle = "Urho3D Sample";
  88. }
  89. void CreateConsoleAndDebugHud()
  90. {
  91. // Get default style
  92. XMLFile@ xmlFile = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
  93. if (xmlFile is null)
  94. return;
  95. // Create console
  96. Console@ console = engine.CreateConsole();
  97. console.defaultStyle = xmlFile;
  98. console.background.opacity = 0.8f;
  99. // Create debug HUD
  100. DebugHud@ debugHud = engine.CreateDebugHud();
  101. debugHud.defaultStyle = xmlFile;
  102. }
  103. void HandleKeyDown(StringHash eventType, VariantMap& eventData)
  104. {
  105. int key = eventData["Key"].GetInt();
  106. // Close console (if open) or exit when ESC is pressed
  107. if (key == KEY_ESC)
  108. {
  109. if (!console.visible)
  110. engine.Exit();
  111. else
  112. console.visible = false;
  113. }
  114. // Toggle console with F1
  115. else if (key == KEY_F1)
  116. console.Toggle();
  117. // Toggle debug HUD with F2
  118. else if (key == KEY_F2)
  119. {
  120. if (debugHud.mode == 0 || (debugHud.mode & DEBUGHUD_SHOW_MEMORY) > 0)
  121. debugHud.mode = DEBUGHUD_SHOW_STATS | DEBUGHUD_SHOW_MODE | DEBUGHUD_SHOW_PROFILER;
  122. else
  123. debugHud.mode = 0;
  124. }
  125. else if (key == KEY_F3)
  126. {
  127. if (debugHud.mode == 0 || (debugHud.mode & DEBUGHUD_SHOW_PROFILER) > 0)
  128. debugHud.mode = DEBUGHUD_SHOW_STATS | DEBUGHUD_SHOW_MODE | DEBUGHUD_SHOW_MEMORY;
  129. else
  130. debugHud.mode = 0;
  131. }
  132. // Common rendering quality controls, only when UI has no focused element
  133. if (ui.focusElement is null)
  134. {
  135. // Preferences / Pause
  136. if (key == KEY_SELECT && touchEnabled)
  137. {
  138. paused = !paused;
  139. if (screenJoystickSettingsIndex == M_MAX_UNSIGNED)
  140. {
  141. // Lazy initialization
  142. screenJoystickSettingsIndex = input.AddScreenJoystick(cache.GetResource("XMLFile", "UI/ScreenJoystickSettings_Samples.xml"), cache.GetResource("XMLFile", "UI/DefaultStyle.xml"));
  143. }
  144. else
  145. input.screenJoystickVisible[screenJoystickSettingsIndex] = paused;
  146. }
  147. // Texture quality
  148. else if (key == '1')
  149. {
  150. int quality = renderer.textureQuality;
  151. ++quality;
  152. if (quality > QUALITY_HIGH)
  153. quality = QUALITY_LOW;
  154. renderer.textureQuality = quality;
  155. }
  156. // Material quality
  157. else if (key == '2')
  158. {
  159. int quality = renderer.materialQuality;
  160. ++quality;
  161. if (quality > QUALITY_HIGH)
  162. quality = QUALITY_LOW;
  163. renderer.materialQuality = quality;
  164. }
  165. // Specular lighting
  166. else if (key == '3')
  167. renderer.specularLighting = !renderer.specularLighting;
  168. // Shadow rendering
  169. else if (key == '4')
  170. renderer.drawShadows = !renderer.drawShadows;
  171. // Shadow map resolution
  172. else if (key == '5')
  173. {
  174. int shadowMapSize = renderer.shadowMapSize;
  175. shadowMapSize *= 2;
  176. if (shadowMapSize > 2048)
  177. shadowMapSize = 512;
  178. renderer.shadowMapSize = shadowMapSize;
  179. }
  180. // Shadow depth and filtering quality
  181. else if (key == '6')
  182. {
  183. ShadowQuality quality = renderer.shadowQuality;
  184. quality = ShadowQuality(quality + 1);
  185. if (quality > SHADOWQUALITY_BLUR_VSM)
  186. quality = SHADOWQUALITY_SIMPLE_16BIT;
  187. renderer.shadowQuality = quality;
  188. }
  189. // Occlusion culling
  190. else if (key == '7')
  191. {
  192. bool occlusion = renderer.maxOccluderTriangles > 0;
  193. occlusion = !occlusion;
  194. renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
  195. }
  196. // Instancing
  197. else if (key == '8')
  198. renderer.dynamicInstancing = !renderer.dynamicInstancing;
  199. // Take screenshot
  200. else if (key == '9')
  201. {
  202. Image@ screenshot = Image();
  203. graphics.TakeScreenShot(screenshot);
  204. // Here we save in the Data folder with date and time appended
  205. screenshot.SavePNG(fileSystem.programDir + "Data/Screenshot_" +
  206. time.timeStamp.Replaced(':', '_').Replaced('.', '_').Replaced(' ', '_') + ".png");
  207. }
  208. }
  209. }
  210. void HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
  211. {
  212. // Move the camera by touch, if the camera node is initialized by descendant sample class
  213. if (touchEnabled && cameraNode !is null)
  214. {
  215. for (uint i = 0; i < input.numTouches; ++i)
  216. {
  217. TouchState@ state = input.touches[i];
  218. if (state.touchedElement is null) // Touch on empty space
  219. {
  220. if (state.delta.x !=0 || state.delta.y !=0)
  221. {
  222. Camera@ camera = cameraNode.GetComponent("Camera");
  223. if (camera is null)
  224. return;
  225. yaw += TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.x;
  226. pitch += TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.y;
  227. // Construct new orientation for the camera scene node from yaw and pitch; roll is fixed to zero
  228. cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);
  229. }
  230. else
  231. {
  232. // Move the cursor to the touch position
  233. Cursor@ cursor = ui.cursor;
  234. if (cursor !is null && cursor.visible)
  235. cursor.position = state.position;
  236. }
  237. }
  238. }
  239. }
  240. }
  241. void HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  242. {
  243. // On some platforms like Windows the presence of touch input can only be detected dynamically
  244. InitTouchInput();
  245. UnsubscribeFromEvent("TouchBegin");
  246. }