CSCI441 OpenGL Library 6.0.1.1
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
MD5Model_types.hpp
Go to the documentation of this file.
1
12#ifndef CSCI441_MD5_MODEL_TYPES_HPP
13#define CSCI441_MD5_MODEL_TYPES_HPP
14
15/*
16 * md5mesh model loader + animation
17 * last modification: Dr. Jeffrey Paone
18 * encapsulated into a class
19 * supports texturing
20 *
21 * Doom3's md5mesh viewer with animation. Mesh and Animation declaration
22 * See http://tfc.duke.free.fr/coding/md5-specs-en.html for more details
23 *
24 * Copyright (c) 2005-2007 David HENRY
25 *
26 * Permission is hereby granted, free of charge, to any person
27 * obtaining a copy of this software and associated documentation
28 * files (the "Software"), to deal in the Software without
29 * restriction, including without limitation the rights to use,
30 * copy, modify, merge, publish, distribute, sublicense, and/or
31 * sell copies of the Software, and to permit persons to whom the
32 * Software is furnished to do so, subject to the following conditions:
33 *
34 * The above copyright notice and this permission notice shall be
35 * included in all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40 *
41 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
42 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
43 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45 *
46 */
47
48#ifdef CSCI441_USE_GLEW
49 #include <GL/glew.h>
50#else
51 #include <glad/gl.h>
52#endif
53
54#include <glm/ext/quaternion_float.hpp>
55
56#include <cstring>
57#include <stdexcept>
58
59namespace CSCI441_INTERNAL {
60
62 // md5mtr types
64
67 struct MD5Texture {
71 static constexpr GLshort MAX_NAME_LENGTH = 512;
75 GLuint texHandle = 0;
79 char filename[MAX_NAME_LENGTH] = "";
80
84 MD5Texture() = default;
89 MD5Texture(const MD5Texture &OTHER) {
90 _copyFromSrc(OTHER);
91 }
97 MD5Texture& operator=(const MD5Texture &OTHER) {
98 if (this != &OTHER) {
99 _copyFromSrc(OTHER);
100 }
101 return *this;
102 }
107 MD5Texture(MD5Texture&& src) noexcept {
108 _moveFromSrc(src);
109 }
115 MD5Texture& operator=(MD5Texture&& src) noexcept {
116 if (this != &src) {
117 _moveFromSrc(src);
118 }
119 return *this;
120 }
121 private:
126 void _copyFromSrc(const MD5Texture &src) {
127 this->texHandle = src.texHandle;
128 strncpy(this->filename, src.filename, MAX_NAME_LENGTH);
129 this->filename[ strlen(src.filename) ] = '\0';
130 }
135 void _moveFromSrc(MD5Texture& src) {
136 _copyFromSrc(src);
137
138 src.texHandle = 0;
139 strncpy(src.filename, "", MAX_NAME_LENGTH);
140 src.filename[0] = '\0';
141 }
142 };
143
144 // md5material types
145 struct MD5MaterialShader {
149 static constexpr GLshort MAX_NAME_LENGTH = 512;
153 static constexpr GLshort NUM_TEXTURES = 4;
157 char name[MAX_NAME_LENGTH] = "";
161 MD5Texture textures[NUM_TEXTURES];
165 GLuint displacementScale = 1;
169 enum TextureMap {
173 DIFFUSE,
177 SPECULAR,
181 NORMAL,
185 HEIGHT
186 };
187 MD5MaterialShader() = default;
188 MD5MaterialShader(const MD5MaterialShader &OTHER) {
189 _copyFromSrc(OTHER);
190 }
191 MD5MaterialShader& operator=(const MD5MaterialShader &OTHER) {
192 if (this != &OTHER) {
193 _copyFromSrc(OTHER);
194 }
195 return *this;
196 }
197 MD5MaterialShader(MD5MaterialShader&& src) noexcept {
198 _moveFromSrc(src);
199 }
200 MD5MaterialShader& operator=(MD5MaterialShader&& src) noexcept {
201 if (this != &src) {
202 _moveFromSrc(src);
203 }
204 return *this;
205 }
206 private:
207 void _copyFromSrc(const MD5MaterialShader &src) {
208 for (GLshort i = 0; i < NUM_TEXTURES; i++) {
209 this->textures[i] = src.textures[i];
210 }
211 strncpy(this->name, src.name, MAX_NAME_LENGTH);
212 this->name[ strlen(src.name) ] = '\0';
213 }
214 void _moveFromSrc(MD5MaterialShader &src) {
215 for (GLshort i = 0; i < NUM_TEXTURES; i++) {
216 this->textures[i] = std::move( src.textures[i] );
217 }
218 strncpy(this->name, src.name, MAX_NAME_LENGTH);
219 this->name[ strlen(src.name) ] = '\0';
220 strncpy(src.name, "", MAX_NAME_LENGTH);
221 src.name[0] = '\0';
222 }
223 };
224
226 // md5mesh types
228
231 struct MD5Joint {
235 static constexpr GLint NULL_JOINT = -1;
239 static constexpr GLshort MAX_NAME_LENGTH = 256;
243 char name[MAX_NAME_LENGTH] = "";
247 GLint parent = NULL_JOINT;
251 glm::vec3 position = {0.0f, 0.0f, 0.0f};
255 glm::quat orientation = {0.0f, 0.0f, 0.0f, 0.0f};
256
260 MD5Joint() = default;
265 MD5Joint(const MD5Joint &OTHER) {
266 _copyFromSrc(OTHER);
267 }
273 MD5Joint& operator=(const MD5Joint &OTHER) {
274 if (this != &OTHER) {
275 _copyFromSrc(OTHER);
276 }
277 return *this;
278 }
283 MD5Joint(MD5Joint&& src) noexcept {
284 _moveFromSrc(src);
285 }
291 MD5Joint& operator=(MD5Joint&& src) noexcept {
292 if (this != &src) {
293 _moveFromSrc(src);
294 }
295 return *this;
296 }
297 private:
302 void _copyFromSrc(const MD5Joint& src) {
303 strncpy(this->name, src.name, MAX_NAME_LENGTH);
304 this->name[ strlen(src.name) ] = '\0';
305 this->parent = src.parent;
306 this->position = src.position;
307 this->orientation = src.orientation;
308 }
314 void _moveFromSrc(MD5Joint& src) {
315 // copy values from source
316 _copyFromSrc(src);
317 // reset source
318 strncpy(src.name, "", MAX_NAME_LENGTH);
319 src.name[0] = '\0';
320 src.parent = NULL_JOINT;
321 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
322 src.orientation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
323 }
324 };
325
329 struct MD5Vertex {
333 glm::vec2 texCoord = {0.0f, 0.0f};
337 GLint start = 0;
341 GLint count = 0;
342
346 MD5Vertex() = default;
351 MD5Vertex(const MD5Vertex &OTHER) {
352 _copyFromSrc(OTHER);
353 }
359 MD5Vertex& operator=(const MD5Vertex &OTHER) {
360 if (this != &OTHER) {
361 _copyFromSrc(OTHER);
362 }
363 return *this;
364 }
369 MD5Vertex(MD5Vertex&& src) noexcept {
370 _moveFromSrc(src);
371 }
377 MD5Vertex& operator=(MD5Vertex&& src) noexcept {
378 if (this != &src) {
379 _moveFromSrc(src);
380 }
381 return *this;
382 }
383 private:
388 void _copyFromSrc(const MD5Vertex &src) {
389 this->texCoord = src.texCoord;
390 this->start = src.start;
391 this->count = src.count;
392 }
397 void _moveFromSrc(MD5Vertex& src) {
398 _copyFromSrc(src);
399
400 src.texCoord = glm::vec2(0.0f, 0.0f);
401 src.start = 0;
402 src.count = 0;
403 }
404 };
405
409 struct MD5Triangle {
413 static constexpr GLshort NUM_VERTICES = 3;
417 GLint index[NUM_VERTICES] = {0};
418
422 MD5Triangle() = default;
427 MD5Triangle(const MD5Triangle &OTHER) {
428 _copyFromSrc(OTHER);
429 }
435 MD5Triangle& operator=(const MD5Triangle &OTHER) {
436 if (this != &OTHER) {
437 _copyFromSrc(OTHER);
438 }
439 return *this;
440 }
445 MD5Triangle(MD5Triangle&& src) noexcept {
446 _moveFromSrc(src);
447 }
453 MD5Triangle& operator=(MD5Triangle&& src) noexcept {
454 if (this != &src) {
455 _moveFromSrc(src);
456 }
457 return *this;
458 }
459 private:
464 void _copyFromSrc(const MD5Triangle &src) {
465 for (GLshort i = 0; i < NUM_VERTICES; i++) {
466 this->index[i] = src.index[i];
467 }
468 }
473 void _moveFromSrc(MD5Triangle &src) {
474 _copyFromSrc(src);
475
476 for (GLint & i : src.index) {
477 i = 0;
478 }
479 }
480 };
481
485 struct MD5Weight {
489 GLint joint = MD5Joint::NULL_JOINT;
493 GLfloat bias = 0.f;
497 glm::vec3 position = {0.0f, 0.0f, 0.0f};
498
502 MD5Weight() = default;
507 MD5Weight(const MD5Weight &OTHER) {
508 _copyFromSrc(OTHER);
509 }
515 MD5Weight& operator=(const MD5Weight &OTHER) {
516 if (this != &OTHER) {
517 _copyFromSrc(OTHER);
518 }
519 return *this;
520 }
525 MD5Weight(MD5Weight&& src) noexcept {
526 _moveFromSrc(src);
527 }
533 MD5Weight& operator=(MD5Weight&& src) noexcept {
534 if (this != &src) {
535 _moveFromSrc(src);
536 }
537 return *this;
538 }
539 private:
544 void _copyFromSrc(const MD5Weight &src) {
545 this->joint = src.joint;
546 this->bias = src.bias;
547 this->position = src.position;
548 }
553 void _moveFromSrc(MD5Weight &src) {
554 _copyFromSrc(src);
555
556 src.joint = MD5Joint::NULL_JOINT;
557 src.bias = 0.0f;
558 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
559 }
560 };
561
565 struct MD5Mesh {
566
570 MD5Vertex* vertices = nullptr;
574 MD5Triangle* triangles = nullptr;
578 MD5Weight* weights = nullptr;
579
580 MD5MaterialShader* shader = nullptr;
581
585 GLint numVertices = 0;
589 GLint numTriangles = 0;
593 GLint numWeights = 0;
597 MD5Mesh() = default;
601 ~MD5Mesh() {
602 delete[] vertices;
603 vertices = nullptr;
604
605 delete[] triangles;
606 triangles = nullptr;
607
608 delete[] weights;
609 weights = nullptr;
610 }
615 MD5Mesh(const MD5Mesh &OTHER) = delete;
620 MD5Mesh& operator=(const MD5Mesh &OTHER) = delete;
621
626 MD5Mesh(MD5Mesh&& src) noexcept {
627 _moveFromSrc(src);
628 }
634 MD5Mesh& operator=(MD5Mesh&& src) noexcept {
635 if (this != &src) {
636 _moveFromSrc(src);
637 }
638 return *this;
639 }
640 private:
645 void _moveFromSrc(MD5Mesh& src) {
646 this->vertices = src.vertices;
647 src.vertices = nullptr;
648
649 this->triangles = src.triangles;
650 src.triangles = nullptr;
651
652 this->weights = src.weights;
653 src.weights = nullptr;
654
655 this->shader = src.shader;
656 src.shader = nullptr;
657
658 this->numVertices = src.numVertices;
659 src.numVertices = 0;
660
661 this->numTriangles = src.numTriangles;
662 src.numTriangles = 0;
663
664 this->numWeights = src.numWeights;
665 src.numWeights = 0;
666 }
667 };
668
670 // md5anim types
672
675 struct MD5JointInfo {
679 static constexpr GLshort MAX_NAME_LENGTH = 256;
683 char name[MAX_NAME_LENGTH] = "";
687 GLint parent = MD5Joint::NULL_JOINT;
691 GLuint flags = 0;
695 GLint startIndex = 0;
696
700 MD5JointInfo() = default;
705 MD5JointInfo(const MD5JointInfo& OTHER) {
706 _copyFromSrc(OTHER);
707 }
713 MD5JointInfo& operator=(const MD5JointInfo& OTHER) {
714 if (this != &OTHER) {
715 _copyFromSrc(OTHER);
716 }
717 return *this;
718 }
723 MD5JointInfo(MD5JointInfo&& src) noexcept {
724 _moveFromSrc(src);
725 }
731 MD5JointInfo& operator=(MD5JointInfo&& src) noexcept {
732 if (this != &src) {
733 _moveFromSrc(src);
734 }
735 return *this;
736 }
737 private:
742 void _copyFromSrc(const MD5JointInfo &src) {
743 strncpy(this->name, src.name, MAX_NAME_LENGTH);
744 this->name[ strlen(src.name) ] = '\0';
745 this->parent = src.parent;
746 this->flags = src.flags;
747 this->startIndex = src.startIndex;
748 }
753 void _moveFromSrc(MD5JointInfo &src) {
754 _copyFromSrc(src);
755
756 strncpy(src.name, "", MAX_NAME_LENGTH);
757 src.name[0] = '\0';
758 src.parent = MD5Joint::NULL_JOINT;
759 src.flags = 0;
760 src.startIndex = 0;
761 }
762 };
763
767 struct MD5BaseFrameJoint {
771 glm::vec3 position = {0.0f, 0.0f, 0.0f};
775 glm::quat orientation = {0.0f, 0.0f, 0.0f, 0.0f};
776
780 MD5BaseFrameJoint() = default;
785 MD5BaseFrameJoint(const MD5BaseFrameJoint& OTHER) {
786 _copyFromSrc(OTHER);
787 }
793 MD5BaseFrameJoint& operator=(const MD5BaseFrameJoint &OTHER) {
794 if (this != &OTHER) {
795 _copyFromSrc(OTHER);
796 }
797 return *this;
798 }
803 MD5BaseFrameJoint(MD5BaseFrameJoint&& src) noexcept {
804 _moveFromSrc(src);
805 }
811 MD5BaseFrameJoint& operator=(MD5BaseFrameJoint&& src) noexcept {
812 if (this != &src) {
813 _moveFromSrc(src);
814 }
815 return *this;
816 }
817 private:
822 void _copyFromSrc(const MD5BaseFrameJoint &src) {
823 this->position = src.position;
824 this->orientation = src.orientation;
825 }
830 void _moveFromSrc(MD5BaseFrameJoint &src) {
831 _copyFromSrc(src);
832
833 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
834 src.orientation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
835 }
836 };
837
842 struct MD5BoundingBox {
846 glm::vec3 min = {0.0f, 0.0f, 0.0f};
850 glm::vec3 max = {0.0f, 0.0f, 0.0f};
851
855 MD5BoundingBox() = default;
860 MD5BoundingBox(const MD5BoundingBox &OTHER) {
861 _copyFromSrc(OTHER);
862 }
868 MD5BoundingBox& operator=(const MD5BoundingBox &OTHER) {
869 if (this != &OTHER) {
870 _copyFromSrc(OTHER);
871 }
872 return *this;
873 }
878 MD5BoundingBox(MD5BoundingBox&& src) noexcept {
879 _moveFromSrc(src);
880 }
886 MD5BoundingBox& operator=(MD5BoundingBox&& src) noexcept {
887 if (this != &src) {
888 _moveFromSrc(src);
889 }
890 return *this;
891 }
892 private:
897 void _copyFromSrc(const MD5BoundingBox& src) {
898 this->min = src.min;
899 this->max = src.max;
900 }
905 void _moveFromSrc(MD5BoundingBox& src) {
906 _copyFromSrc(src);
907
908 src.min = glm::vec3(0.0f, 0.0f, 0.0f);
909 src.max = glm::vec3(0.0f, 0.0f, 0.0f);
910 }
911 };
912
916 class MD5Animation {
917 public:
922 GLint frameRate = 0;
923
928 [[nodiscard]] GLint getNumberOfFrames() const { return _numFrames; }
935 void setNumberOfFrames(const GLint numFrames) {
936 // if previously set, delete prior allocation to avoid memory leak
937 if(_skeletonFrames != nullptr) {
938 for (GLint i = 0; i < _numFrames; ++i) {
939 delete _skeletonFrames[i];
940 }
941 }
942 delete[] _skeletonFrames;
943 _skeletonFrames = nullptr; // no longer exists, in event new set equals zero
944 delete[] _boundingBoxes;
945 _boundingBoxes = nullptr; // no longer exists, in event new set equals zero
946
947 _numFrames = numFrames;
948 if ( _numFrames > 0 ) {
949 _skeletonFrames = new MD5Joint*[_numFrames];
950 for (GLint i = 0; i < _numFrames; ++i) {
951 _skeletonFrames[i] = nullptr;
952 }
953 _boundingBoxes = new MD5BoundingBox[_numFrames];
954 }
955 }
956
961 [[nodiscard]] GLint getNumberOfJoints() const { return _numJoints; }
969 void setNumberOfJoints(const GLint numJoints) {
970 // if previously set, delete prior allocation to avoid memory leak
971 if(_skeletonFrames != nullptr) {
972 for (GLint i = 0; i < _numFrames; ++i) {
973 delete _skeletonFrames[i];
974 _skeletonFrames[i] = nullptr; // no longer exists, in event new set equals zero
975 }
976 }
977
978 _numJoints = numJoints;
979 if (_numJoints > 0) {
980 if(_skeletonFrames != nullptr) {
981 for(GLint i = 0; i < _numFrames; ++i) {
982 // Allocate memory for joints of each frame
983 _skeletonFrames[i] = new MD5Joint[_numJoints];
984 }
985 }
986 }
987 }
988
996 [[nodiscard]] const MD5Joint* getSkeletonFrame(const GLint frameIndex) const {
997 if ( frameIndex < 0 || frameIndex >= _numFrames ) {
998 throw std::out_of_range("frameIndex out of range");
999 }
1000 if (_skeletonFrames == nullptr) {
1001 throw std::out_of_range("skeleton frames are null, setNumberOfFrames() may not have been called");
1002 }
1003 return _skeletonFrames[frameIndex];
1004 }
1014 [[nodiscard]] MD5Joint& getSkeletonFrameJoint(const GLint frameIndex, const GLint jointIndex) const {
1015 if ( frameIndex < 0 || frameIndex >= _numFrames ) {
1016 throw std::out_of_range("frameIndex out of range");
1017 }
1018 if ( jointIndex < 0 || jointIndex >= _numJoints ) {
1019 throw std::out_of_range("jointIndex out of range");
1020 }
1021 if (_skeletonFrames == nullptr) {
1022 throw std::out_of_range("skeleton frames are null, setNumberOfFrames() may not have been called");
1023 }
1024 if (_skeletonFrames[frameIndex] == nullptr) {
1025 throw std::out_of_range("skeleton joints are null, setNumberOfJoints() may not have been called");
1026 }
1027 return _skeletonFrames[frameIndex][jointIndex];
1028 }
1029
1037 [[nodiscard]] MD5BoundingBox& getBoundingBox(const GLint frameIndex) const {
1038 if(frameIndex < 0 || frameIndex >= _numFrames) {
1039 throw std::out_of_range("frameIndex out of range");
1040 }
1041 if (_boundingBoxes == nullptr) {
1042 throw std::out_of_range("bounding boxes are null, setNumberOfFrames() may not have been called");
1043 }
1044 return _boundingBoxes[frameIndex];
1045 }
1046
1050 MD5Animation() = default;
1054 ~MD5Animation() {
1055 if(_skeletonFrames != nullptr) {
1056 for (GLint i = 0; i < _numFrames; i++) {
1057 delete[] _skeletonFrames[i];
1058 _skeletonFrames[i] = nullptr;
1059 }
1060 }
1061 delete[] _skeletonFrames;
1062 _skeletonFrames = nullptr;
1063
1064 delete[] _boundingBoxes;
1065 _boundingBoxes = nullptr;
1066 }
1067
1072 MD5Animation(const MD5Animation& OTHER) = delete;
1077 MD5Animation& operator=(const MD5Animation& OTHER) = delete;
1078
1083 MD5Animation(MD5Animation&& src) noexcept {
1084 _moveFromSrc(src);
1085 }
1091 MD5Animation& operator=(MD5Animation&& src) noexcept {
1092 if (this != &src) {
1093 _moveFromSrc(src);
1094 }
1095 return *this;
1096 }
1097 private:
1102 GLint _numFrames = 0;
1107 GLint _numJoints = 0;
1112 MD5Joint** _skeletonFrames = nullptr;
1117 MD5BoundingBox* _boundingBoxes = nullptr;
1118
1123 void _moveFromSrc(MD5Animation &src) {
1124 this->_numFrames = src._numFrames;
1125 src._numFrames = 0;
1126
1127 this->_numJoints = src._numJoints;
1128 src._numJoints = 0;
1129
1130 this->frameRate = src.frameRate;
1131 src.frameRate = 0;
1132
1133 this->_skeletonFrames = src._skeletonFrames;
1134 src._skeletonFrames = nullptr;
1135
1136 this->_boundingBoxes = src._boundingBoxes;
1137 src._boundingBoxes = nullptr;
1138 }
1139 };
1140
1144 struct MD5AnimationState {
1148 GLint currFrame = 0;
1152 GLint nextFrame = 0;
1156 GLfloat lastTime = 0.0f;
1161 GLfloat maxTime = 0.0f;
1162
1166 MD5AnimationState() = default;
1171 MD5AnimationState(const MD5AnimationState &OTHER) {
1172 _copyFromSrc(OTHER);
1173 }
1179 MD5AnimationState& operator=(const MD5AnimationState &OTHER) {
1180 if (this != &OTHER) {
1181 _copyFromSrc(OTHER);
1182 }
1183 return *this;
1184 }
1189 MD5AnimationState(MD5AnimationState&& src) noexcept {
1190 _moveFromSrc(src);
1191 }
1197 MD5AnimationState& operator=(MD5AnimationState&& src) noexcept {
1198 if (this != &src) {
1199 _moveFromSrc(src);
1200 }
1201 return *this;
1202 }
1203 private:
1208 void _copyFromSrc(const MD5AnimationState &src) {
1209 this->currFrame = src.currFrame;
1210 this->nextFrame = src.nextFrame;
1211 this->lastTime = src.lastTime;
1212 this->maxTime = src.maxTime;
1213 }
1218 void _moveFromSrc(MD5AnimationState &src) {
1219 _copyFromSrc(src);
1220
1221 src.currFrame = 0;
1222 src.nextFrame = 0;
1223 src.lastTime = 0.0f;
1224 src.maxTime = 0.0f;
1225 }
1226 };
1227}
1228
1229#endif//CSCI441_MD5_MODEL_TYPES_HPP