From f50b60e8ebd9a17778e5872a47a775fe2f25d94c Mon Sep 17 00:00:00 2001 From: Brad Beveridge Date: Thu, 12 Dec 2024 20:23:41 +1300 Subject: [PATCH] Add support for fs.FS file system support --- asig/asig.go | 124 +++++++++++++++++++++++++++++++++++++++++++++-- asig/material.go | 3 +- asig/wrap.c | 53 ++++++++++++++++++-- asig/wrap.h | 20 ++++++++ main.go | 5 +- 5 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 asig/wrap.h diff --git a/asig/asig.go b/asig/asig.go index 363cd4e..b79cbc3 100755 --- a/asig/asig.go +++ b/asig/asig.go @@ -5,14 +5,17 @@ package asig #cgo LDFLAGS: -L libs #cgo windows,amd64 LDFLAGS: -l assimp_windows_amd64 #cgo darwin,amd64 LDFLAGS: -l assimp_darwin_amd64 -#cgo darwin,arm64 LDFLAGS: -l assimp_darwin_arm64 +#cgo darwin,arm64 LDFLAGS: -l assimp +#cgo darwin,arm64 LDFLAGS: -Wl,-rpath,/usr/local/lib -#include "wrap.c" -#include +#include "wrap.h" */ import "C" import ( "errors" + "io" + "io/fs" + "runtime" "unsafe" "github.com/bloeys/gglm/gglm" @@ -158,6 +161,121 @@ func ImportFile(file string, postProcessFlags PostProcess) (s *Scene, release fu return s, func() { s.releaseCResources() }, nil } +//export go_aiFileOpenProc +func go_aiFileOpenProc(io *C.struct_aiFileIO, name *C.char, flags *C.char) *C.struct_aiFile { + fsWrapper := (*fsWrapper)(unsafe.Pointer(io.UserData)) + + file, err := fsWrapper.fsys.Open(C.GoString(name)) + if err != nil { + return nil + } + fsWrapper.Pin(&file) + + ret := &C.struct_aiFile{ + ReadProc: (C.aiFileReadProc)(C.cgo_aiFileReadProc), + WriteProc: (C.aiFileWriteProc)(C.cgo_aiFileWriteProc), + TellProc: (C.aiFileTellProc)(C.cgo_aiFileTellProc), + FileSizeProc: (C.aiFileTellProc)(C.cgo_aiFileFileSizeProc), + SeekProc: (C.aiFileSeek)(C.cgo_aiFileSeekProc), + FlushProc: (C.aiFileFlushProc)(C.cgo_aiFileFlushProc), + UserData: (*C.char)(unsafe.Pointer(&file)), + } + fsWrapper.Pin(ret) + + return ret +} + +//export go_aiFileCloseProc +func go_aiFileCloseProc(io *C.struct_aiFileIO, file *C.struct_aiFile) { + f := *(*fs.File)(unsafe.Pointer(file.UserData)) + f.Close() +} + +//export go_aiFileReadProc +func go_aiFileReadProc(file *C.struct_aiFile, buffer *C.char, size C.size_t, count C.size_t) C.size_t { + f := *(*fs.File)(unsafe.Pointer(file.UserData)) + slice := unsafe.Slice((*byte)(unsafe.Pointer(buffer)), size*count) + + n, err := f.Read(slice) + if err != nil { + return (C.size_t)(0) + } + return (C.size_t)(n) +} + +//export go_aiFileWriteProc +func go_aiFileWriteProc(file *C.struct_aiFile, buffer *C.char, size C.size_t, count C.size_t) C.size_t { + panic("aiFileWrite not supported") +} + +//export go_aiFileFileSizeProc +func go_aiFileFileSizeProc(file *C.struct_aiFile) C.size_t { + f := *(*fs.File)(unsafe.Pointer(file.UserData)) + info, err := f.Stat() + if err != nil { + return 0 + } + return (C.size_t)(info.Size()) +} + +//export go_aiFileFlushProc +func go_aiFileFlushProc(file *C.struct_aiFile) { + panic("aiFileFlush not supported") +} + +//export go_aiFileTellProc +func go_aiFileTellProc(file *C.struct_aiFile) C.size_t { + panic("aiFileTell not supported") +} + +//export go_aiFileSeekProc +func go_aiFileSeekProc(file *C.struct_aiFile, offset C.size_t, origin C.enum_aiOrigin) C.enum_aiReturn { + f := *(*fs.File)(unsafe.Pointer(file.UserData)) + if s, ok := f.(io.Seeker); ok { + _, err := s.Seek(int64(offset), int(origin)) + if err == nil { + return aiReturnSuccess + } + } + return aiReturnFailure +} + +type fsWrapper struct { + pinnedMemory runtime.Pinner + fsys fs.FS +} + +func (fws *fsWrapper) Pin(pointer interface{}) { + fws.pinnedMemory.Pin(pointer) +} + +func ImportFileEx(file string, postProcessFlags PostProcess, fsys fs.FS) (s *Scene, release func(), err error) { + cstr := C.CString(file) + defer C.free(unsafe.Pointer(cstr)) + + wrapper := &fsWrapper{ + pinnedMemory: runtime.Pinner{}, + fsys: fsys, + } + wrapper.Pin(wrapper) + defer wrapper.pinnedMemory.Unpin() + + cio := &C.struct_aiFileIO{ + OpenProc: (C.aiFileOpenProc)(C.cgo_aiFileOpenProc), + CloseProc: (C.aiFileCloseProc)(C.cgo_aiFileCloseProc), + UserData: (*C.char)(unsafe.Pointer(wrapper)), + } + wrapper.Pin(cio) + + cs := C.aiImportFileEx(cstr, C.uint(postProcessFlags), cio) + if cs == nil { + return nil, func() {}, getAiErr() + } + + s = parseScene(cs) + return s, func() { s.releaseCResources() }, nil +} + func getAiErr() error { return errors.New("asig error: " + C.GoString(C.aiGetErrorString())) } diff --git a/asig/material.go b/asig/material.go index f564527..1a86767 100755 --- a/asig/material.go +++ b/asig/material.go @@ -6,8 +6,7 @@ package asig #cgo windows,amd64 LDFLAGS: -l assimp_windows_amd64 #cgo darwin,arm64 LDFLAGS: -l assimp_darwin_arm64 -#include "wrap.c" -#include +#include "wrap.h" */ import "C" import ( diff --git a/asig/wrap.c b/asig/wrap.c index 07a0668..75ea603 100755 --- a/asig/wrap.c +++ b/asig/wrap.c @@ -1,3 +1,50 @@ -#include // Plain-C interface -#include // Output data structure -#include +#include "wrap.h" +#include + +extern C_STRUCT aiFile *go_aiFileOpenProc(C_STRUCT aiFileIO *io, char *name, char *flags); +C_STRUCT aiFile *cgo_aiFileOpenProc(C_STRUCT aiFileIO *io, const char *name, const char *flags) +{ + return go_aiFileOpenProc(io, (char *)name, (char *)flags); +} + +extern void go_aiFileCloseProc(C_STRUCT aiFileIO *io, C_STRUCT aiFile *file); +void cgo_aiFileCloseProc(C_STRUCT aiFileIO *io, C_STRUCT aiFile *file) +{ + go_aiFileCloseProc(io, file); +} + +extern size_t go_aiFileWriteProc(C_STRUCT aiFile *file, const char *buffer, size_t size, size_t count); +size_t cgo_aiFileWriteProc(C_STRUCT aiFile *file, const char *buffer, size_t size, size_t count) +{ + return go_aiFileWriteProc(file, (char *)buffer, size, count); +} + +extern size_t go_aiFileReadProc(C_STRUCT aiFile *, char *, size_t, size_t); +size_t cgo_aiFileReadProc(C_STRUCT aiFile *file, char *buffer, size_t size, size_t count) +{ + return go_aiFileReadProc(file, buffer, size, count); +} + +extern size_t go_aiFileTellProc(C_STRUCT aiFile *file); +size_t cgo_aiFileTellProc(C_STRUCT aiFile *file) +{ + return go_aiFileTellProc(file); +} + +extern size_t go_aiFileFileSizeProc(C_STRUCT aiFile *file); +size_t cgo_aiFileFileSizeProc(C_STRUCT aiFile *file) +{ + return go_aiFileFileSizeProc(file); +} + +extern void go_aiFileFlushProc(C_STRUCT aiFile *file); +void cgo_aiFileFlushProc(C_STRUCT aiFile *file) +{ + go_aiFileFlushProc(file); +} + +extern C_ENUM aiReturn go_aiFileSeekProc(C_STRUCT aiFile *file, size_t offset, C_ENUM aiOrigin origin); +C_ENUM aiReturn cgo_aiFileSeekProc(C_STRUCT aiFile *file, size_t offset, C_ENUM aiOrigin origin) +{ + return go_aiFileSeekProc(file, offset, origin); +} diff --git a/asig/wrap.h b/asig/wrap.h new file mode 100644 index 0000000..7f76955 --- /dev/null +++ b/asig/wrap.h @@ -0,0 +1,20 @@ +#ifndef WRAP_H +#define WRAP_H + +#include // Plain-C interface +#include // Plain-C interface +#include // Output data structure +#include +#include + +C_STRUCT aiFile *cgo_aiFileOpenProc(C_STRUCT aiFileIO *io, const char *name, const char *flags); +void cgo_aiFileCloseProc(C_STRUCT aiFileIO *io, C_STRUCT aiFile *file); + +size_t cgo_aiFileWriteProc(C_STRUCT aiFile *, const char *, size_t, size_t); +size_t cgo_aiFileReadProc(C_STRUCT aiFile *, char *, size_t, size_t); +size_t cgo_aiFileTellProc(C_STRUCT aiFile *); +size_t cgo_aiFileFileSizeProc(C_STRUCT aiFile *); +void cgo_aiFileFlushProc(C_STRUCT aiFile *); +C_ENUM aiReturn cgo_aiFileSeekProc(C_STRUCT aiFile *, size_t, C_ENUM aiOrigin); + +#endif \ No newline at end of file diff --git a/main.go b/main.go index 6033cb2..16c2963 100755 --- a/main.go +++ b/main.go @@ -4,13 +4,16 @@ import ( "bytes" "fmt" "image/png" + "os" "github.com/bloeys/assimp-go/asig" ) func main() { - scene, release, err := asig.ImportFile("obj.obj", asig.PostProcessTriangulate|asig.PostProcessJoinIdenticalVertices) + //scene, release, err := asig.ImportFile("obj.obj", asig.PostProcessTriangulate|asig.PostProcessJoinIdenticalVertices) + fsys := os.DirFS(".") + scene, release, err := asig.ImportFileEx("obj.obj", asig.PostProcessTriangulate|asig.PostProcessJoinIdenticalVertices, fsys) if err != nil { panic(err) }