Skip to content

Commit 4bcc54a

Browse files
committed
Implement embedded texture (AiTexture)
1 parent eb1e917 commit 4bcc54a

File tree

1 file changed

+72
-5
lines changed

1 file changed

+72
-5
lines changed

Sources/Assimp/AiTexture.swift

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,91 @@
77

88
import CAssimp
99

10+
/// Helper structure to describe an embedded texture
11+
///
12+
/// Normally textures are contained in external files but some file formats embed them directly in the model file.
13+
/// There are two types of embedded textures:
14+
/// 1. Uncompressed textures.
15+
/// The color data is given in an uncompressed format.
16+
/// 2. Compressed textures stored in a file format like png or jpg.
17+
/// 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.
18+
///
19+
/// 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).
1020
public struct AiTexture {
1121
let texture: aiTexture
1222

1323
public init(_ aiTexture: aiTexture) {
1424
texture = aiTexture
1525
}
1626

17-
var width: Int {
27+
/// Texture original filename.
28+
///
29+
/// Used to get the texture reference.
30+
public var filename: String? {
31+
String(aiString: texture.mFilename)
32+
}
33+
34+
/// A hint from the loader to make it easier for applications
35+
/// to determine the type of embedded textures.
36+
///
37+
/// If mHeight != 0 this member is show how data is packed. Hint will consist of
38+
/// two parts: channel order and channel bitness (count of the bits for every
39+
/// color channel). For simple parsing by the viewer it's better to not omit
40+
/// absent color channel and just use 0 for bitness. For example:
41+
/// 1. Image contain RGBA and 8 bit per channel, achFormatHint == "rgba8888";
42+
/// 2. Image contain ARGB and 8 bit per channel, achFormatHint == "argb8888";
43+
/// 3. Image contain RGB and 5 bit for R and B channels and 6 bit for G channel, achFormatHint == "rgba5650";
44+
/// 4. One color image with B channel and 1 bit for it, achFormatHint == "rgba0010";
45+
/// If mHeight == 0 then achFormatHint is set set to '\\0\\0\\0\\0' if the loader has no additional
46+
/// information about the texture file format used OR the
47+
/// file extension of the format without a trailing dot. If there
48+
/// are multiple file extensions for a format, the shortest
49+
/// extension is chosen (JPEG maps to 'jpg', not to 'jpeg').
50+
/// E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case.
51+
/// The fourth character will always be '\\0'.
52+
public var achFormatHint: String {
53+
CArray<CChar>.read(texture.achFormatHint) { body in
54+
String(cString: body.baseAddress!)
55+
}
56+
}
57+
58+
/// Width of the texture, in pixels
59+
///
60+
/// If mHeight is zero the texture is compressed in a format like JPEG.
61+
/// In this case mWidth specifies the size of the memory area pcData is pointing to, in bytes.
62+
public var width: Int {
1863
Int(texture.mWidth)
1964
}
2065

21-
var height: Int {
66+
/// Height of the texture, in pixels
67+
///
68+
/// If this value is zero, pcData points to a compressed texture in any format (e.g. JPEG).
69+
public var height: Int {
2270
Int(texture.mHeight)
2371
}
2472

25-
var pcData: [aiTexel] {
26-
[aiTexel](UnsafeMutableBufferPointer<aiTexel>(start: texture.pcData,
27-
count: width * height))
73+
@inline(__always)
74+
public var isCompressed: Bool {
75+
height == 0
76+
}
77+
78+
/// Data of the texture.
79+
///
80+
/// Points to an array of mWidth * mHeight aiTexel's.
81+
/// The format of the texture data is always ARGB8888 to make the implementation for user of the library as easy as possible.
82+
/// If mHeight = 0 this is a pointer to a memory buffer of size mWidth containing the compressed texture data.
83+
public var pcData: [aiTexel] {
84+
let count: Int = height == 0 ? width : (width * height)
85+
return [aiTexel](UnsafeMutableBufferPointer<aiTexel>(start: texture.pcData,
86+
count: count))
87+
}
88+
89+
public var rawPcData: UnsafeBufferPointer<UInt8> {
90+
let count: Int = height == 0 ? width : (width * height)
91+
let length = MemoryLayout<aiTexel>.stride * count
92+
return texture.pcData.withMemoryRebound(to: UInt8.self, capacity: length) { ptr in
93+
UnsafeBufferPointer<UInt8>(start: ptr, count: length)
94+
}
2895
}
2996
}
3097

0 commit comments

Comments
 (0)