diff --git a/README.md b/README.md index aa6d8ef..f5583ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # assimp-go +## Using assimp-go + +The `release()` function is used to free underlying C resources and should be called after all processing that requires C code is done. +`release()` Will not affect the returned Go structs like `Scene` or `Mesh`. Returned Go data will remain valid. + +`asig.X` functions call into C and therefore should not be used on released objects. Calling any `asig.X` function after `release()` is **undefined**. + +While `asig` functions should NOT be called on a Scene (or its objects) after they have been released, methods on structs (e.g. `myScene.XYZ`, `myMesh.ABCD()`) are **safe** even after release. + ## Developing assimp-go We link against static assimp libraries that are built for each platform and added to the `asig/libs` package. @@ -21,11 +30,11 @@ For platform specific steps: **Windows**: > Note: You must compile with the same C/C++ compiler you use with Go (e.g. if you use MinGW with Go, then compile assimp with MinGW by sepcifying the correct `-G` option) - +--- > Note: If you get compilation errors with things like `File too big` or `can't write 166 bytes to section` then cmake isn't detecting you are using MinGW, so add this flag `-D CMAKE_COMPILER_IS_MINGW=TRUE` Now assuming you are using MinGW on windows: - Clone wanted release of assimp and run `cmake CMakeLists.txt -D BUILD_SHARED_LIBS=OFF -D ASSIMP_BUILD_ZLIB=ON -D ASSIMP_BUILD_ASSIMP_TOOLS=OFF -D ASSIMP_BUILD_TESTS=OFF -G "MinGW Makefiles"` in the root folder - Run `cmake --build . --parallel 6` -- Copy the generated `*.lib` file into `asig/lib` +- Copy the generated `*.lib` (or `*.a`) files into `asig/lib` diff --git a/asig/asig.go b/asig/asig.go index c46c44f..237a9af 100755 --- a/asig/asig.go +++ b/asig/asig.go @@ -28,7 +28,59 @@ type Node struct { type Animation struct { } +type Texel struct { + R, G, B, A byte +} + type Texture struct { + /** Width of the texture, in pixels + * + * If mHeight is zero the texture is compressed in a format + * like JPEG. In this case mWidth specifies the size of the + * memory area pcData is pointing to, in bytes. + */ + Width uint + + /** Height of the texture, in pixels + * + * If this value is zero, pcData points to an compressed texture + * in any format (e.g. JPEG). + */ + Height uint + + /** A hint from the loader to make it easier for applications + * to determine the type of embedded textures. + * + * If mHeight != 0 this member is show how data is packed. Hint will consist of + * two parts: channel order and channel bitness (count of the bits for every + * color channel). For simple parsing by the viewer it's better to not omit + * absent color channel and just use 0 for bitness. For example: + * 1. Image contain RGBA and 8 bit per channel, achFormatHint == "rgba8888"; + * 2. Image contain ARGB and 8 bit per channel, achFormatHint == "argb8888"; + * 3. Image contain RGB and 5 bit for R and B channels and 6 bit for G channel, achFormatHint == "rgba5650"; + * 4. One color image with B channel and 1 bit for it, achFormatHint == "rgba0010"; + * If mHeight == 0 then achFormatHint is set set to '\\0\\0\\0\\0' if the loader has no additional + * information about the texture file format used OR the + * file extension of the format without a trailing dot. If there + * are multiple file extensions for a format, the shortest + * extension is chosen (JPEG maps to 'jpg', not to 'jpeg'). + * E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. + * The fourth character will always be '\\0'. + */ + FormatHint string + + /** Data of the texture. + * + * Points to an array of mWidth * mHeight aiTexel's. + * The format of the texture data is always ARGB8888 to + * make the implementation for user of the library as easy + * as possible. If mHeight = 0 this is a pointer to a memory + * buffer of size mWidth containing the compressed texture + * data. Good luck, have fun! + */ + Texels []Texel + + Filename string } type Light struct { @@ -41,7 +93,8 @@ type Metadata struct { } type Scene struct { - Flags SceneFlag + cScene *C.struct_aiScene + Flags SceneFlag RootNode *Node Meshes []*Mesh @@ -52,27 +105,39 @@ type Scene struct { Cameras []*Camera } -func ImportFile(file string, postProcessFlags PostProcess) (*Scene, error) { +func (s *Scene) releaseCResources() { + C.aiReleaseImport(s.cScene) +} + +// +// Assimp API +// + +func ImportFile(file string, postProcessFlags PostProcess) (s *Scene, release func(), err error) { cstr := C.CString(file) defer C.free(unsafe.Pointer(cstr)) cs := C.aiImportFile(cstr, C.uint(postProcessFlags)) if cs == nil { - return nil, getAiErr() + return nil, func() {}, getAiErr() } - defer C.aiReleaseImport(cs) - return parseScene(cs), nil + s = parseScene(cs) + return s, func() { s.releaseCResources() }, nil } func getAiErr() error { return errors.New("asig error: " + C.GoString(C.aiGetErrorString())) } +// +// Parsers +// + func parseScene(cs *C.struct_aiScene) *Scene { - s := &Scene{} + s := &Scene{cScene: cs} s.Flags = SceneFlag(cs.mFlags) s.Meshes = parseMeshes(cs.mMeshes, uint(cs.mNumMeshes)) s.Materials = parseMaterials(cs.mMaterials, uint(cs.mNumMaterials)) @@ -350,6 +415,7 @@ func parseMaterials(cMatsIn **C.struct_aiMaterial, count uint) []*Material { for i := 0; i < int(count); i++ { mats[i] = &Material{ + cMat: cMats[i], Properties: parseMatProperties(cMats[i].mProperties, uint(cMats[i].mNumProperties)), AllocatedStorage: uint(cMats[i].mNumAllocated), } diff --git a/asig/material.go b/asig/material.go index aa73d53..a669d15 100755 --- a/asig/material.go +++ b/asig/material.go @@ -1,6 +1,32 @@ package asig +/* +#cgo CFLAGS: -I . +#cgo LDFLAGS: -L ./libs -l assimp_windows_amd64 -l IrrXML_windows_amd64 -l zlib_windows_amd64 + +#include //Needed for C.free + +#include + +//Functions +unsigned int aiGetMaterialTextureCount(const struct aiMaterial* pMat, enum aiTextureType type); + +enum aiReturn aiGetMaterialTexture( + const struct aiMaterial* mat, + enum aiTextureType type, + unsigned int index, + struct aiString* path, + enum aiTextureMapping* mapping, + unsigned int* uvindex, + ai_real* blend, + enum aiTextureOp* op, + enum aiTextureMapMode* mapmode, + unsigned int* flags); +*/ +import "C" + type Material struct { + cMat *C.struct_aiMaterial /** List of all material properties loaded. */ Properties []*MaterialProperty @@ -38,3 +64,7 @@ type MaterialProperty struct { */ Data []byte } + +func GetMaterialTextureCount(m *Material, texType TextureType) int { + return int(C.aiGetMaterialTextureCount(m.cMat, uint32(texType))) +} diff --git a/main.go b/main.go index 81a0357..21d42e5 100755 --- a/main.go +++ b/main.go @@ -8,7 +8,9 @@ import ( func main() { - scene, err := asig.ImportFile("tex-cube.fbx", asig.PostProcessTriangulate) + scene, release, err := asig.ImportFile("tex-cube.fbx", asig.PostProcessTriangulate) + defer release() + if err != nil { panic(err) } @@ -28,6 +30,8 @@ func main() { p := scene.Materials[i].Properties[j] fmt.Printf("Data Type: %v; Len Bytes: %v; Texture Type: %v\n", p.TypeInfo.String(), len(p.Data), p.Semantic.String()) + + fmt.Println("Texture count:", asig.GetMaterialTextureCount(scene.Materials[i], asig.TextureTypeDiffuse)) } } }