Sample.as 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. MouseMode useMouseMode_ = MM_ABSOLUTE;
  21. void SampleStart()
  22. {
  23. if (GetPlatform() == "Android" || GetPlatform() == "iOS" || input.touchEmulation)
  24. // On mobile platform, enable touch by adding a screen joystick
  25. InitTouchInput();
  26. else if (input.numJoysticks == 0)
  27. // On desktop platform, do not detect touch when we already got a joystick
  28. SubscribeToEvent("TouchBegin", "HandleTouchBegin");
  29. // Create logo
  30. CreateLogo();
  31. // Set custom window Title & Icon
  32. SetWindowTitleAndIcon();
  33. // Create console and debug HUD
  34. CreateConsoleAndDebugHud();
  35. // Subscribe key down event
  36. SubscribeToEvent("KeyDown", "HandleKeyDown");
  37. // Subscribe key up event
  38. SubscribeToEvent("KeyUp", "HandleKeyUp");
  39. // Subscribe scene update event
  40. SubscribeToEvent("SceneUpdate", "HandleSceneUpdate");
  41. }
  42. void InitTouchInput()
  43. {
  44. touchEnabled = true;
  45. XMLFile@ layout = cache.GetResource("XMLFile", "UI/ScreenJoystick_Samples.xml");
  46. if (!patchInstructions.empty)
  47. {
  48. // Patch the screen joystick layout further on demand
  49. XMLFile@ patchFile = XMLFile();
  50. if (patchFile.FromString(patchInstructions))
  51. layout.Patch(patchFile);
  52. }
  53. screenJoystickIndex = input.AddScreenJoystick(layout, cache.GetResource("XMLFile", "UI/DefaultStyle.xml"));
  54. input.screenJoystickVisible[0] = true;
  55. }
  56. void SampleInitMouseMode(MouseMode mode)
  57. {
  58. useMouseMode_ = mode;
  59. if (GetPlatform() != "Web")
  60. {
  61. if (useMouseMode_ == MM_FREE)
  62. input.mouseVisible = true;
  63. if (useMouseMode_ != MM_ABSOLUTE)
  64. {
  65. input.mouseMode = useMouseMode_;
  66. if (console.visible)
  67. input.SetMouseMode(MM_ABSOLUTE, true);
  68. }
  69. }
  70. else
  71. {
  72. input.mouseVisible = true;
  73. SubscribeToEvent("MouseDown", "HandleMouseModeRequest");
  74. SubscribeToEvent("MouseModeChanged", "HandleMouseModeChange");
  75. }
  76. }
  77. void SetLogoVisible(bool enable)
  78. {
  79. if (logoSprite !is null)
  80. logoSprite.visible = enable;
  81. }
  82. void CreateLogo()
  83. {
  84. // Get logo texture
  85. Texture2D@ logoTexture = cache.GetResource("Texture2D", "Textures/LogoLarge.png");
  86. if (logoTexture is null)
  87. return;
  88. // Create logo sprite and add to the UI layout
  89. logoSprite = ui.root.CreateChild("Sprite");
  90. // Set logo sprite texture
  91. logoSprite.texture = logoTexture;
  92. int textureWidth = logoTexture.width;
  93. int textureHeight = logoTexture.height;
  94. // Set logo sprite scale
  95. logoSprite.SetScale(256.0f / textureWidth);
  96. // Set logo sprite size
  97. logoSprite.SetSize(textureWidth, textureHeight);
  98. // Set logo sprite hot spot
  99. logoSprite.SetHotSpot(0, textureHeight);
  100. // Set logo sprite alignment
  101. logoSprite.SetAlignment(HA_LEFT, VA_BOTTOM);
  102. // Make logo not fully opaque to show the scene underneath
  103. logoSprite.opacity = 0.75f;
  104. // Set a low priority for the logo so that other UI elements can be drawn on top
  105. logoSprite.priority = -100;
  106. }
  107. void SetWindowTitleAndIcon()
  108. {
  109. Image@ icon = cache.GetResource("Image", "Textures/UrhoIcon.png");
  110. graphics.windowIcon = icon;
  111. graphics.windowTitle = "Urho3D Sample";
  112. }
  113. void CreateConsoleAndDebugHud()
  114. {
  115. // Get default style
  116. XMLFile@ xmlFile = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
  117. if (xmlFile is null)
  118. return;
  119. // Create console
  120. Console@ console = engine.CreateConsole();
  121. console.defaultStyle = xmlFile;
  122. console.background.opacity = 0.8f;
  123. // Create debug HUD
  124. DebugHud@ debugHud = engine.CreateDebugHud();
  125. debugHud.defaultStyle = xmlFile;
  126. }
  127. void HandleKeyUp(StringHash eventType, VariantMap& eventData)
  128. {
  129. int key = eventData["Key"].GetInt();
  130. // Close console (if open) or exit when ESC is pressed
  131. if (key == KEY_ESC)
  132. {
  133. if (console.visible)
  134. console.visible = false;
  135. else
  136. {
  137. if (GetPlatform() == "Web")
  138. {
  139. input.mouseVisible = true;
  140. if (useMouseMode_ != MM_ABSOLUTE)
  141. input.mouseMode = MM_FREE;
  142. }
  143. else
  144. engine.Exit();
  145. }
  146. }
  147. }
  148. void HandleKeyDown(StringHash eventType, VariantMap& eventData)
  149. {
  150. int key = eventData["Key"].GetInt();
  151. // Toggle console with F1
  152. if (key == KEY_F1)
  153. console.Toggle();
  154. // Toggle debug HUD with F2
  155. else if (key == KEY_F2)
  156. {
  157. if (debugHud.mode == 0 || (debugHud.mode & DEBUGHUD_SHOW_MEMORY) > 0)
  158. debugHud.mode = DEBUGHUD_SHOW_STATS | DEBUGHUD_SHOW_MODE | DEBUGHUD_SHOW_PROFILER;
  159. else
  160. debugHud.mode = 0;
  161. }
  162. else if (key == KEY_F3)
  163. {
  164. if (debugHud.mode == 0 || (debugHud.mode & DEBUGHUD_SHOW_PROFILER) > 0)
  165. debugHud.mode = DEBUGHUD_SHOW_STATS | DEBUGHUD_SHOW_MODE | DEBUGHUD_SHOW_MEMORY;
  166. else
  167. debugHud.mode = 0;
  168. }
  169. // Common rendering quality controls, only when UI has no focused element
  170. if (ui.focusElement is null)
  171. {
  172. // Preferences / Pause
  173. if (key == KEY_SELECT && touchEnabled)
  174. {
  175. paused = !paused;
  176. if (screenJoystickSettingsIndex == M_MAX_UNSIGNED)
  177. {
  178. // Lazy initialization
  179. screenJoystickSettingsIndex = input.AddScreenJoystick(cache.GetResource("XMLFile", "UI/ScreenJoystickSettings_Samples.xml"), cache.GetResource("XMLFile", "UI/DefaultStyle.xml"));
  180. }
  181. else
  182. input.screenJoystickVisible[screenJoystickSettingsIndex] = paused;
  183. }
  184. // Texture quality
  185. else if (key == '1')
  186. {
  187. int quality = renderer.textureQuality;
  188. ++quality;
  189. if (quality > QUALITY_HIGH)
  190. quality = QUALITY_LOW;
  191. renderer.textureQuality = quality;
  192. }
  193. // Material quality
  194. else if (key == '2')
  195. {
  196. int quality = renderer.materialQuality;
  197. ++quality;
  198. if (quality > QUALITY_HIGH)
  199. quality = QUALITY_LOW;
  200. renderer.materialQuality = quality;
  201. }
  202. // Specular lighting
  203. else if (key == '3')
  204. renderer.specularLighting = !renderer.specularLighting;
  205. // Shadow rendering
  206. else if (key == '4')
  207. renderer.drawShadows = !renderer.drawShadows;
  208. // Shadow map resolution
  209. else if (key == '5')
  210. {
  211. int shadowMapSize = renderer.shadowMapSize;
  212. shadowMapSize *= 2;
  213. if (shadowMapSize > 2048)
  214. shadowMapSize = 512;
  215. renderer.shadowMapSize = shadowMapSize;
  216. }
  217. // Shadow depth and filtering quality
  218. else if (key == '6')
  219. {
  220. ShadowQuality quality = renderer.shadowQuality;
  221. quality = ShadowQuality(quality + 1);
  222. if (quality > SHADOWQUALITY_BLUR_VSM)
  223. quality = SHADOWQUALITY_SIMPLE_16BIT;
  224. renderer.shadowQuality = quality;
  225. }
  226. // Occlusion culling
  227. else if (key == '7')
  228. {
  229. bool occlusion = renderer.maxOccluderTriangles > 0;
  230. occlusion = !occlusion;
  231. renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
  232. }
  233. // Instancing
  234. else if (key == '8')
  235. renderer.dynamicInstancing = !renderer.dynamicInstancing;
  236. // Take screenshot
  237. else if (key == '9')
  238. {
  239. Image@ screenshot = Image();
  240. graphics.TakeScreenShot(screenshot);
  241. // Here we save in the Data folder with date and time appended
  242. screenshot.SavePNG(fileSystem.programDir + "Data/Screenshot_" +
  243. time.timeStamp.Replaced(':', '_').Replaced('.', '_').Replaced(' ', '_') + ".png");
  244. }
  245. }
  246. }
  247. void HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
  248. {
  249. // Move the camera by touch, if the camera node is initialized by descendant sample class
  250. if (touchEnabled && cameraNode !is null)
  251. {
  252. for (uint i = 0; i < input.numTouches; ++i)
  253. {
  254. TouchState@ state = input.touches[i];
  255. if (state.touchedElement is null) // Touch on empty space
  256. {
  257. if (state.delta.x !=0 || state.delta.y !=0)
  258. {
  259. Camera@ camera = cameraNode.GetComponent("Camera");
  260. if (camera is null)
  261. return;
  262. yaw += TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.x;
  263. pitch += TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.y;
  264. // Construct new orientation for the camera scene node from yaw and pitch; roll is fixed to zero
  265. cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);
  266. }
  267. else
  268. {
  269. // Move the cursor to the touch position
  270. Cursor@ cursor = ui.cursor;
  271. if (cursor !is null && cursor.visible)
  272. cursor.position = state.position;
  273. }
  274. }
  275. }
  276. }
  277. }
  278. void HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  279. {
  280. // On some platforms like Windows the presence of touch input can only be detected dynamically
  281. InitTouchInput();
  282. UnsubscribeFromEvent("TouchBegin");
  283. }
  284. // If the user clicks the canvas, attempt to switch to relative mouse mode on web platform
  285. void HandleMouseModeRequest(StringHash eventType, VariantMap& eventData)
  286. {
  287. if (console !is null && console.visible)
  288. return;
  289. if (useMouseMode_ == MM_ABSOLUTE)
  290. input.mouseVisible = false;
  291. else if (useMouseMode_ == MM_FREE)
  292. input.mouseVisible = true;
  293. input.mouseMode = useMouseMode_;
  294. }
  295. void HandleMouseModeChange(StringHash eventType, VariantMap& eventData)
  296. {
  297. bool mouseLocked = eventData["MouseLocked"].GetBool();
  298. input.SetMouseVisible(!mouseLocked);
  299. }