mirror of
https://github.com/bloeys/assimp-go.git
synced 2025-12-29 08:28:20 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d583049090 | |||
| 9acd5bee18 | |||
| 5b5d091d56 | |||
| c0a308b178 | |||
| 5573ffdbf6 | |||
| dee2332b9a | |||
| 4462a3be04 | |||
| 3b31e8d677 | |||
| 32c5def787 | |||
| e96f70d88f | |||
| 672802a705 | |||
| fb9d44beca | |||
| 8bf9dc9121 | |||
| 8c752a0bda | |||
| 77e62588fe | |||
| e7e81afc7c | |||
| 6b6255d4a3 | |||
| 72a0b83122 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -13,6 +13,6 @@
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
*.a
|
||||
*.obj
|
||||
*.fbx
|
||||
*.fbx
|
||||
*.glb
|
||||
104
README.md
104
README.md
@ -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
13130
aig/aig.go
File diff suppressed because it is too large
Load Diff
241
aig/aig.i
241
aig/aig.i
@ -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;
|
||||
17519
aig/aig_wrap.cxx
17519
aig/aig_wrap.cxx
File diff suppressed because it is too large
Load Diff
618
asig/asig.go
Executable file
618
asig/asig.go
Executable 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
330
asig/enums.go
Executable 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
|
||||
)
|
||||
BIN
asig/libs/libIrrXML_windows_amd64.a
Executable file
BIN
asig/libs/libIrrXML_windows_amd64.a
Executable file
Binary file not shown.
BIN
asig/libs/libassimp_windows_amd64.a
Executable file
BIN
asig/libs/libassimp_windows_amd64.a
Executable file
Binary file not shown.
BIN
asig/libs/libzlib_windows_amd64.a
Executable file
BIN
asig/libs/libzlib_windows_amd64.a
Executable file
Binary file not shown.
97
asig/material.go
Executable file
97
asig/material.go
Executable 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
87
asig/mesh.go
Executable 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
Reference in New Issue
Block a user