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 import derelict.opengl;
34 import dagon.core.interfaces;
35 import dagon.core.ownership;
36 import dagon.graphics.texture;
37 import dagon.graphics.mesh;
38 
39 interface AnimatedModel
40 {
41     void calcBindPose(AnimationFrameData* data);
42     void calcFrame(uint f1, uint f2, float t, AnimationFrameData* data);
43     void blendFrame(uint f1, uint f2, float t, AnimationFrameData* data, float blendFactor);
44     Vector3f[] getVertices();
45     Vector3f[] getNormals();
46     Vector2f[] getTexcoords();
47     uint[3][] getTriangles();
48     AnimationFacegroup[] getFacegroups();
49     size_t numBones();
50     bool getAnimation(string name, AnimationData* data);
51     uint numAnimationFrames();
52 }
53 
54 struct AnimationFacegroup
55 {
56     size_t firstTriangle;
57     size_t numTriangles;
58     Texture texture;
59     string textureName;
60 }
61 
62 struct AnimationData
63 {
64     uint firstFrame;
65     uint numFrames;
66     float framerate;
67 }
68 
69 struct AnimationFrameData
70 {
71     Vector3f[] vertices;
72     Vector3f[] normals;
73     Vector2f[] texcoords;
74     uint[3][] tris;
75     Matrix4x4f[] frame;
76 }
77 
78 struct ActorState
79 {
80     uint currentFrame = 0;
81     uint nextFrame = 1;
82     float t = 0.0f;
83 }
84 
85 class Actor: Owner, Drawable
86 {
87     AnimatedModel model;
88     AnimationFrameData frameData;
89     AnimationData animation;
90     AnimationData nextAnimation;
91     bool hasNextAnimation = false;
92     float blendFactor = 0.0f;
93     ActorState state;
94     ActorState nextState;
95     bool playing = false;
96     float defaultFramerate = 24.0f;
97     float speed = 1.0f;
98     bool swapZY = true;
99     
100     GLuint vao = 0;
101     GLuint vbo = 0;
102     GLuint nbo = 0;
103     GLuint tbo = 0;
104     GLuint eao = 0;
105 
106     this(AnimatedModel m, Owner owner)
107     {
108         super(owner);
109         model = m;
110 
111         if (model.getVertices().length)
112             frameData.vertices = New!(Vector3f[])(model.getVertices().length);
113         if (model.getNormals().length)
114             frameData.normals = New!(Vector3f[])(model.getNormals().length);
115         if (model.getTexcoords().length)
116             frameData.texcoords = model.getTexcoords(); // no need to make a copy, texcoords don't change frame to frame
117         if (model.getTriangles().length)
118             frameData.tris = model.getTriangles(); // no need to make a copy, indices don't change frame to frame
119         if (model.numBones())
120             frameData.frame = New!(Matrix4x4f[])(model.numBones());
121 
122         model.calcBindPose(&frameData);
123 
124         switchToFullSequence();
125         
126         foreach(ref v; frameData.vertices)
127             v = Vector3f(0, 0, 0);
128             
129         foreach(ref n; frameData.normals)
130             n = Vector3f(0, 0, 0);
131         
132         glGenBuffers(1, &vbo);
133         glBindBuffer(GL_ARRAY_BUFFER, vbo);
134         glBufferData(GL_ARRAY_BUFFER, frameData.vertices.length * float.sizeof * 3, frameData.vertices.ptr, GL_DYNAMIC_DRAW); 
135 
136         glGenBuffers(1, &nbo);
137         glBindBuffer(GL_ARRAY_BUFFER, nbo);
138         glBufferData(GL_ARRAY_BUFFER, frameData.normals.length * float.sizeof * 3, frameData.normals.ptr, GL_DYNAMIC_DRAW);
139 
140         glGenBuffers(1, &tbo);
141         glBindBuffer(GL_ARRAY_BUFFER, tbo);
142         glBufferData(GL_ARRAY_BUFFER, frameData.texcoords.length * float.sizeof * 2, frameData.texcoords.ptr, GL_DYNAMIC_DRAW);
143 
144         glGenBuffers(1, &eao);
145         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
146         glBufferData(GL_ELEMENT_ARRAY_BUFFER, frameData.tris.length * uint.sizeof * 3, frameData.tris.ptr, GL_DYNAMIC_DRAW);
147         
148         glGenVertexArrays(1, &vao);
149         glBindVertexArray(vao);
150         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
151     
152         glEnableVertexAttribArray(VertexAttrib.Vertices);
153         glBindBuffer(GL_ARRAY_BUFFER, vbo);
154         glVertexAttribPointer(VertexAttrib.Vertices, 3, GL_FLOAT, GL_FALSE, 0, null);
155     
156         glEnableVertexAttribArray(VertexAttrib.Normals);
157         glBindBuffer(GL_ARRAY_BUFFER, nbo);
158         glVertexAttribPointer(VertexAttrib.Normals, 3, GL_FLOAT, GL_FALSE, 0, null);
159     
160         glEnableVertexAttribArray(VertexAttrib.Texcoords);
161         glBindBuffer(GL_ARRAY_BUFFER, tbo);
162         glVertexAttribPointer(VertexAttrib.Texcoords, 2, GL_FLOAT, GL_FALSE, 0, null);
163         
164         glBindBuffer(GL_ARRAY_BUFFER, 0);
165         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
166 
167         glBindVertexArray(0);
168     }
169 
170     ~this()
171     {
172         if (frameData.vertices.length) Delete(frameData.vertices);
173         if (frameData.normals.length) Delete(frameData.normals);
174         if (frameData.frame.length) Delete(frameData.frame);
175     }
176 
177     void switchToBindPose()
178     {
179         model.calcBindPose(&frameData);
180         playing = false;
181     }
182 
183     void switchToAnimation(string name)
184     {
185         model.getAnimation(name, &animation);
186         state.currentFrame = animation.firstFrame;
187         state.nextFrame = state.currentFrame + 1;
188         state.t = 0.0f;
189     }
190 
191     void switchToAnimationSmooth(string name, float smooth)
192     {
193         model.getAnimation(name, &nextAnimation);
194         hasNextAnimation = true;
195         nextState.currentFrame = nextAnimation.firstFrame;
196         nextState.nextFrame = nextState.currentFrame + 1;
197         nextState.t = 0.0f;
198     }
199 
200     void switchToSequence(uint startFrame, uint endFrame)
201     {
202         //model.getAnimation(name, &nextAnimation);
203         animation.firstFrame = startFrame;
204         animation.numFrames = endFrame - startFrame;
205         state.currentFrame = animation.firstFrame;
206         state.nextFrame = state.currentFrame + 1;
207         state.t = 0.0f;
208     }
209 
210     void switchToSequenceSmooth(uint startFrame, uint endFrame, float smooth)
211     {
212         //model.getAnimation(name, &nextAnimation);
213         nextAnimation.firstFrame = startFrame;
214         nextAnimation.numFrames = endFrame - startFrame;
215         hasNextAnimation = true;
216         nextState.currentFrame = nextAnimation.firstFrame;
217         nextState.nextFrame = nextState.currentFrame + 1;
218         nextState.t = 0.0f;
219     }
220 
221     void switchToFullSequence()
222     {
223         switchToAnimation("");
224         animation.framerate = defaultFramerate;
225         state.currentFrame = animation.firstFrame;
226         state.nextFrame = state.currentFrame + 1;
227         state.t = 0.0f;
228     }
229 
230     void play()
231     {
232         playing = true;
233     }
234 
235     void pause()
236     {
237         playing = false;
238     }
239 
240     void update(double dt)
241     {
242         if (!playing)
243             return;
244 
245         model.calcFrame(state.currentFrame, state.nextFrame, state.t, &frameData);
246 
247         state.t += defaultFramerate * dt * speed; //animation.framerate
248 
249         if (state.t >= 1.0f)
250         {
251             state.t = 0.0f;
252             state.currentFrame++;
253             state.nextFrame++;
254 
255             if (state.currentFrame == animation.firstFrame + animation.numFrames - 1)
256             {
257                 state.nextFrame = animation.firstFrame;
258             }
259             else if (state.currentFrame == animation.firstFrame + animation.numFrames)
260             {
261                 state.currentFrame = animation.firstFrame;
262                 state.nextFrame = state.currentFrame + 1;
263             }
264         }
265 
266         if (hasNextAnimation)
267         {
268             model.blendFrame(nextState.currentFrame, nextState.nextFrame, nextState.t, &frameData, blendFactor);
269             nextState.t += defaultFramerate * dt * speed; //nextAnimation.framerate
270             blendFactor += dt; // TODO: time multiplier
271 
272             if (nextState.t >= 1.0f)
273             {
274                 nextState.t = 0.0f;
275                 nextState.currentFrame++;
276                 nextState.nextFrame++;
277 
278                 if (nextState.currentFrame == nextAnimation.numFrames - 1)
279                 {
280                     nextState.nextFrame = nextAnimation.firstFrame;
281                 }
282                 else if (nextState.currentFrame == nextAnimation.numFrames)
283                 {
284                     nextState.currentFrame = nextAnimation.firstFrame;
285                     nextState.nextFrame = nextState.currentFrame + 1;
286                 }
287             }
288 
289             if (blendFactor >= 1.0f)
290             {
291                 blendFactor = 0.0f;
292                 hasNextAnimation = false;
293                 animation = nextAnimation;
294                 state = nextState;
295             }
296         }
297         
298         glBindBuffer(GL_ARRAY_BUFFER, vbo);
299         glBufferSubData(GL_ARRAY_BUFFER, 0, frameData.vertices.length * float.sizeof * 3, frameData.vertices.ptr);
300         glBindBuffer(GL_ARRAY_BUFFER, nbo);
301         glBufferSubData(GL_ARRAY_BUFFER, 0, frameData.normals.length * float.sizeof * 3, frameData.normals.ptr);
302         glBindBuffer(GL_ARRAY_BUFFER, 0);
303     }
304 
305     void render(RenderingContext* rc)
306     {
307         //glDisable(GL_CULL_FACE);
308         glBindVertexArray(vao);
309         foreach(ref fg; model.getFacegroups)
310         {
311             glActiveTexture(GL_TEXTURE0);
312             if (fg.texture)
313                 fg.texture.bind();
314             glDrawElements(GL_TRIANGLES, cast(uint)(3 * fg.numTriangles), GL_UNSIGNED_INT, &frameData.tris[fg.firstTriangle]);
315             if (fg.texture)
316                 fg.texture.unbind();
317         }
318         glBindVertexArray(0);
319     }
320 }