assimp-ffi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,407 @@
1
+ module Assimp
2
+
3
+ TextureOp = enum(:texture_op, [
4
+ :Multiply,
5
+ :Add,
6
+ :Subtract,
7
+ :Divide,
8
+ :SmoothAdd,
9
+ :SignedAdd
10
+ ])
11
+
12
+ TextureMapMode = enum(:texture_map_mode, [
13
+ :Wrap,
14
+ :Clamp,
15
+ :Mirror,
16
+ :Decal
17
+ ])
18
+
19
+ TextureMapping = enum(:texture_mapping, [
20
+ :UV,
21
+ :SPHERE,
22
+ :CYLINDER,
23
+ :BOX,
24
+ :PLANE,
25
+ :OTHER
26
+ ])
27
+
28
+ TextureType = enum(:texture_type, [
29
+ :NONE,
30
+ :DIFFUSE,
31
+ :SPECULAR,
32
+ :AMBIENT,
33
+ :EMISSIVE,
34
+ :HEIGHT,
35
+ :NORMALS,
36
+ :SHININESS,
37
+ :OPACITY,
38
+ :DISPLACEMENT,
39
+ :LIGHTMAP,
40
+ :REFLECTION,
41
+ :UNKNOWN
42
+ ])
43
+
44
+ ShadingMode = enum(:shading_mode, [
45
+ :Flat, 1,
46
+ :Gouraud,
47
+ :Phong,
48
+ :Blinn,
49
+ :Toon,
50
+ :OrenNayar,
51
+ :Minnaert,
52
+ :CookTorrance,
53
+ :NoShading,
54
+ :Fresnel
55
+ ])
56
+
57
+ TextureFlags = bitmask(:texture_flags, [
58
+ :Invert,
59
+ :UseAlpha,
60
+ :IgnoreAlpha
61
+ ])
62
+
63
+ BlendMode = enum(:blend_mode, [
64
+ :Default,
65
+ :Additive
66
+ ])
67
+
68
+ class UVTransform < FFI::Struct
69
+ extend StructAccessors
70
+ pack 1
71
+ layout :translation, Vector2D,
72
+ :scaling, Vector2D,
73
+ :rotation, :ai_real
74
+ struct_attr_accessor :translation,
75
+ :scaling,
76
+ :rotation
77
+ end
78
+
79
+ PropertyTypeInfo = enum(:property_type_info, [
80
+ :Float, 1,
81
+ :Double,
82
+ :String,
83
+ :Integer,
84
+ :Buffer
85
+ ])
86
+
87
+ MATKEY_NAME = "?mat.name"
88
+ MATKEY_TWOSIDED = "$mat.twosided"
89
+ MATKEY_SHADING_MODEL = "$mat.shadingm"
90
+ MATKEY_ENABLE_WIREFRAME = "$mat.wireframe"
91
+ MATKEY_BLEND_FUNC = "$mat.blend"
92
+ MATKEY_OPACITY = "$mat.opacity"
93
+ MATKEY_BUMPSCALING = "$mat.bumpscaling"
94
+ MATKEY_SHININESS = "$mat.shininess"
95
+ MATKEY_REFLECTIVITY = "$mat.reflectivity"
96
+ MATKEY_SHININESS_STRENGTH = "$mat.shinpercent"
97
+ MATKEY_REFRACTI = "$mat.refracti"
98
+ MATKEY_COLOR_DIFFUSE = "$clr.diffuse"
99
+ MATKEY_COLOR_AMBIENT = "$clr.ambient"
100
+ MATKEY_COLOR_SPECULAR = "$clr.specular"
101
+ MATKEY_COLOR_EMISSIVE = "$clr.emissive"
102
+ MATKEY_COLOR_TRANSPARENT = "$clr.transparent"
103
+ MATKEY_COLOR_REFLECTIVE = "$clr.reflective"
104
+ MATKEY_GLOBAL_BACKGROUND_IMAGE = "?bg.global"
105
+ MATKEY_TEXTURE = "$tex.file"
106
+ MATKEY_UVWSRC = "$tex.uvwsrc"
107
+ MATKEY_TEXOP = "$tex.op"
108
+ MATKEY_MAPPING = "$tex.mapping"
109
+ MATKEY_TEXBLEND = "$tex.blend"
110
+ MATKEY_MAPPINGMODE_U = "$tex.mapmodeu"
111
+ MATKEY_MAPPINGMODE_V = "$tex.mapmodev"
112
+ MATKEY_MAPPINGMODE_W = "$tex.mapmodew"
113
+ MATKEY_TEXMAP_AXIS = "$tex.mapaxis"
114
+ MATKEY_UVTRANSFORM = "$tex.uvtrafo"
115
+ MATKEY_TEXFLAGS = "$tex.flags"
116
+
117
+ class MaterialProperty < FFI::Struct
118
+ TEX_PROPERTIES = [ MATKEY_TEXTURE,
119
+ MATKEY_UVWSRC,
120
+ MATKEY_TEXOP,
121
+ MATKEY_MAPPING,
122
+ MATKEY_TEXBLEND,
123
+ MATKEY_MAPPINGMODE_U,
124
+ MATKEY_MAPPINGMODE_V,
125
+ MATKEY_MAPPINGMODE_W,
126
+ MATKEY_TEXMAP_AXIS,
127
+ MATKEY_UVTRANSFORM,
128
+ MATKEY_TEXFLAGS ]
129
+ COLOR_PROPERTIES = [ MATKEY_COLOR_DIFFUSE,
130
+ MATKEY_COLOR_AMBIENT,
131
+ MATKEY_COLOR_SPECULAR,
132
+ MATKEY_COLOR_EMISSIVE,
133
+ MATKEY_COLOR_TRANSPARENT,
134
+ MATKEY_COLOR_REFLECTIVE ]
135
+ STRING_PROPERTIES = [ MATKEY_NAME,
136
+ MATKEY_GLOBAL_BACKGROUND_IMAGE,
137
+ MATKEY_TEXTURE ]
138
+ BOOL_PROPERTIES = [ MATKEY_TWOSIDED, MATKEY_ENABLE_WIREFRAME ]
139
+ INTEGER_PROPERTIES = BOOL_PROPERTIES +
140
+ [ MATKEY_UVWSRC,
141
+ MATKEY_SHADING_MODEL,
142
+ MATKEY_MAPPINGMODE_U,
143
+ MATKEY_MAPPINGMODE_V,
144
+ MATKEY_MAPPINGMODE_W,
145
+ MATKEY_BLEND_FUNC,
146
+ MATKEY_TEXFLAGS,
147
+ MATKEY_MAPPING,
148
+ MATKEY_TEXOP ]
149
+ FLOAT_PROPERTIES = COLOR_PROPERTIES +
150
+ [ MATKEY_UVTRANSFORM,
151
+ MATKEY_TEXBLEND,
152
+ MATKEY_OPACITY,
153
+ MATKEY_SHININESS,
154
+ MATKEY_REFLECTIVITY,
155
+ MATKEY_REFRACTI,
156
+ MATKEY_SHININESS_STRENGTH,
157
+ MATKEY_BUMPSCALING,
158
+ MATKEY_TEXMAP_AXIS ]
159
+
160
+ extend StructAccessors
161
+ layout :key, String,
162
+ :semantic, TextureType,
163
+ :index, :uint,
164
+ :data_length, :uint,
165
+ :type, PropertyTypeInfo,
166
+ :data, :pointer #byte[data_length]
167
+ struct_attr_accessor :key,
168
+ :semantic,
169
+ :index,
170
+ :data_length,
171
+ :type
172
+
173
+ @__has_ref = true
174
+
175
+ def set_property(key, val, semantic: 0, index: 0, type: nil)
176
+ if type
177
+ self.type = type
178
+ else
179
+ case key
180
+ when *STRING_PROPERTIES
181
+ self.type = :String
182
+ when *INTEGER_PROPERTIES
183
+ self.type = :Integer
184
+ when *FLOAT_PROPERTIES
185
+ if ENV["ASSIMP_DOUBLE_PRECISION"]
186
+ self.type = :Double
187
+ else
188
+ self.type = :Float
189
+ end
190
+ else
191
+ raise ArgumentError::new("Could not determine property type!")
192
+ end
193
+ end
194
+ if semantic == 0 && TEX_PROPERTIES.include?(key)
195
+ raise ArgumentError::new("Missing semantic for texture property!")
196
+ elsif semantic != 0 && ! TEX_PROPERTIES.include?(key)
197
+ raise ArgumentError::new("Semantic given for non texture property!")
198
+ else
199
+ self.semantic = semantic
200
+ end
201
+ if index != 0 && ! TEX_PROPERTIES.include?(key)
202
+ raise ArgumentError::new("Index given for non texture property!")
203
+ else
204
+ self.index = index
205
+ end
206
+ self.key = key
207
+ self.data = val
208
+ self
209
+ end
210
+
211
+ def data=(val)
212
+ ptr = nil
213
+ case type
214
+ when :String
215
+ length = val.bytesize
216
+ ptr = FFI::MemoryPointer::new(length+4+1)
217
+ ptr.write_uint(length)
218
+ ptr.put_string(4, val)
219
+ when :Integer
220
+ if val.kind_of? Array
221
+ ptr = FFI::MemoryPointer::new(:int, val.length)
222
+ ptr.write_array_of_int(val)
223
+ else
224
+ i = nil
225
+ case key
226
+ when *BOOL_PROPERTIES
227
+ if val.nil? || val == false || val == 0
228
+ i = Assimp::FALSE
229
+ else
230
+ i = Assimp::TRUE
231
+ end
232
+ when MATKEY_SHADING_MODEL
233
+ i = ShadingMode.to_native(val, nil)
234
+ when MATKEY_MAPPINGMODE_U, MATKEY_MAPPINGMODE_V, MATKEY_MAPPINGMODE_W
235
+ i = TextureMapMode.to_native(val, nil)
236
+ when MATKEY_BLEND_FUNC
237
+ i = BlendMode.to_native(val, nil)
238
+ when MATKEY_TEXFLAGS
239
+ i = TextureFlags.to_native(val, nil)
240
+ when MATKEY_MAPPING
241
+ i = TextureMapping.to_native(val, nil)
242
+ when MATKEY_TEXOP
243
+ i = TextureOp.to_native(val, nil)
244
+ else
245
+ i = val
246
+ end
247
+ ptr = FFI::MemoryPointer::new(:int)
248
+ ptr.write_int(i)
249
+ end
250
+ when :Float
251
+ if val.kind_of? Array
252
+ ptr = FFI::MemoryPointer::new(:float, val.length)
253
+ ptr.write_array_of_float(val)
254
+ elsif val.kind_of? FFI::Struct
255
+ ptr = FFI::MemoryPointer::new(val.class.size)
256
+ ptr.write_array_of_uint8(val.pointer.read_array_of_uint8(val.class.size))
257
+ else
258
+ ptr = FFI::MemoryPointer::new(:float)
259
+ ptr.write_float(val)
260
+ end
261
+ when :Double
262
+ if val.kind_of? Array
263
+ ptr = FFI::MemoryPointer::new(:double, val.length)
264
+ ptr.write_array_of_double(val)
265
+ elsif val.kind_of? FFI::Struct
266
+ ptr = FFI::MemoryPointer::new(val.class.size)
267
+ ptr.write_array_of_uint8(val.pointer.read_array_of_uint8(val.class.size))
268
+ else
269
+ ptr.write_double(val)
270
+ end
271
+ when :Buffer
272
+ if val.kind_of? FFI::Pointer
273
+ ptr = FFI::MemoryPointer::new(val.size)
274
+ ptr.write_array_of_uint8(val.pointer.read_array_of_uint8(val.size))
275
+ else
276
+ ptr = FFI::MemoryPointer.from_string(val)
277
+ end
278
+ else
279
+ raise ArgumentError::new("Invalid type: #{type.inspect}!")
280
+ end
281
+ @data = ptr
282
+ self[:data] = ptr
283
+ self.data_length = (ptr ? ptr.size : 0)
284
+ val
285
+ end
286
+
287
+ def data
288
+ case type
289
+ when :String
290
+ length = self[:data].read_uint
291
+ self[:data].get_string(4, length)
292
+ when :Integer
293
+ if data_length == 4
294
+ i = self[:data].read_int
295
+ case key
296
+ when *BOOL_PROPERTIES
297
+ i != 0
298
+ when MATKEY_SHADING_MODEL
299
+ ShadingMode[i]
300
+ when MATKEY_MAPPINGMODE_U, MATKEY_MAPPINGMODE_V, MATKEY_MAPPINGMODE_W
301
+ TextureMapMode[i]
302
+ when MATKEY_BLEND_FUNC
303
+ BlendMode[i]
304
+ when MATKEY_TEXFLAGS
305
+ TextureFlags[i]
306
+ when MATKEY_MAPPING
307
+ TextureMapping[i]
308
+ when MATKEY_TEXOP
309
+ TextureOp[i]
310
+ else
311
+ i
312
+ end
313
+ elsif data_length > 4
314
+ self[:data].read_array_of_int(data_length/4)
315
+ else
316
+ nil
317
+ end
318
+ when :Float
319
+ if data_length == 4
320
+ self[:data].read_float
321
+ elsif data_length > 4
322
+ if key.match("\\$clr\\.") && data_length == Color4D.size
323
+ Color4D.new(self[:data])
324
+ elsif key == MATKEY_TEXMAP_AXIS && data_length == Vector3D.size
325
+ Vector3D.new(self[:data])
326
+ elsif key == MATKEY_UVTRANSFORM && data_length == UVTransform.size
327
+ UVTransform.new(self[:data])
328
+ else
329
+ self[:data].read_array_of_float(data_length/4)
330
+ end
331
+ else
332
+ nil
333
+ end
334
+ when :Double
335
+ if data_length == 8
336
+ self[:data].read_double
337
+ elsif data_length > 8
338
+ if key.match("\\$clr\\.") && data_length == Color4D.size
339
+ Color4D.new(self[:data])
340
+ elsif key == MATKEY_TEXMAP_AXIS && data_length == Vector3D.size
341
+ Vector3D.new(self[:data])
342
+ elsif key == MATKEY_UVTRANSFORM && data_length == UVTransform.size
343
+ UVTransform.new(self[:data])
344
+ else
345
+ self[:data].read_array_of_double(data_length/8)
346
+ end
347
+ else
348
+ nil
349
+ end
350
+ when :Buffer
351
+ self[:data].slice(0, data_length)
352
+ else
353
+ raise "Invalid type: #{type.inspect}!"
354
+ end
355
+ end
356
+
357
+ def to_s
358
+ "#{key}: #{data}"
359
+ end
360
+ end
361
+
362
+ class Material < FFI::Struct
363
+ extend StructAccessors
364
+ layout :properties, :pointer, #MaterialProperty*[num_properties]
365
+ :num_properties, :uint,
366
+ :num_allocated, :uint
367
+ struct_attr_accessor :num_properties,
368
+ :num_allocated
369
+ struct_ref_array_attr_accessor [:properties, MaterialProperty]
370
+
371
+ def property(key, type, index)
372
+ ptr = FFI::MemoryPointer::new(:pointer)
373
+ res = Assimp::aiGetMaterialProperty(self, key, type, index, ptr)
374
+ raise "get_material_property error!" unless res == :SUCCESS
375
+ new_ptr = ptr.read_pointer
376
+ return nil if new_ptr.null?
377
+ MaterialProperty::new(new_ptr)
378
+ end
379
+
380
+ end
381
+
382
+ attach_function :aiGetMaterialProperty,
383
+ [Material.ptr, :string, :uint, :uint, :pointer ], Return
384
+
385
+
386
+ attach_function :aiGetMaterialFloatArray,
387
+ [Material.ptr, :string, :uint, :uint, :pointer, :pointer], Return
388
+
389
+ attach_function :aiGetMaterialIntegerArray,
390
+ [Material.ptr, :string, :uint, :uint, :pointer, :pointer], Return
391
+
392
+ attach_function :aiGetMaterialColor,
393
+ [Material.ptr, :string, :uint, :uint, Color4D.ptr], Return
394
+
395
+ attach_function :aiGetMaterialUVTransform,
396
+ [Material.ptr, :string, :uint, :uint, UVTransform.ptr], Return
397
+
398
+ attach_function :aiGetMaterialString,
399
+ [Material.ptr, :string, :uint, :uint, String.ptr], Return
400
+
401
+ attach_function :aiGetMaterialTextureCount,
402
+ [Material.ptr, TextureType], :uint
403
+
404
+ attach_function :aiGetMaterialTexture,
405
+ [Material.ptr, TextureType, :uint, String.ptr, :pointer, :uint, :pointer, :pointer, :pointer, :pointer], Return
406
+
407
+ end
@@ -0,0 +1,100 @@
1
+ module Assimp
2
+
3
+ class Matrix3x3 < FFI::Struct
4
+ extend StructAccessors
5
+ layout :a1, :ai_real, :a2, :ai_real, :a3, :ai_real,
6
+ :b1, :ai_real, :b2, :ai_real, :b3, :ai_real,
7
+ :c1, :ai_real, :c2, :ai_real, :c3, :ai_real
8
+ struct_attr_accessor :a1, :a2, :a3,
9
+ :b1, :b2, :b3,
10
+ :c1, :c2, :c3
11
+
12
+ def self.identity
13
+ m = Matrix3x3::new
14
+ Assimp::aiIdentityMatrix3(m)
15
+ m
16
+ end
17
+
18
+ def self.rotation(a, axis)
19
+ # https://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle
20
+ c = Math::cos(a)
21
+ s = Math::sin(a)
22
+ t = 1 - c
23
+ x = axis.x
24
+ y = axis.y
25
+ z = axis.z
26
+
27
+ out = Matrix3x3
28
+ out.a1 = t*x*x + c
29
+ out.a2 = t*x*y - s*z
30
+ out.a3 = t*x*z + s*y
31
+ out.b1 = t*x*y + s*z
32
+ out.b2 = t*y*y + c
33
+ out.b3 = t*y*z - s*x
34
+ out.c1 = t*x*z - s*y
35
+ out.c2 = t*y*z + s*x
36
+ out.c3 = t*z*z + c
37
+ out
38
+ end
39
+
40
+ def to_s
41
+ <<EOF
42
+ < <#{a1}, #{a2}, #{a3}>,
43
+ <#{b1}, #{b2}, #{b3}>,
44
+ <#{c1}, #{c2}, #{c3}> >
45
+ EOF
46
+ end
47
+
48
+ def quaternion
49
+ q = Quaternion::new
50
+ Assimp::aiCreateQuaternionFromMatrix(q, self)
51
+ end
52
+
53
+ def transpose!
54
+ Assimp::aiTransposeMatrix3(self)
55
+ self
56
+ end
57
+
58
+ def transpose
59
+ t = self.dup
60
+ t.transpose!
61
+ end
62
+
63
+ def *(other)
64
+ if other.kind_of?(Matrix3x3)
65
+ m = self.dup
66
+ Assimp::aiMultiplyMatrix3(m, other)
67
+ m
68
+ elsif other.kind_of?(Vector3D)
69
+ v = other.dup
70
+ Assimp::aiTransformVecByMatrix3(v, self)
71
+ v
72
+ else
73
+ "Unsupported operand: #{other.inspect}!"
74
+ end
75
+ end
76
+
77
+ def determinant
78
+ a1*b2*c3 - a1*b3*c2 + a2*b3*c1 - a2*b1*c3 + a3*b1*c2 - a3*b2*c1
79
+ end
80
+
81
+ def inverse
82
+ det = determinant
83
+ raise "Not inversible!" if det == 0.0
84
+ m = Matrix3x3::new
85
+ invdet = 1.0/det
86
+ m.a1 = invdet * (b2 * c3 - b3 * c2)
87
+ m.a2 = -invdet * (a2 * c3 - a3 * c2)
88
+ m.a3 = invdet * (a2 * b3 - a3 * b2)
89
+ m.b1 = -invdet * (b1 * c3 - b3 * c1)
90
+ m.b2 = invdet * (a1 * c3 - a3 * c1)
91
+ m.b3 = -invdet * (a1 * b3 - a3 * b1)
92
+ m.c1 = invdet * (b1 * c2 - b2 * c1)
93
+ m.c2 = -invdet * (a1 * c2 - a2 * c1)
94
+ m.c3 = invdet * (a1 * b2 - a2 * b1)
95
+ m
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,178 @@
1
+ module Assimp
2
+
3
+ class Matrix4x4 < FFI::Struct
4
+ extend StructAccessors
5
+ layout :a1, :ai_real, :a2, :ai_real, :a3, :ai_real, :a4, :ai_real,
6
+ :b1, :ai_real, :b2, :ai_real, :b3, :ai_real, :b4, :ai_real,
7
+ :c1, :ai_real, :c2, :ai_real, :c3, :ai_real, :c4, :ai_real,
8
+ :d1, :ai_real, :d2, :ai_real, :d3, :ai_real, :d4, :ai_real
9
+ struct_attr_accessor :a1, :a2, :a3, :a4,
10
+ :b1, :b2, :b3, :b4,
11
+ :c1, :c2, :c3, :c4,
12
+ :d1, :d2, :d3, :d4
13
+
14
+ def self.identity
15
+ m = Matrix4x4::new
16
+ Assimp::aiIdentityMatrix4(m)
17
+ m
18
+ end
19
+
20
+ def self.rotation(a, axis)
21
+ # https://en.wikipedia.org/wiki/Rotation_matrix#Axis_and_angle
22
+ c = Math::cos(a)
23
+ s = Math::sin(a)
24
+ t = 1 - c
25
+ x = axis.x
26
+ y = axis.y
27
+ z = axis.z
28
+
29
+ out = Matrix4x4
30
+ out.a1 = t*x*x + c
31
+ out.a2 = t*x*y - s*z
32
+ out.a3 = t*x*z + s*y
33
+ out.a4 = 0.0
34
+ out.b1 = t*x*y + s*z
35
+ out.b2 = t*y*y + c
36
+ out.b3 = t*y*z - s*x
37
+ out.b4 = 0.0
38
+ out.c1 = t*x*z - s*y
39
+ out.c2 = t*y*z + s*x
40
+ out.c3 = t*z*z + c
41
+ out.c4 = 0.0
42
+ out.d1 = 0.0
43
+ out.d2 = 0.0
44
+ out.d3 = 0.0
45
+ out.d4 = 1.0
46
+ out
47
+ end
48
+
49
+ def self.translation(vec)
50
+ out = identity
51
+ out.a4 = vec.x
52
+ out.b4 = vec.y
53
+ out.c4 = vec.z
54
+ out
55
+ end
56
+
57
+ def self.scaling(vec)
58
+ out = identity
59
+ out.a1 = v.x
60
+ out.b2 = v.y
61
+ out.c3 = v.z
62
+ out
63
+ end
64
+
65
+ def identity!
66
+ Assimp::aiIdentityMatrix4(self)
67
+ self
68
+ end
69
+
70
+ def to_s
71
+ <<EOF
72
+ < <#{a1}, #{a2}, #{a3}, #{a4}>,
73
+ <#{b1}, #{b2}, #{b3}, #{b4}>,
74
+ <#{c1}, #{c2}, #{c3}, #{c4}>,
75
+ <#{d1}, #{d2}, #{d3}, #{d4}> >
76
+ EOF
77
+ end
78
+
79
+ def decompose
80
+ scaling = Vector3D::new
81
+ rotation = Quaternion::new
82
+ position = Vector3D::new
83
+ Assimp::aiDecomposeMatrix(self, scaling, rotation, position)
84
+ [scaling, rotation, position]
85
+ end
86
+
87
+ def transpose!
88
+ Assimp::aiTransposeMatrix4(self)
89
+ self
90
+ end
91
+
92
+ def transpose
93
+ t = self.dup
94
+ t.transpose!
95
+ end
96
+
97
+ def *(other)
98
+ if other.kind_of?(Matrix4x4)
99
+ m = self.dup
100
+ Assimp::aiMultiplyMatrix4(m, other)
101
+ m
102
+ elsif other.kind_of?(Vector3D)
103
+ v = other.dup
104
+ Assimp::aiTransformVecByMatrix4(v, self)
105
+ v
106
+ else
107
+ "Unsupported operand: #{other.inspect}!"
108
+ end
109
+ end
110
+
111
+ def determinant
112
+ a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4 +
113
+ a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4 -
114
+ a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3 +
115
+ a3*b4*c1*d2 - a3*b4*c2*d1 + a3*b1*c2*d4 - a3*b1*c4*d2 +
116
+ a3*b2*c4*d1 - a3*b2*c1*d4 - a4*b1*c2*d3 + a4*b1*c3*d2 -
117
+ a4*b2*c3*d1 + a4*b2*c1*d3 - a4*b3*c1*d2 + a4*b3*c2*d1
118
+ end
119
+
120
+ def inverse
121
+ det = determinant
122
+ raise "Not inversible!" if det == 0.0
123
+ m = Matrix4x4::new
124
+ invdet = 1.0/det
125
+ m.a1 = invdet * (b2 * (c3 * d4 - c4 * d3) +
126
+ b3 * (c4 * d2 - c2 * d4) +
127
+ b4 * (c2 * d3 - c3 * d2))
128
+ m.a2 = -invdet * (a2 * (c3 * d4 - c4 * d3) +
129
+ a3 * (c4 * d2 - c2 * d4) +
130
+ a4 * (c2 * d3 - c3 * d2))
131
+ m.a3 = invdet * (a2 * (b3 * d4 - b4 * d3) +
132
+ a3 * (b4 * d2 - b2 * d4) +
133
+ a4 * (b2 * d3 - b3 * d2))
134
+ m.a4 = -invdet * (a2 * (b3 * c4 - b4 * c3) +
135
+ a3 * (b4 * c2 - b2 * c4) +
136
+ a4 * (b2 * c3 - b3 * c2))
137
+ m.b1 = -invdet * (b1 * (c3 * d4 - c4 * d3) +
138
+ b3 * (c4 * d1 - c1 * d4) +
139
+ b4 * (c1 * d3 - c3 * d1))
140
+ m.b2 = invdet * (a1 * (c3 * d4 - c4 * d3) +
141
+ a3 * (c4 * d1 - c1 * d4) +
142
+ a4 * (c1 * d3 - c3 * d1))
143
+ m.b3 = -invdet * (a1 * (b3 * d4 - b4 * d3) +
144
+ a3 * (b4 * d1 - b1 * d4) +
145
+ a4 * (b1 * d3 - b3 * d1))
146
+ m.b4 = invdet * (a1 * (b3 * c4 - b4 * c3) +
147
+ a3 * (b4 * c1 - b1 * c4) +
148
+ a4 * (b1 * c3 - b3 * c1))
149
+ m.c1 = invdet * (b1 * (c2 * d4 - c4 * d2) +
150
+ b2 * (c4 * d1 - c1 * d4) +
151
+ b4 * (c1 * d2 - c2 * d1))
152
+ m.c2 = -invdet * (a1 * (c2 * d4 - c4 * d2) +
153
+ a2 * (c4 * d1 - c1 * d4) +
154
+ a4 * (c1 * d2 - c2 * d1))
155
+ m.c3 = invdet * (a1 * (b2 * d4 - b4 * d2) +
156
+ a2 * (b4 * d1 - b1 * d4) +
157
+ a4 * (b1 * d2 - b2 * d1))
158
+ m.c4 = -invdet * (a1 * (b2 * c4 - b4 * c2) +
159
+ a2 * (b4 * c1 - b1 * c4) +
160
+ a4 * (b1 * c2 - b2 * c1))
161
+ m.d1 = -invdet * (b1 * (c2 * d3 - c3 * d2) +
162
+ b2 * (c3 * d1 - c1 * d3) +
163
+ b3 * (c1 * d2 - c2 * d1))
164
+ m.d2 = invdet * (a1 * (c2 * d3 - c3 * d2) +
165
+ a2 * (c3 * d1 - c1 * d3) +
166
+ a3 * (c1 * d2 - c2 * d1))
167
+ m.d3 = -invdet * (a1 * (b2 * d3 - b3 * d2) +
168
+ a2 * (b3 * d1 - b1 * d3) +
169
+ a3 * (b1 * d2 - b2 * d1))
170
+ m.d4 = invdet * (a1 * (b2 * c3 - b3 * c2) +
171
+ a2 * (b3 * c1 - b1 * c3) +
172
+ a3 * (b1 * c2 - b2 * c1))
173
+ m
174
+ end
175
+
176
+ end
177
+
178
+ end