Compare commits

...

6 commits

Author SHA1 Message Date
78cafe6566 Add threading support to LoadableResource. 2024-08-29 00:19:52 +02:00
e748831f3a Fix crash with loadables in Android. Warn if done() is being called twice. 2024-08-29 00:13:37 +02:00
c731c3c5ab Add new_scenes to prevent modifying the currently iterated scenes. 2024-08-29 00:09:34 +02:00
3ff1d663a2 Prevent cycles with ARC by adding {.cursor.} to all "back" references.
TODO: Use destructors to set all cursors of children objects to `nil`.
2024-08-29 00:07:09 +02:00
1557d59d0f Add option to always use GLSL tone mapping instead of GL_FRAMEBUFFER_SRGB. 2024-08-29 00:01:54 +02:00
6636b5e595 Add proc to show/hide on-screen keyboard and character callbacks (except ios).
* Add `myouSetKeyboardVisible(bool)` and export it.
* Add `screen.char_callbacks` to receive platform character events.
* Remove duplicate code for mouse emulation with touch (commited by mistake).
2024-08-28 23:57:29 +02:00
10 changed files with 135 additions and 120 deletions

View file

@ -58,12 +58,14 @@ type LoadableResource* = ref object of RootObj
done_func: proc() done_func: proc()
cancel_func: proc() cancel_func: proc()
str*: proc(): string str*: proc(): string
use_threads: bool
result: ref Result # only to be used with loadAll result: ref Result # only to be used with loadAll
proc newLoadableResource*[T: LoadableResource]( proc newLoadableResource*[T: LoadableResource](
start: proc(self: LoadableResource), start: proc(self: LoadableResource),
done: proc() = nil, done: proc() = nil,
str: proc(): string = nil, str: proc(): string = nil,
use_threads = false,
): T = ): T =
new(result) new(result)
result.start_func = start result.start_func = start
@ -71,10 +73,28 @@ proc newLoadableResource*[T: LoadableResource](
result.str = str result.str = str
if str == nil: if str == nil:
result.str = proc(): string = "" result.str = proc(): string = ""
result.use_threads = use_threads
# main -> thread channels
var to_start: Channel[LoadableResource]
# main <- thread channels
var to_return: Channel[(LoadableResource, bool, string, pointer, int)]
var to_done: Channel[LoadableResource]
proc start*[T: LoadableResource](self: T) = proc start*[T: LoadableResource](self: T) =
self.status = Started self.status = Started
self.start_func(self) if self.use_threads:
to_start.send self
else:
self.start_func(self)
proc doneImpl*[T: LoadableResource](self: T) =
if self.status == Started:
self.cancel()
else:
self.status = NotStarted
if self.done_func != nil:
self.done_func()
proc `onload=`*[T: LoadableResource](self: T, onload_func: proc(ok: bool, err: string, p: pointer, len: int)) = proc `onload=`*[T: LoadableResource](self: T, onload_func: proc(ok: bool, err: string, p: pointer, len: int)) =
self.onload_func = onload_func self.onload_func = onload_func
@ -85,25 +105,24 @@ proc onload*[T: LoadableResource](self: T, ok: bool, err: string, p: pointer, le
if self.result != nil: if self.result != nil:
self.result[] = (ok, err, p, len) self.result[] = (ok, err, p, len)
if self.onload_func != nil: if self.onload_func != nil:
self.onload_func(ok, err, p, len) if self.use_threads:
to_return.send((self.LoadableResource, ok, err, p, len))
else:
self.onload_func(ok, err, p, len)
else: # cancelled else: # cancelled
self.status = NotStarted self.doneImpl()
if self.done_func != nil:
self.done_func()
# TODO: check if we can always use destructors instead of calling this # TODO: check if we can always use destructors instead of calling this
proc done*[T: LoadableResource](self: T) = proc done*[T: LoadableResource](self: T) =
if self.status == Started: if self.use_threads:
self.cancel() to_done.send self
else: else:
self.status = NotStarted self.doneImpl()
if self.done_func != nil:
self.done_func()
proc cancel*[T: LoadableResource](self: T) = proc cancel*[T: LoadableResource](self: T) =
if self.status != Started: if self.status != Started:
return return
if self.cancel_func != nil: if self.cancel_func == nil:
# self.`onload=`(proc(ok, err, p, len: auto) = # self.`onload=`(proc(ok, err, p, len: auto) =
# self.done()) # self.done())
self.onload_func = proc(ok: bool, err: string, p: pointer, len: int) = self.onload_func = proc(ok: bool, err: string, p: pointer, len: int) =
@ -128,6 +147,31 @@ proc cancel*[T: LoadableResource](self: T) =
# results.add res.result[] # results.add res.result[]
# res.result = nil # res.result = nil
var worker: Thread[void]
proc workerThreadProc() {.thread.} =
while true:
let res = to_start.recv()
if res == nil:
break
cast[proc(self: LoadableResource) {.gcsafe.}](res.start_func)(res)
worker.createThread(workerThreadProc)
to_start.open()
to_return.open()
to_done.open()
proc updateLoadableWorkerThreads*() =
while true:
let tried = to_return.tryRecv()
if not tried.dataAvailable:
break
let (res, ok, err, p, len) = tried.msg
res.onload_func(ok, err, p, len)
while true:
let tried = to_done.tryRecv()
if not tried.dataAvailable:
break
tried.msg.done_func()
type Fetch* = ref object of LoadableResource type Fetch* = ref object of LoadableResource
custom: pointer custom: pointer
@ -226,6 +270,7 @@ proc loadUri*(
var done_func: proc() var done_func: proc()
var self: Fetch var self: Fetch
var uri = uri var uri = uri
var use_threads = false
when not defined(onlyLocalFiles): when not defined(onlyLocalFiles):
when defined(emscripten): when defined(emscripten):
const is_remote = true const is_remote = true
@ -261,6 +306,7 @@ proc loadUri*(
discard emscripten_fetch_close(cast[ptr emscripten_fetch_t](self.custom)) discard emscripten_fetch_close(cast[ptr emscripten_fetch_t](self.custom))
self.custom = nil self.custom = nil
else: else:
use_threads = true
var client = newHttpClient() var client = newHttpClient()
var response: string var response: string
start_func = proc(self: LoadableResource) = start_func = proc(self: LoadableResource) =
@ -281,9 +327,14 @@ proc loadUri*(
if not is_remote: if not is_remote:
start_func = proc(self: LoadableResource) = start_func = proc(self: LoadableResource) =
when not defined(release):
var done_called = false
try: try:
var memfile = memfiles.open(uri, mode=fmRead) var memfile = memfiles.open(uri, mode=fmRead)
self.done_func = proc() = self.done_func = proc() =
when not defined(release):
assert not done_called, "Done is being called multiple times. Did you forget to set auto_done = false?"
done_called = true
memfile.close() memfile.close()
self.onload(true, "", memfile.mem, memfile.size) self.onload(true, "", memfile.mem, memfile.size)
# TODO!!!! check whether these objects are freed # TODO!!!! check whether these objects are freed
@ -293,7 +344,7 @@ proc loadUri*(
if cast[Fetch](self).auto_done: if cast[Fetch](self).auto_done:
self.done() self.done()
proc str(): string = uri proc str(): string = uri
self = newLoadableResource[Fetch](start_func, done_func, str) self = newLoadableResource[Fetch](start_func, done_func, str, use_threads=use_threads)
self.onload_func = onload_func self.onload_func = onload_func
self.auto_done = auto_done self.auto_done = auto_done
if auto_start: if auto_start:

View file

@ -89,9 +89,11 @@ export ubo
export util export util
export vmath except Quat export vmath except Quat
import platform/platform
when defined(android): when defined(android):
import platform/platform
export platform.myouAndroidGetActivity export platform.myouAndroidGetActivity
export platform.myouAndroidGetJniEnv export platform.myouAndroidGetJniEnv
export platform.myouAndroidGetInternalDataPath export platform.myouAndroidGetInternalDataPath
export platform.myouAndroidGetExternalDataPath export platform.myouAndroidGetExternalDataPath
export platform.myouSetKeyboardVisible

View file

@ -340,4 +340,4 @@ proc newMainFramebuffer*(engine: MyouEngine): Framebuffer =
result.engine = engine result.engine = engine
result.framebuffer = 0 result.framebuffer = 0
result.is_complete = true result.is_complete = true
result.use_sRGB = true result.use_sRGB = not engine.use_glsl_tone_mapping

View file

@ -88,14 +88,9 @@ proc registerBlendLoader*(engine: MyouEngine) =
e.newBlendLoader() e.newBlendLoader()
) )
var used_resources: seq[LoadableResource]
method close*(self: BlendLoader) = method close*(self: BlendLoader) =
if self.resource != nil: if self.resource != nil:
self.resource.done() self.resource.done()
# TODO: investigate
# this is a hack to avoid a crasn on android
used_resources.add self.resource
self.resource = nil self.resource = nil
self.blend_file = nil self.blend_file = nil
self.cached_materials.clear() self.cached_materials.clear()
@ -111,12 +106,16 @@ proc loadAsync(self: BlendLoader, callback: proc()) =
callback() callback()
else: else:
self.close() self.close()
self.resource = self.blend_file_path.loadUri proc(ok, err, data, len: auto) = self.resource = loadUri(self.blend_file_path,
if ok: proc(ok, err, data, len: auto) =
self.blend_file = openBlendFile(self.blend_file_path, data, len) if ok:
callback() self.blend_file = openBlendFile(self.blend_file_path, data, len)
else: callback()
raise IOError.newException err else:
raise IOError.newException err
,
auto_done = false
)
type BlenderObTypes = enum type BlenderObTypes = enum
BEmpty = 0 BEmpty = 0

View file

@ -64,6 +64,7 @@ proc newMyouEngine*(
opengl_version = default_gl_version, opengl_version = default_gl_version,
opengl_es = default_gl_es, opengl_es = default_gl_es,
glsl_version = "", glsl_version = "",
use_glsl_tone_mapping = true,
): MyouEngine ): MyouEngine
proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string
proc get_builtin_shader_textures*(): Table[string, Texture] proc get_builtin_shader_textures*(): Table[string, Texture]
@ -76,6 +77,7 @@ import ./screen
import ./platform/platform import ./platform/platform
import ./loaders/blend import ./loaders/blend
import ./util import ./util
from loadable import updateLoadableWorkerThreads
import arr_ref import arr_ref
export arr_ref export arr_ref
@ -87,6 +89,7 @@ proc newMyouEngine*(
opengl_version = default_gl_version, opengl_version = default_gl_version,
opengl_es = default_gl_es, opengl_es = default_gl_es,
glsl_version = "", glsl_version = "",
use_glsl_tone_mapping = true,
): MyouEngine = ): MyouEngine =
## Creates a Myou Engine instance. You need to call this before you can use ## 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 ## the engine. You also need to call `run <#run,MyouEngine>`_ at the end of
@ -103,6 +106,10 @@ proc newMyouEngine*(
# to override it with per-camera exposure settings # to override it with per-camera exposure settings
if opengl_es: if opengl_es:
assert opengl_version >= 300, "Minimum supported OpenGL ES version is 3.0" 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 """ result.tone_mapping_library = dedent """
float linearrgb_to_srgb(float c){ float linearrgb_to_srgb(float c){
if (c < 0.0031308) return (c < 0.0) ? 0.0 : c * 12.92; if (c < 0.0031308) return (c < 0.0) ? 0.0 : c * 12.92;
@ -119,8 +126,8 @@ proc newMyouEngine*(
#define MYOU_TONE_MAP(x) linearrgb_to_srgb(x) #define MYOU_TONE_MAP(x) linearrgb_to_srgb(x)
""" """
result.tone_mapping_function = "MYOU_TONE_MAP" result.tone_mapping_function = "MYOU_TONE_MAP"
result.use_glsl_tone_mapping = true
else: else:
assert opengl_version >= 330, "Minimum supported OpenGL version is 3.3"
result.tone_mapping_library = "\n#define MYOU_TONE_MAP(x) x\n" result.tone_mapping_library = "\n#define MYOU_TONE_MAP(x) x\n"
echo "assigning renderer" echo "assigning renderer"
@ -159,6 +166,13 @@ proc myou_main_loop*(self: MyouEngine) =
## ##
## You usually don't need to call this. Use `run <#run,MyouEngine>`_ ## You usually don't need to call this. Use `run <#run,MyouEngine>`_
## instead. ## 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 time = getmonotime().ticks.float/1000000000
let delta_seconds = time - last_time let delta_seconds = time - last_time
for _,scene in self.scenes.pairs: for _,scene in self.scenes.pairs:

View file

@ -162,3 +162,7 @@ proc myouOnTouch(touch: int32, ending: char, x, y: float32) {.exportc,cdecl.} =
proc platform_switch_screen*(screen: Screen): bool {.inline.} = proc platform_switch_screen*(screen: Screen): bool {.inline.} =
discard discard
proc myouSetKeyboardVisible*(show: bool) =
assert false, "TODO: myouSetKeyboardVisible in generic"

View file

@ -42,6 +42,7 @@ import std/math
import std/sequtils import std/sequtils
import std/strformat import std/strformat
import std/strutils import std/strutils
import std/unicode
import ./gl import ./gl
import ../screen import ../screen
import ../util import ../util
@ -106,8 +107,8 @@ proc glfmMain(w: Window) {.cdecl,exportc,noreturn.} =
proc make_window*(width, height: int32, title: string): Window = proc make_window*(width, height: int32, title: string): Window =
if window == nil: if window == nil:
return return
window.glfmSetKeyFunc proc(display, keyCode, action, mods: auto): auto {.cdecl.} = window.glfmSetKeyFunc proc(display: ptr GLFMDisplay; keyCode: GLFMKey;
# dump (cast[KeyCode](keyCode), keyCode.int, action, mods) action: GLFMKeyAction; mods: cint): bool {.cdecl.} =
let key = cast[KeyCode](keyCode) let key = cast[KeyCode](keyCode)
let shiftKey = (mods and 1).bool let shiftKey = (mods and 1).bool
let ctrlKey = (mods and 2).bool let ctrlKey = (mods and 2).bool
@ -121,6 +122,11 @@ proc make_window*(width, height: int32, title: string): Window =
key: key, key: key,
)) ))
return true return true
window.glfmSetCharFunc proc(display: ptr GLFMDisplay; utf8: cstring; modifiers: cint) {.cdecl.} =
let codepoint = cast[uint32](($utf8).runeAt(0))
for cb in display.screen.char_callbacks:
cb(codepoint)
window.glfmSetTouchFunc proc (display: ptr GLFMDisplay; touch: cint; phase: GLFMTouchPhase; window.glfmSetTouchFunc proc (display: ptr GLFMDisplay; touch: cint; phase: GLFMTouchPhase;
x: cdouble; y: cdouble): bool {.cdecl.} = x: cdouble; y: cdouble): bool {.cdecl.} =
let screen = window.screen let screen = window.screen
@ -166,77 +172,6 @@ proc make_window*(width, height: int32, title: string): Window =
screen.last_buttons = screen.last_buttons and not (1'i8 shl btn) screen.last_buttons = screen.last_buttons and not (1'i8 shl btn)
screen.last_x = x screen.last_x = x
screen.last_y = y screen.last_y = y
# template send_move(x, y: untyped) =
# let buttons = screen.last_buttons
# let left = (buttons and 1).bool
# let middle = (buttons and 2).bool
# let right = (buttons and 4).bool
# let position = vec2(x,y)
# let movement = vec2(x-screen.last_x, y-screen.last_y)
# for cb in screen.mouse_move_callbacks:
# cb(MouseMoveEvent(
# left: left, middle: middle, right: right,
# # shiftKey: shiftKey, ctrlKey: ctrlKey, altKey: altKey, metaKey: metaKey,
# position: position, movement: movement,
# ))
# screen.last_x = x
# screen.last_y = y
# template send_btn(pressed1, btn, x, y: untyped) =
# for cb in window.screen.mouse_button_callbacks:
# cb(MouseButtonEvent(
# pressed: pressed1,
# button: cast[MouseButton](btn),
# position: vec2(x,y)
# ))
# if pressed1:
# screen.last_buttons = screen.last_buttons or (1'i8 shl btn)
# else:
# screen.last_buttons = screen.last_buttons and not (1'i8 shl btn)
# screen.last_x = x
# screen.last_y = y
# template swap_1_2(count: untyped): untyped =
# case count:
# of 1: 2
# of 2: 1
# else: count
# if screen.is_touch:
# # mouse emulation
# if phase in [GLFMTouchPhaseMoved, GLFMTouchPhaseHover]:
# let last = screen.touches[0]
# if last[0] == touch:
# let dx = x - last[1]
# let dy = y - last[2]
# screen.touches[0][1] = x
# screen.touches[0][2] = y
# send_move(screen.last_x + dx, screen.last_y + dy)
# elif phase == GLFMTouchPhaseBegan:
# let count = screen.touches.len
# screen.touches.add (touch.int32, x.float, y.float)
# # in glfm buttons 1 and 2 are swapped so mouse emulation
# # through number of touches behave as we expect (no swap_1_2 here)
# let button = count
# if screen.last_buttons == 0:
# send_btn(true, button, x, y)
# else:
# let previous = screen.last_buttons.countTrailingZeroBits
# if previous < count:
# send_btn(true, button, screen.last_x, screen.last_y)
# send_btn(false, previous, screen.last_x, screen.last_y)
# else:
# screen.touches.keepItIf it[0] != touch
# if screen.touches.len == 0:
# let previous = screen.last_buttons.countTrailingZeroBits
# send_btn(false, previous, x, y)
# else:
# if phase in [GLFMTouchPhaseMoved, GLFMTouchPhaseHover]:
# send_move(x,y)
# else:
# let pressed = phase == GLFMTouchPhaseBegan
# # in glfm buttons 1 and 2 are swapped compared to glfw
# # (but they match DOM)
# send_btn(pressed, touch.swap_1_2, x, y)
return true return true
window.glfmSetAppFocusFunc proc(window: Window, focused: bool) {.cdecl.} = window.glfmSetAppFocusFunc proc(window: Window, focused: bool) {.cdecl.} =
@ -369,5 +304,5 @@ proc myouAndroidGetExternalDataPath*(): string =
let activity = cast[ptr array[6, cstring]](window.glfmAndroidGetActivity()) let activity = cast[ptr array[6, cstring]](window.glfmAndroidGetActivity())
return $activity[5] return $activity[5]
proc myouSetKeyboardVisible*(show: bool) =
window.glfmSetKeyboardVisible(show)

View file

@ -88,6 +88,10 @@ proc make_window*(width, height: int32, title: string): Window =
for cb in window.screen.key_callbacks: for cb in window.screen.key_callbacks:
cb(e) cb(e)
) )
discard glfw.setCharCallback(window, proc(window: Window, codepoint: uint32) {.cdecl.} =
for cb in window.screen.char_callbacks:
cb(codepoint)
)
discard glfw.setCursorPosCallback(window, proc(window: Window, x, y: float) {.cdecl.} = discard glfw.setCursorPosCallback(window, proc(window: Window, x, y: float) {.cdecl.} =
# TODO: when a mouse button is pressed do we need to poll the position # TODO: when a mouse button is pressed do we need to poll the position
# with glfw.getCursorPos until released? not needed on linux # with glfw.getCursorPos until released? not needed on linux
@ -232,3 +236,7 @@ proc start_platform_main_loop*(engine: MyouEngine, main_loop: proc(self: MyouEng
proc myouAndroidGetActivity*(): pointer = proc myouAndroidGetActivity*(): pointer =
assert false, "Not using Android" assert false, "Not using Android"
proc myouSetKeyboardVisible*(show: bool) =
discard

View file

@ -95,7 +95,7 @@ proc initScene*(self: Scene, engine: MyouEngine, name: string = "Scene",
while self.name in engine.scenes: while self.name in engine.scenes:
collision_seq += 1 collision_seq += 1
self.name = name & "$" & $collision_seq self.name = name & "$" & $collision_seq
engine.scenes[self.name] = self engine.new_scenes[self.name] = self
self.mesh_passes.setLen 3 self.mesh_passes.setLen 3
self.world = newWorld(self) self.world = newWorld(self)
self.background_color = vec4(0, 0, 0, 1) self.background_color = vec4(0, 0, 0, 1)

View file

@ -81,11 +81,11 @@ type
renderer*: RenderManager renderer*: RenderManager
tone_mapping_library*: string tone_mapping_library*: string
tone_mapping_function*: string tone_mapping_function*: string
use_glsl_tone_mapping*: bool
loaders_by_ext*: Table[string, seq[proc(e: MyouEngine): Loader]] loaders_by_ext*: Table[string, seq[proc(e: MyouEngine): Loader]]
# TODO: remove this and query it when screen is created
width*, height*: int
glsl_version*: string glsl_version*: string
all_framebuffers*: seq[Framebuffer] ## private all_framebuffers*: seq[Framebuffer] ## private
new_scenes*: Table[string, Scene] ## private
# gameobject.nim # gameobject.nim
@ -99,7 +99,7 @@ type
GameObject* = ref object of RootObj GameObject* = ref object of RootObj
# TODO: remove otype # TODO: remove otype
otype*: ObjectType ## private otype*: ObjectType ## private
engine*: MyouEngine ## private engine* {.cursor.}: MyouEngine ## private
debug*: bool ## private debug*: bool ## private
position*: Vec3 position*: Vec3
rotation*: Quat rotation*: Quat
@ -111,12 +111,12 @@ type
object_color*: Vec4 object_color*: Vec4
# alpha*: float # alpha*: float
matrix_parent_inverse*: Mat4 matrix_parent_inverse*: Mat4
scene*: Scene scene* {.cursor.}: Scene
source_scene_name*: string source_scene_name*: string
# data_dir*: string # data_dir*: string
# dupli_group*: unknown # dupli_group*: unknown
visible*: bool visible*: bool
parent*: GameObject parent* {.cursor.}: GameObject
children*: seq[GameObject] children*: seq[GameObject]
auto_update_matrix*: bool auto_update_matrix*: bool
world_matrix*: Mat4 world_matrix*: Mat4
@ -159,7 +159,8 @@ type
# most fields should be private # most fields should be private
MeshData* = ref object MeshData* = ref object
engine*: MyouEngine engine* {.cursor.}: MyouEngine
# TODO: seq of {.cursor.}s?
users*: seq[GameObject] ## private users*: seq[GameObject] ## private
hash*: string hash*: string
varrays*: seq[ArrRef[float32]] varrays*: seq[ArrRef[float32]]
@ -288,8 +289,8 @@ type
# shadows # shadows
ShadowManager* = ref object of RootObj ShadowManager* = ref object of RootObj
engine*: MyouEngine engine* {.cursor.}: MyouEngine
light*: Light light* {.cursor.}: Light
framebuffer*: Framebuffer framebuffer*: Framebuffer
texture*: Texture texture*: Texture
sampler_type*: string sampler_type*: string
@ -331,7 +332,7 @@ type
padding3: float32 padding3: float32
Scene* = ref object Scene* = ref object
engine*: MyouEngine engine* {.cursor.}: MyouEngine
name*: string name*: string
enabled*: bool enabled*: bool
children*: seq[GameObject] children*: seq[GameObject]
@ -407,7 +408,7 @@ type
viewport_size*, viewport_size_inv*: Vec2 viewport_size*, viewport_size_inv*: Vec2
RenderManager* = ref object RenderManager* = ref object
engine*: MyouEngine engine* {.cursor.}: MyouEngine
initialized*: bool initialized*: bool
# temporary_framebuffers*: Table[int, ByteFramebuffer] # temporary_framebuffers*: Table[int, ByteFramebuffer]
render_tick*: int render_tick*: int
@ -493,7 +494,7 @@ type
# ubo.nim # ubo.nim
UBO* = ref object UBO* = ref object
renderer*: RenderManager renderer* {.cursor.}: RenderManager
name*: string name*: string
size32*: int size32*: int
byte_storage*: ArrRef[byte] byte_storage*: ArrRef[byte]
@ -530,7 +531,7 @@ type
EsPrecisionHigh EsPrecisionHigh
Material* = ref object Material* = ref object
engine*: MyouEngine engine* {.cursor.}: MyouEngine
name*: string name*: string
textures*: OrderedTable[string, Texture] textures*: OrderedTable[string, Texture]
ubos*: seq[UBO] ubos*: seq[UBO]
@ -561,7 +562,7 @@ type
# TODO: choose better names # TODO: choose better names
Shader* = ref object Shader* = ref object
engine*: MyouEngine # do we need this? engine* {.cursor.}: MyouEngine # do we need this?
id*: int id*: int
program*: GLuint program*: GLuint
material*: Material # do we need this? material*: Material # do we need this?
@ -640,7 +641,7 @@ type
tile_size*: Vec2 tile_size*: Vec2
Texture* = ref object of RootObj Texture* = ref object of RootObj
engine*: MyouEngine engine* {.cursor.}: MyouEngine
name*: string name*: string
storage*: TextureStorage ## private storage*: TextureStorage ## private
loaded*: bool loaded*: bool
@ -661,7 +662,7 @@ type
DepthTexture DepthTexture
Framebuffer* = ref object of RootObj Framebuffer* = ref object of RootObj
engine*: MyouEngine engine* {.cursor.}: MyouEngine
width*, height*: int width*, height*: int
format*: TextureFormat format*: TextureFormat
depth_type*: FramebufferDepthType depth_type*: FramebufferDepthType
@ -753,7 +754,7 @@ type
# loader_base.nim # loader_base.nim
Loader* = ref object of RootObj Loader* = ref object of RootObj
engine*: MyouEngine engine* {.cursor.}: MyouEngine
shader_library*: string shader_library*: string
shader_textures*: Table[string, Texture] shader_textures*: Table[string, Texture]
# on_destroy*: OnDestroy # on_destroy*: OnDestroy
@ -778,7 +779,7 @@ type
Body* = ref object Body* = ref object
Screen* = ref object of RootObj Screen* = ref object of RootObj
engine*: MyouEngine engine* {.cursor.}: MyouEngine
width*, height*: int32 width*, height*: int32
orientation*: int8 orientation*: int8
viewports*: seq[Viewport] viewports*: seq[Viewport]
@ -789,6 +790,7 @@ type
last_x*, last_y*: float ## private last_x*, last_y*: float ## private
last_buttons*, last_mods*: int8 ## private last_buttons*, last_mods*: int8 ## private
key_callbacks*: seq[proc(event: KeyEvent)] ## private key_callbacks*: seq[proc(event: KeyEvent)] ## private
char_callbacks*: seq[proc(codepoint: uint32)] ## private
mouse_move_callbacks*: seq[proc(event: MouseMoveEvent)] ## private mouse_move_callbacks*: seq[proc(event: MouseMoveEvent)] ## private
mouse_button_callbacks*: seq[proc(event: MouseButtonEvent)] ## private mouse_button_callbacks*: seq[proc(event: MouseButtonEvent)] ## private
mouse_wheel_callbacks*: seq[proc(event: MouseWheelEvent)] ## private mouse_wheel_callbacks*: seq[proc(event: MouseWheelEvent)] ## private