Compare commits

..

No commits in common. "119a0fa8011ab81c059d38c8bfffef2f34b8e528" and "cea7df69471f23208314a7acaf5339147c1bedd4" have entirely different histories.

11 changed files with 122 additions and 146 deletions

3
.gitmodules vendored
View file

@ -4,6 +4,3 @@
[submodule "libs/pixie"] [submodule "libs/pixie"]
path = libs/pixie path = libs/pixie
url = https://git.myou.dev/MyouProject/pixie url = https://git.myou.dev/MyouProject/pixie
[submodule "libs/nim_zstd"]
path = libs/nim_zstd
url = https://github.com/DiThi/nim_zstd

View file

@ -131,9 +131,78 @@ when defined(isNimSkull):
if a.len != 0: if a.len != 0:
copyMem(result[0].addr, a.arr.addr, result.len * sizeof(T)) copyMem(result[0].addr, a.arr.addr, result.len * sizeof(T))
# The following is just copied straight from hashes.nim, just replacing openArray by ArrRef...
when defined(js):
proc imul(a, b: uint32): uint32 =
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
let mask = 0xffff'u32
var
aHi = (a shr 16) and mask
aLo = a and mask
bHi = (b shr 16) and mask
bLo = b and mask
result = (aLo * bLo) + (aHi * bLo + aLo * bHi) shl 16
else:
template imul(a, b: uint32): untyped = a * b
proc rotl32(x: uint32, r: int): uint32 {.inline.} =
(x shl r) or (x shr (32 - r))
proc hash*[T](arr: ArrRef[T]): Hash = proc hash*[T](arr: ArrRef[T]): Hash =
# Make use of stdlib's murmur3 # https://github.com/PeterScott/murmur3/blob/master/murmur3.c
# NOTE: We use the size of elements in bytes instead of the actual size const
# just in case the actual size is bigger than that. c1 = 0xcc9e2d51'u32
hash(cast[ptr UncheckedArray[byte]](arr.arr.addr).toOpenArray(0, arr.len * sizeof(T) - 1)) c2 = 0x1b873593'u32
# TODO: for bigger elements, would a different algorithm be faster? n1 = 0xe6546b64'u32
m1 = 0x85ebca6b'u32
m2 = 0xc2b2ae35'u32
let
x = arr.to byte
size = len(x)
stepSize = 4 # 32-bit
n = size div stepSize
var
h1: uint32
i = 0
# body
while i < n * stepSize:
var k1: uint32
when defined(js) or defined(sparc) or defined(sparc64):
var j = stepSize
while j > 0:
dec j
k1 = (k1 shl 8) or (ord(x[i+j])).uint32
else:
k1 = cast[ptr uint32](unsafeAddr x[i])[]
inc i, stepSize
k1 = imul(k1, c1)
k1 = rotl32(k1, 15)
k1 = imul(k1, c2)
h1 = h1 xor k1
h1 = rotl32(h1, 13)
h1 = h1*5 + n1
# tail
var k1: uint32
var rem = size mod stepSize
while rem > 0:
dec rem
k1 = (k1 shl 8) or (ord(x[i+rem])).uint32
k1 = imul(k1, c1)
k1 = rotl32(k1, 15)
k1 = imul(k1, c2)
h1 = h1 xor k1
# finalization
h1 = h1 xor size.uint32
h1 = h1 xor (h1 shr 16)
h1 = imul(h1, m1)
h1 = h1 xor (h1 shr 13)
h1 = imul(h1, m2)
h1 = h1 xor (h1 shr 16)
return cast[Hash](h1)

@ -1 +0,0 @@
Subproject commit 75ee00aa3da80903dc509f1ff1605304cc77c173

View file

