diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/semiconginev2/old/engine.nim	Wed Jul 17 21:01:37 2024 +0700
@@ -0,0 +1,229 @@
+import std/compilesettings
+import std/algorithm
+import std/monotimes
+import std/options
+import std/strformat
+import std/sequtils
+import std/logging
+import std/os
+
+import ./platform/window
+
+import ./core
+import ./vulkan/instance
+import ./vulkan/device
+import ./vulkan/physicaldevice
+import ./vulkan/shader
+
+import ./scene
+import ./material
+import ./renderer
+import ./audio
+import ./input
+import ./text
+import ./panel
+
+import ./steam
+
+const COUNT_N_RENDERTIMES = 199
+
+type
+  EngineState* = enum
+    Starting
+    Running
+    Shutdown
+  Engine* = object
+    applicationName: string
+    showFps: bool
+    device: Device
+    debugger: Debugger
+    instance: Instance
+    window: NativeWindow
+    renderer: Option[Renderer]
+    fullscreen: bool
+    lastNRenderTimes: array[COUNT_N_RENDERTIMES, int64]
+    currentRenderTimeI: int = 0
+
+# forward declarations
+func GetAspectRatio*(engine: Engine): float32
+
+proc Destroy*(engine: var Engine) =
+  checkVkResult engine.device.vk.vkDeviceWaitIdle()
+  if engine.renderer.isSome:
+    engine.renderer.get.Destroy()
+  engine.device.Destroy()
+  if engine.debugger.messenger.Valid:
+    engine.debugger.Destroy()
+  engine.window.Destroy()
+  engine.instance.Destroy()
+  if SteamAvailable():
+    SteamShutdown()
+
+
+proc InitEngine*(
+  applicationName = querySetting(projectName),
+  showFps = DEBUG,
+  vulkanVersion = VK_MAKE_API_VERSION(0, 1, 3, 0),
+  vulkanLayers: openArray[string] = [],
+): Engine =
+  echo "Set log level to ", ENGINE_LOGLEVEL
+  setLogFilter(ENGINE_LOGLEVEL)
+
+  TrySteamInit()
+  if SteamAvailable():
+    echo "Starting with Steam"
+  else:
+    echo "Starting without Steam"
+
+  result.applicationName = applicationName
+  result.showFps = showFps
+  result.window = CreateWindow(result.applicationName)
+
+  var
+    layers = @vulkanLayers
+    instanceExtensions: seq[string]
+
+  if DEBUG:
+    instanceExtensions.add "VK_EXT_debug_utils"
+    layers.add "VK_LAYER_KHRONOS_validation"
+    # This stuff might be usefull if we one day to smart GPU memory allocation,
+    # but right now it just clobbers up the console log:
+    # putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT")
+    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")
+
+  result.instance = result.window.CreateInstance(
+    vulkanVersion = vulkanVersion,
+    instanceExtensions = instanceExtensions,
+    layers = layers.deduplicate(),
+  )
+  if DEBUG:
+    result.debugger = result.instance.CreateDebugMessenger()
+  # create devices
+  let selectedPhysicalDevice = result.instance.GetPhysicalDevices().FilterBestGraphics()
+  result.device = result.instance.CreateDevice(
+    selectedPhysicalDevice,
+    enabledExtensions = @[],
+    selectedPhysicalDevice.FilterForGraphicsPresentationQueues()
+  )
+  StartMixerThread()
+
+proc InitRenderer*(
+  engine: var Engine,
+  shaders: openArray[(MaterialType, ShaderConfiguration)],
+  clearColor = NewVec4f(0, 0, 0, 0),
+  backFaceCulling = true,
+  vSync = false,
+  inFlightFrames = 2,
+  samples = VK_SAMPLE_COUNT_1_BIT,
+) =
+
+  assert not engine.renderer.isSome
+  var allShaders = @shaders
+  if not shaders.mapIt(it[0]).contains(EMPTY_MATERIAL):
+    allShaders.add (EMPTY_MATERIAL, EMPTY_SHADER)
+  if not shaders.mapIt(it[0]).contains(PANEL_MATERIAL_TYPE):
+    allShaders.add (PANEL_MATERIAL_TYPE, PANEL_SHADER)
+  if not shaders.mapIt(it[0]).contains(TEXT_MATERIAL_TYPE):
+    allShaders.add (TEXT_MATERIAL_TYPE, TEXT_SHADER)
+  engine.renderer = some(engine.device.InitRenderer(
+    shaders = allShaders,
+    clearColor = clearColor,
+    backFaceCulling = backFaceCulling,
+    vSync = vSync,
+    inFlightFrames = inFlightFrames,
+    samples = samples,
+  ))
+
+proc InitRenderer*(engine: var Engine, clearColor = NewVec4f(0, 0, 0, 0), vSync = false) =
+  checkVkResult engine.device.vk.vkDeviceWaitIdle()
+  engine.InitRenderer(@[], clearColor, vSync = vSync)
+  checkVkResult engine.device.vk.vkDeviceWaitIdle()
+
+proc LoadScene*(engine: var Engine, scene: var Scene) =
+  debug &"start loading scene '{scene.name}'"
+  assert engine.renderer.isSome
+  assert not scene.loaded
+  checkVkResult engine.device.vk.vkDeviceWaitIdle()
+  scene.AddShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.GetAspectRatio)
+  engine.renderer.get.SetupDrawableBuffers(scene)
+  engine.renderer.get.UpdateMeshData(scene, forceAll = true)
+  engine.renderer.get.UpdateUniformData(scene, forceAll = true)
+  checkVkResult engine.device.vk.vkDeviceWaitIdle()
+  debug &"done loading scene '{scene.name}'"
+
+proc UnloadScene*(engine: var Engine, scene: Scene) =
+  debug &"unload scene '{scene.name}'"
+  engine.renderer.get.Destroy(scene)
+
+proc RenderScene*(engine: var Engine, scene: var Scene) =
+  if WindowIsMinimized():
+    return
+  assert engine.renderer.isSome, "Renderer has not yet been initialized, call 'engine.InitRenderer' first"
+  assert engine.renderer.get.HasScene(scene), &"Scene '{scene.name}' has not been loaded yet"
+  let t0 = getMonoTime()
+
+  if engine.renderer.get.StartNewFrame():
+    scene.SetShaderGlobal(ASPECT_RATIO_ATTRIBUTE, engine.GetAspectRatio)
+    engine.renderer.get.UpdateMeshData(scene)
+    engine.renderer.get.UpdateUniformData(scene)
+    engine.renderer.get.Render(scene)
+
+  if engine.showFps:
+    let nanoSecs = getMonoTime().ticks - t0.ticks
+    engine.lastNRenderTimes[engine.currentRenderTimeI] = nanoSecs
+    inc engine.currentRenderTimeI
+    if engine.currentRenderTimeI >= engine.lastNRenderTimes.len:
+      engine.currentRenderTimeI = 0
+      engine.lastNRenderTimes.sort
+      let
+        min = float(engine.lastNRenderTimes[0]) / 1_000_000
+        median = float(engine.lastNRenderTimes[engine.lastNRenderTimes.len div 2]) / 1_000_000
+        max = float(engine.lastNRenderTimes[^1]) / 1_000_000
+      engine.window.SetTitle(&"{engine.applicationName} ({min:.2}, {median:.2}, {max:.2})")
+
+
+# wrappers for internal things
+func GpuDevice*(engine: Engine): Device = engine.device
+func GetWindow*(engine: Engine): auto = engine.window
+func GetAspectRatio*(engine: Engine): float32 = engine.GetWindow().Size[0] / engine.GetWindow().Size[1]
+proc ShowSystemCursor*(engine: Engine) = engine.window.ShowSystemCursor()
+proc HideSystemCursor*(engine: Engine) = engine.window.HideSystemCursor()
+func Fullscreen*(engine: Engine): bool = engine.fullscreen
+proc `Fullscreen=`*(engine: var Engine, enable: bool) =
+  if enable != engine.fullscreen:
+    engine.fullscreen = enable
+    engine.window.Fullscreen(engine.fullscreen)
+
+func Limits*(engine: Engine): VkPhysicalDeviceLimits =
+  engine.device.physicalDevice.properties.limits
+
+func MaxFramebufferSampleCount*(engine: Engine, maxSamples = VK_SAMPLE_COUNT_8_BIT): VkSampleCountFlagBits =
+  let available = VkSampleCountFlags(
+    engine.Limits.framebufferColorSampleCounts.uint32 and engine.Limits.framebufferDepthSampleCounts.uint32
+  ).toEnums
+  return min(max(available), maxSamples)
+
+proc UpdateInputs*(engine: Engine): bool =
+  UpdateInputs(engine.window.PendingEvents())
+
+proc ProcessEvents*(engine: Engine, panel: var Panel) =
+  let hasMouseNow = panel.Contains(MousePositionNormalized(engine.window.Size), engine.GetAspectRatio)
+
+  # enter/leave events
+  if hasMouseNow:
+    if panel.hasMouse:
+      if panel.onMouseMove != nil: panel.onMouseMove(panel)
+    else:
+      if panel.onMouseEnter != nil: panel.onMouseEnter(panel)
+  else:
+    if panel.hasMouse:
+      if panel.onMouseLeave != nil: panel.onMouseLeave(panel)
+
+  # button events
+  if hasMouseNow:
+    if MouseWasPressed():
+      if panel.onMouseDown != nil: panel.onMouseDown(panel, MousePressedButtons())
+    if MouseWasReleased():
+      if panel.onMouseUp != nil: panel.onMouseUp(panel, MouseReleasedButtons())
+
+  panel.hasMouse = hasMouseNow