comparison semiconginev2/old/engine.nim @ 1218:56781cc0fc7c compiletime-tests

did: renamge main package
author sam <sam@basx.dev>
date Wed, 17 Jul 2024 21:01:37 +0700
parents semicongine/old/engine.nim@a3eb305bcac2
children
comparison
equal deleted inserted replaced
1217:f819a874058f 1218:56781cc0fc7c
1 import std/compilesettings
2 import std/algorithm
3 import std/monotimes
4 import std/options
5 import std/strformat
6 import std/sequtils
7 import std/logging
8 import std/os
9
10 import ./platform/window
11
12 import ./core
13 import ./vulkan/instance
14 import ./vulkan/device
15 import ./vulkan/physicaldevice
16 import ./vulkan/shader
17
18 import ./scene
19 import ./material
20 import ./renderer
21 import ./audio
22 import ./input
23 import ./text
24 import ./panel
25
26 import ./steam
27
28 const COUNT_N_RENDERTIMES = 199
29
30 type
31 EngineState* = enum
32 Starting
33 Running
34 Shutdown
35 Engine* = object
36 applicationName: string
37 showFps: bool
38 device: Device
39 debugger: Debugger
40 instance: Instance
41 window: NativeWindow
42 renderer: Option[Renderer]
43 fullscreen: bool
44 lastNRenderTimes: array[COUNT_N_RENDERTIMES, int64]
45 currentRenderTimeI: int = 0
46
47 # forward declarations
48 func GetAspectRatio*(engine: Engine): float32
49
50 proc Destroy*(engine: var Engine) =
51 checkVkResult engine.device.vk.vkDeviceWaitIdle()
52 if engine.renderer.isSome:
53 engine.renderer.get.Destroy()
54 engine.device.Destroy()
55 if engine.debugger.messenger.Valid:
56 engine.debugger.Destroy()
57 engine.window.Destroy()
58 engine.instance.Destroy()
59 if SteamAvailable():
60 SteamShutdown()
61
62
63 proc InitEngine*(
64 applicationName = querySetting(projectName),
65 showFps = DEBUG,
66 vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0),
67 vulkanLayers: openArray[string] = [],
68 ): Engine =
69 echo "Set log level to ", ENGINE_LOGLEVEL
70 setLogFilter(ENGINE_LOGLEVEL)
71
72 TrySteamInit()
73 if SteamAvailable():
74 echo "Starting with Steam"
75 else:
76 echo "Starting without Steam"
77
78 result.applicationName = applicationName
79 result.showFps = showFps
80 result.window = CreateWindow(result.applicationName)
81
82 var
83 layers = @vulkanLayers
84 instanceExtensions: seq[string]
85
86 if DEBUG:
87 instanceExtensions.add "VK_EXT_debug_utils"
88 layers.add "VK_LAYER_KHRONOS_validation"
89 # This stuff might be usefull if we one day to smart GPU memory allocation,
90 # but right now it just clobbers up the console log:
91 # putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT")
92 putEnv("VK_LAYER_ENABLES", "VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_AMD,VALIDATION_CHECK_ENABLE_VENDOR_SPECIFIC_NVIDIA,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXTVK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT")
93
94 result.instance = result.window.CreateInstance(
95 vulkanVersion = vulkanVersion,
96 instanceExtensions = instanceExtensions,
97 layers = layers.deduplicate(),
98 )
99 if DEBUG:
100 result.debugger = result.instance.CreateDebugMessenger()
101 # create devices
102 let selectedPhysicalDevice = result.instance.GetPhysicalDevices().FilterBestGraphics()
103 result.device = result.instance.CreateDevice(
104 selectedPhysicalDevice,
105 enabledExtensions = @[],
106 selectedPhysicalDevice.FilterForGraphicsPresentationQueues()
107 )
108 StartMixerThread()
109
110 proc InitRenderer*(
111 engine: var Engine,
112 shaders: openArray[(MaterialType, ShaderConfiguration)],
113 clearColor = NewVec4f(0, 0, 0, 0),
114 backFaceCulling = true,
115 vSync = false,
116 inFlightFrames = 2,
117 samples = VK_SAMPLE_COUNT_1_BIT,
118 ) =
119
120 assert not engine.renderer.isSome
121 var allShaders = @shaders
122 if not shaders.mapIt(it[0]).contains(EMPTY_MATERIAL):
123 allShaders.add (EMPTY_MATERIAL, EMPTY_SHADER)
124 if not shaders.mapIt(it[0]).contains(PANEL_MATERIAL_TYPE):
125 allShaders.add (PANEL_MATERIAL_TYPE, PANEL_SHADER)
126 if not shaders.mapIt(it[0]).contains(TEXT_MATERIAL_TYPE):
127 allShaders.add (TEXT_MATERIAL_TYPE, TEXT_SHADER)
128 engine.renderer = some(engine.device.InitRenderer(
129 shaders = allShaders,
130 clearColor = clearColor,
131 backFaceCulling = backFaceCulling,
132 vSync = vSync,
133 inFlightFrames = inFlightFrames,
134 samples = samples,
135 ))
136
137 proc InitRenderer*(engine: var Engine, clearColor = NewVec4f(0, 0, 0, 0), vSync = false) =
138 checkVkResult engine.device.vk.vkDeviceWaitIdle()
139 engine.InitRenderer(@[], clearColor, vSync = vSync)
140 checkVkResult engine.device.vk.vkDeviceWaitIdle()
141
142 proc LoadScene*(engine: var Engine, scene: var Scene) =
143 debug &"start loading scene '{scene.name}'"
144 assert engine.renderer.isSome
145 assert not scene.loaded
146 checkVkResult engine.device.vk.vkDeviceWaitIdle()
147 scene.AddShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.GetAspectRatio)
148 engine.renderer.get.SetupDrawableBuffers(scene)
149 engine.renderer.get.UpdateMeshData(scene, forceAll = true)
150 engine.renderer.get.UpdateUniformData(scene, forceAll = true)
151 checkVkResult engine.device.vk.vkDeviceWaitIdle()
152 debug &"done loading scene '{scene.name}'"
153
154 proc UnloadScene*(engine: var Engine, scene: Scene) =
155 debug &"unload scene '{scene.name}'"
156 engine.renderer.get.Destroy(scene)
157
158 proc RenderScene*(engine: var Engine, scene: var Scene) =
159 if WindowIsMinimized():
160 return
161 assert engine.renderer.isSome, "Renderer has not yet been initialized, call 'engine.InitRenderer' first"
162 assert engine.renderer.get.HasScene(scene), &"Scene '{scene.name}' has not been loaded yet"
163 let t0 = getMonoTime()
164
165 if engine.renderer.get.StartNewFrame():
166 scene.SetShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.GetAspectRatio)
167 engine.renderer.get.UpdateMeshData(scene)
168 engine.renderer.get.UpdateUniformData(scene)
169 engine.renderer.get.Render(scene)
170
171 if engine.showFps:
172 let nanoSecs = getMonoTime().ticks - t0.ticks
173 engine.lastNRenderTimes[engine.currentRenderTimeI] = nanoSecs
174 inc engine.currentRenderTimeI
175 if engine.currentRenderTimeI >= engine.lastNRenderTimes.len:
176 engine.currentRenderTimeI = 0
177 engine.lastNRenderTimes.sort
178 let
179 min = float(engine.lastNRenderTimes[0]) / 1_000_000
180 median = float(engine.lastNRenderTimes[engine.lastNRenderTimes.len div 2]) / 1_000_000
181 max = float(engine.lastNRenderTimes[^1]) / 1_000_000
182 engine.window.SetTitle(&"{engine.applicationName} ({min:.2}, {median:.2}, {max:.2})")
183
184
185 # wrappers for internal things
186 func GpuDevice*(engine: Engine): Device = engine.device
187 func GetWindow*(engine: Engine): auto = engine.window
188 func GetAspectRatio*(engine: Engine): float32 = engine.GetWindow().Size[0] / engine.GetWindow().Size[1]
189 proc ShowSystemCursor*(engine: Engine) = engine.window.ShowSystemCursor()
190 proc HideSystemCursor*(engine: Engine) = engine.window.HideSystemCursor()
191 func Fullscreen*(engine: Engine): bool = engine.fullscreen
192 proc `Fullscreen=`*(engine: var Engine, enable: bool) =
193 if enable != engine.fullscreen:
194 engine.fullscreen = enable
195 engine.window.Fullscreen(engine.fullscreen)
196
197 func Limits*(engine: Engine): VkPhysicalDeviceLimits =
198 engine.device.physicalDevice.properties.limits
199
200 func MaxFramebufferSampleCount*(engine: Engine, maxSamples = VK_SAMPLE_COUNT_8_BIT): VkSampleCountFlagBits =
201 let available = VkSampleCountFlags(
202 engine.Limits.framebufferColorSampleCounts.uint32 and engine.Limits.framebufferDepthSampleCounts.uint32
203 ).toEnums
204 return min(max(available), maxSamples)
205
206 proc UpdateInputs*(engine: Engine): bool =
207 UpdateInputs(engine.window.PendingEvents())
208
209 proc ProcessEvents*(engine: Engine, panel: var Panel) =
210 let hasMouseNow = panel.Contains(MousePositionNormalized(engine.window.Size), engine.GetAspectRatio)
211
212 # enter/leave events
213 if hasMouseNow:
214 if panel.hasMouse:
215 if panel.onMouseMove != nil: panel.onMouseMove(panel)
216 else:
217 if panel.onMouseEnter != nil: panel.onMouseEnter(panel)
218 else:
219 if panel.hasMouse:
220 if panel.onMouseLeave != nil: panel.onMouseLeave(panel)
221
222 # button events
223 if hasMouseNow:
224 if MouseWasPressed():
225 if panel.onMouseDown != nil: panel.onMouseDown(panel, MousePressedButtons())
226 if MouseWasReleased():
227 if panel.onMouseUp != nil: panel.onMouseUp(panel, MouseReleasedButtons())
228
229 panel.hasMouse = hasMouseNow