thumbnail.lua 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. -- Copyright (c) 2012-2026 Daniele Bartolini et al.
  2. -- SPDX-License-Identifier: MIT
  3. require "core/editors/level_editor/camera"
  4. require "core/editors/unit"
  5. UnitPreview = class(UnitPreview)
  6. function UnitPreview:init(world, unit_name)
  7. self._object = UnitBox(world
  8. , Device.guid()
  9. , World.spawn_unit(world, unit_name)
  10. , unit_name
  11. )
  12. end
  13. function UnitPreview:destroy()
  14. self._object:destroy()
  15. end
  16. function UnitPreview:render(camera)
  17. local obb_tm, obb_he = self._object:obb()
  18. local camera_pos
  19. local camera_rot
  20. if RenderWorld.sprite_instance(Thumbnail._rw, self._object._unit_id) then
  21. camera_pos = Vector3.up()
  22. camera_rot = Quaternion.look(Vector3.normalize(-camera_pos), Vector3.forward())
  23. else
  24. camera_pos = Vector3(1, -1, 1)
  25. camera_rot = Quaternion.look(Vector3.normalize(-camera_pos))
  26. end
  27. local camera_pose = Matrix4x4.from_quaternion_translation(camera_rot, camera_pos)
  28. camera:set_local_pose(camera_pose)
  29. camera:frame_obb(obb_tm, obb_he)
  30. end
  31. TexturePreview = class(TexturePreview)
  32. function TexturePreview:init(world, texture_name)
  33. self._texture_name = texture_name
  34. self._material_name = "core/editors/thumbnail/gui"
  35. self._material = Gui.material(Thumbnail._gui, self._material_name)
  36. end
  37. function TexturePreview:destroy()
  38. end
  39. function TexturePreview:render(camera)
  40. Material.set_texture(self._material, "u_albedo_map", self._texture_name)
  41. Gui.image(Thumbnail._gui, Vector2(0, 0), Vector2(128, 128), self._material_name, Color4.white())
  42. end
  43. MaterialPreview = class(MaterialPreview)
  44. function MaterialPreview:init(world, material_name)
  45. self._unit_preview = UnitPreview(world, "core/units/primitives/sphere")
  46. local unit_box = self._unit_preview._object
  47. local render_world = unit_box._rw
  48. local mesh_instance = RenderWorld.mesh_instance(render_world, unit_box:unit_id())
  49. RenderWorld.mesh_set_material(render_world, mesh_instance, material_name)
  50. end
  51. function MaterialPreview:destroy()
  52. self._unit_preview:destroy()
  53. end
  54. function MaterialPreview:render(camera)
  55. local camera_pos = Vector3(1, -1, 0.5)
  56. local camera_rot = Quaternion.from_axis_angle(Vector3.up(), 45.0 * (math.pi / 180.0))
  57. local camera_pose = Matrix4x4.from_quaternion_translation(camera_rot, camera_pos)
  58. camera:set_local_pose(camera_pose)
  59. end
  60. Thumbnail = Thumbnail or {}
  61. function Thumbnail:init()
  62. self._world = Device.create_world()
  63. World.disable_unit_callbacks(self._world)
  64. self._sg = World.scene_graph(self._world)
  65. self._rw = World.render_world(self._world)
  66. self._pw = World.physics_world(self._world)
  67. self._camera = Camera(self._world, World.spawn_unit(self._world, "core/units/camera"))
  68. self._object = nil
  69. self._gui = World.create_screen_gui(self._world)
  70. self._requests = {}
  71. self._pending = {}
  72. local light_unit = World.spawn_unit(self._world, "core/units/light"
  73. , Vector3(1000, 0, 0)
  74. , Quaternion.from_axis_angle(Vector3.forward(), 45.0 * (math.pi / 180.0))
  75. )
  76. local light = RenderWorld.light_instance(self._rw, light_unit)
  77. if light ~= nil then
  78. RenderWorld.light_set_type(self._rw, light, "directional")
  79. RenderWorld.light_set_intensity(self._rw, light, 3)
  80. end
  81. end
  82. function Thumbnail:thumbnail_ready(screenshot_path)
  83. local req = table.remove(self._pending, 1)
  84. if req == nil then
  85. return
  86. end
  87. Device.console_send { type = "thumbnail", resource_type = req.type, resource_name = req.name, path = req.path }
  88. end
  89. function Thumbnail:update(dt)
  90. World.update(self._world, dt)
  91. local req = table.remove(self._requests, 1)
  92. if req == nil then
  93. return
  94. end
  95. if self._object ~= nil then
  96. self._object:destroy()
  97. self._object = nil
  98. end
  99. if req.type == "unit" then
  100. self._object = UnitPreview(self._world, req.name)
  101. elseif req.type == "sound" then
  102. self._object = UnitPreview(self._world, "core/units/sound")
  103. elseif req.type == "texture" then
  104. self._object = TexturePreview(self._world, req.name)
  105. elseif req.type == "material" then
  106. self._object = MaterialPreview(self._world, req.name)
  107. else
  108. return
  109. end
  110. if self._object ~= nil then
  111. self._object:render(self._camera)
  112. end
  113. self._camera:update(dt, 0, 0, 0, 0)
  114. Device.render(self._world, self._camera:unit())
  115. table.insert(self._pending, req)
  116. Device.screenshot(req.path)
  117. end
  118. function Thumbnail:render(dt)
  119. end
  120. function Thumbnail:shutdown()
  121. World.destroy_gui(self._world, self._gui)
  122. Device.destroy_world(self._world)
  123. end
  124. function Thumbnail:add_request(type, name, thumbnail_path)
  125. table.insert(self._requests, { type = type, name = name, path = thumbnail_path })
  126. end
  127. function init()
  128. Device.enable_resource_autoload(true)
  129. Thumbnail:init()
  130. end
  131. function update(dt)
  132. Thumbnail:update(dt)
  133. end
  134. function render(dt)
  135. Thumbnail:render(dt)
  136. end
  137. function shutdown()
  138. Thumbnail:shutdown()
  139. end
  140. function screenshot(path)
  141. Thumbnail:thumbnail_ready(path)
  142. end