mirror of
https://github.com/bloeys/assimp-go.git
synced 2025-12-29 08:28:20 +00:00
Handle (embedded)textures
This commit is contained in:
93
asig/asig.go
93
asig/asig.go
@ -32,7 +32,9 @@ type Texel struct {
|
||||
R, G, B, A byte
|
||||
}
|
||||
|
||||
type Texture 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
|
||||
@ -70,16 +72,12 @@ type Texture struct {
|
||||
FormatHint string
|
||||
|
||||
/** Data of the texture.
|
||||
*
|
||||
* Points to an array of mWidth * mHeight aiTexel's.
|
||||
* The format of the texture data is always ARGB8888 to
|
||||
* make the implementation for user of the library as easy
|
||||
* as possible. If mHeight = 0 this is a pointer to a memory
|
||||
* buffer of size mWidth containing the compressed texture
|
||||
* data. Good luck, have fun!
|
||||
* Points to an array of mWidth * mHeight aiTexel's (or just len=Width if Height=0, which happens when data is compressed).
|
||||
* The format of the texture data is always RGBA8888.
|
||||
*/
|
||||
Texels []Texel
|
||||
Data []byte
|
||||
|
||||
IsCompressed bool
|
||||
Filename string
|
||||
}
|
||||
|
||||
@ -99,10 +97,25 @@ type Scene struct {
|
||||
RootNode *Node
|
||||
Meshes []*Mesh
|
||||
Materials []*Material
|
||||
Animations []*Animation
|
||||
Textures []*Texture
|
||||
Lights []*Light
|
||||
Cameras []*Camera
|
||||
|
||||
/** 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() {
|
||||
@ -141,10 +154,64 @@ func parseScene(cs *C.struct_aiScene) *Scene {
|
||||
s.Flags = SceneFlag(cs.mFlags)
|
||||
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 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 {
|
||||
|
||||
@ -1,5 +1,18 @@
|
||||
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 (
|
||||
|
||||
@ -24,6 +24,10 @@ enum aiReturn aiGetMaterialTexture(
|
||||
unsigned int* flags);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Material struct {
|
||||
cMat *C.struct_aiMaterial
|
||||
@ -59,12 +63,35 @@ type MaterialProperty struct {
|
||||
*/
|
||||
TypeInfo MatPropertyTypeInfo
|
||||
|
||||
/** Binary buffer to hold the property's value.
|
||||
* The size of the buffer is always mDataLength.
|
||||
*/
|
||||
//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))
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@ -2,4 +2,4 @@ module github.com/bloeys/assimp-go
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/bloeys/gglm v0.2.6 // indirect
|
||||
require github.com/bloeys/gglm v0.2.6
|
||||
|
||||
41
main.go
41
main.go
@ -1,14 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image/png"
|
||||
|
||||
"github.com/bloeys/assimp-go/asig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
scene, release, err := asig.ImportFile("tex-cube.fbx", asig.PostProcessTriangulate)
|
||||
scene, release, err := asig.ImportFile("tex-cube.glb", asig.PostProcessTriangulate)
|
||||
defer release()
|
||||
|
||||
if err != nil {
|
||||
@ -17,7 +19,7 @@ func main() {
|
||||
|
||||
for i := 0; i < len(scene.Meshes); i++ {
|
||||
|
||||
println("Mesh:", i, "; Verts:", len(scene.Meshes[i].Vertices), "; Normals:", len(scene.Meshes[i].Normals))
|
||||
println("Mesh:", i, "; Verts:", len(scene.Meshes[i].Vertices), "; Normals:", len(scene.Meshes[i].Normals), "; MatIndex:", scene.Meshes[i].MaterialIndex)
|
||||
for j := 0; j < len(scene.Meshes[i].Vertices); j++ {
|
||||
fmt.Printf("V(%v): (%v, %v, %v)\n", j, scene.Meshes[i].Vertices[j].X(), scene.Meshes[i].Vertices[j].Y(), scene.Meshes[i].Vertices[j].Z())
|
||||
}
|
||||
@ -25,13 +27,40 @@ func main() {
|
||||
|
||||
for i := 0; i < len(scene.Materials); i++ {
|
||||
|
||||
m := scene.Materials[i]
|
||||
println("Mesh:", i, "; Props:", len(scene.Materials[i].Properties))
|
||||
for j := 0; j < len(scene.Materials[i].Properties); j++ {
|
||||
texCount := asig.GetMaterialTextureCount(m, asig.TextureTypeDiffuse)
|
||||
fmt.Println("Texture count:", texCount)
|
||||
|
||||
p := scene.Materials[i].Properties[j]
|
||||
fmt.Printf("Data Type: %v; Len Bytes: %v; Texture Type: %v\n", p.TypeInfo.String(), len(p.Data), p.Semantic.String())
|
||||
if texCount > 0 {
|
||||
|
||||
fmt.Println("Texture count:", asig.GetMaterialTextureCount(scene.Materials[i], asig.TextureTypeDiffuse))
|
||||
texInfo, err := asig.GetMaterialTexture(m, asig.TextureTypeDiffuse, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%v", texInfo)
|
||||
}
|
||||
}
|
||||
|
||||
ts := scene.Textures
|
||||
for i := 0; i < len(ts); i++ {
|
||||
t := ts[i]
|
||||
|
||||
fmt.Printf("T(%v): Name=%v, Hint=%v, Width=%v, Height=%v, NumTexels=%v", i, t.Filename, t.FormatHint, t.Width, t.Height, len(t.Data))
|
||||
|
||||
if t.FormatHint == "png" {
|
||||
decodePNG(t.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodePNG(texels []byte) {
|
||||
|
||||
img, err := png.Decode(bytes.NewReader(texels))
|
||||
if err != nil {
|
||||
panic("wow2: " + err.Error())
|
||||
}
|
||||
|
||||
println("C:", img.At(100, 100))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user