18 Commits

Author SHA1 Message Date
d583049090 Update to 5.1.6+use dll+update readme 2022-01-22 03:39:12 +04:00
9acd5bee18 Metadata+Fix node bug 2021-11-20 01:24:37 +04:00
5b5d091d56 Nodes implementation 2021-11-20 00:37:59 +04:00
c0a308b178 Add usage and features to readme 2021-11-20 00:12:07 +04:00
5573ffdbf6 Merge pull request #1 from bloeys/noswig
Noswig
2021-11-19 21:11:01 +04:00
dee2332b9a Correct comments 2021-11-19 21:10:11 +04:00
4462a3be04 Handle (embedded)textures 2021-11-19 21:05:21 +04:00
3b31e8d677 Working on mats&textures+better release handling+readme 2021-11-19 17:29:01 +04:00
32c5def787 Stringer for some enums 2021-11-19 14:58:59 +04:00
e96f70d88f Parse materials 2021-11-19 13:40:09 +04:00
672802a705 Scene flags+start material import 2021-11-19 13:27:31 +04:00
fb9d44beca Add PostProcess enum 2021-11-19 09:03:35 +04:00
8bf9dc9121 Clean resources after import+error handling 2021-11-19 08:35:56 +04:00
8c752a0bda Protect parsers against null pointers 2021-11-18 21:05:24 +04:00
77e62588fe Full mesh parsing 2021-11-18 21:02:14 +04:00
e7e81afc7c Initial implementation without using swig 2021-11-18 17:58:48 +04:00
6b6255d4a3 Update readme 2021-11-15 10:37:29 +04:00
72a0b83122 Change package name aig->asig 2021-11-15 10:35:13 +04:00
106 changed files with 1287 additions and 30917 deletions

4
.gitignore vendored
View File

@ -13,6 +13,6 @@
# Dependency directories (remove the comment below to include it)
vendor/
*.a
*.obj
*.fbx
*.fbx
*.glb

104
README.md
View File

