Replace the use of pointer/len and "done()" by SliceMem and destructors.

This commit is contained in:
Alberto Torres 2024-08-31 00:40:02 +02:00
parent 8eda3e5969
commit d784dd3a52
5 changed files with 81 additions and 128 deletions

View file

@ -42,6 +42,9 @@
## ##
## TODO: investigate the use of signals instead of callbacks ## TODO: investigate the use of signals instead of callbacks
{.hint[ConvFromXtoItselfNotNeeded]:off.}
import arr_ref # for SliceMem
type LoadableResourceStatus* = enum type LoadableResourceStatus* = enum
NotStarted NotStarted
@ -49,27 +52,24 @@ type LoadableResourceStatus* = enum
Finished Finished
Error Error
type Result = tuple[ok: bool, err: string, p: pointer, len: int] # type Result = tuple[ok: bool, err: string, data: SliceMem[byte]]
type LoadableResource* = ref object of RootObj type LoadableResource* = ref object of RootObj
status: LoadableResourceStatus status: LoadableResourceStatus
start_func: proc(self: LoadableResource) start_func: proc(self: LoadableResource) {.closure.}
onload_func: proc(ok: bool, err: string, p: pointer, len: int) onload_func: proc(ok: bool, err: string, data: SliceMem[byte]) {.closure.}
done_func: proc() cancel_func: proc() {.closure.}
cancel_func: proc()
str*: proc(): string str*: proc(): string
use_threads: bool 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,
str: proc(): string = nil, str: proc(): string = nil,
use_threads = false, use_threads = false,
): T = ): T =
new(result) new(result)
result.start_func = start result.start_func = start
result.done_func = done
result.str = str result.str = str
if str == nil: if str == nil:
result.str = proc(): string = "" result.str = proc(): string = ""
@ -78,8 +78,7 @@ proc newLoadableResource*[T: LoadableResource](
# main -> thread channels # main -> thread channels
var to_start: Channel[LoadableResource] var to_start: Channel[LoadableResource]
# main <- thread channels # main <- thread channels
var to_return: Channel[(LoadableResource, bool, string, pointer, int)] var to_return: Channel[(LoadableResource, bool, string, SliceMem[byte])]
var to_done: Channel[LoadableResource]
proc start*[T: LoadableResource](self: T) = proc start*[T: LoadableResource](self: T) =
self.status = Started self.status = Started
@ -88,46 +87,24 @@ proc start*[T: LoadableResource](self: T) =
else: else:
self.start_func(self) self.start_func(self)
proc doneImpl*[T: LoadableResource](self: T) = proc `onload=`*[T: LoadableResource](self: T, onload_func: proc(ok: bool, err: string, data: SliceMem[byte])) =
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)) =
self.onload_func = onload_func self.onload_func = onload_func
proc onload*[T: LoadableResource](self: T, ok: bool, err: string, p: pointer, len: int) = proc onload*[T: LoadableResource](self: T, ok: bool, err: string, data = SliceMem[byte]()) =
if self.status == Started: if self.status == Started:
self.status = if ok: Finished else: Error self.status = if ok: Finished else: Error
if self.result != nil: # if self.result != nil:
self.result[] = (ok, err, p, len) # self.result[] = (ok, err, data)
if self.onload_func != nil: if self.onload_func != nil:
if self.use_threads: if self.use_threads:
to_return.send((self.LoadableResource, ok, err, p, len)) to_return.send((self.LoadableResource, ok, err, data))
else: else:
self.onload_func(ok, err, p, len) self.onload_func(ok, err, data)
else: # cancelled
self.doneImpl()
# TODO: check if we can always use destructors instead of calling this
proc done*[T: LoadableResource](self: T) =
if self.use_threads:
to_done.send self
else:
self.doneImpl()
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.done())
self.onload_func = proc(ok: bool, err: string, p: pointer, len: int) =
self.done()
else:
self.cancel_func() self.cancel_func()
self.status = NotStarted self.status = NotStarted
@ -158,24 +135,22 @@ proc workerThreadProc() {.thread.} =
worker.createThread(workerThreadProc) worker.createThread(workerThreadProc)
to_start.open() to_start.open()
to_return.open() to_return.open()
to_done.open()
proc updateLoadableWorkerThreads*() = proc updateLoadableWorkerThreads*() =
while true: while true:
let tried = to_return.tryRecv() let tried = to_return.tryRecv()
if not tried.dataAvailable: if not tried.dataAvailable:
break break
let (res, ok, err, p, len) = tried.msg let (res, ok, err, data) = tried.msg
res.onload_func(ok, err, p, len) res.onload_func(ok, err, data)
while true:
let tried = to_done.tryRecv() proc terminateLoadableWorkerThreads*() =
if not tried.dataAvailable: # TODO: test this
break to_start.send(nil.LoadableResource)
tried.msg.done_func() worker.joinThread()
type Fetch* = ref object of LoadableResource type Fetch* = ref object of LoadableResource
custom: pointer custom: pointer
auto_done: bool
when not defined(onlyLocalFiles): when not defined(onlyLocalFiles):
when defined(emscripten): when defined(emscripten):
@ -258,16 +233,14 @@ func escapeUTF8*(s: string): string =
proc loadUri*( proc loadUri*(
uri: string, uri: string,
onload_func: proc(ok: bool, err: string, data: pointer, len: int) = nil, onload_func: proc(ok: bool, err: string, data: SliceMem[byte]) = nil,
range = (-1,-1), range = (-1,-1),
auto_start = true, auto_start = true,
auto_done = true,
): Fetch {.discardable.} = ): Fetch {.discardable.} =
echo "fetching ", uri echo "fetching ", uri
var start_func: proc(self: LoadableResource) var start_func: proc(self: LoadableResource)
var done_func: proc()
var self: Fetch var self: Fetch
var uri = uri var uri = uri
var use_threads = false var use_threads = false
@ -289,22 +262,16 @@ proc loadUri*(
attr.onsuccess = proc(fetch: ptr emscripten_fetch_t) {.cdecl.} = attr.onsuccess = proc(fetch: ptr emscripten_fetch_t) {.cdecl.} =
var self = cast[Fetch](fetch.userData) var self = cast[Fetch](fetch.userData)
self.custom = fetch.pointer self.custom = fetch.pointer
self.onload(true, "", fetch.data, fetch.numBytes.int) self.onload(true, "", newSliceMem(fetch.data, fetch.numBytes.int, proc() =
if self.auto_done: emscripten_fetch_close(fetch)
self.done() ))
attr.onerror = proc(fetch: ptr emscripten_fetch_t) {.cdecl.} = attr.onerror = proc(fetch: ptr emscripten_fetch_t) {.cdecl.} =
var self = cast[Fetch](fetch.userData) var self = cast[Fetch](fetch.userData)
let err_msg = $fetch.statusText.addr.cstring let err_msg = $fetch.statusText.addr.cstring
let err = emscripten_fetch_close(fetch) let err = emscripten_fetch_close(fetch)
# self.onload(false, &"Error: {err_msg} ({EMSCRIPTEN_RESULT_STRINGS[err.int + 8]})", nil, 0) # self.onload(false, &"Error: {err_msg} ({EMSCRIPTEN_RESULT_STRINGS[err.int + 8]})", nil, 0)
self.onload(false, &"Error fetching {fetch.url}: {err_msg}", nil, 0) self.onload(false, &"Error fetching {fetch.url}: {err_msg}")
if self.auto_done:
self.done()
discard emscripten_fetch(attr, uri.cstring) discard emscripten_fetch(attr, uri.cstring)
done_func = proc() =
if self.custom != nil:
discard emscripten_fetch_close(cast[ptr emscripten_fetch_t](self.custom))
self.custom = nil
else: else:
use_threads = true use_threads = true
var client = newHttpClient() var client = newHttpClient()
@ -316,37 +283,27 @@ proc loadUri*(
response = client.getContent(uri) response = client.getContent(uri)
ok = true ok = true
except: except:
self.onload(false, &"Error fetching {uri}: {getCurrentExceptionMsg()}", nil, 0) self.onload(false, &"Error fetching {uri}: {getCurrentExceptionMsg()}")
if ok: if ok:
let p = response[0].addr self.onload(true, "", newSliceMem(response[0].addr.pointer, response.len, proc() =
self.onload(true, "", p, response.len) discard response
if self.auto_done: ))
self.done()
done_func = proc() =
response = ""
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.onload(true, "", newSliceMem(memfile.mem, memfile.size, proc() =
when not defined(release): try:
assert not done_called, "Done is being called multiple times. Did you forget to set auto_done = false?" memfile.close()
done_called = true # this should never happen but destructors require it
memfile.close() except OSError: discard
self.onload(true, "", memfile.mem, memfile.size) ))
# TODO!!!! check whether these objects are freed
# and if we have to add a destructor, or what
except OSError: except OSError:
self.onload(false, "Could not open file: " & uri, nil, 0) self.onload(false, "Could not open file: " & uri)
if cast[Fetch](self).auto_done:
self.done()
proc str(): string = uri proc str(): string = uri
self = newLoadableResource[Fetch](start_func, done_func, str, use_threads=use_threads) self = newLoadableResource[Fetch](start_func, str, use_threads=use_threads)
self.onload_func = onload_func self.onload_func = onload_func
self.auto_done = auto_done
if auto_start: if auto_start:
start(self) start(self)
return self return self

View file

@ -109,31 +109,34 @@ proc getDimensionsFormat*(p: pointer, len: int): (int, int, TextureFormat) =
hdr.int * toHDR + is16.int * (R_u16.int-R_u8.int)).TextureFormat hdr.int * toHDR + is16.int * (R_u16.int-R_u8.int)).TextureFormat
return (width, height, format) return (width, height, format)
proc loadFileFromPointersLen*(tex: Texture, pointers: seq[(pointer, int)], proc loadFileFromSlices*(tex: Texture, slices: seq[SliceMem[byte]],
callback: proc(tex: Texture, p: pointer), flip = true) = callback: proc(tex: Texture, data: SliceMem[byte]), flip = true) =
when not defined(nimdoc): when not defined(nimdoc):
assert tex.tex_type != TexCube, "Loading a cube texture from file is not supported yet" assert tex.tex_type != TexCube, "Loading a cube texture from file is not supported yet"
let layer_stride = tex.width * tex.height * tex.format.stride let layer_stride = tex.width * tex.height * tex.format.stride
var multilayer_buffer: ArrRef[byte] var multilayer_buffer: ArrRef[byte]
assert tex.depth == pointers.len assert tex.depth == slices.len
if tex.depth > 1: if tex.depth > 1:
multilayer_buffer = newArrRef[byte](layer_stride * tex.depth) multilayer_buffer = newArrRef[byte](layer_stride * tex.depth)
var pos = 0 var pos = 0
for (p, len) in pointers: for slice in slices:
when defined(myouUsePixie): when defined(myouUsePixie):
var image: Image var image: Image
proc destructor() = discard image
else: else:
var image: imagePixelData[byte] var image: imagePixelData[byte]
var image_16: imagePixelData[uint16] var image_16: imagePixelData[uint16]
var image_f: imagePixelData[float32] var image_f: imagePixelData[float32]
proc destructor() =
discard image; discard image_16; discard image_f
var buffer: ArrRef[byte] var buffer: ArrRef[byte]
# a reference to this pointer is kept with one of the vars above # a reference to this pointer is kept with one of the vars above
var pixels_ptr: pointer var pixels_ptr: pointer
var pixels_len: int var pixels_len: int
var flip = flip var flip = flip
if isEXR(p, len): if isEXR(slice.data, slice.byte_len):
let (width, height, pixels) = decodeEXR(p, len) let (width, height, pixels) = decodeEXR(slice.data, slice.byte_len)
assert width == tex.width and height == tex.height, "Image size mismatch" assert width == tex.width and height == tex.height, "Image size mismatch"
buffer = pixels.to byte buffer = pixels.to byte
pixels_ptr = buffer[0].addr pixels_ptr = buffer[0].addr
@ -148,8 +151,8 @@ proc loadFileFromPointersLen*(tex: Texture, pointers: seq[(pointer, int)],
setFlipVerticallyOnLoad(flip) setFlipVerticallyOnLoad(flip)
flip = false flip = false
var w,h,c = 0 var w,h,c = 0
if isHDRFromMemory(p.toOpenArrayByte(0, len-1)): if isHDRFromMemory(slice.toOpenArrayByte):
image_f = loadFFromMemory(p.toOpenArrayByte(0, len-1), w,h,c,0) image_f = loadFFromMemory(slice.toOpenArrayByte, w,h,c,0)
pixels_ptr = image_f.data pixels_ptr = image_f.data
pixels_len = image_f.byteLen pixels_len = image_f.byteLen
when myouConvertHdrToFloat16: when myouConvertHdrToFloat16:
@ -158,12 +161,12 @@ proc loadFileFromPointersLen*(tex: Texture, pointers: seq[(pointer, int)],
cast[ptr UncheckedArray[Float16]](pixels_ptr), cast[ptr UncheckedArray[Float16]](pixels_ptr),
image_f.len) image_f.len)
pixels_len = pixels_len div 2 pixels_len = pixels_len div 2
elif is16BitFromMemory(p.toOpenArrayByte(0, len-1)): elif is16BitFromMemory(slice.toOpenArrayByte):
image_16 = load16FromMemory(p.toOpenArrayByte(0, len-1), w,h,c,0) image_16 = load16FromMemory(slice.toOpenArrayByte, w,h,c,0)
pixels_ptr = image_16.data pixels_ptr = image_16.data
pixels_len = image_16.byteLen pixels_len = image_16.byteLen
else: else:
image = loadFromMemory(p.toOpenArrayByte(0, len-1), w,h,c,0) image = loadFromMemory(slice.toOpenArrayByte, w,h,c,0)
pixels_ptr = image.data pixels_ptr = image.data
pixels_len = image.len pixels_len = image.len
assert layer_stride == pixels_len, assert layer_stride == pixels_len,
@ -171,11 +174,11 @@ proc loadFileFromPointersLen*(tex: Texture, pointers: seq[(pointer, int)],
if flip: if flip:
swap_lines(pixels_ptr, tex.width * tex.format.stride, tex.height) swap_lines(pixels_ptr, tex.width * tex.format.stride, tex.height)
if tex.depth == 1: if tex.depth == 1:
callback(tex, pixels_ptr) callback(tex, newSliceMem(pixels_ptr, pixels_len, destructor))
return return
copyMem(multilayer_buffer[pos].addr, pixels_ptr, layer_stride) copyMem(multilayer_buffer[pos].addr, pixels_ptr, layer_stride)
pos += layer_stride pos += layer_stride
callback(tex, multilayer_buffer[0].addr) callback(tex, multilayer_buffer.toSliceMem)
proc swap_lines(p: pointer, line_stride, line_count: int) = proc swap_lines(p: pointer, line_stride, line_count: int) =

View file

@ -49,7 +49,8 @@ proc bind_it*(texture: Texture, reserve_slot: static[int32] = -1, needs_active_t
proc unbind*(texture: Texture) proc unbind*(texture: Texture)
proc unbindAllTextures*() proc unbindAllTextures*()
proc destroy*(texture: Texture) proc destroy*(texture: Texture)
proc loadFromPixels*(self: Texture, pixels: pointer) proc loadFromPixelsPointer*(self: Texture, pixels: pointer)
proc loadFromPixels*[T](self: Texture, pixels: SliceMem[T])
proc loadCubeSideFromPixels*(self: Texture, pixels: pointer, side: int32 = 0) proc loadCubeSideFromPixels*(self: Texture, pixels: pointer, side: int32 = 0)
proc setFilter*(self: Texture, filter: TextureFilter) proc setFilter*(self: Texture, filter: TextureFilter)
proc newTexture*(engine: MyouEngine, name: string, width, height: int, depth: int = 1, proc newTexture*(engine: MyouEngine, name: string, width, height: int, depth: int = 1,
@ -59,7 +60,7 @@ proc newTexture*(engine: MyouEngine, name: string, width, height: int, depth: in
pixels: ArrRef[float32] = nil): Texture pixels: ArrRef[float32] = nil): Texture
proc generateMipmap*(self: Texture) proc generateMipmap*(self: Texture)
func to_sRGB*(format: TextureFormat): TextureFormat func to_sRGB*(format: TextureFormat): TextureFormat
proc newTexture*(engine: MyouEngine, name: string, p: pointer, len: int, is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte], is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture
proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool, proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: bool,
filter: TextureFilter = Trilinear, filter: TextureFilter = Trilinear,
tex_type: TextureType = Tex2D, tex_type: TextureType = Tex2D,
@ -327,7 +328,7 @@ proc destroy*(texture: Texture) =
texture.unbind() texture.unbind()
texture.freeTextureStorage() texture.freeTextureStorage()
proc loadFromPixels*(self: Texture, pixels: pointer) = proc loadFromPixelsPointer*(self: Texture, pixels: pointer) =
let ts = self.storage let ts = self.storage
self.loaded = true self.loaded = true
self.bind_it(needs_active_texture=true) self.bind_it(needs_active_texture=true)
@ -344,6 +345,9 @@ proc loadFromPixels*(self: Texture, pixels: pointer) =
if self.needsMipmap: if self.needsMipmap:
glGenerateMipmap(ts.target) glGenerateMipmap(ts.target)
proc loadFromPixels*[T](self: Texture, pixels: SliceMem[T]) =
self.loadFromPixelsPointer(pixels.data)
proc loadCubeSideFromPixels*(self: Texture, pixels: pointer, side: int32 = 0) = proc loadCubeSideFromPixels*(self: Texture, pixels: pointer, side: int32 = 0) =
let ts = self.storage let ts = self.storage
self.loaded = true self.loaded = true
@ -416,7 +420,7 @@ proc newTexture*(engine: MyouEngine, name: string,
self.engine.renderer.enqueue proc()= self.engine.renderer.enqueue proc()=
self.ensure_storage() self.ensure_storage()
if pixels != nil: if pixels != nil:
self.loadFromPixels(pixels.toPointer) self.loadFromPixelsPointer(pixels.toPointer)
else: else:
self.preallocate() self.preallocate()
when defined(myouUseRenderdoc): when defined(myouUseRenderdoc):
@ -436,14 +440,14 @@ func to_sRGB*(format: TextureFormat): TextureFormat =
of RGB_u8: SRGB_u8 of RGB_u8: SRGB_u8
else: raise newException(ValueError, "There's no sRGB version of " & $format) else: raise newException(ValueError, "There's no sRGB version of " & $format)
proc newTexture*(engine: MyouEngine, name: string, p: pointer, len: int, is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture = proc newTexture*(engine: MyouEngine, name: string, data: SliceMem[byte], is_sRGB: bool, filter: TextureFilter = Trilinear, depth=1, flip=true): Texture =
# TODO: replace this function by one taking a LoadableResource # TODO: replace this function by one taking a LoadableResource
var (width, height, format) = getDimensionsFormat(p, len) var (width, height, format) = getDimensionsFormat(data.data, data.byte_len)
if is_sRGB: if is_sRGB:
format = format.to_sRGB format = format.to_sRGB
let self = engine.newTexture(name, width, height, depth, format, filter=filter) let self = engine.newTexture(name, width, height, depth, format, filter=filter)
engine.renderer.enqueue proc() = engine.renderer.enqueue proc() =
self.loadFileFromPointersLen(@[(p, len)], loadFromPixels, flip=flip) self.loadFileFromSlices(@[data], loadFromPixels, flip=flip)
self.loaded = true self.loaded = true
return self return self
@ -457,9 +461,9 @@ proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: b
# note: format does not matter at this point, will be replaced later # note: format does not matter at this point, will be replaced later
let self = engine.newTexture(name, 0, 0, filter=filter, format=RGBA_u8) let self = engine.newTexture(name, 0, 0, filter=filter, format=RGBA_u8)
var res: LoadableResource var res: LoadableResource
proc load(ok: bool, err: string, p: pointer, len: int) = proc load(ok: bool, err: string, data: SliceMem[byte]) =
assert ok, &"Error loading texture '{self.name}' from '{file_name}': {err}" assert ok, &"Error loading texture '{self.name}' from '{file_name}': {err}"
let ktx_info = GetDdsKtxInfo(p, len) let ktx_info = GetDdsKtxInfo(data.data, data.byte_len)
if ktx_info.isSome: if ktx_info.isSome:
let ktx_info = ktx_info.get let ktx_info = ktx_info.get
assert ktx_info.is_cubemap == (self.tex_type == TexCube) assert ktx_info.is_cubemap == (self.tex_type == TexCube)
@ -472,7 +476,7 @@ proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: b
engine.renderer.enqueue proc()= engine.renderer.enqueue proc()=
try: try:
self.ensure_storage() self.ensure_storage()
self.loadCompressedData(ktx_info, ParseDdsKtx(p, len)) self.loadCompressedData(ktx_info, ParseDdsKtx(data.data, data.byte_len))
self.setMipmapRange(0, ktx_info.num_mipmaps - 1) self.setMipmapRange(0, ktx_info.num_mipmaps - 1)
self.loaded = true self.loaded = true
# except Exception as e: # except Exception as e:
@ -482,10 +486,8 @@ proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: b
# echo line # echo line
echo getCurrentExceptionMsg() echo getCurrentExceptionMsg()
echo "Error loading texture " & file_name echo "Error loading texture " & file_name
finally:
res.done()
else: else:
var (width, height, format) = getDimensionsFormat(p, len) var (width, height, format) = getDimensionsFormat(data.data, data.byte_len)
if is_sRGB: if is_sRGB:
format = format.to_sRGB format = format.to_sRGB
self.width = width self.width = width
@ -494,15 +496,13 @@ proc newTexture*(engine: MyouEngine, name: string, file_name: string, is_sRGB: b
engine.renderer.enqueue proc()= engine.renderer.enqueue proc()=
try: try:
self.ensure_storage() self.ensure_storage()
self.loadFileFromPointersLen(@[(p, len)], loadFromPixels) self.loadFileFromSlices(@[data], loadFromPixels)
self.loaded = true self.loaded = true
except: except:
# TODO: use logging # TODO: use logging
echo getCurrentExceptionMsg() echo getCurrentExceptionMsg()
echo "Error loading texture " & file_name echo "Error loading texture " & file_name
finally: res = file_name.loadUri(load, auto_start=false)
res.done()
res = file_name.loadUri(load, auto_start=false, auto_done=false)
res.start() res.start()
return self return self

View file

@ -32,6 +32,7 @@
{.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
{.warning[rsemMethodLockMismatch]: off.} # TODO: is this important?
const myouUseBlendLoader {.booldefine.} = true const myouUseBlendLoader {.booldefine.} = true
@ -90,7 +91,6 @@ proc registerBlendLoader*(engine: MyouEngine) =
method close*(self: BlendLoader) = method close*(self: BlendLoader) =
if self.resource != nil: if self.resource != nil:
self.resource.done()
self.resource = nil self.resource = nil
self.blend_file = nil self.blend_file = nil
self.cached_materials.clear() self.cached_materials.clear()
@ -107,14 +107,12 @@ proc loadAsync(self: BlendLoader, callback: proc()) =
else: else:
self.close() self.close()
self.resource = loadUri(self.blend_file_path, self.resource = loadUri(self.blend_file_path,
proc(ok, err, data, len: auto) = proc(ok, err, data: auto) =
if ok: if ok:
self.blend_file = openBlendFile(self.blend_file_path, data, len) self.blend_file = openBlendFile(self.blend_file_path, data.data, data.byte_len)
callback() callback()
else: else:
raise IOError.newException err raise IOError.newException err
,
auto_done = false
) )
type BlenderObTypes = enum type BlenderObTypes = enum
@ -180,8 +178,10 @@ method loadTextureImpl*(self: BlendLoader, name: string, img: FNode): Texture =
# todo: was this necessary? # todo: was this necessary?
# let seek = img.packedfile.seek.i32[0] # let seek = img.packedfile.seek.i32[0]
let size = img.packedfile.size.i32[0] let size = img.packedfile.size.i32[0]
let arr = img.packedfile.data.get_array(size, char) let arr = img.packedfile.data.get_array(size, byte)
return self.engine.newTexture(name, arr, size, is_sRGB) # TODO: get SliceMems from blend file instead of UncheckedArray
let s = SliceMem[byte](data: arr, byte_len: size)
return self.engine.newTexture(name, s, is_sRGB)
else: else:
# echo "loading image as REGULAR file" # echo "loading image as REGULAR file"
if self.path_handler != nil: if self.path_handler != nil:
@ -367,7 +367,7 @@ proc loadObjectImpl(self: BlendLoader, scene: Scene, obn: FNode): (GameObject, s
PointLight PointLight
let color = vec3(data.r.f32[0], data.g.f32[0], data.b.f32[0]) let color = vec3(data.r.f32[0], data.g.f32[0], data.b.f32[0])
let mode = data.mode.i32[0] let mode = data.mode.i32[0]
let use_shadow = mode.testBit(0) # let use_shadow = mode.testBit(0)
let use_dist = mode.testBit(20) let use_dist = mode.testBit(20)
let cutoff = if use_dist: data.att_dist.f32[0] else: 0'f32 let cutoff = if use_dist: data.att_dist.f32[0] else: 0'f32
var ob = self.engine.new_light( var ob = self.engine.new_light(

View file

@ -121,13 +121,6 @@ proc hash*(n: FNode): Hash =
# NOTE: assuming read only data (otherwise we should hash the contents) # NOTE: assuming read only data (otherwise we should hash the contents)
hash (n.p, n.count) hash (n.p, n.count)
# proc `=destroy`(self: var BlendFileVal) =
# try:
# self.mem_file.close()
# except OSError:
# # this should never happen but compiler requires it for hooks
# discard
const BASIC_TYPE_LENGTHS = [1, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 0, 1] const BASIC_TYPE_LENGTHS = [1, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 0, 1]
template `[]`*(blocks: NamedBlocks, s: string): untyped = blocks[[s[0],s[1]]] template `[]`*(blocks: NamedBlocks, s: string): untyped = blocks[[s[0],s[1]]]