1 /*
2 Copyright (c) 2017-2018 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.graphics.animmodel;
29 
30 import dlib.core.memory;
31 import dlib.math.vector;
32 import dlib.math.matrix;
33 
34 import dagon.core.libs;
35 import dagon.core.interfaces;
36 import dagon.core.ownership;
37 import dagon.graphics.texture;
38 import dagon.graphics.mesh;
39 
40 interface AnimatedModel
41 {
42     void calcBindPose(AnimationFrameData* data);
43     void calcFrame(uint f1, uint f2, float t, AnimationFrameData* data);
44     void blendFrame(uint f1, uint f2, float t, AnimationFrameData* data, float blendFactor);
45     Vector3f[] getVertices();
46     Vector3f[] getNormals();
47     Vector2f[] getTexcoords();
48     uint[3][] getTriangles();
49     AnimationFacegroup[] getFacegroups();
50     size_t numBones();
51     bool getAnimation(string name, AnimationData* data);
52     uint numAnimationFrames();
53 }
54 
55 struct AnimationFacegroup
56 {
57     size_t firstTriangle;
58     size_t numTriangles;
59     Texture texture;
60     string textureName;
61 }
62 
63 struct AnimationData
64 {
65     uint firstFrame;
66     uint numFrames;
67     float framerate;
68 }
69 
70 struct AnimationFrameData
71 {
72     Vector3f[] vertices;
73     Vector3f[] normals;
74     Vector2f[] texcoords;
75     uint[3][] tris;
76     Matrix4x4f[] frame;
77 }
78 
79 struct ActorState
80 {
81     uint currentFrame = 0;
82     uint nextFrame = 1;
83     float t = 0.0f;
84 }
85 
86 class Actor: Owner, Drawable
87 {
88     AnimatedModel model;
89     AnimationFrameData frameData;
90     AnimationData animation;
91     AnimationData nextAnimation;
92     bool hasNextAnimation = false;
93     float blendFactor = 0.0f;
94     ActorState state;
95     ActorState nextState;
96     bool playing = false;
97     float defaultFramerate = 24.0f;
98     float speed = 1.0f;
99     bool swapZY = true;
100     
101     GLuint vao = 0;
102     GLuint vbo = 0;
103     GLuint nbo = 0;
104     GLuint tbo = 0;
105     GLuint eao = 0;
106 
107     this(AnimatedModel m, Owner owner)
108     {
109         super(owner);
110         model = m;
111 
112         if (model.getVertices().length)
113             frameData.vertices = New!(Vector3f[])(model.getVertices().length);
114         if (model.getNormals().length)
115             frameData.normals = New!(Vector3f[])(model.getNormals().length);
116         if (model.getTexcoords().length)
117             frameData.texcoords = model.getTexcoords(); // no need to make a copy, texcoords don't change frame to frame
118         if (model.getTriangles().length)
119             frameData.tris = model.getTriangles(); // no need to make a copy, indices don't change frame to frame
120         if (model.numBones())
121             frameData.frame = New!(Matrix4x4f[])(model.numBones());
122 
123         model.calcBindPose(&frameData);
124 
125         switchToFullSequence();
126         
127         foreach(ref v; frameData.vertices)
128             v = Vector3f(0, 0, 0);
129             
130         foreach(ref n; frameData.normals)
131             n = Vector3f(0, 0, 0);
132         
133         glGenBuffers(1, &vbo);
134         glBindBuffer(GL_ARRAY_BUFFER, vbo);
135         glBufferData(GL_ARRAY_BUFFER, frameData.vertices.length * float.sizeof * 3, frameData.vertices.ptr, GL_DYNAMIC_DRAW); 
136 
137         glGenBuffers(1, &nbo);
138         glBindBuffer(GL_ARRAY_BUFFER, nbo);
139         glBufferData(GL_ARRAY_BUFFER, frameData.normals.length * float.sizeof * 3, frameData.normals.ptr, GL_DYNAMIC_DRAW);
140 
141         glGenBuffers(1, &tbo);
142         glBindBuffer(GL_ARRAY_BUFFER, tbo);
143         glBufferData(GL_ARRAY_BUFFER, frameData.texcoords.length * float.sizeof * 2, frameData.texcoords.ptr, GL_DYNAMIC_DRAW);
144 
145         glGenBuffers(1, &eao);
146         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
147         glBufferData(GL_ELEMENT_ARRAY_BUFFER, frameData.tris.length * uint.sizeof * 3, frameData.tris.ptr, GL_DYNAMIC_DRAW);
148         
149         glGenVertexArrays(1, &vao);
150         glBindVertexArray(vao);
151         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
152     
153         glEnableVertexAttribArray(VertexAttrib.Vertices);
154         glBindBuffer(GL_ARRAY_BUFFER, vbo);
155         glVertexAttribPointer(VertexAttrib.Vertices, 3, GL_FLOAT, GL_FALSE, 0, null);
156     
157         glEnableVertexAttribArray(VertexAttrib.Normals);
158         glBindBuffer(GL_ARRAY_BUFFER, nbo);
159         glVertexAttribPointer(VertexAttrib.Normals, 3, GL_FLOAT, GL_FALSE, 0, null);
160     
161         glEnableVertexAttribArray(VertexAttrib.Texcoords);
162         glBindBuffer(GL_ARRAY_BUFFER, tbo);
163         glVertexAttribPointer(VertexAttrib.Texcoords, 2, GL_FLOAT, GL_FALSE, 0, null);
164         
165         glBindBuffer(GL_ARRAY_BUFFER, 0);
166         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
167 
168         glBindVertexArray(0);
169     }
170 
171     ~this()
172     {
173         if (frameData.vertices.length) Delete(frameData.vertices);
174         if (frameData.normals.length) Delete(frameData.normals);
175         if (frameData.frame.length) Delete(frameData.frame);
176     }
177 
178     void switchToBindPose()
179     {
180         model.calcBindPose(&frameData);
181         playing = false;
182     }
183 
184     void switchToAnimation(string name)
185     {
186         model.getAnimation(name, &animation);
187         state.currentFrame = animation.firstFrame;
188         state.nextFrame = state.currentFrame + 1;
189         state.t = 0.0f;
190     }
191 
192     void switchToAnimationSmooth(string name, float smooth)
193     {
194         model.getAnimation(name, &nextAnimation);
195         hasNextAnimation = true;
196         nextState.currentFrame = nextAnimation.firstFrame;
197         nextState.nextFrame = nextState.currentFrame + 1;
198         nextState.t = 0.0f;
199     }
200 
201     void switchToSequence(uint startFrame, uint endFrame)
202     {
203         //model.getAnimation(name, &nextAnimation);
204         animation.firstFrame = startFrame;
205         animation.numFrames = endFrame - startFrame;
206         state.currentFrame = animation.firstFrame;
207         state.nextFrame = state.currentFrame + 1;
208         state.t = 0.0f;
209     }
210 
211     void switchToSequenceSmooth(uint startFrame, uint endFrame, float smooth)
212     {
213         //model.getAnimation(name, &nextAnimation);
214         nextAnimation.firstFrame = startFrame;
215         nextAnimation.numFrames = endFrame - startFrame;
216         hasNextAnimation = true;
217         nextState.currentFrame = nextAnimation.firstFrame;
218         nextState.nextFrame = nextState.currentFrame + 1;
219         nextState.t = 0.0f;
220     }
221 
222     void switchToFullSequence()
223     {
224         switchToAnimation("");
225         animation.framerate = defaultFramerate;
226         state.currentFrame = animation.firstFrame;
227         state.nextFrame = state.currentFrame + 1;
228         state.t = 0.0f;
229     }
230 
231     void play()
232     {
233         playing = true;
234     }
235 
236     void pause()
237     {
238         playing = false;
239     }
240 
241     void update(double dt)
242     {
243         if (!playing)
244             return;
245 
246         model.calcFrame(state.currentFrame, state.nextFrame, state.t, &frameData);
247 
248         state.t += defaultFramerate * dt * speed; //animation.framerate
249 
250         if (state.t >= 1.0f)
251         {
252             state.t = 0.0f;
253             state.currentFrame++;
254             state.nextFrame++;
255 
256             if (state.currentFrame == animation.firstFrame + animation.numFrames - 1)
257             {
258                 state.nextFrame = animation.firstFrame;
259             }
260             else if (state.currentFrame == animation.firstFrame + animation.numFrames)
261             {
262                 state.currentFrame = animation.firstFrame;
263                 state.nextFrame = state.currentFrame + 1;
264             }
265         }
266 
267         if (hasNextAnimation)
268         {
269             model.blendFrame(nextState.currentFrame, nextState.nextFrame, nextState.t, &frameData, blendFactor);
270             nextState.t += defaultFramerate * dt * speed; //nextAnimation.framerate
271             blendFactor += dt; // TODO: time multiplier
272 
273             if (nextState.t >= 1.0f)
274             {
275                 nextState.t = 0.0f;
276                 nextState.currentFrame++;
277                 nextState.nextFrame++;
278 
279                 if (nextState.currentFrame == nextAnimation.numFrames - 1)
280                 {
281                     nextState.nextFrame = nextAnimation.firstFrame;
282                 }
283                 else if (nextState.currentFrame == nextAnimation.numFrames)
284                 {
285                     nextState.currentFrame = nextAnimation.firstFrame;
286                     nextState.nextFrame = nextState.currentFrame + 1;
287                 }
288             }
289 
290             if (blendFactor >= 1.0f)
291             {
292                 blendFactor = 0.0f;
293                 hasNextAnimation = false;
294                 animation = nextAnimation;
295                 state = nextState;
296             }
297         }
298         
299         glBindBuffer(GL_ARRAY_BUFFER, vbo);
300         glBufferSubData(GL_ARRAY_BUFFER, 0, frameData.vertices.length * float.sizeof * 3, frameData.vertices.ptr);
301         glBindBuffer(GL_ARRAY_BUFFER, nbo);
302         glBufferSubData(GL_ARRAY_BUFFER, 0, frameData.normals.length * float.sizeof * 3, frameData.normals.ptr);
303         glBindBuffer(GL_ARRAY_BUFFER, 0);
304     }
305 
306     void render(RenderingContext* rc)
307     {
308         //glDisable(GL_CULL_FACE);
309         glBindVertexArray(vao);
310         foreach(ref fg; model.getFacegroups)
311         {
312             glActiveTexture(GL_TEXTURE0);
313             if (fg.texture)
314                 fg.texture.bind();
315             glDrawElements(GL_TRIANGLES, cast(uint)(3 * fg.numTriangles), GL_UNSIGNED_INT, &frameData.tris[fg.firstTriangle]);
316             if (fg.texture)
317                 fg.texture.unbind();
318         }
319         glBindVertexArray(0);
320     }
321 }