@ -1,31 +1,111 @@
# assimp-go
A Handcrafted Open Asset Import Library (AssImp) wrapper for Go.
## Features
The following features are already implemented:
* Loading all supported model formats into a Scene object
* Mesh data
* Materials
* Textures and embedded textures
* Error reporting
* Enums relevant to the above operations
Unimplemented (yet) AssImp Scene objects:
* Animation
* Lights
* Camera
## Using assimp-go
### Requirements
To run the project you need:
* A recent version of [Go](https://golang.org/) installed (1.17+)
* A C/C++ compiler installed and in your path
* Windows: [MingW](https://www.mingw-w64.org/downloads/#mingw-builds) or similar
* Mac/Linux: Should be installed by default, but if not try [GCC](https://gcc.gnu.org/) or [Clang](https://releases.llvm.org/download.html)
Then simply clone and use `go run .`
> Note: that it might take a while to run the first time because of downloading/compiling dependencies.
`assimp-go` dynamically links (e.g. through a DLL) AssImp using platform dependent libraries, which are made available with the GitHub releases.
Currently only `Windows` libraries are available, but more should be easy to add by compiling AssImp on the wanted platform. (Make a PR if you can help us get those binaries!)
### Getting Started
```Go
func main() {
//Load this .fbx model with the following post processing flags
scene, release, err := asig.ImportFile("my-cube.fbx", asig.PostProcessTriangulate | asig.PostProcessJoinIdenticalVertices)
if err != nil {
panic(err)
}
for i := 0; i < len(scene.Materials); i++ {
m := scene.Materials[i]
//Check how many diffuse textures are attached to this material
texCount := asig.GetMaterialTextureCount(m, asig.TextureTypeDiffuse)
fmt.Println("Texture count:", texCount)
//If we have at least 1 diffuse texture attached to this material, load the first diffuse texture (index 0)
if texCount > 0 {
texInfo, err := asig.GetMaterialTexture(m, asig.TextureTypeDiffuse, 0)
if err != nil {
panic(err)
}
fmt.Printf("%v\n", texInfo)
}
}
//Now that we are done with all our `asig.XYZ` calls we can release underlying C resources.
//
//NOTE: Our Go objects (like scene, scene.Materials etc) will remain intact ;), but we must NOT use asig.XYZ calls on this scene and its children anymore
release()
}
```
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 `aig/libs` package.
We link against assimp libraries that are built for each platform and the `*.a` files are added to the `asig/libs` package.
Depending on the platform we select one of them and link against it when doing `go build`.
The general steps are:
- Copy assimp includes into `aig/assimp`
- Copy `zlib.h`, `zconf.h` and `irrXML.h` into `aig/zlib` and `aig/irrxml` respectively.
- Copy static libraries into `aig/libs`
- Generate the wrappers using `swig -go -c++ -intgosize 64 aig/aig.i`
- Add `#cgo LDFLAGS: -L ./staticLibs -l zlibstatic -l IrrXML -l assimp` at the top of the 'C' import in `aig.go`
* Copy assimp includes into `asig/assimp`
* Copy `zlib.h`, `zconf.h` and `irrXML.h` into `asig/zlib` and `asig/irrxml` respectively.
* Copy static libraries and DLL import libraries into `asig/libs`
> Note: When dealing with static libraries the compiler will probably (e.g. MinGW does this) ignore `lib` suffixes and `.a`/`.lib` suffixes.
> Note: When dealing with libraries the compiler will probably (e.g. MinGW does this) ignore `lib` prefixes and `.a`/`.lib` suffixes.
So if your lib name is `libassimp.a` you need to pass it to CGO as `-l assimp`, otherwise you will get an error about library not found.
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: 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 specifying the correct `-G` option to cMake)
---
> 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 `aig/lib`
* Clone wanted release of assimp and run `cmake CMakeLists.txt -D ASSIMP_BUILD_ASSIMP_TOOLS=OFF -G "MinGW Makefiles"` in the root folder
* Run `cmake --build . --parallel 6`
* Copy the generated `*.lib` (or `*.a`) files from the `lib` folder and into `asig/lib`, and copy the generated dll from AssImp `bin` folder into the root of `assimp-go`.

13130
aig/aig.go

File diff suppressed because it is too large Load Diff

241
aig/aig.i
View File

@ -1,241 +0,0 @@
%module aig
//NOTE: Add this above the 'C' package in aig_wrap.go `#cgo LDFLAGS: -L ./staticLibs -l zlibstatic -l IrrXML -l assimp` after generating
// SWIG helpers for std::string and std::vector wrapping.
%include <std_string.i>
%include <std_vector.i>
//Needed defines
#define AI_NO_EXCEPT noexcept
#define C_STRUCT struct
#define AI_FORCE_INLINE inline
#define C_ENUM enum
#define ASSIMP_API
#define PACK_STRUCT
//Macros
%define ASSIMP_ARRAY(CLASS, TYPE, NAME, LENGTH)
%newobject CLASS::NAME;
%extend CLASS {
std::vector<TYPE > *NAME() const {
std::vector<TYPE > *result = new std::vector<TYPE >;
result->reserve(LENGTH);
for (unsigned int i = 0; i < LENGTH; ++i) {
result->push_back($self->NAME[i]);
}
return result;
}
}
%ignore CLASS::NAME;
%enddef
%define ASSIMP_POINTER_ARRAY(CLASS, TYPE, NAME, LENGTH)
%newobject CLASS::NAME;
%extend CLASS {
std::vector<TYPE *> *NAME() const {
std::vector<TYPE *> *result = new std::vector<TYPE *>;
result->reserve(LENGTH);
TYPE *currentValue = $self->NAME;
TYPE *valueLimit = $self->NAME + LENGTH;
while (currentValue < valueLimit) {
result->push_back(currentValue);
++currentValue;
}
return result;
}
}
%ignore CLASS::NAME;
%enddef
%define ASSIMP_POINTER_ARRAY_ARRAY(CLASS, TYPE, NAME, OUTER_LENGTH, INNER_LENGTH)
%newobject CLASS::NAME;
%extend CLASS {
std::vector<std::vector<TYPE *> > *NAME() const {
std::vector<std::vector<TYPE *> > *result = new std::vector<std::vector<TYPE *> >;
result->reserve(OUTER_LENGTH);
for (unsigned int i = 0; i < OUTER_LENGTH; ++i) {
std::vector<TYPE *> currentElements;
if ($self->NAME[i] != 0) {
currentElements.reserve(INNER_LENGTH);
TYPE *currentValue = $self->NAME[i];
TYPE *valueLimit = $self->NAME[i] + INNER_LENGTH;
while (currentValue < valueLimit) {
currentElements.push_back(currentValue);
++currentValue;
}
}
result->push_back(currentElements);
}
return result;
}
}
%ignore CLASS::NAME;
%enddef
//We need these otherwise swig won't generate interfaces for these types correctly
//because swig gets confused when there is a typedef and a templated class, so we put the typedefs here
//and a template directive at the end
typedef float ai_real;
typedef aiVector3t<ai_real> aiVector3D;
typedef aiVector2t<ai_real> aiVector2D;
typedef aiMatrix3x3t<ai_real> aiMatrix3x3;
typedef aiMatrix4x4t<ai_real> aiMatrix4x4;
%{
#include "assimp/cimport.h"
#include "assimp/scene.h"
#include "assimp/mesh.h"
#include "assimp/vector2.h"
#include "assimp/vector3.h"
#include "assimp/matrix3x3.h"
#include "assimp/matrix4x4.h"
#include "assimp/Defines.h"
#include "assimp/color4.h"
#include "assimp/postprocess.h"
#include "assimp/types.h"
#include "assimp/texture.h"
#include "assimp/light.h"
#include "assimp/camera.h"
#include "assimp/material.h"
#include "assimp/anim.h"
#include "assimp/metadata.h"
#include "zlib/zconf.h"
#include "zlib/zlib.h"
#include "irrxml/irrXML.h"
%}
//Features
%feature("d:stripprefix", "aiProcess_") aiPostProcessSteps;
//Ignores
%ignore aiString::Set(const std::string& pString);
//aiScene macros
ASSIMP_ARRAY(aiScene, aiAnimation*, mAnimations, $self->mNumAnimations);
ASSIMP_ARRAY(aiScene, aiCamera*, mCameras, $self->mNumCameras);
ASSIMP_ARRAY(aiScene, aiLight*, mLights, $self->mNumLights);
ASSIMP_ARRAY(aiScene, aiMaterial*, mMaterials, $self->mNumMaterials);
ASSIMP_ARRAY(aiScene, aiMesh*, mMeshes, $self->mNumMeshes);
ASSIMP_ARRAY(aiScene, aiTexture*, mTextures, $self->mNumTextures);
ASSIMP_ARRAY(aiNode, aiNode*, mChildren, $self->mNumChildren);
ASSIMP_ARRAY(aiNode, unsigned int, mMeshes, $self->mNumMeshes);
//aiMesh macros
ASSIMP_ARRAY(aiFace, unsigned int, mIndices, $self->mNumIndices);
ASSIMP_POINTER_ARRAY(aiBone, aiVertexWeight, mWeights, $self->mNumWeights);
ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mVertices, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mNormals, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mTangents, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mBitangents, $self->mNumVertices);
ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices);
ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices);
ASSIMP_ARRAY(aiMesh, aiAnimMesh*, mAnimMeshes, $self->mNumAnimMeshes);
ASSIMP_ARRAY(aiMesh, aiBone*, mBones, $self->mNumBones);
ASSIMP_ARRAY(aiMesh, unsigned int, mNumUVComponents, AI_MAX_NUMBER_OF_TEXTURECOORDS);
ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mVertices, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mNormals, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mTangents, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mBitangents, $self->mNumVertices);
ASSIMP_POINTER_ARRAY(aiMesh, aiFace, mFaces, $self->mNumFaces);
ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices);
ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices);
//Camera macros
ASSIMP_ARRAY(aiMaterial, aiMaterialProperty*, mProperties, $self->mNumProperties)
//Material settings
%include <typemaps.i>
%apply enum SWIGTYPE *OUTPUT { aiTextureMapping* mapping };
%apply unsigned int *OUTPUT { unsigned int* uvindex };
%apply float *OUTPUT { float* blend };
%apply enum SWIGTYPE *OUTPUT { aiTextureOp* op };
%apply unsigned int *OUTPUT { unsigned int* flags };
//Final includes
%include "assimp/cimport.h" // Plain-C interface
%include "assimp/scene.h" // Output data structure
%include "assimp/mesh.h"
%include "assimp/vector2.h"
%include "assimp/vector3.h"
%include "assimp/matrix3x3.h"
%include "assimp/matrix4x4.h"
%include "assimp/Defines.h"
%include "assimp/color4.h"
%include "assimp/types.h"
%include "assimp/texture.h"
%include "assimp/light.h"
%include "assimp/camera.h"
%include "assimp/material.h"
%include "assimp/anim.h"
%include "assimp/metadata.h"
%include "assimp/postprocess.h"
%include "zlib/zconf.h"
%include "zlib/zlib.h"
%include "irrxml/irrXML.h"
// We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros
// here at the end to avoid running into forward reference issues (SWIG would
// spit out the helper functions before the header includes for the element
// types otherwise).
%template(UintVector) std::vector<unsigned int>;
%template(aiAnimationVector) std::vector<aiAnimation *>;
%template(aiAnimMeshVector) std::vector<aiAnimMesh *>;
%template(aiBonesVector) std::vector<aiBone *>;
%template(aiCameraVector) std::vector<aiCamera *>;
%template(aiColor4DVector) std::vector<aiColor4D *>;
%template(aiColor4DVectorVector) std::vector<std::vector<aiColor4D *> >;
%template(aiFaceVector) std::vector<aiFace *>;
%template(aiLightVector) std::vector<aiLight *>;
%template(aiMaterialVector) std::vector<aiMaterial *>;
%template(aiMaterialPropertyVector) std::vector<aiMaterialProperty *>;
%template(aiMeshAnimVector) std::vector<aiMeshAnim *>;
%template(aiMeshVector) std::vector<aiMesh *>;
%template(aiNodeVector) std::vector<aiNode *>;
%template(aiNodeAnimVector) std::vector<aiNodeAnim *>;
%template(aiTextureVector) std::vector<aiTexture *>;
%template(aiVector3DVector) std::vector<aiVector3D *>;
%template(aiVector3DVectorVector) std::vector<std::vector<aiVector3D *> >;
%template(aiVertexWeightVector) std::vector<aiVertexWeight *>;
%template(GetInteger) aiMaterial::Get<int>;
%template(GetFloat) aiMaterial::Get<float>;
%template(GetColor4D) aiMaterial::Get<aiColor4D>;
%template(GetColor3D) aiMaterial::Get<aiColor3D>;
%template(GetString) aiMaterial::Get<aiString>;
%template(aiVector2D) aiVector2t<ai_real>;
%template(aiVector3D) aiVector3t<ai_real>;
%template(aiMatrix3x3) aiMatrix3x3t<ai_real>;
%template(aiMatrix4x4) aiMatrix4x4t<ai_real>;
//Material settings
%clear unsigned int* flags;
%clear aiTextureOp* op;
%clear float *blend;
%clear unsigned int* uvindex;
%clear aiTextureMapping* mapping;
%apply int &OUTPUT { int &pOut };
%apply float &OUTPUT { float &pOut };
%clear int &pOut;
%clear float &pOut;