@ -192,24 +192,7 @@ proc draw_all*(self: RenderManager) =
continue continue
scene.update_all_matrices() scene.update_all_matrices()
scene.update_lights() scene.update_lights()
# TODO: move this # TODO: render probes required by cameras of enabled screens
var update_probe_ubo = false
for probe in scene.cubemap_probes:
let upd = case probe.update_strategy:
of UpdateNever: false
of UpdateOnFirstUse:
# TODO: detect when relevant objects are fully loaded
# and also when anything that affects it is visible and
# nearby
not probe.used
of UpdateAlways: true
if upd:
probe.render_cubemap(true)
probe.used = true
update_probe_ubo = true
if update_probe_ubo:
scene.cubemap_UBO.update()
# TODO: render shadows required by cameras of enabled screens # TODO: render shadows required by cameras of enabled screens
for screen in self.engine.screens: for screen in self.engine.screens:
if not screen.enabled: if not screen.enabled:

View file

@ -33,11 +33,8 @@
{.warning[UseBase]: off.} # can't seem to satisy this... {.warning[UseBase]: off.} # can't seem to satisy this...
{.warning[UnusedImport]: off.} # for ./loader_base {.warning[UnusedImport]: off.} # for ./loader_base
const myouUseBlendLoader {.booldefine.} = true
import ../types import ../types
import ./loader_base import ./loader_base
export loader_base
import std/tables import std/tables
import std/strutils import std/strutils
import std/strformat import std/strformat
@ -69,9 +66,8 @@ import float16
when defined(nimdoc): when defined(nimdoc):
type TYPES* = BlendLoader type TYPES* = BlendLoader
proc newBlendLoader*(engine: MyouEngine, proc newBlendLoader*(engine: MyouEngine, use_indices:bool = true,
shader_library: string = "", shader_library: string = "", shader_textures = initTable[string, Texture]()): BlendLoader =
shader_textures = initTable[string, Texture]()): BlendLoader =
result = new BlendLoader result = new BlendLoader
result.engine = engine result.engine = engine
if shader_library != "": if shader_library != "":
@ -80,13 +76,8 @@ proc newBlendLoader*(engine: MyouEngine,
else: else:
result.shader_library = get_builtin_shader_library() result.shader_library = get_builtin_shader_library()
result.shader_textures = get_builtin_shader_textures() result.shader_textures = get_builtin_shader_textures()
result.use_indices = true result.file_extensions = @["blend"]
result.use_indices = use_indices
proc registerBlendLoader*(engine: MyouEngine) =
when myouUseBlendLoader:
engine.registerLoader(@["blend"], proc(e: MyouEngine): Loader =
e.newBlendLoader()
)
var used_resources: seq[LoadableResource] var used_resources: seq[LoadableResource]
@ -584,16 +575,10 @@ method loadScene*(self: BlendLoader, name: string="", scene: Scene=nil, callback
if scn["id"]["name"].cstr == idname.cstring: if scn["id"]["name"].cstr == idname.cstring:
let node = scn let node = scn
var scene = scene var scene = scene
let was_first_scene = self.engine.scenes.len == 0
if scene == nil: if scene == nil:
scene = self.engine.new_scene(name=name) scene = self.engine.new_scene(name=name)
self.loadSceneImpl(node, scene) self.loadSceneImpl(node, scene)
callback(scene) callback(scene)
# TODO: when loading is async, move this stuff after loading has
# finished
if was_first_scene and not scene.enabled:
echo "Warning: Your scene is not enabled, use 'scene.enable_render()' or 'scene.enable_all()'"
scene.render_all_cubemaps(true)
return return
assert false, &"Scene {name} not found" assert false, &"Scene {name} not found"

View file

@ -32,11 +32,10 @@
{.experimental: "dotOperators".} {.experimental: "dotOperators".}
import std/[strutils, tables, algorithm, sequtils, strformat, bitops] import strutils, tables, algorithm, sequtils, strformat, bitops
import std/memfiles import memfiles
# import sugar # import sugar
import std/hashes import hashes
import zstd/decompress
# TODO!! ADD BOUND CHECKS TO ALL FNODES AND DNA1 PARSING! # TODO!! ADD BOUND CHECKS TO ALL FNODES AND DNA1 PARSING!
# TODO: implement big endian, test 32 bit # TODO: implement big endian, test 32 bit
@ -57,8 +56,6 @@ type
old_mem_ptr: pointer old_mem_ptr: pointer
# end pointer for bounds checking # end pointer for bounds checking
endp: pointer endp: pointer
# byte seq in case we used zstd
byte_seq: seq[byte]
BlendFile* = ref BlendFileVal BlendFile* = ref BlendFileVal
@ -145,16 +142,13 @@ template `-`(p, q: pointer): int = cast[int](cast[int](p) -% cast[int](q))
template `+=`(p: pointer, i: Natural) = p = cast[pointer](cast[int](p) +% cast[int](i)) template `+=`(p: pointer, i: Natural) = p = cast[pointer](cast[int](p) +% cast[int](i))
# this is for getting a string that may not be null terminated # this is for getting a string that may not be null terminated
# otherwise you could just do $cast[cstring](x.addr) # otherwise you can just do $cast[cstring](x.addr)
proc getString(data: pointer, max_size: Natural): string = proc getString(data: pointer, max_size: Natural): string =
let u8 = cast[ptr UncheckedArray[char]](data) let u8 = cast[ptr UncheckedArray[char]](data)
var i = 0 for i in 0 ..< max_size:
while i < max_size:
if u8[i] == '\0': if u8[i] == '\0':
break break
inc(i) result &= u8[i]
result.setLen i
copyMem(result.cstring, data, i)
proc build_dna_table(dna_table: ptr FBlock64): (TypeAttrsRef, StructToTypeMap, seq[cstring], TypeLengths) = proc build_dna_table(dna_table: ptr FBlock64): (TypeAttrsRef, StructToTypeMap, seq[cstring], TypeLengths) =
var type_attrs = new TypeAttrsRef var type_attrs = new TypeAttrsRef
@ -236,21 +230,25 @@ proc build_dna_table(dna_table: ptr FBlock64): (TypeAttrsRef, StructToTypeMap, s
) )
aoffset += asize aoffset += asize
offset += 4 offset += 4
# if true:
# # if lengths[type_id] != aoffset:
# echo &"{types[type_id]}: {lengths[type_id]}, {aoffset}"
# var offsets = toSeq(type_attrs[type_id].pairs)
# for _,(k,v) in offsets.sortedByIt(it[1].offset):
# echo &"{types[type_id]}.{k}:\t\t{v.offset}"
assert lengths[type_id] == aoffset assert lengths[type_id] == aoffset
# type_attrs[type_id]["(size)"] = AttrOffset(offset: lengths[type_id]) # type_attrs[type_id]["(size)"] = AttrOffset(offset: lengths[type_id])
return (type_attrs, struct_to_type, types, lengths) return (type_attrs, struct_to_type, types, lengths)
proc openBlendFile*(path: string, data: pointer, len: int): BlendFile = proc openBlendFile*(path: string, data: pointer, len: int): BlendFile =
result = new BlendFile result = new BlendFile
# result.mem_file = memfiles.open(path, mode=fmRead)
result.file_path = path result.file_path = path
let (mem, file_length) = if cast[ptr uint32](data)[] == 0xFD2FB528'u32: # let mem = result.mem_file.mem
# Zstandard compressed file # result.mem = mem
# TODO: store offsets of each zstd frame so we can semi-random access # let file_length = result.mem_file.size
# big files later let mem = data
result.byte_seq = decompress cast[ptr UncheckedArray[byte]](data).toOpenArray(0, len-1) let file_length = len
(result.byte_seq[0].addr.pointer, result.byte_seq.len)
else:
(data, len)
assert file_length > 32, "Invalid file size" assert file_length > 32, "Invalid file size"
result.endp = mem + file_length result.endp = mem + file_length
let u8 = cast[ptr UncheckedArray[uint8]](mem) let u8 = cast[ptr UncheckedArray[uint8]](mem)

View file

@ -31,22 +31,13 @@
# version of this file under either the CPAL or the [AGPL-3] License. # version of this file under either the CPAL or the [AGPL-3] License.
import ../types import ../types
import std/tables
when defined(nimdoc): when defined(nimdoc):
type TYPES* = Loader type TYPES* = Loader
method openAssetFile*(self: Loader, path: string) {.base.} = method openAssetFile*(self: Loader, path: string) {.base, locks: "unknown".} =
discard discard
method loadScene*(self: Loader, name: string="", scene: Scene=nil, method loadScene*(self: Loader, name: string="", scene: Scene=nil): Scene {.base, locks: "unknown".} =
callback: proc(scene: Scene)) {.base.} =
discard discard
method loadImageImpl*(self: Loader) {.base.} = method loadImageImpl*(self: Loader) {.base, locks: "unknown".} =
discard discard
proc registerLoader*(engine: MyouEngine,
extensions: seq[string],
constructor: proc(e: MyouEngine): Loader) =
for ext in extensions:
engine.loaders_by_ext.mgetOrPut(ext, @[]).add constructor

View file

@ -74,7 +74,6 @@ import std/monotimes
import ./graphics/render import ./graphics/render
import ./screen import ./screen
import ./platform/platform import ./platform/platform
import ./loaders/blend
import ./util import ./util
import arr_ref import arr_ref
@ -131,8 +130,6 @@ proc newMyouEngine*(
init_graphics(result, width, height, title, opengl_version, opengl_es) init_graphics(result, width, height, title, opengl_version, opengl_es)
discard result.newScreen(width, height, title) discard result.newScreen(width, height, title)
registerBlendLoader(result)
proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string = proc get_builtin_shader_library*(use_cubemap_prefiltering = true): string =
## Returns a string with the code of the default shader library of the ## 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 ## engine. If you use this, you may want to also add the textures given by
@ -182,18 +179,3 @@ proc run*(self: MyouEngine) =
last_time = getmonotime().ticks.float/1000000000 last_time = getmonotime().ticks.float/1000000000
when not defined(nimdoc): when not defined(nimdoc):
start_platform_main_loop(self, myou_main_loop) 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)

View file

@ -38,16 +38,6 @@ when defined(nimdoc):
type TYPES* = ProbeInfluenceType | ProbeParallaxType | CubemapProbe | CubemapProbeUniform | SH9Uniform type TYPES* = ProbeInfluenceType | ProbeParallaxType | CubemapProbe | CubemapProbeUniform | SH9Uniform
# Forward declarations and ob type methods # Forward declarations and ob type methods
proc newCubemapProbe*(engine: MyouEngine, name: string="camera", scene: Scene = nil,
influence_type: ProbeInfluenceType = SphereInfluence,
influence_distance: float32 = 2.5,
falloff: float32 = 0.2,
intensity: float32 = 1,
clipping_start: float32 = 0.8,
clipping_end: float32 = 40,
parallax_type: ProbeParallaxType = NoParallax,
parallax_distance: float32 = 0.0, # 0 means auto
): CubemapProbe
func getCubemapSideMatrix*(side: int, position = vec3()): Mat4 func getCubemapSideMatrix*(side: int, position = vec3()): Mat4
proc render_cubemap*(self: CubemapProbe, use_roughness_prefiltering = false, mipmap_shader: Material = nil) proc render_cubemap*(self: CubemapProbe, use_roughness_prefiltering = false, mipmap_shader: Material = nil)
proc render_background_cubemap*(scene: Scene, use_roughness_prefiltering = false, mipmap_shader: Material = nil, world_to_cube_matrix: Mat4 = mat4(), upload_UBO = true) proc render_background_cubemap*(scene: Scene, use_roughness_prefiltering = false, mipmap_shader: Material = nil, world_to_cube_matrix: Mat4 = mat4(), upload_UBO = true)
@ -96,7 +86,6 @@ proc newCubemapProbe*(engine: MyouEngine, name: string="camera", scene: Scene =
parallax_distance parallax_distance
else: else:
influence_distance influence_distance
self.update_strategy = UpdateOnFirstUse
return self return self

View file

@ -351,17 +351,6 @@ proc destroy*(self: Scene) =
self.engine.scenes.del(self.name) self.engine.scenes.del(self.name)
return return
proc enable_render*(self: Scene) =
self.enabled = true
proc enable_physics*(self: Scene) =
if self.world != nil:
self.world.enabled = true
proc enable_all*(self: Scene) =
self.enable_render()
self.enable_physics()
proc new_gameobject*(self: Scene, name: string): GameObject = proc new_gameobject*(self: Scene, name: string): GameObject =
return self.engine.new_gameobject(name=name, scene=self) return self.engine.new_gameobject(name=name, scene=self)
@ -539,6 +528,10 @@ proc get_lighting_code*(self: Scene): string =
code.add staticOrDebugRead "shadows/simple_shadow.glsl" code.add staticOrDebugRead "shadows/simple_shadow.glsl"
return code.join "\n" return code.join "\n"
# template as_float_array(x: untyped): untyped =
# cast[array[sizeof(typeof(x)) div 4, float]](x)
proc update_lights*(self: Scene) = proc update_lights*(self: Scene) =
if self.lighting_UBOs.len == 0: if self.lighting_UBOs.len == 0:
return return

View file

@ -81,7 +81,6 @@ type
renderer*: RenderManager renderer*: RenderManager
tone_mapping_library*: string tone_mapping_library*: string
tone_mapping_function*: string tone_mapping_function*: string
loaders_by_ext*: Table[string, seq[proc(e: MyouEngine): Loader]]
# TODO: remove this and query it when screen is created # TODO: remove this and query it when screen is created
width*, height*: int width*, height*: int
glsl_version*: string glsl_version*: string
@ -694,11 +693,6 @@ type
# cubemap_probe.nim # cubemap_probe.nim
ProbeUpdateStrategy* = enum
UpdateNever
UpdateOnFirstUse
UpdateAlways
ProbeInfluenceType* = enum ProbeInfluenceType* = enum
SphereInfluence SphereInfluence
BoxInfluence BoxInfluence
@ -720,8 +714,6 @@ type
intensity*: float32 intensity*: float32
clipping_start*: float32 clipping_start*: float32
clipping_end*: float32 clipping_end*: float32
update_strategy*: ProbeUpdateStrategy
used*: bool
# NOTE: layout must match struct CubemapInfo in scene.nim # NOTE: layout must match struct CubemapInfo in scene.nim
CubemapProbeUniform* = object CubemapProbeUniform* = object
@ -746,16 +738,6 @@ type
influence_distance*: float32 influence_distance*: float32
falloff*: float32 falloff*: float32
# loader_base.nim
Loader* = ref object of RootObj
engine*: MyouEngine
shader_library*: string
shader_textures*: Table[string, Texture]
# on_destroy*: OnDestroy
path_handler*: proc(path: string): string
override_textures_sampler_type*: Table[string, string]
# INCOMPLETE # INCOMPLETE
Armature* = ref object of GameObject Armature* = ref object of GameObject
@ -768,8 +750,6 @@ type
parent_object*: GameObject parent_object*: GameObject
World* = ref object of RootObj World* = ref object of RootObj
enabled*: bool
DebugDraw* = ref object of RootObj DebugDraw* = ref object of RootObj
Body* = ref object Body* = ref object
@ -826,6 +806,15 @@ const HARDCODED_MAXUBOS* = 80
# LOADERS # LOADERS
type Loader* = ref object of RootObj
engine*: MyouEngine
file_extensions*: seq[string]
shader_library*: string
shader_textures*: Table[string, Texture]
# on_destroy*: OnDestroy
path_handler*: proc(path: string): string
override_textures_sampler_type*: Table[string, string]
type BlendLoader* = ref object of Loader type BlendLoader* = ref object of Loader
blend_file_path*: string ## private blend_file_path*: string ## private
blend_file*: BlendFile ## private blend_file*: BlendFile ## private
@ -834,14 +823,15 @@ type BlendLoader* = ref object of Loader
(string, seq[Varying], OrderedTable[string, string], OrderedTable[string, TexturePixels])] ## private (string, seq[Varying], OrderedTable[string, string], OrderedTable[string, TexturePixels])] ## private
resource*: LoadableResource resource*: LoadableResource
template enqueue*(renderer: RenderManager, fun: proc()) = template AllLoaders*: untyped = @[
## Run a proc after the renderer has been initialized. newBlendLoader,
## ]
## If it was already initialized, it runs it immediately.
if renderer.initialized: template enqueue*(self: RenderManager, fun: proc()) =
if self.initialized:
fun() fun()
else: else:
renderer.queue.add fun self.queue.add fun
when not defined(release): when not defined(release):
from sugar import dump from sugar import dump