48_Hello3DUI.lua 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. -- A 3D UI demonstration based on the HelloGUI sample. Renders UI alternatively
  2. -- either to a 3D scene object using UIComponent, or directly to the backbuffer.
  3. require "LuaScripts/Utilities/Sample"
  4. local window = nil
  5. local dragBeginPosition = IntVector2(0, 0)
  6. local textureRoot = nil
  7. local current = nil
  8. local renderOnCube = false
  9. local drawDebug = false
  10. local animateCube = true
  11. function Start()
  12. -- Execute the common startup for samples
  13. SampleStart()
  14. -- Enable OS cursor
  15. input.mouseVisible = true
  16. -- Load XML file containing default UI style sheet
  17. local style = cache:GetResource("XMLFile", "UI/DefaultStyle.xml")
  18. -- Set the loaded style as default style
  19. ui.root.defaultStyle = style
  20. -- Initialize Scene
  21. InitScene()
  22. -- Initialize Window
  23. InitWindow()
  24. -- Create and add some controls to the Window
  25. InitControls()
  26. -- Create a draggable Fish
  27. CreateDraggableFish()
  28. -- Create 3D UI rendered on a cube.
  29. Init3DUI()
  30. -- Set the mouse mode to use in the sample
  31. SampleInitMouseMode(MM_FREE)
  32. end
  33. function InitControls()
  34. -- Create a CheckBox
  35. local checkBox = CheckBox:new()
  36. checkBox:SetName("CheckBox")
  37. -- Create a Button
  38. local button = Button:new()
  39. button:SetName("Button")
  40. button.minHeight = 24
  41. -- Create a LineEdit
  42. local lineEdit = LineEdit:new()
  43. lineEdit:SetName("LineEdit")
  44. lineEdit.minHeight = 24
  45. -- Add controls to Window
  46. window:AddChild(checkBox)
  47. window:AddChild(button)
  48. window:AddChild(lineEdit)
  49. -- Apply previously set default style
  50. checkBox:SetStyleAuto()
  51. button:SetStyleAuto()
  52. lineEdit:SetStyleAuto()
  53. local instructions = Text:new()
  54. instructions:SetStyleAuto()
  55. instructions.text = "[TAB] - toggle between rendering on screen or cube.\n"..
  56. "[Space] - toggle cube rotation."
  57. ui.root:AddChild(instructions)
  58. end
  59. function InitScene()
  60. scene_ = Scene()
  61. scene_:CreateComponent("Octree")
  62. local zone = scene_:CreateComponent("Zone")
  63. zone.boundingBox = BoundingBox(-1000.0, 1000.0)
  64. zone.fogColor = Color(0.5, 0.5, 0.5)
  65. zone.fogStart = 100.0
  66. zone.fogEnd = 300.0
  67. -- Create a child scene node (at world origin) and a StaticModel component into it.
  68. local boxNode = scene_:CreateChild("Box")
  69. boxNode.scale = Vector3(5.0, 5.0, 5.0)
  70. boxNode.rotation = Quaternion(90, Vector3(1, 0, 0))
  71. -- Create a box model and hide it initially.
  72. local boxModel = boxNode:CreateComponent("StaticModel")
  73. boxModel.model = cache:GetResource("Model", "Models/Box.mdl")
  74. boxNode.enabled = false
  75. -- Create a camera.
  76. cameraNode = scene_:CreateChild("Camera")
  77. cameraNode:CreateComponent("Camera")
  78. -- Set an initial position for the camera scene node.
  79. cameraNode.position = Vector3(0.0, 0.0, -10.0)
  80. -- Set up a viewport so 3D scene can be visible.
  81. local viewport = Viewport:new(scene_, cameraNode:GetComponent("Camera"))
  82. renderer:SetViewport(0, viewport)
  83. -- Subscribe to update event and animate cube and handle input.
  84. SubscribeToEvent("Update", "HandleUpdate")
  85. end
  86. function InitWindow()
  87. -- Create the Window and add it to the UI's root node
  88. window = Window:new()
  89. ui.root:AddChild(window)
  90. -- Set Window size and layout settings
  91. window.minWidth = 384
  92. window:SetLayout(LM_VERTICAL, 6, IntRect(6, 6, 6, 6))
  93. window:SetAlignment(HA_CENTER, VA_CENTER)
  94. window:SetName("Window")
  95. -- Create Window 'titlebar' container
  96. local titleBar = UIElement:new()
  97. titleBar:SetMinSize(0, 24)
  98. titleBar.verticalAlignment = VA_TOP
  99. titleBar.layoutMode = LM_HORIZONTAL
  100. -- Create the Window title Text
  101. local windowTitle = Text:new()
  102. windowTitle.name = "WindowTitle"
  103. windowTitle.text = "Hello GUI!"
  104. -- Create the Window's close button
  105. local buttonClose = Button:new()
  106. buttonClose:SetName("CloseButton")
  107. -- Add the controls to the title bar
  108. titleBar:AddChild(windowTitle)
  109. titleBar:AddChild(buttonClose)
  110. -- Add the title bar to the Window
  111. window:AddChild(titleBar)
  112. -- Create a list.
  113. local list = window:CreateChild("ListView")
  114. list.selectOnClickEnd = true
  115. list.highlightMode = HM_ALWAYS
  116. list.minHeight = 200
  117. for i = 0, 31 do
  118. local text = Text:new()
  119. text:SetStyleAuto()
  120. text.text = "List item " .. i
  121. text.name = "Item " .. i
  122. list:AddItem(text)
  123. end
  124. -- Apply styles
  125. window:SetStyleAuto()
  126. list:SetStyleAuto()
  127. windowTitle:SetStyleAuto()
  128. buttonClose:SetStyle("CloseButton")
  129. -- Subscribe to buttonClose release (following a 'press') events
  130. SubscribeToEvent(buttonClose, "Released",
  131. function (eventType, eventData)
  132. engine:Exit()
  133. end)
  134. -- Subscribe also to all UI mouse clicks just to see where we have clicked
  135. SubscribeToEvent("UIMouseClick", HandleControlClicked)
  136. end
  137. function CreateDraggableFish()
  138. -- Create a draggable Fish button
  139. local draggableFish = ui.root:CreateChild("Button", "Fish")
  140. draggableFish.texture = cache:GetResource("Texture2D", "Textures/UrhoDecal.dds") -- Set texture
  141. draggableFish.blendMode = BLEND_ADD
  142. draggableFish:SetSize(128, 128)
  143. draggableFish:SetPosition((GetGraphics().width - draggableFish.width) / 2, 200)
  144. -- Add a tooltip to Fish button
  145. local toolTip = draggableFish:CreateChild("ToolTip")
  146. toolTip.position = IntVector2(draggableFish.width + 5, draggableFish.width/2) -- Slightly offset from fish
  147. local textHolder = toolTip:CreateChild("BorderImage")
  148. textHolder:SetStyle("ToolTipBorderImage")
  149. local toolTipText = textHolder:CreateChild("Text")
  150. toolTipText:SetStyle("ToolTipText")
  151. toolTipText.text = "Please drag me!"
  152. -- Subscribe draggableFish to Drag Events (in order to make it draggable)
  153. -- See "Event list" in documentation's Main Page for reference on available Events and their eventData
  154. SubscribeToEvent(draggableFish, "DragBegin",
  155. function (eventType, eventData)
  156. -- Get UIElement relative position where input (touch or click) occurred (top-left = IntVector2(0,0))
  157. dragBeginPosition = IntVector2(eventData["ElementX"]:GetInt(), eventData["ElementY"]:GetInt())
  158. end)
  159. SubscribeToEvent(draggableFish, "DragMove",
  160. function (eventType, eventData)
  161. local dragCurrentPosition = IntVector2(eventData["X"]:GetInt(), eventData["Y"]:GetInt())
  162. -- Get the dragged fish element
  163. -- Note difference to C++: in C++ we would call GetPtr() and cast the pointer to UIElement, here we must specify
  164. -- what kind of object we are getting. Null will be returned on type mismatch
  165. local draggedElement = eventData["Element"]:GetPtr("UIElement")
  166. draggedElement:SetPosition(dragCurrentPosition - dragBeginPosition)
  167. end)
  168. SubscribeToEvent(draggableFish, "DragEnd",
  169. function (eventType, eventData)
  170. end)
  171. end
  172. function HandleControlClicked(eventType, eventData)
  173. -- Get the Text control acting as the Window's title
  174. local element = window:GetChild("WindowTitle", true)
  175. local windowTitle = tolua.cast(element, 'Text')
  176. -- Get control that was clicked
  177. local clicked = eventData["Element"]:GetPtr("UIElement")
  178. local name = "...?"
  179. if clicked ~= nil then
  180. -- Get the name of the control that was clicked
  181. name = clicked.name
  182. end
  183. -- Update the Window's title text
  184. windowTitle.text = "Hello " .. name .. "!"
  185. end
  186. function Init3DUI()
  187. -- Node that will get UI rendered on it.
  188. local boxNode = scene_:GetChild("Box")
  189. -- Create a component that sets up UI rendering. It sets material to StaticModel of the node.
  190. local component = boxNode:CreateComponent("UIComponent")
  191. -- Optionally modify material. Technique is changed so object is visible without any lights.
  192. component.material:SetTechnique(0, cache:GetResource("Technique", "Techniques/DiffUnlit.xml"))
  193. -- Save root element of texture UI for later use.
  194. textureRoot = component.root
  195. -- Set size of root element. This is size of texture as well.
  196. textureRoot:SetSize(512, 512)
  197. end
  198. function HandleUpdate(eventType, eventData)
  199. local timeStep = eventData["TimeStep"]:GetFloat()
  200. local node = scene_:GetChild("Box")
  201. if current ~= nil and drawDebug then
  202. ui:DebugDraw(current)
  203. end
  204. if input:GetMouseButtonPress(MOUSEB_LEFT) then
  205. current = ui:GetElementAt(input.mousePosition)
  206. end
  207. if input:GetKeyPress(KEY_TAB) then
  208. renderOnCube = not renderOnCube
  209. -- Toggle between rendering on screen or to texture.
  210. if renderOnCube then
  211. node.enabled = true
  212. textureRoot:AddChild(window)
  213. else
  214. node.enabled = false
  215. ui.root:AddChild(window)
  216. end
  217. end
  218. if input:GetKeyPress(KEY_SPACE) then
  219. animateCube = not animateCube
  220. end
  221. if input:GetKeyPress(KEY_F2) then
  222. drawDebug = not drawDebug
  223. end
  224. if animateCube then
  225. node:Yaw(6.0 * timeStep * 1.5)
  226. node:Roll(-6.0 * timeStep * 1.5)
  227. node:Pitch(-6.0 * timeStep * 1.5)
  228. end
  229. end
  230. -- Create XML patch instructions for screen joystick layout specific to this sample app
  231. function GetScreenJoystickPatchString()
  232. return
  233. "<patch>" ..
  234. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" ..
  235. " <attribute name=\"Is Visible\" value=\"false\" />" ..
  236. " </add>" ..
  237. "</patch>"
  238. end