File diff suppressed because it is too large Load Diff

618
asig/asig.go Executable file
View File

@ -0,0 +1,618 @@
package asig
/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: -L ./libs -l assimp_windows_amd64 -l IrrXML_windows_amd64 -l zlib_windows_amd64
#include <wrap.cxx>
#include <stdlib.h> //Needed for C.free
*/
import "C"
import (
"errors"
"unsafe"
"github.com/bloeys/gglm/gglm"
)
type Node struct {
Name string
//The transformation relative to the node's parent
Transformation *gglm.Mat4
//Parent node. NULL if this node is the root node
Parent *Node
//The child nodes of this node. NULL if mNumChildren is 0
Children []*Node
//Each entry is an index into the mesh list of the scene
MeshIndicies []uint
/** Metadata associated with this node or NULL if there is no metadata.
* Whether any metadata is generated depends on the source file format. See the
* @link importer_notes @endlink page for more information on every source file
* format. Importers that don't document any metadata don't write any.
*/
Metadata map[string]Metadata
}
type Animation struct {
}
type EmbeddedTexture struct {
cTex *C.struct_aiTexture
/** 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 Height != 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 Width * Height (or just len=Width if Height=0, which happens when data is compressed, like if the data is a PNG).
* The format of the texture data is always ARGB8888.
*/
Data []byte
IsCompressed bool
Filename string
}
type Light struct {
}
type Camera struct {
}
type Metadata struct {
Type MetadataType
Value interface{}
}
type MetadataEntry struct {
Data []byte
}
type Scene struct {
cScene *C.struct_aiScene
Flags SceneFlag
RootNode *Node
Meshes []*Mesh
Materials []*Material
/** Helper structure to describe an embedded texture
*
* Normally textures are contained in external files but some file formats embed
* them directly in the model file. There are two types of embedded textures:
* 1. Uncompressed textures. The color data is given in an uncompressed format.
* 2. Compressed textures stored in a file format like png or jpg. The raw file
* bytes are given so the application must utilize an image decoder (e.g. DevIL) to
* get access to the actual color data.
*
* Embedded textures are referenced from materials using strings like "*0", "*1", etc.
* as the texture paths (a single asterisk character followed by the
* zero-based index of the texture in the aiScene::mTextures array).
*/
Textures []*EmbeddedTexture
// Animations []*Animation
// Lights []*Light
// Cameras []*Camera
}
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, func() {}, getAiErr()
}
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{cScene: cs}
s.Flags = SceneFlag(cs.mFlags)
s.RootNode = parseRootNode(cs.mRootNode)
s.Meshes = parseMeshes(cs.mMeshes, uint(cs.mNumMeshes))
s.Materials = parseMaterials(cs.mMaterials, uint(cs.mNumMaterials))
s.Textures = parseTextures(cs.mTextures, uint(s.cScene.mNumTextures))
return s
}
func parseRootNode(cNodesIn *C.struct_aiNode) *Node {
rn := &Node{
Name: parseAiString(cNodesIn.mName),
Transformation: parseMat4(&cNodesIn.mTransformation),
Parent: nil,
MeshIndicies: parseUInts(cNodesIn.mMeshes, uint(cNodesIn.mNumMeshes)),
Metadata: parseMetadata(cNodesIn.mMetaData),
}
rn.Children = parseNodes(cNodesIn.mChildren, rn, uint(cNodesIn.mNumChildren))
return rn
}
func parseNodes(cNodesIn **C.struct_aiNode, parent *Node, parentChildrenCount uint) []*Node {
if cNodesIn == nil {
return []*Node{}
}
nodes := make([]*Node, parentChildrenCount)
cNodes := unsafe.Slice(cNodesIn, parentChildrenCount)
for i := 0; i < len(nodes); i++ {
n := cNodes[i]
//Fill basic node info
nodes[i] = &Node{
Name: parseAiString(n.mName),
Transformation: parseMat4(&n.mTransformation),
Parent: parent,
MeshIndicies: parseUInts(n.mMeshes, uint(n.mNumMeshes)),
Metadata: parseMetadata(n.mMetaData),
}
//Parse node's children
nodes[i].Children = parseNodes(n.mChildren, nodes[i], parentChildrenCount)
}
return nodes
}
func parseMetadata(cMetaIn *C.struct_aiMetadata) map[string]Metadata {
if cMetaIn == nil {
return map[string]Metadata{}
}
meta := make(map[string]Metadata, cMetaIn.mNumProperties)
cKeys := unsafe.Slice(cMetaIn.mKeys, cMetaIn.mNumProperties)
cVals := unsafe.Slice(cMetaIn.mValues, cMetaIn.mNumProperties)
for i := 0; i < int(cMetaIn.mNumProperties); i++ {
meta[parseAiString(cKeys[i])] = parseMetadataEntry(cVals[i])
}
return meta
}
func parseMetadataEntry(cv C.struct_aiMetadataEntry) Metadata {
m := Metadata{Type: MetadataType(cv.mType)}
if cv.mData == nil {
return m
}
switch m.Type {
case MetadataTypeBool:
m.Value = *(*bool)(cv.mData)
case MetadataTypeFloat32:
m.Value = *(*float32)(cv.mData)
case MetadataTypeFloat64:
m.Value = *(*float64)(cv.mData)
case MetadataTypeInt32:
m.Value = *(*int32)(cv.mData)
case MetadataTypeUint64:
m.Value = *(*uint64)(cv.mData)
case MetadataTypeString:
m.Value = parseAiString(*(*C.struct_aiString)(cv.mData))
case MetadataTypeVec3:
m.Value = parseVec3((*C.struct_aiVector3D)(cv.mData))
}
return m
}
func parseTextures(cTexIn **C.struct_aiTexture, count uint) []*EmbeddedTexture {
if cTexIn == nil {
return []*EmbeddedTexture{}
}
textures := make([]*EmbeddedTexture, count)
cTex := unsafe.Slice(cTexIn, count)
for i := 0; i < int(count); i++ {
textures[i] = &EmbeddedTexture{
cTex: cTex[i],
Width: uint(cTex[i].mWidth),
Height: uint(cTex[i].mHeight),
FormatHint: C.GoString(&cTex[i].achFormatHint[0]),
Filename: parseAiString(cTex[i].mFilename),
Data: parseTexels(cTex[i].pcData, uint(cTex[i].mWidth), uint(cTex[i].mHeight)),
IsCompressed: cTex[i].mHeight == 0,
}
}
return textures
}
func parseTexels(cTexelsIn *C.struct_aiTexel, width, height uint) []byte {
//e.g. like a png. Otherwise we have pure color data
isCompressed := height == 0
texelCount := width
if !isCompressed {
texelCount *= height
}
texelCount /= 4
data := make([]byte, texelCount*4)
cTexels := unsafe.Slice(cTexelsIn, texelCount)
for i := 0; i < int(texelCount); i++ {
//Order here is important as in a compressed format the order will represent arbitrary bytes, not colors.
//In aiTexel the struct field order is {b,g,r,a}, which puts A in the high bits and leads to a format of ARGB8888, therefore it must be maintained here
index := i * 4
data[index] = byte(cTexels[i].b)
data[index+1] = byte(cTexels[i].g)
data[index+2] = byte(cTexels[i].r)
data[index+3] = byte(cTexels[i].a)
}
return data
}
func parseMeshes(cm **C.struct_aiMesh, count uint) []*Mesh {
if cm == nil {
return []*Mesh{}
}
meshes := make([]*Mesh, count)
cmeshes := unsafe.Slice(cm, count)
for i := 0; i < int(count); i++ {
m := &Mesh{}
cmesh := cmeshes[i]
vertCount := uint(cmesh.mNumVertices)
m.Vertices = parseVec3s(cmesh.mVertices, vertCount)
m.Normals = parseVec3s(cmesh.mNormals, vertCount)
m.Tangents = parseVec3s(cmesh.mTangents, vertCount)
m.BitTangents = parseVec3s(cmesh.mBitangents, vertCount)
//Color sets
m.ColorSets = parseColorSet(cmesh.mColors, vertCount)
//Tex coords
m.TexCoords = parseTexCoords(cmesh.mTextureCoords, vertCount)
m.TexCoordChannelCount = [8]uint{}
for j := 0; j < len(cmesh.mTextureCoords); j++ {
//If a color set isn't available then it is nil
if cmesh.mTextureCoords[j] == nil {
continue
}
m.TexCoordChannelCount[j] = uint(cmeshes[j].mNumUVComponents[j])
}
//Faces
cFaces := unsafe.Slice(cmesh.mFaces, cmesh.mNumFaces)
m.Faces = make([]Face, cmesh.mNumFaces)
for j := 0; j < len(m.Faces); j++ {
m.Faces[j] = Face{
Indices: parseUInts(cFaces[j].mIndices, uint(cFaces[j].mNumIndices)),
}
}
//Other
m.Bones = parseBones(cmesh.mBones, uint(cmesh.mNumBones))
m.AnimMeshes = parseAnimMeshes(cmesh.mAnimMeshes, uint(cmesh.mNumAnimMeshes))
m.AABB = AABB{
Min: parseVec3(&cmesh.mAABB.mMin),
Max: parseVec3(&cmesh.mAABB.mMax),
}
m.MorphMethod = MorphMethod(cmesh.mMethod)
m.MaterialIndex = uint(cmesh.mMaterialIndex)
m.Name = parseAiString(cmesh.mName)
meshes[i] = m
}
return meshes
}
func parseVec3(cv *C.struct_aiVector3D) gglm.Vec3 {
if cv == nil {
return gglm.Vec3{}
}
return gglm.Vec3{
Data: [3]float32{
float32(cv.x),
float32(cv.y),
float32(cv.z),
},
}
}
func parseAnimMeshes(cam **C.struct_aiAnimMesh, count uint) []*AnimMesh {
if cam == nil {
return []*AnimMesh{}
}
animMeshes := make([]*AnimMesh, count)
cAnimMeshes := unsafe.Slice(cam, count)
for i := 0; i < int(count); i++ {
m := cAnimMeshes[i]
animMeshes[i] = &AnimMesh{
Name: parseAiString(m.mName),
Vertices: parseVec3s(m.mVertices, uint(m.mNumVertices)),
Normals: parseVec3s(m.mNormals, uint(m.mNumVertices)),
Tangents: parseVec3s(m.mTangents, uint(m.mNumVertices)),
BitTangents: parseVec3s(m.mBitangents, uint(m.mNumVertices)),
Colors: parseColorSet(m.mColors, uint(m.mNumVertices)),
TexCoords: parseTexCoords(m.mTextureCoords, uint(m.mNumVertices)),
Weight: float32(m.mWeight),
}
}
return animMeshes
}
func parseTexCoords(ctc [MaxTexCoords]*C.struct_aiVector3D, vertCount uint) [MaxTexCoords][]gglm.Vec3 {
texCoords := [MaxTexCoords][]gglm.Vec3{}
for j := 0; j < len(ctc); j++ {
//If a color set isn't available then it is nil
if ctc[j] == nil {
continue
}
texCoords[j] = parseVec3s(ctc[j], vertCount)
}
return texCoords
}
func parseColorSet(cc [MaxColorSets]*C.struct_aiColor4D, vertCount uint) [MaxColorSets][]gglm.Vec4 {
colorSet := [MaxColorSets][]gglm.Vec4{}
for j := 0; j < len(cc); j++ {
//If a color set isn't available then it is nil
if cc[j] == nil {
continue
}
colorSet[j] = parseColors(cc[j], vertCount)
}
return colorSet
}
func parseBones(cbs **C.struct_aiBone, count uint) []*Bone {
if cbs == nil {
return []*Bone{}
}
bones := make([]*Bone, count)
cbones := unsafe.Slice(cbs, count)
for i := 0; i < int(count); i++ {
cBone := cbones[i]
bones[i] = &Bone{
Name: parseAiString(cBone.mName),
Weights: parseVertexWeights(cBone.mWeights, uint(cBone.mNumWeights)),
OffsetMatrix: *parseMat4(&cBone.mOffsetMatrix),
}
}
return bones
}
func parseMat4(cm4 *C.struct_aiMatrix4x4) *gglm.Mat4 {
if cm4 == nil {
return &gglm.Mat4{}
}
return &gglm.Mat4{
Data: [4][4]float32{
{float32(cm4.a1), float32(cm4.b1), float32(cm4.c1), float32(cm4.d1)},
{float32(cm4.a2), float32(cm4.b2), float32(cm4.c2), float32(cm4.d2)},
{float32(cm4.a3), float32(cm4.b3), float32(cm4.c3), float32(cm4.d3)},
{float32(cm4.a4), float32(cm4.b4), float32(cm4.c4), float32(cm4.d4)},
},
}
}
func parseVertexWeights(cWeights *C.struct_aiVertexWeight, count uint) []VertexWeight {
if cWeights == nil {
return []VertexWeight{}
}
vw := make([]VertexWeight, count)
cvw := unsafe.Slice(cWeights, count)
for i := 0; i < int(count); i++ {
vw[i] = VertexWeight{
VertIndex: uint(cvw[i].mVertexId),
Weight: float32(cvw[i].mWeight),
}
}
return vw
}
func parseAiString(aiString C.struct_aiString) string {
return C.GoStringN(&aiString.data[0], C.int(aiString.length))
}
func parseUInts(cui *C.uint, count uint) []uint {
if cui == nil {
return []uint{}
}
uints := make([]uint, count)
cUInts := unsafe.Slice(cui, count)
for i := 0; i < len(cUInts); i++ {
uints[i] = uint(cUInts[i])
}
return uints
}
func parseVec3s(cv *C.struct_aiVector3D, count uint) []gglm.Vec3 {
if cv == nil {
return []gglm.Vec3{}
}
carr := unsafe.Slice(cv, count)
verts := make([]gglm.Vec3, count)
for i := 0; i < int(count); i++ {
verts[i] = gglm.Vec3{
Data: [3]float32{
float32(carr[i].x),
float32(carr[i].y),
float32(carr[i].z),
},
}
}
return verts
}
func parseColors(cv *C.struct_aiColor4D, count uint) []gglm.Vec4 {
if cv == nil {
return []gglm.Vec4{}
}
carr := unsafe.Slice(cv, count)
verts := make([]gglm.Vec4, count)
for i := 0; i < int(count); i++ {
verts[i] = gglm.Vec4{
Data: [4]float32{
float32(carr[i].r),
float32(carr[i].g),
float32(carr[i].b),
float32(carr[i].a),
},
}
}
return verts
}
func parseMaterials(cMatsIn **C.struct_aiMaterial, count uint) []*Material {
mats := make([]*Material, count)
cMats := unsafe.Slice(cMatsIn, count)
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),
}
}
return mats
}
func parseMatProperties(cMatPropsIn **C.struct_aiMaterialProperty, count uint) []*MaterialProperty {
matProps := make([]*MaterialProperty, count)
cMatProps := unsafe.Slice(cMatPropsIn, count)
for i := 0; i < int(count); i++ {
cmp := cMatProps[i]
matProps[i] = &MaterialProperty{
name: parseAiString(cmp.mKey),
Semantic: TextureType(cmp.mSemantic),
Index: uint(cmp.mIndex),
TypeInfo: MatPropertyTypeInfo(cmp.mType),
Data: C.GoBytes(unsafe.Pointer(cmp.mData), C.int(cmp.mDataLength)),
}
}
return matProps
}

