213 lines
7.9 KiB
Nim
213 lines
7.9 KiB
Nim
# The contents of this file are subject to the Common Public Attribution License
|
|
# Version 1.0 (the “License”); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
# https://myou.dev/licenses/LICENSE-CPAL. The License is based on the Mozilla
|
|
# Public License Version 1.1 but Sections 14 and 15 have been added to cover use
|
|
# of software over a computer network and provide for limited attribution for
|
|
# the Original Developer. In addition, Exhibit A has been modified to be
|
|
# consistent with Exhibit B.
|
|
#
|
|
# Software distributed under the License is distributed on an “AS IS” basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
# the specific language governing rights and limitations under the License.
|
|
#
|
|
# The Original Code is Myou Engine.
|
|
#
|
|
# the Original Developer is the Initial Developer.
|
|
#
|
|
# The Initial Developer of the Original Code is the Myou Engine developers.
|
|
# All portions of the code written by the Myou Engine developers are Copyright
|
|
# (c) 2024. All Rights Reserved.
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of the
|
|
# GNU Affero General Public License version 3 (the [AGPL-3] License), in which
|
|
# case the provisions of [AGPL-3] License are applicable instead of those above.
|
|
#
|
|
# If you wish to allow use of your version of this file only under the terms of
|
|
# the [AGPL-3] License and not to allow others to use your version of this file
|
|
# under the CPAL, indicate your decision by deleting the provisions above and
|
|
# replace them with the notice and other provisions required by the [AGPL-3]
|
|
# License. If you do not delete the provisions above, a recipient may use your
|
|
# version of this file under either the CPAL or the [AGPL-3] License.
|
|
|
|
|
|
|
|
## This module containst the functions to start using Myou Engine.
|
|
|
|
# TODO: runnableExamples is broken because we can't pass compile options
|
|
|
|
## ```nim
|
|
## let engine = newMyouEngine(1024, 768, "My Game")
|
|
##
|
|
## # Create or load your initial scene here
|
|
##
|
|
## engine.run()
|
|
## ```
|
|
|
|
import ./types
|
|
import std/tables
|
|
|
|
when defined(android):
|
|
const default_gl_version = 320
|
|
const default_gl_es = true
|
|
elif defined(emscripten) or defined(ios):
|
|
const default_gl_version = 300
|
|
const default_gl_es = true
|
|
else:
|
|
const default_gl_version = 330
|
|
const default_gl_es = false
|
|
|
|
# Forward declarations
|
|
proc newMyouEngine*(
|
|
width, height: int32,
|
|
title = "Myou Engine window",
|
|
opengl_version = default_gl_version,
|
|
opengl_es = default_gl_es,
|
|
glsl_version = "",
|
|
use_glsl_tone_mapping = true,
|
|
): MyouEngine
|
|
proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string
|
|
proc get_builtin_shader_textures*(): Table[string, Texture]
|
|
# End forward declarations
|
|
|
|
import std/strutils
|
|
import std/monotimes
|
|
import ./graphics/render
|
|
import ./screen
|
|
import ./platform/platform
|
|
import ./loaders/blend
|
|
import ./util
|
|
from loadable import updateLoadableWorkerThreads
|
|
import arr_ref
|
|
|
|
export arr_ref
|
|
export tables
|
|
|
|
proc newMyouEngine*(
|
|
width, height: int32,
|
|
title = "Myou Engine window",
|
|
opengl_version = default_gl_version,
|
|
opengl_es = default_gl_es,
|
|
glsl_version = "",
|
|
use_glsl_tone_mapping = true,
|
|
): MyouEngine =
|
|
## Creates a Myou Engine instance. You need to call this before you can use
|
|
## the engine. You also need to call `run <#run,MyouEngine>`_ at the end of
|
|
## your main project file.
|
|
result = new MyouEngine
|
|
result.glsl_version = if glsl_version != "":
|
|
glsl_version
|
|
elif opengl_es:
|
|
$opengl_version & " es"
|
|
else:
|
|
$opengl_version
|
|
|
|
# TODO: move/copy to camera or to scene?
|
|
# to override it with per-camera exposure settings
|
|
if opengl_es:
|
|
assert opengl_version >= 300, "Minimum supported OpenGL ES version is 3.0"
|
|
else:
|
|
assert opengl_version >= 330, "Minimum supported OpenGL version is 3.3"
|
|
|
|
if opengl_es or use_glsl_tone_mapping:
|
|
result.tone_mapping_library = dedent """
|
|
float linearrgb_to_srgb(float c){
|
|
if (c < 0.0031308) return (c < 0.0) ? 0.0 : c * 12.92;
|
|
else return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
|
|
}
|
|
vec4 linearrgb_to_srgb(vec4 col){
|
|
return vec4(
|
|
linearrgb_to_srgb(col.r),
|
|
linearrgb_to_srgb(col.g),
|
|
linearrgb_to_srgb(col.b),
|
|
col.a
|
|
);
|
|
}
|
|
#define MYOU_TONE_MAP(x) linearrgb_to_srgb(x)
|
|
"""
|
|
result.tone_mapping_function = "MYOU_TONE_MAP"
|
|
result.use_glsl_tone_mapping = true
|
|
else:
|
|
result.tone_mapping_library = "\n#define MYOU_TONE_MAP(x) x\n"
|
|
|
|
echo "assigning renderer"
|
|
result.renderer = result.newRenderManager
|
|
# this will call result.renderer.initialize() now or later
|
|
# but first it will ensure a screen can be created
|
|
when not defined(nimdoc):
|
|
init_graphics(result, width, height, title, opengl_version, opengl_es)
|
|
discard result.newScreen(width, height, title)
|
|
|
|
registerBlendLoader(result)
|
|
|
|
proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string =
|
|
## Returns a string with the code of the default shader library of the
|
|
## engine. If you use this, you may want to also add the textures given by
|
|
## `get_builtin_shader_textures<#get_builtin_shader_textures>`_.
|
|
return @[
|
|
if use_cubemap_prefiltering:
|
|
"#define PREFILTERED_CUBEMAPS"
|
|
else: "",
|
|
# staticOrDebugRead "shaders/debug_text.glsl",
|
|
staticOrDebugRead "shaders/cube_prefilter.glsl",
|
|
staticOrDebugRead "shaders/spherical_harmonics.glsl",
|
|
staticOrDebugRead "shaders/shader_library.glsl",
|
|
].join("\n")
|
|
|
|
proc get_builtin_shader_textures*(): Table[string, Texture] =
|
|
## Returns a table of textures to be used with the library that is returned
|
|
## by `get_builtin_shader_library<#get_builtin_shader_library,bool>`_.
|
|
discard
|
|
|
|
var last_time: float
|
|
|
|
proc myou_main_loop*(self: MyouEngine) =
|
|
## Runs one iteration of the engine main loop. It doesn't swap buffers.
|
|
##
|
|
## You usually don't need to call this. Use `run <#run,MyouEngine>`_
|
|
## instead.
|
|
updateLoadableWorkerThreads()
|
|
# TODO: make a table object that can be iterated while changing, e.g. with a
|
|
# seq and a dirty flag to update the seq
|
|
if self.new_scenes.len != 0:
|
|
for name,scene in self.new_scenes.pairs:
|
|
self.scenes[name] = scene
|
|
self.new_scenes.clear()
|
|
let time = getmonotime().ticks.float/1000000000
|
|
let delta_seconds = time - last_time
|
|
for _,scene in self.scenes.pairs:
|
|
if not scene.enabled:
|
|
continue
|
|
for f in scene.pre_draw_callbacks:
|
|
f(scene, delta_seconds)
|
|
self.renderer.draw_all()
|
|
for _,scene in self.scenes.pairs:
|
|
if not scene.enabled:
|
|
continue
|
|
for f in scene.post_draw_callbacks:
|
|
f(scene, delta_seconds)
|
|
last_time = time
|
|
|
|
proc run*(self: MyouEngine) =
|
|
## Starts the main loop of the engine. You should call it at the end of your
|
|
## main file. In mobile platforms and on web, this function doesn't block,
|
|
## and instead it just configures the main loop function. Therefore you
|
|
## shouldn't run any code after calling it.
|
|
last_time = getmonotime().ticks.float/1000000000
|
|
when not defined(nimdoc):
|
|
start_platform_main_loop(self, myou_main_loop)
|
|
|
|
proc loadScene*(self: MyouEngine, uri: string, callback: proc(scene: Scene), name = "", ext = "") =
|
|
let ext = if ext == "":
|
|
uri.rsplit('.', 1)[1]
|
|
else:
|
|
ext
|
|
|
|
if ext notin self.loaders_by_ext:
|
|
raise ValueError.newException "File extension not supported: " & ext
|
|
|
|
# TODO: use the next loader if the first one fails
|
|
let loaders = self.loaders_by_ext[ext]
|
|
let loader = loaders[0](self)
|
|
loader.openAssetFile(uri)
|
|
loader.loadScene(name, nil, callback)
|