Mercurial > games > semicongine
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 |