330
asig/enums.go Executable file
View File

@ -0,0 +1,330 @@
package asig
type aiReturn int32
const (
//Indicates that a function was successful
aiReturnSuccess = 0x0
//Indicates that a function failed
aiReturnFailure = -0x1
//Indicates that not enough memory was available to perform the requested operation
aiReturnOutofMemory = -0x3
)
type SceneFlag int32
const (
/**
* Specifies that the scene data structure that was imported is not complete.
* This flag bypasses some internal validations and allows the import
* of animation skeletons, material libraries or camera animation paths
* using Assimp. Most applications won't support such data.
*/
SceneFlagIncomplete SceneFlag = 1 << 0
/**
* This flag is set by the validation postprocess-step (PostProcessValidateDataStructure)
* if the validation is successful. In a validated scene you can be sure that
* any cross references in the data structure (e.g. vertex indices) are valid.
*/
SceneFlagValidated SceneFlag = 1 << 1
/**
* This flag is set by the validation postprocess-step (PostProcessValidateDataStructure)
* if the validation is successful but some issues have been found.
* This can for example mean that a texture that does not exist is referenced
* by a material or that the bone weights for a vertex don't sum to 1.0 ... .
* In most cases you should still be able to use the import. This flag could
* be useful for applications which don't capture Assimp's log output.
*/
SceneFlagValidationWarning SceneFlag = 1 << 2
/**
* This flag is currently only set by the PostProcessJoinIdenticalVertices step.
* It indicates that the vertices of the output meshes aren't in the internal
* verbose format anymore. In the verbose format all vertices are unique,
* no vertex is ever referenced by more than one face.
*/
SceneFlagNonVerboseFormat SceneFlag = 1 << 3
/**
* Denotes pure height-map terrain data. Pure terrains usually consist of quads,
* sometimes triangles, in a regular grid. The x,y coordinates of all vertex
* positions refer to the x,y coordinates on the terrain height map, the z-axis
* stores the elevation at a specific point.
*
* TER (Terragen) and HMP (3D Game Studio) are height map formats.
* @note Assimp is probably not the best choice for loading *huge* terrains -
* fully triangulated data takes extremely much free store and should be avoided
* as long as possible (typically you'll do the triangulation when you actually
* need to render it).
*/
SceneFlagTerrain SceneFlag = 1 << 4
/**
* Specifies that the scene data can be shared between structures. For example:
* one vertex in few faces. SceneFlagNonVerboseFormat can not be
* used for this because SceneFlagNonVerboseFormat has internal
* meaning about postprocessing steps.
*/
SceneFlagAllowShared SceneFlag = 1 << 5
)
//aiGetErrorString specifies the types of primitives that can be present in a mesh
type PrimitiveType int32
const (
PrimitiveTypePoint = 1 << 0
PrimitiveTypeLine = 1 << 1
PrimitiveTypeTriangle = 1 << 2
PrimitiveTypePolygon = 1 << 3
)
//MorphMethod specifies the Supported methods of mesh morphing
type MorphMethod int32
const (
//Interpolation between morph targets
MorphMethodVertexBlend = 0x1
//Normalized morphing between morph targets
MorphMethodMorphNormalized = 0x2
//Relative morphing between morph targets
MorphMethodMorphRelative = 0x3
)
//PostProcess defines the flags for all possible post processing steps.
type PostProcess int64
const (
PostProcessCalcTangentSpace PostProcess = 0x1
PostProcessJoinIdenticalVertices PostProcess = 0x2
PostProcessMakeLeftHanded PostProcess = 0x4
PostProcessTriangulate PostProcess = 0x8
PostProcessRemoveComponent PostProcess = 0x10
PostProcessGenNormals PostProcess = 0x20
PostProcessGenSmoothNormals PostProcess = 0x40
PostProcessSplitLargeMeshes PostProcess = 0x80
PostProcessPreTransformVertices PostProcess = 0x100
PostProcessLimitBoneWeights PostProcess = 0x200
PostProcessValidateDataStructure PostProcess = 0x400
PostProcessImproveCacheLocality PostProcess = 0x800
PostProcessRemoveRedundantMaterials PostProcess = 0x1000
PostProcessFixInfacingNormals PostProcess = 0x2000
PostProcessSortByPType PostProcess = 0x8000
PostProcessFindDegenerates PostProcess = 0x10000
PostProcessFindInvalidData PostProcess = 0x20000
PostProcessGenUVCoords PostProcess = 0x40000
PostProcessTransformUVCoords PostProcess = 0x80000
PostProcessFindInstances PostProcess = 0x100000
PostProcessOptimizeMeshes PostProcess = 0x200000
PostProcessOptimizeGraph PostProcess = 0x400000
PostProcessFlipUVs PostProcess = 0x800000
PostProcessFlipWindingOrder PostProcess = 0x1000000
PostProcessSplitByBoneCount PostProcess = 0x2000000
PostProcessDebone PostProcess = 0x4000000
PostProcessGlobalScale PostProcess = 0x8000000
PostProcessEmbedTextures PostProcess = 0x10000000
PostProcessForceGenNormals PostProcess = 0x20000000
PostProcessDropNormals PostProcess = 0x40000000
PostProcessGenBoundingBoxes PostProcess = 0x80000000
)
type TextureType int32
const (
/** Dummy value.
*
* No texture, but the value to be used as 'texture semantic'
* (MaterialProperty.Semantic) for all material properties
* *not* related to textures.
*/
TextureTypeNone TextureType = 0
/** The texture is combined with the result of the diffuse
* lighting equation.
*/
TextureTypeDiffuse TextureType = 1
/** The texture is combined with the result of the specular
* lighting equation.
*/
TextureTypeSpecular TextureType = 2
/** The texture is combined with the result of the ambient
* lighting equation.
*/
TextureTypeAmbient TextureType = 3
/** The texture is added to the result of the lighting
* calculation. It isn't influenced by incoming light.
*/
TextureTypeEmissive TextureType = 4
/** The texture is a height map.
*
* By convention, higher gray-scale values stand for
* higher elevations from the base height.
*/
TextureTypeHeight TextureType = 5
/** The texture is a (tangent space) normal-map.
*
* Agn, there are several conventions for tangent-space
* normal maps. Assimp does (intentionally) not
* distinguish here.
*/
TextureTypeNormal TextureType = 6
/** The texture defines the glossiness of the material.
*
* The glossiness is in fact the exponent of the specular
* (phong) lighting equation. Usually there is a conversion
* function defined to map the linear color values in the
* texture to a suitable exponent. Have fun.
*/
TextureTypeShininess TextureType = 7
/** The texture defines per-pixel opacity.
*
* Usually 'white' means opaque and 'black' means
* 'transparency'. Or quite the opposite. Have fun.
*/
TextureTypeOpacity TextureType = 8
/** Displacement texture
*
* The exact purpose and format is application-dependent.
* Higher color values stand for higher vertex displacements.
*/
TextureTypeDisplacement TextureType = 9
/** Lightmap texture (aka Ambient Occlusion)
*
* Both 'Lightmaps' and dedicated 'ambient occlusion maps' are
* covered by this material property. The texture contains a
* scaling value for the final color value of a pixel. Its
* intensity is not affected by incoming light.
*/
TextureTypeLightmap TextureType = 10
/** Reflection texture
*
* Contains the color of a perfect mirror reflection.
* Rarely used, almost never for real-time applications.
*/
TextureTypeReflection TextureType = 11
/** Unknown texture
* A texture reference that does not match any of the definitions
* above is considered to be 'unknown'. It is still imported,
* but is excluded from any further post-processing.
*/
TextureTypeUnknown TextureType = 18
)
/** PBR Materials
* PBR definitions from maya and other modelling packages now use this standard.
* This was originally introduced around 2012.
* Support for this is in game engines like Godot, Unreal or Unity3D.
* Modelling packages which use this are very common now.
*/
const (
TextureTypeBaseColor TextureType = 12
TextureTypeNormalCamera TextureType = 13
TextureTypeEmissionColor TextureType = 14
TextureTypeMetalness TextureType = 15
TextureTypeDiffuseRoughness TextureType = 16
TextureTypeAmbientOcclusion TextureType = 17
)
func (tp TextureType) String() string {
switch tp {
case TextureTypeNone:
return "None"
case TextureTypeDiffuse:
return "Diffuse"
case TextureTypeSpecular:
return "Specular"
case TextureTypeAmbient:
return "Ambient"
case TextureTypeAmbientOcclusion:
return "AmbientOcclusion"
case TextureTypeBaseColor:
return "BaseColor"
case TextureTypeDiffuseRoughness:
return "DiffuseRoughness"
case TextureTypeDisplacement:
return "Displacement"
case TextureTypeEmissionColor:
return "EmissionColor"
case TextureTypeEmissive:
return "Emissive"
case TextureTypeHeight:
return "Height"
case TextureTypeLightmap:
return "Lightmap"
case TextureTypeMetalness:
return "Metalness"
case TextureTypeNormal:
return "Normal"
case TextureTypeNormalCamera:
return "NormalCamera"
case TextureTypeOpacity:
return "Opacity"
case TextureTypeReflection:
return "Reflection"
case TextureTypeShininess:
return "Shininess"
case TextureTypeUnknown:
return "Unknown"
default:
return "Invalid"
}
}
type MatPropertyTypeInfo int32
const (
MatPropTypeInfoFloat32 MatPropertyTypeInfo = iota + 1
MatPropTypeInfoFloat64
MatPropTypeInfoString
MatPropTypeInfoInt32
//Simple binary buffer, content undefined. Not convertible to anything.
MatPropTypeInfoBuffer
)
func (mpti MatPropertyTypeInfo) String() string {
switch mpti {
case MatPropTypeInfoFloat32:
return "Float32"
case MatPropTypeInfoFloat64:
return "Float64"
case MatPropTypeInfoString:
return "String"
case MatPropTypeInfoInt32:
return "Int32"
case MatPropTypeInfoBuffer:
return "Buffer"
default:
return "Unknown"
}
}
type MetadataType int32
const (
MetadataTypeBool MetadataType = 0
MetadataTypeInt32 MetadataType = 1
MetadataTypeUint64 MetadataType = 2
MetadataTypeFloat32 MetadataType = 3
MetadataTypeFloat64 MetadataType = 4
MetadataTypeString MetadataType = 5
MetadataTypeVec3 MetadataType = 6
MetadataTypeMAX MetadataType = 7
)

