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 }