@@ -24,31 +24,6 @@ pub const MeshConfig = struct {
2424 material : ? graphics.Material = null ,
2525};
2626
27- pub const PlayingAnimation = struct {
28- anim_idx : usize = 0 ,
29- time : f32 = 0.0 ,
30- speed : f32 = 0.0 ,
31- playing : bool = false ,
32- looping : bool = true ,
33-
34- // calculated on play
35- duration : f32 = 0.0 ,
36-
37- pub fn isDonePlaying (self : * PlayingAnimation ) bool {
38- return self .time >= self .duration ;
39- }
40- };
41-
42- const AnimationTransform = struct {
43- translation : math.Vec3 = math .Vec3 .zero ,
44- scale : math.Vec3 = math .Vec3 .one ,
45- rotation : math.Quaternion = math .Quaternion .identity ,
46-
47- pub fn toMat4 (self : * const AnimationTransform ) math.Mat4 {
48- return math .Mat4 .recompose (self .translation , self .rotation , self .scale );
49- }
50- };
51-
5227pub fn init () ! void {
5328 zmesh .init (mem .getAllocator ());
5429}
@@ -63,10 +38,9 @@ pub const Mesh = struct {
6338 bindings : graphics.Bindings = undefined ,
6439 material : graphics.Material = undefined ,
6540 bounds : boundingbox.BoundingBox = undefined ,
66- zmesh_data : * zmesh.io.zcgltf.Data = undefined ,
6741
68- joint_locations : [ 64 ] math.Mat4 = [ _ ] math.Mat4 { math . Mat4 . identity } ** 64 ,
69- playing_animation : PlayingAnimation = .{} ,
42+ has_skin : bool = false ,
43+ zmesh_data : * zmesh.io.zcgltf.Data = undefined ,
7044
7145 pub fn initFromFile (allocator : std.mem.Allocator , filename : [:0 ]const u8 , cfg : MeshConfig ) ? Mesh {
7246 const data = zmesh .io .parseAndLoadFile (filename ) catch {
@@ -169,240 +143,21 @@ pub const Mesh = struct {
169143 }
170144
171145 pub fn deinit (self : * Mesh ) void {
172- zmesh .io .freeData (self .zmesh_data );
146+ if (self .has_skin )
147+ zmesh .io .freeData (self .zmesh_data );
148+
173149 self .bindings .destroy ();
174150 }
175151
176152 /// Draw this mesh
177153 pub fn draw (self : * Mesh , proj_view_matrix : math.Mat4 , model_matrix : math.Mat4 ) void {
178- self .material .params .joints = & self .joint_locations ;
179154 graphics .drawWithMaterial (& self .bindings , & self .material , proj_view_matrix , model_matrix );
180155 }
181156
182157 /// Draw this mesh, using the specified material instead of the set one
183158 pub fn drawWithMaterial (self : * Mesh , material : * graphics.Material , proj_view_matrix : math.Mat4 , model_matrix : math.Mat4 ) void {
184- self .material .params .joints = & self .joint_locations ;
185159 graphics .drawWithMaterial (& self .bindings , material , proj_view_matrix , model_matrix );
186160 }
187-
188- pub fn resetJoints (self : * Mesh ) void {
189- for (0.. self .joint_locations .len ) | i | {
190- self .joint_locations [i ] = math .Mat4 .identity ;
191- }
192- }
193-
194- pub fn getAnimationsCount (self : * Mesh ) usize {
195- return self .zmesh_data .animations_count ;
196- }
197-
198- pub fn playAnimation (self : * Mesh , anim_idx : usize , speed : f32 , loop : bool ) void {
199- self .playing_animation .looping = loop ;
200- self .playing_animation .time = 0.0 ;
201- self .playing_animation .speed = speed ;
202-
203- if (anim_idx >= self .zmesh_data .animations_count ) {
204- debug .log ("warning: animation {} not found!" , .{anim_idx });
205- self .playing_animation .anim_idx = 0 ;
206- self .playing_animation .playing = false ;
207- self .playing_animation .duration = 0 ;
208- return ;
209- }
210-
211- self .playing_animation .anim_idx = anim_idx ;
212- self .playing_animation .playing = true ;
213-
214- const animation = self .zmesh_data .animations .? [anim_idx ];
215- self .playing_animation .duration = zmesh .io .computeAnimationDuration (& animation );
216- }
217-
218- pub fn playAnimationByName (self : * Mesh , anim_name : []const u8 , speed : f32 , loop : bool ) void {
219- // convert to a sentinel terminated pointer
220- const anim_name_z = @as ([* :0 ]u8 , @constCast (@ptrCast (anim_name )));
221-
222- // Go find the animation whose name matches
223- for (0.. self .zmesh_data .animations_count ) | i | {
224- if (self .zmesh_data .animations .? [i ].name ) | name | {
225- const result = std .mem .orderZ (u8 , name , anim_name_z );
226- if (result == .eq ) {
227- // debug.log("Found animation index for {s} : {}", .{ anim_name, i });
228- self .playAnimation (i , speed , loop );
229- return ;
230- }
231- }
232- }
233-
234- debug .log ("Could not find skined mesh animation to play: '{s}'" , .{anim_name });
235- }
236-
237- pub fn updateAnimation (self : * Mesh , delta_time : f32 ) void {
238- if (self .zmesh_data .skins == null or self .zmesh_data .animations == null )
239- return ;
240-
241- if (! self .playing_animation .playing )
242- return ;
243-
244- self .playing_animation .time += delta_time * self .playing_animation .speed ;
245-
246- const animation = self .zmesh_data .animations .? [self .playing_animation .anim_idx ];
247- const animation_duration = self .playing_animation .duration ;
248-
249- // loop if we need to!
250- var t = self .playing_animation .time ;
251- if (self .playing_animation .looping ) {
252- t = @mod (t , animation_duration );
253- }
254-
255- const nodes = self .zmesh_data .skins .? [0 ].joints ;
256- const nodes_count = self .zmesh_data .skins .? [0 ].joints_count ;
257-
258- var local_transforms : [64 ]AnimationTransform = [_ ]AnimationTransform {undefined } ** 64 ;
259-
260- for (0.. nodes_count ) | i | {
261- const node = nodes [i ];
262- local_transforms [i ] = .{
263- .translation = math .Vec3 .fromArray (node .translation ),
264- .scale = math .Vec3 .fromArray (node .scale ),
265- .rotation = math .Quaternion .new (node .rotation [0 ], node .rotation [1 ], node .rotation [2 ], node .rotation [3 ]),
266- };
267- }
268-
269- for (0.. animation .channels_count ) | i | {
270- const channel = animation .channels [i ];
271- const sampler = animation .samplers [i ];
272-
273- var node_idx : usize = 0 ;
274- var found_node = false ;
275- for (0.. nodes_count ) | ni | {
276- if (nodes [ni ] == channel .target_node .? ) {
277- node_idx = ni ;
278- found_node = true ;
279- break ;
280- }
281- }
282-
283- if (! found_node )
284- continue ;
285-
286- switch (channel .target_path ) {
287- .translation = > {
288- const sampled_translation = self .sampleAnimation (math .Vec3 , sampler , t );
289- local_transforms [node_idx ].translation = sampled_translation ;
290- },
291- .scale = > {
292- const sampled_scale = self .sampleAnimation (math .Vec3 , sampler , t );
293- local_transforms [node_idx ].scale = sampled_scale ;
294- },
295- .rotation = > {
296- const sampled_quaternion = self .sampleAnimation (math .Quaternion , sampler , t );
297- local_transforms [node_idx ].rotation = sampled_quaternion ;
298- },
299- else = > {
300- // unhandled!
301- },
302- }
303- }
304-
305- var local_transform_mats : [64 ]math.Mat4 = [_ ]math.Mat4 {math .Mat4 .identity } ** 64 ;
306- for (0.. nodes_count ) | i | {
307- local_transform_mats [i ] = local_transforms [i ].toMat4 ();
308- }
309-
310- // update each joint location based on each node in the joint heirarchy
311- for (0.. nodes_count ) | i | {
312- var node = nodes [i ];
313- self .joint_locations [i ] = local_transform_mats [i ];
314-
315- while (node .parent ) | parent | : (node = parent ) {
316- var parent_idx : usize = 0 ;
317- var found_node = false ;
318-
319- for (0.. nodes_count ) | ni | {
320- if (nodes [ni ] == parent ) {
321- parent_idx = ni ;
322- found_node = true ;
323- break ;
324- }
325- }
326-
327- if (! found_node )
328- continue ;
329-
330- const parent_transform = local_transform_mats [parent_idx ];
331- self .joint_locations [i ] = parent_transform .mul (self .joint_locations [i ]);
332- }
333- }
334-
335- // apply the inverse bind matrices
336- const inverse_bind_mat_data = zmesh .io .getAnimationSamplerData (self .zmesh_data .skins .? [0 ].inverse_bind_matrices .? );
337- for (0.. nodes_count ) | i | {
338- const inverse_mat = access (math .Mat4 , inverse_bind_mat_data , i );
339- self .joint_locations [i ] = self .joint_locations [i ].mul (inverse_mat );
340- }
341- }
342-
343- pub fn sampleAnimation (self : * Mesh , comptime T : type , sampler : zmesh.io.zcgltf.AnimationSampler , t : f32 ) T {
344- _ = self ;
345-
346- const samples = zmesh .io .getAnimationSamplerData (sampler .input );
347- const data = zmesh .io .getAnimationSamplerData (sampler .output );
348-
349- switch (sampler .interpolation ) {
350- .step = > {
351- return access (T , data , stepInterpolation (samples , t ));
352- },
353- .linear = > {
354- const r = linearInterpolation (samples , t );
355- const v0 = access (T , data , r .prev_i );
356- const v1 = access (T , data , r .next_i );
357-
358- if (T == math .Quaternion ) {
359- return T .slerp (v0 , v1 , r .alpha );
360- }
361-
362- return T .lerp (v0 , v1 , r .alpha );
363- },
364- .cubic_spline = > {
365- @panic ("Cubicspline in animations not implemented!" );
366- },
367- }
368- }
369-
370- /// Returns the index of the last sample less than `t`.
371- fn stepInterpolation (samples : []const f32 , t : f32 ) usize {
372- std .debug .assert (samples .len > 0 );
373- const S = struct {
374- fn lessThan (_ : void , lhs : f32 , rhs : f32 ) bool {
375- return lhs < rhs ;
376- }
377- };
378- const i = std .sort .lowerBound (f32 , t , samples , {}, S .lessThan );
379- return if (i > 0 ) i - 1 else 0 ;
380- }
381-
382- /// Returns the indices of the samples around `t` and `alpha` to interpolate between those.
383- fn linearInterpolation (samples : []const f32 , t : f32 ) struct {
384- prev_i : usize ,
385- next_i : usize ,
386- alpha : f32 ,
387- } {
388- const i = stepInterpolation (samples , t );
389- if (i == samples .len - 1 ) return .{ .prev_i = i , .next_i = i , .alpha = 0 };
390-
391- const d = samples [i + 1 ] - samples [i ];
392- std .debug .assert (d > 0 );
393- const alpha = std .math .clamp ((t - samples [i ]) / d , 0 , 1 );
394-
395- return .{ .prev_i = i , .next_i = i + 1 , .alpha = alpha };
396- }
397-
398- pub fn access (comptime T : type , data : []const f32 , i : usize ) T {
399- return switch (T ) {
400- Vec3 = > Vec3 .new (data [3 * i + 0 ], data [3 * i + 1 ], data [3 * i + 2 ]),
401- math .Quaternion = > math .Quaternion .new (data [4 * i + 0 ], data [4 * i + 1 ], data [4 * i + 2 ], data [4 * i + 3 ]),
402- math .Mat4 = > math .Mat4 .fromSlice (data [16 * i .. ][0.. 16]),
403- else = > @compileError ("unexpected type" ),
404- };
405- }
406161};
407162
408163/// Create a mesh out of some vertex data
@@ -431,6 +186,7 @@ pub fn createSkinnedMesh(vertices: []graphics.Vertex, indices: []u32, normals: [
431186 .material = material ,
432187 .bounds = boundingbox .BoundingBox .initFromVerts (vertices ),
433188 .zmesh_data = data ,
189+ .has_skin = true ,
434190 };
435191 return m ;
436192}
0 commit comments