Binary file not shown.

Binary file not shown.

BIN
asig/libs/libzlib_windows_amd64.a Executable file

Binary file not shown.

97
asig/material.go Executable file
View File

@ -0,0 +1,97 @@
package asig
/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: -L ./libs -l assimp_windows_amd64 -l IrrXML_windows_amd64 -l zlib_windows_amd64
#include <stdlib.h> //Needed for C.free
#include <assimp/scene.h>
//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"
import (
"errors"
"fmt"
)
type Material struct {
cMat *C.struct_aiMaterial
/** List of all material properties loaded. */
Properties []*MaterialProperty
/** Storage allocated */
AllocatedStorage uint
}
type MaterialProperty struct {
//Specifies the name of the property (aka key). Keys are generally case insensitive.
name string
/** Textures: Specifies their exact usage semantic.
* For non-texture properties, this member is always 0 (aka TextureTypeNone).
*/
Semantic TextureType
/** Textures: Specifies the index of the texture.
* For non-texture properties, this member is always 0.
*/
Index uint
/** Type information for the property.
*
* Defines the data layout inside the data buffer. This is used
* by the library internally to perform debug checks and to
* utilize proper type conversions.
* (It's probably a hacky solution, but it works.)
*/
TypeInfo MatPropertyTypeInfo
//Binary buffer to hold the property's value.
Data []byte
}
func GetMaterialTextureCount(m *Material, texType TextureType) int {
return int(C.aiGetMaterialTextureCount(m.cMat, uint32(texType)))
}
type GetMatTexInfo struct {
Path string
}
func GetMaterialTexture(m *Material, texType TextureType, texIndex uint) (*GetMatTexInfo, error) {
outCPath := &C.struct_aiString{}
status := aiReturn(C.aiGetMaterialTexture(m.cMat, uint32(texType), C.uint(texIndex), outCPath, nil, nil, nil, nil, nil, nil))
if status == aiReturnSuccess {
return &GetMatTexInfo{
Path: parseAiString(*outCPath),
}, nil
}
if status == aiReturnFailure {
return nil, errors.New("get texture failed: " + getAiErr().Error())
}
if status == aiReturnOutofMemory {
return nil, errors.New("get texture failed: out of memory")
}
return nil, errors.New("get texture failed: unknown error with code " + fmt.Sprintf("%v", status))
}

