Sample.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. local logoSprite = nil
  10. scene_ = nil -- Scene
  11. screenJoystickIndex = M_MAX_UNSIGNED -- Screen joystick index for navigational controls (mobile platforms only)
  12. screenJoystickSettingsIndex = M_MAX_UNSIGNED -- Screen joystick index for settings (mobile platforms only)
  13. touchEnabled = false -- Flag to indicate whether touch input has been enabled
  14. paused = false -- Pause flag
  15. drawDebug = false -- Draw debug geometry flag
  16. cameraNode = nil -- Camera scene node
  17. yaw = 0 -- Camera yaw angle
  18. pitch = 0 -- Camera pitch angle
  19. TOUCH_SENSITIVITY = 2
  20. debugHudMode = 0
  21. useMouseMode_ = MM_ABSOLUTE
  22. function SampleStart()
  23. if GetPlatform() == "Android" or GetPlatform() == "iOS" or input.touchEmulation then
  24. -- On mobile platform, enable touch by adding a screen joystick
  25. InitTouchInput()
  26. elseif input:GetNumJoysticks() == 0 then
  27. -- On desktop platform, do not detect touch when we already got a joystick
  28. SubscribeToEvent("TouchBegin", "HandleTouchBegin")
  29. end
  30. -- Create logo
  31. CreateLogo()
  32. -- Set custom window Title & Icon
  33. SetWindowTitleAndIcon()
  34. -- Create console and debug HUD
  35. CreateConsoleAndDebugHud()
  36. -- Subscribe key down event
  37. SubscribeToEvent("KeyDown", "HandleKeyDown")
  38. -- Subscribe key up event
  39. SubscribeToEvent("KeyUp", "HandleKeyUp")
  40. -- Subscribe scene update event
  41. SubscribeToEvent("SceneUpdate", "HandleSceneUpdate")
  42. end
  43. function InitTouchInput()
  44. touchEnabled = true
  45. local layout = cache:GetResource("XMLFile", "UI/ScreenJoystick_Samples.xml")
  46. local patchString = GetScreenJoystickPatchString()
  47. if patchString ~= "" then
  48. -- Patch the screen joystick layout further on demand
  49. local patchFile = XMLFile()
  50. if patchFile:FromString(patchString) then layout:Patch(patchFile) end
  51. end
  52. screenJoystickIndex = input:AddScreenJoystick(layout, cache:GetResource("XMLFile", "UI/DefaultStyle.xml"))
  53. input:SetScreenJoystickVisible(screenJoystickSettingsIndex, true)
  54. end
  55. function SampleInitMouseMode(mode)
  56. useMouseMode_ = mode
  57. if GetPlatform() ~= "Web" then
  58. if useMouseMode_ == MM_FREE then
  59. input.mouseVisible = true
  60. end
  61. if useMouseMode_ ~= MM_ABSOLUTE then
  62. input.mouseMode = useMouseMode_
  63. if console ~= nil and console.visible then
  64. input:SetMouseMode(MM_ABSOLUTE, true)
  65. end
  66. end
  67. else
  68. input.mouseVisible = true
  69. SubscribeToEvent("MouseDown", "HandleMouseModeRequest")
  70. SubscribeToEvent("MouseModeChanged", "HandleMouseModeChange")
  71. end
  72. end
  73. function SetLogoVisible(enable)
  74. if logoSprite ~= nil then
  75. logoSprite.visible = enable
  76. end
  77. end
  78. function CreateLogo()
  79. -- Get logo texture
  80. local logoTexture = cache:GetResource("Texture2D", "Textures/LogoLarge.png")
  81. if logoTexture == nil then
  82. return
  83. end
  84. -- Create logo sprite and add to the UI layout
  85. logoSprite = ui.root:CreateChild("Sprite")
  86. -- Set logo sprite texture
  87. logoSprite:SetTexture(logoTexture)
  88. local textureWidth = logoTexture.width
  89. local textureHeight = logoTexture.height
  90. -- Set logo sprite scale
  91. logoSprite:SetScale(256 / textureWidth)
  92. -- Set logo sprite size
  93. logoSprite:SetSize(textureWidth, textureHeight)
  94. -- Set logo sprite hot spot
  95. logoSprite.hotSpot = IntVector2(0, textureHeight)
  96. -- Set logo sprite alignment
  97. logoSprite:SetAlignment(HA_LEFT, VA_BOTTOM);
  98. -- Make logo not fully opaque to show the scene underneath
  99. logoSprite.opacity = 0.75
  100. -- Set a low priority for the logo so that other UI elements can be drawn on top
  101. logoSprite.priority = -100
  102. end
  103. function SetWindowTitleAndIcon()
  104. local icon = cache:GetResource("Image", "Textures/UrhoIcon.png")
  105. graphics:SetWindowIcon(icon)
  106. graphics.windowTitle = "Urho3D Sample"
  107. end
  108. function CreateConsoleAndDebugHud()
  109. -- Get default style
  110. local uiStyle = cache:GetResource("XMLFile", "UI/DefaultStyle.xml")
  111. if uiStyle == nil then
  112. return
  113. end
  114. -- Create console
  115. engine:CreateConsole()
  116. console.defaultStyle = uiStyle
  117. console.background.opacity = 0.8
  118. -- Create debug HUD
  119. engine:CreateDebugHud()
  120. debugHud.defaultStyle = uiStyle
  121. end
  122. function HandleKeyUp(eventType, eventData)
  123. local key = eventData["Key"]:GetInt()
  124. -- Close console (if open) or exit when ESC is pressed
  125. if key == KEY_ESC then
  126. if console:IsVisible() then
  127. console:SetVisible(false)
  128. else
  129. if GetPlatform() == "Web" then
  130. input.mouseVisible = true;
  131. if (useMouseMode_ ~= MM_ABSOLUTE) then
  132. input.mouseMode = MM_FREE;
  133. end
  134. else
  135. engine:Exit();
  136. end
  137. end
  138. end
  139. end
  140. function HandleKeyDown(eventType, eventData)
  141. local key = eventData["Key"]:GetInt()
  142. if key == KEY_F1 then
  143. console:Toggle()
  144. elseif key == KEY_F2 then
  145. if debugHud:GetMode() == DEBUGHUD_SHOW_ALL_MEMORY or debugHud:GetMode() == 0 then
  146. debugHud:SetMode(DEBUGHUD_SHOW_ALL)
  147. else
  148. debugHud:SetMode(0)
  149. end
  150. elseif key == KEY_F3 then
  151. if debugHud:GetMode() == DEBUGHUD_SHOW_ALL or debugHud:GetMode() == 0 then
  152. debugHud:SetMode(DEBUGHUD_SHOW_ALL_MEMORY)
  153. else
  154. debugHud:SetMode(0)
  155. end
  156. end
  157. if ui.focusElement == nil then
  158. -- Preferences / Pause
  159. if key == KEY_SELECT and touchEnabled then
  160. paused = not paused
  161. if screenJoystickSettingsIndex == M_MAX_UNSIGNED then
  162. -- Lazy initialization
  163. screenJoystickSettingsIndex = input:AddScreenJoystick(cache:GetResource("XMLFile", "UI/ScreenJoystickSettings_Samples.xml"), cache:GetResource("XMLFile", "UI/DefaultStyle.xml"))
  164. else
  165. input:SetScreenJoystickVisible(screenJoystickSettingsIndex, paused)
  166. end
  167. -- Texture quality
  168. elseif key == KEY_1 then
  169. local quality = renderer.textureQuality
  170. quality = quality + 1
  171. if quality > QUALITY_HIGH then
  172. quality = QUALITY_LOW
  173. end
  174. renderer.textureQuality = quality
  175. -- Material quality
  176. elseif key == KEY_2 then
  177. local quality = renderer.materialQuality
  178. quality = quality + 1
  179. if quality > QUALITY_HIGH then
  180. quality = QUALITY_LOW
  181. end
  182. renderer.materialQuality = quality
  183. -- Specular lighting
  184. elseif key == KEY_3 then
  185. renderer.specularLighting = not renderer.specularLighting
  186. -- Shadow rendering
  187. elseif key == KEY_4 then
  188. renderer.drawShadows = not renderer.drawShadows
  189. -- Shadow map resolution
  190. elseif key == KEY_5 then
  191. local shadowMapSize = renderer.shadowMapSize
  192. shadowMapSize = shadowMapSize * 2
  193. if shadowMapSize > 2048 then
  194. shadowMapSize = 512
  195. end
  196. renderer.shadowMapSize = shadowMapSize
  197. -- Shadow depth and filtering quality
  198. elseif key == KEY_6 then
  199. local quality = renderer.shadowQuality
  200. quality = quality + 1
  201. if quality > SHADOWQUALITY_BLUR_VSM then
  202. quality = SHADOWQUALITY_SIMPLE_16BIT
  203. end
  204. renderer.shadowQuality = quality
  205. -- Occlusion culling
  206. elseif key == KEY_7 then
  207. local occlusion = renderer.maxOccluderTriangles > 0
  208. occlusion = not occlusion
  209. if occlusion then
  210. renderer.maxOccluderTriangles = 5000
  211. else
  212. renderer.maxOccluderTriangles = 0
  213. end
  214. -- Instancing
  215. elseif key == KEY_8 then
  216. renderer.dynamicInstancing = not renderer.dynamicInstancing
  217. -- Take screenshot
  218. elseif key == KEY_9 then
  219. local screenshot = Image()
  220. graphics:TakeScreenShot(screenshot)
  221. local timeStamp = Time:GetTimeStamp()
  222. timeStamp = string.gsub(timeStamp, "[:. ]", "_")
  223. -- Here we save in the Data folder with date and time appended
  224. screenshot:SavePNG(fileSystem:GetProgramDir() .. "Data/Screenshot_" .. timeStamp .. ".png")
  225. end
  226. end
  227. end
  228. function HandleSceneUpdate(eventType, eventData)
  229. -- Move the camera by touch, if the camera node is initialized by descendant sample class
  230. if touchEnabled and cameraNode then
  231. for i=0, input:GetNumTouches()-1 do
  232. local state = input:GetTouch(i)
  233. if not state.touchedElement then -- Touch on empty space
  234. if state.delta.x or state.delta.y then
  235. local camera = cameraNode:GetComponent("Camera")
  236. if not camera then return end
  237. yaw = yaw + TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.x
  238. pitch = pitch + TOUCH_SENSITIVITY * camera.fov / graphics.height * state.delta.y
  239. -- Construct new orientation for the camera scene node from yaw and pitch; roll is fixed to zero
  240. cameraNode:SetRotation(Quaternion(pitch, yaw, 0))
  241. else
  242. -- Move the cursor to the touch position
  243. local cursor = ui:GetCursor()
  244. if cursor and cursor:IsVisible() then cursor:SetPosition(state.position) end
  245. end
  246. end
  247. end
  248. end
  249. end
  250. function HandleTouchBegin(eventType, eventData)
  251. -- On some platforms like Windows the presence of touch input can only be detected dynamically
  252. InitTouchInput()
  253. UnsubscribeFromEvent("TouchBegin")
  254. end
  255. -- If the user clicks the canvas, attempt to switch to relative mouse mode on web platform
  256. function HandleMouseModeRequest(eventType, eventData)
  257. if console ~= nil and console.visible then
  258. return
  259. end
  260. if input.mouseMode == MM_ABSOLUTE then
  261. input.mouseVisible = false
  262. elseif useMouseMode_ == MM_FREE then
  263. input.mouseVisible = true
  264. end
  265. input.mouseMode = useMouseMode_
  266. end
  267. -- If the user clicks the canvas, attempt to switch to relative mouse mode on web platform
  268. function HandleMouseModeChange(eventType, eventData)
  269. mouseLocked = eventData["MouseLocked"]:GetBool()
  270. input.mouseVisible = not mouseLocked;
  271. end
  272. -- Create empty XML patch instructions for screen joystick layout if none defined
  273. function GetScreenJoystickPatchString()
  274. return ""
  275. end