Skip to content

Commit b2fdc4a

Browse files
authored
Merge pull request #5 from ctreffs/feature/embedded-textures
Embedded textures
2 parents 8f9e72b + 15547cb commit b2fdc4a

File tree

9 files changed

+108
-15
lines changed

9 files changed

+108
-15
lines changed

Sources/Assimp/AiMatKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ extension AiMatKey {
7474
case GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR = "$mat.gltf.pbrMetallicRoughness.metallicFactor"
7575
case GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR = "$mat.gltf.pbrMetallicRoughness.roughnessFactor"
7676
case GLTF_ALPHAMODE = "$mat.gltf.alphaMode"
77-
case GLTF_ALPHACUTOFF = "$mat.gltf.alphaCutoff"
77+
case GLTF_ALPHACUTOFF = "$mat.gltf.alphaCutoff"
7878
case GLTF_PBRSPECULARGLOSSINESS = "$mat.gltf.pbrSpecularGlossiness"
7979
case GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR = "$mat.gltf.pbrMetallicRoughness.glossinessFactor"
8080
case GLTF_UNLIT = "$mat.gltf.unlit"

Sources/Assimp/AiMaterial.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ public struct AiMaterial {
8282
- aiGetMaterialUVTransform
8383
- aiGetMaterialXXX
8484
*/
85-
8685
public func getMaterialProperty(_ key: AiMatKey) -> AiMaterialProperty? {
8786
withUnsafePointer(to: self.material) { matPtr -> AiMaterialProperty? in
8887
let matPropPtr = UnsafeMutablePointer<UnsafePointer<aiMaterialProperty>?>.allocate(capacity: MemoryLayout<aiMaterialProperty>.stride)

Sources/Assimp/AiMesh.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ extension AiMesh: Equatable {
269269
lhs.textureCoords == rhs.textureCoords &&
270270
lhs.vertices == rhs.vertices
271271

272-
//FIXME: lhs.colors == rhs.colors &&
272+
// FIXME: lhs.colors == rhs.colors &&
273273

274274
}
275275
}

Sources/Assimp/AiNode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct AiNode {
2525
///
2626
/// Implementations should be able to handle tokens such as whitespace, tabs, line feeds, quotation marks, ampersands etc.
2727
///
28-
///Sometimes assimp introduces new nodes not present in the source file into the hierarchy (usually out of necessity because sometimes the source hierarchy format is simply not compatible).
28+
/// Sometimes assimp introduces new nodes not present in the source file into the hierarchy (usually out of necessity because sometimes the source hierarchy format is simply not compatible).
2929
///
3030
/// Their names are surrounded by
3131
/// `<>`

Sources/Assimp/AiPostProcessStep.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public struct AiPostProcessStep: OptionSet {
3131
/// Full, weight-based skinning is expensive while animating nodes is extremely cheap,
3232
/// so this step is offered to clean up the data in that regard.
3333
///
34-
///Use #AI_CONFIG_PP_DB_THRESHOLD to control this.
35-
///Use #AI_CONFIG_PP_DB_ALL_OR_NONE if you want bones removed if and only if all bones within the scene qualify for removal.
34+
/// Use #AI_CONFIG_PP_DB_THRESHOLD to control this.
35+
/// Use #AI_CONFIG_PP_DB_ALL_OR_NONE if you want bones removed if and only if all bones within the scene qualify for removal.
3636
public static let debone = AiPostProcessStep(rawValue: aiProcess_Debone.rawValue)
3737

3838
/// This step searches all meshes for degenerate primitives and converts them to proper lines or points.

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

Sources/Assimp/CArray.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// CArray.swift
3+
//
4+
//
5+
// Created by Christian Treffs on 09.01.21.
6+
//
7+
8+
enum CArray<T> {
9+
@discardableResult
10+
@_transparent
11+
static func write<C, O>(_ cArray: inout C, _ body: (UnsafeMutableBufferPointer<T>) throws -> O) rethrows -> O {
12+
try withUnsafeMutablePointer(to: &cArray) {
13+
try body(UnsafeMutableBufferPointer<T>(start: UnsafeMutableRawPointer($0).assumingMemoryBound(to: T.self),
14+
count: (MemoryLayout<C>.stride / MemoryLayout<T>.stride)))
15+
}
16+
}
17+
18+
@discardableResult
19+
@_transparent
20+
static func read<C, O>(_ cArray: C, _ body: (UnsafeBufferPointer<T>) throws -> O) rethrows -> O {
21+
try withUnsafePointer(to: cArray) {
22+
try body(UnsafeBufferPointer<T>(start: UnsafeRawPointer($0).assumingMemoryBound(to: T.self),
23+
count: (MemoryLayout<C>.stride / MemoryLayout<T>.stride)))
24+
}
25+
}
26+
}

Sources/Assimp/String+aiString.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extension String {
1515
}
1616
guard let boundMemory: UnsafePointer<CChar> = bytesPtr.baseAddress?.bindMemory(to: CChar.self,
1717
capacity: Int(aiString.length)) else {
18-
return nil
18+
return nil
1919
}
2020

2121
let stringBuffer = UnsafeBufferPointer<CChar>(start: boundMemory,
@@ -36,7 +36,7 @@ extension String {
3636
count: length)
3737

3838
let codeUnits: [UTF8.CodeUnit] = bufferPtr
39-
//.map { $0 > 0 ? $0 : Int8(0x20) } // this replaces all invalid characters with blank space
39+
// .map { $0 > 0 ? $0 : Int8(0x20) } // this replaces all invalid characters with blank space
4040
.map { UTF8.CodeUnit($0) }
4141

4242
self.init(decoding: codeUnits, as: UTF8.self)

Tests/AssimpTests/XCTestManifests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ extension AssimpTests {
77
// to regenerate.
88
static let __allTests__AssimpTests = [
99
("testFailingInitializer", testFailingInitializer),
10+
("testLoadAiScene3DS", testLoadAiScene3DS),
1011
("testLoadAiSceneDAE", testLoadAiSceneDAE),
1112
("testLoadAiSceneObj", testLoadAiSceneObj),
1213
("testVec2fFromAiVector2D", testVec2fFromAiVector2D),
1314
("testVec3fFromAiVector3D", testVec3fFromAiVector3D),
14-
("testVersion", testVersion)
15+
("testVersion", testVersion),
1516
]
1617
}
1718

1819
public func __allTests() -> [XCTestCaseEntry] {
1920
return [
20-
testCase(AssimpTests.__allTests__AssimpTests)
21+
testCase(AssimpTests.__allTests__AssimpTests),
2122
]
2223
}
2324
#endif

0 commit comments

Comments
 (0)