87
asig/mesh.go Executable file
View File

@ -0,0 +1,87 @@
package asig
import "github.com/bloeys/gglm/gglm"
const (
MaxColorSets = 8
MaxTexCoords = 8
)
type Mesh struct {
//Bitwise combination of PrimitiveType enum
PrimitiveTypes PrimitiveType
Vertices []gglm.Vec3
Normals []gglm.Vec3
Tangents []gglm.Vec3
BitTangents []gglm.Vec3
//ColorSets vertex color sets where each set is either empty or has length=len(Vertices), with max number of sets=MaxColorSets
ColorSets [MaxColorSets][]gglm.Vec4
//TexCoords (aka UV channels) where each TexCoords[i] has NumUVComponents[i] channels, and is either empty or has length=len(Vertices), with max number of TexCoords per vertex = MaxTexCoords
TexCoords [MaxTexCoords][]gglm.Vec3
TexCoordChannelCount [MaxTexCoords]uint
Faces []Face
Bones []*Bone
AnimMeshes []*AnimMesh
AABB AABB
MorphMethod MorphMethod
MaterialIndex uint
Name string
}
type Face struct {
Indices []uint
}
type AnimMesh struct {
Name string
/** Replacement for Mes.Vertices. If this array is non-NULL,
* it *must* contain mNumVertices entries. The corresponding
* array in the host mesh must be non-NULL as well - animation
* meshes may neither add or nor remove vertex components (if
* a replacement array is NULL and the corresponding source
* array is not, the source data is taken instead)*/
Vertices []gglm.Vec3
Normals []gglm.Vec3
Tangents []gglm.Vec3
BitTangents []gglm.Vec3
Colors [MaxColorSets][]gglm.Vec4
TexCoords [MaxTexCoords][]gglm.Vec3
Weight float32
}
type AABB struct {
Min gglm.Vec3
Max gglm.Vec3
}
type Bone struct {
Name string
//The influence weights of this bone
Weights []VertexWeight
/** Matrix that transforms from bone space to mesh space in bind pose.
*
* This matrix describes the position of the mesh
* in the local space of this bone when the skeleton was bound.
* Thus it can be used directly to determine a desired vertex position,
* given the world-space transform of the bone when animated,
* and the position of the vertex in mesh space.
*
* It is sometimes called an inverse-bind matrix,
* or inverse bind pose matrix.
*/
OffsetMatrix gglm.Mat4
}
type VertexWeight struct {
VertIndex uint
//The strength of the influence in the range (0...1). The total influence from all bones at one vertex is 1
Weight float32
}

Some files were not shown because too many files have changed in this diff Show More