CSCI441 OpenGL Library 5.25.0.0
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 }
134 void _moveFromSrc(MD5Texture& src) {
135 _copyFromSrc(src);
136
137 src.texHandle = 0;
138 strncpy(src.filename, "", MAX_NAME_LENGTH);
139 }
140 };
141
142 // md5material types
143 struct MD5MaterialShader {
147 static constexpr GLshort MAX_NAME_LENGTH = 512;
151 static constexpr GLshort NUM_TEXTURES = 4;
155 char name[MAX_NAME_LENGTH] = "";
159 MD5Texture textures[NUM_TEXTURES];
163 GLuint displacementScale = 1;
167 enum TextureMap {
171 DIFFUSE,
175 SPECULAR,
179 NORMAL,
183 HEIGHT
184 };
185 MD5MaterialShader() = default;
186 MD5MaterialShader(const MD5MaterialShader &OTHER) {
187 _copyFromSrc(OTHER);
188 }
189 MD5MaterialShader& operator=(const MD5MaterialShader &OTHER) {
190 if (this != &OTHER) {
191 _copyFromSrc(OTHER);
192 }
193 return *this;
194 }
195 MD5MaterialShader(MD5MaterialShader&& src) noexcept {
196 _moveFromSrc(src);
197 }
198 MD5MaterialShader& operator=(MD5MaterialShader&& src) noexcept {
199 if (this != &src) {
200 _moveFromSrc(src);
201 }
202 return *this;
203 }
204 private:
205 void _copyFromSrc(const MD5MaterialShader &src) {
206 for (GLshort i = 0; i < NUM_TEXTURES; i++) {
207 this->textures[i] = src.textures[i];
208 }
209 strncpy(this->name, src.name, MAX_NAME_LENGTH);
210 }
211 void _moveFromSrc(MD5MaterialShader &src) {
212 for (GLshort i = 0; i < NUM_TEXTURES; i++) {
213 this->textures[i] = std::move( src.textures[i] );
214 }
215 strncpy(this->name, src.name, MAX_NAME_LENGTH);
216 strncpy(src.name, "", MAX_NAME_LENGTH);
217 }
218 };
219
221 // md5mesh types
223
226 struct MD5Joint {
230 static constexpr GLint NULL_JOINT = -1;
234 static constexpr GLshort MAX_NAME_LENGTH = 256;
238 char name[MAX_NAME_LENGTH] = "";
242 GLint parent = NULL_JOINT;
246 glm::vec3 position = {0.0f, 0.0f, 0.0f};
250 glm::quat orientation = {0.0f, 0.0f, 0.0f, 0.0f};
251
255 MD5Joint() = default;
260 MD5Joint(const MD5Joint &OTHER) {
261 _copyFromSrc(OTHER);
262 }
268 MD5Joint& operator=(const MD5Joint &OTHER) {
269 if (this != &OTHER) {
270 _copyFromSrc(OTHER);
271 }
272 return *this;
273 }
278 MD5Joint(MD5Joint&& src) noexcept {
279 _moveFromSrc(src);
280 }
286 MD5Joint& operator=(MD5Joint&& src) noexcept {
287 if (this != &src) {
288 _moveFromSrc(src);
289 }
290 return *this;
291 }
292 private:
297 void _copyFromSrc(const MD5Joint& src) {
298 strncpy(this->name, src.name, MAX_NAME_LENGTH);
299 this->parent = src.parent;
300 this->position = src.position;
301 this->orientation = src.orientation;
302 }
308 void _moveFromSrc(MD5Joint& src) {
309 // copy values from source
310 _copyFromSrc(src);
311 // reset source
312 strncpy(src.name, "", MAX_NAME_LENGTH);
313 src.parent = NULL_JOINT;
314 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
315 src.orientation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
316 }
317 };
318
322 struct MD5Vertex {
326 glm::vec2 texCoord = {0.0f, 0.0f};
330 GLint start = 0;
334 GLint count = 0;
335
339 MD5Vertex() = default;
344 MD5Vertex(const MD5Vertex &OTHER) {
345 _copyFromSrc(OTHER);
346 }
352 MD5Vertex& operator=(const MD5Vertex &OTHER) {
353 if (this != &OTHER) {
354 _copyFromSrc(OTHER);
355 }
356 return *this;
357 }
362 MD5Vertex(MD5Vertex&& src) noexcept {
363 _moveFromSrc(src);
364 }
370 MD5Vertex& operator=(MD5Vertex&& src) noexcept {
371 if (this != &src) {
372 _moveFromSrc(src);
373 }
374 return *this;
375 }
376 private:
381 void _copyFromSrc(const MD5Vertex &src) {
382 this->texCoord = src.texCoord;
383 this->start = src.start;
384 this->count = src.count;
385 }
390 void _moveFromSrc(MD5Vertex& src) {
391 _copyFromSrc(src);
392
393 src.texCoord = glm::vec2(0.0f, 0.0f);
394 src.start = 0;
395 src.count = 0;
396 }
397 };
398
402 struct MD5Triangle {
406 static constexpr GLshort NUM_VERTICES = 3;
410 GLint index[NUM_VERTICES] = {0};
411
415 MD5Triangle() = default;
420 MD5Triangle(const MD5Triangle &OTHER) {
421 _copyFromSrc(OTHER);
422 }
428 MD5Triangle& operator=(const MD5Triangle &OTHER) {
429 if (this != &OTHER) {
430 _copyFromSrc(OTHER);
431 }
432 return *this;
433 }
438 MD5Triangle(MD5Triangle&& src) noexcept {
439 _moveFromSrc(src);
440 }
446 MD5Triangle& operator=(MD5Triangle&& src) noexcept {
447 if (this != &src) {
448 _moveFromSrc(src);
449 }
450 return *this;
451 }
452 private:
457 void _copyFromSrc(const MD5Triangle &src) {
458 for (GLshort i = 0; i < NUM_VERTICES; i++) {
459 this->index[i] = src.index[i];
460 }
461 }
466 void _moveFromSrc(MD5Triangle &src) {
467 _copyFromSrc(src);
468
469 for (GLint & i : src.index) {
470 i = 0;
471 }
472 }
473 };
474
478 struct MD5Weight {
482 GLint joint = MD5Joint::NULL_JOINT;
486 GLfloat bias = 0.f;
490 glm::vec3 position = {0.0f, 0.0f, 0.0f};
491
495 MD5Weight() = default;
500 MD5Weight(const MD5Weight &OTHER) {
501 _copyFromSrc(OTHER);
502 }
508 MD5Weight& operator=(const MD5Weight &OTHER) {
509 if (this != &OTHER) {
510 _copyFromSrc(OTHER);
511 }
512 return *this;
513 }
518 MD5Weight(MD5Weight&& src) noexcept {
519 _moveFromSrc(src);
520 }
526 MD5Weight& operator=(MD5Weight&& src) noexcept {
527 if (this != &src) {
528 _moveFromSrc(src);
529 }
530 return *this;
531 }
532 private:
537 void _copyFromSrc(const MD5Weight &src) {
538 this->joint = src.joint;
539 this->bias = src.bias;
540 this->position = src.position;
541 }
546 void _moveFromSrc(MD5Weight &src) {
547 _copyFromSrc(src);
548
549 src.joint = MD5Joint::NULL_JOINT;
550 src.bias = 0.0f;
551 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
552 }
553 };
554
558 struct MD5Mesh {
559
563 MD5Vertex* vertices = nullptr;
567 MD5Triangle* triangles = nullptr;
571 MD5Weight* weights = nullptr;
572
573 MD5MaterialShader* shader = nullptr;
574
578 GLint numVertices = 0;
582 GLint numTriangles = 0;
586 GLint numWeights = 0;
590 MD5Mesh() = default;
594 ~MD5Mesh() {
595 delete[] vertices;
596 vertices = nullptr;
597
598 delete[] triangles;
599 triangles = nullptr;
600
601 delete[] weights;
602 weights = nullptr;
603 }
608 MD5Mesh(const MD5Mesh &OTHER) = delete;
613 MD5Mesh& operator=(const MD5Mesh &OTHER) = delete;
614
619 MD5Mesh(MD5Mesh&& src) noexcept {
620 _moveFromSrc(src);
621 }
627 MD5Mesh& operator=(MD5Mesh&& src) noexcept {
628 if (this != &src) {
629 _moveFromSrc(src);
630 }
631 return *this;
632 }
633 private:
638 void _moveFromSrc(MD5Mesh& src) {
639 this->vertices = src.vertices;
640 src.vertices = nullptr;
641
642 this->triangles = src.triangles;
643 src.triangles = nullptr;
644
645 this->weights = src.weights;
646 src.weights = nullptr;
647
648 this->shader = src.shader;
649 src.shader = nullptr;
650
651 this->numVertices = src.numVertices;
652 src.numVertices = 0;
653
654 this->numTriangles = src.numTriangles;
655 src.numTriangles = 0;
656
657 this->numWeights = src.numWeights;
658 src.numWeights = 0;
659 }
660 };
661
663 // md5anim types
665
668 struct MD5JointInfo {
672 static constexpr GLshort MAX_NAME_LENGTH = 256;
676 char name[MAX_NAME_LENGTH] = "";
680 GLint parent = MD5Joint::NULL_JOINT;
684 GLuint flags = 0;
688 GLint startIndex = 0;
689
693 MD5JointInfo() = default;
698 MD5JointInfo(const MD5JointInfo& OTHER) {
699 _copyFromSrc(OTHER);
700 }
706 MD5JointInfo& operator=(const MD5JointInfo& OTHER) {
707 if (this != &OTHER) {
708 _copyFromSrc(OTHER);
709 }
710 return *this;
711 }
716 MD5JointInfo(MD5JointInfo&& src) noexcept {
717 _moveFromSrc(src);
718 }
724 MD5JointInfo& operator=(MD5JointInfo&& src) noexcept {
725 if (this != &src) {
726 _moveFromSrc(src);
727 }
728 return *this;
729 }
730 private:
735 void _copyFromSrc(const MD5JointInfo &src) {
736 strncpy(this->name, src.name, MAX_NAME_LENGTH);
737 this->parent = src.parent;
738 this->flags = src.flags;
739 this->startIndex = src.startIndex;
740 }
745 void _moveFromSrc(MD5JointInfo &src) {
746 _copyFromSrc(src);
747
748 strncpy(src.name, "", MAX_NAME_LENGTH);
749 src.parent = MD5Joint::NULL_JOINT;
750 src.flags = 0;
751 src.startIndex = 0;
752 }
753 };
754
758 struct MD5BaseFrameJoint {
762 glm::vec3 position = {0.0f, 0.0f, 0.0f};
766 glm::quat orientation = {0.0f, 0.0f, 0.0f, 0.0f};
767
771 MD5BaseFrameJoint() = default;
776 MD5BaseFrameJoint(const MD5BaseFrameJoint& OTHER) {
777 _copyFromSrc(OTHER);
778 }
784 MD5BaseFrameJoint& operator=(const MD5BaseFrameJoint &OTHER) {
785 if (this != &OTHER) {
786 _copyFromSrc(OTHER);
787 }
788 return *this;
789 }
794 MD5BaseFrameJoint(MD5BaseFrameJoint&& src) noexcept {
795 _moveFromSrc(src);
796 }
802 MD5BaseFrameJoint& operator=(MD5BaseFrameJoint&& src) noexcept {
803 if (this != &src) {
804 _moveFromSrc(src);
805 }
806 return *this;
807 }
808 private:
813 void _copyFromSrc(const MD5BaseFrameJoint &src) {
814 this->position = src.position;
815 this->orientation = src.orientation;
816 }
821 void _moveFromSrc(MD5BaseFrameJoint &src) {
822 _copyFromSrc(src);
823
824 src.position = glm::vec3(0.0f, 0.0f, 0.0f);
825 src.orientation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
826 }
827 };
828
833 struct MD5BoundingBox {
837 glm::vec3 min = {0.0f, 0.0f, 0.0f};
841 glm::vec3 max = {0.0f, 0.0f, 0.0f};
842
846 MD5BoundingBox() = default;
851 MD5BoundingBox(const MD5BoundingBox &OTHER) {
852 _copyFromSrc(OTHER);
853 }
859 MD5BoundingBox& operator=(const MD5BoundingBox &OTHER) {
860 if (this != &OTHER) {
861 _copyFromSrc(OTHER);
862 }
863 return *this;
864 }
869 MD5BoundingBox(MD5BoundingBox&& src) noexcept {
870 _moveFromSrc(src);
871 }
877 MD5BoundingBox& operator=(MD5BoundingBox&& src) noexcept {
878 if (this != &src) {
879 _moveFromSrc(src);
880 }
881 return *this;
882 }
883 private:
888 void _copyFromSrc(const MD5BoundingBox& src) {
889 this->min = src.min;
890 this->max = src.max;
891 }
896 void _moveFromSrc(MD5BoundingBox& src) {
897 _copyFromSrc(src);
898
899 src.min = glm::vec3(0.0f, 0.0f, 0.0f);
900 src.max = glm::vec3(0.0f, 0.0f, 0.0f);
901 }
902 };
903
907 class MD5Animation {
908 public:
913 GLint frameRate = 0;
914
919 [[nodiscard]] GLint getNumberOfFrames() const { return _numFrames; }
926 void setNumberOfFrames(const GLint numFrames) {
927 // if previously set, delete prior allocation to avoid memory leak
928 if(_skeletonFrames != nullptr) {
929 for (GLint i = 0; i < _numFrames; ++i) {
930 delete _skeletonFrames[i];
931 }
932 }
933 delete[] _skeletonFrames;
934 _skeletonFrames = nullptr; // no longer exists, in event new set equals zero
935 delete[] _boundingBoxes;
936 _boundingBoxes = nullptr; // no longer exists, in event new set equals zero
937
938 _numFrames = numFrames;
939 if ( _numFrames > 0 ) {
940 _skeletonFrames = new MD5Joint*[_numFrames];
941 for (GLint i = 0; i < _numFrames; ++i) {
942 _skeletonFrames[i] = nullptr;
943 }
944 _boundingBoxes = new MD5BoundingBox[_numFrames];
945 }
946 }
947
952 [[nodiscard]] GLint getNumberOfJoints() const { return _numJoints; }
960 void setNumberOfJoints(const GLint numJoints) {
961 // if previously set, delete prior allocation to avoid memory leak
962 if(_skeletonFrames != nullptr) {
963 for (GLint i = 0; i < _numFrames; ++i) {
964 delete _skeletonFrames[i];
965 _skeletonFrames[i] = nullptr; // no longer exists, in event new set equals zero
966 }
967 }
968
969 _numJoints = numJoints;
970 if (_numJoints > 0) {
971 if(_skeletonFrames != nullptr) {
972 for(GLint i = 0; i < _numFrames; ++i) {
973 // Allocate memory for joints of each frame
974 _skeletonFrames[i] = new MD5Joint[_numJoints];
975 }
976 }
977 }
978 }
979
987 [[nodiscard]] const MD5Joint* getSkeletonFrame(const GLint frameIndex) const {
988 if ( frameIndex < 0 || frameIndex >= _numFrames ) {
989 throw std::out_of_range("frameIndex out of range");
990 }
991 if (_skeletonFrames == nullptr) {
992 throw std::out_of_range("skeleton frames are null, setNumberOfFrames() may not have been called");
993 }
994 return _skeletonFrames[frameIndex];
995 }
1005 [[nodiscard]] MD5Joint& getSkeletonFrameJoint(const GLint frameIndex, const GLint jointIndex) const {
1006 if ( frameIndex < 0 || frameIndex >= _numFrames ) {
1007 throw std::out_of_range("frameIndex out of range");
1008 }
1009 if ( jointIndex < 0 || jointIndex >= _numJoints ) {
1010 throw std::out_of_range("jointIndex out of range");
1011 }
1012 if (_skeletonFrames == nullptr) {
1013 throw std::out_of_range("skeleton frames are null, setNumberOfFrames() may not have been called");
1014 }
1015 if (_skeletonFrames[frameIndex] == nullptr) {
1016 throw std::out_of_range("skeleton joints are null, setNumberOfJoints() may not have been called");
1017 }
1018 return _skeletonFrames[frameIndex][jointIndex];
1019 }
1020
1028 [[nodiscard]] MD5BoundingBox& getBoundingBox(const GLint frameIndex) const {
1029 if(frameIndex < 0 || frameIndex >= _numFrames) {
1030 throw std::out_of_range("frameIndex out of range");
1031 }
1032 if (_boundingBoxes == nullptr) {
1033 throw std::out_of_range("bounding boxes are null, setNumberOfFrames() may not have been called");
1034 }
1035 return _boundingBoxes[frameIndex];
1036 }
1037
1041 MD5Animation() = default;
1045 ~MD5Animation() {
1046 if(_skeletonFrames != nullptr) {
1047 for (GLint i = 0; i < _numFrames; i++) {
1048 delete[] _skeletonFrames[i];
1049 _skeletonFrames[i] = nullptr;
1050 }
1051 }
1052 delete[] _skeletonFrames;
1053 _skeletonFrames = nullptr;
1054
1055 delete[] _boundingBoxes;
1056 _boundingBoxes = nullptr;
1057 }
1058
1063 MD5Animation(const MD5Animation& OTHER) = delete;
1068 MD5Animation& operator=(const MD5Animation& OTHER) = delete;
1069
1074 MD5Animation(MD5Animation&& src) noexcept {
1075 _moveFromSrc(src);
1076 }
1082 MD5Animation& operator=(MD5Animation&& src) noexcept {
1083 if (this != &src) {
1084 _moveFromSrc(src);
1085 }
1086 return *this;
1087 }
1088 private:
1093 GLint _numFrames = 0;
1098 GLint _numJoints = 0;
1103 MD5Joint** _skeletonFrames = nullptr;
1108 MD5BoundingBox* _boundingBoxes = nullptr;
1109
1114 void _moveFromSrc(MD5Animation &src) {
1115 this->_numFrames = src._numFrames;
1116 src._numFrames = 0;
1117
1118 this->_numJoints = src._numJoints;
1119 src._numJoints = 0;
1120
1121 this->frameRate = src.frameRate;
1122 src.frameRate = 0;
1123
1124 this->_skeletonFrames = src._skeletonFrames;
1125 src._skeletonFrames = nullptr;
1126
1127 this->_boundingBoxes = src._boundingBoxes;
1128 src._boundingBoxes = nullptr;
1129 }
1130 };
1131
1135 struct MD5AnimationState {
1139 GLint currFrame = 0;
1143 GLint nextFrame = 0;
1147 GLfloat lastTime = 0.0f;
1152 GLfloat maxTime = 0.0f;
1153
1157 MD5AnimationState() = default;
1162 MD5AnimationState(const MD5AnimationState &OTHER) {
1163 _copyFromSrc(OTHER);
1164 }
1170 MD5AnimationState& operator=(const MD5AnimationState &OTHER) {
1171 if (this != &OTHER) {
1172 _copyFromSrc(OTHER);
1173 }
1174 return *this;
1175 }
1180 MD5AnimationState(MD5AnimationState&& src) noexcept {
1181 _moveFromSrc(src);
1182 }
1188 MD5AnimationState& operator=(MD5AnimationState&& src) noexcept {
1189 if (this != &src) {
1190 _moveFromSrc(src);
1191 }
1192 return *this;
1193 }
1194 private:
1199 void _copyFromSrc(const MD5AnimationState &src) {
1200 this->currFrame = src.currFrame;
1201 this->nextFrame = src.nextFrame;
1202 this->lastTime = src.lastTime;
1203 this->maxTime = src.maxTime;
1204 }
1209 void _moveFromSrc(MD5AnimationState &src) {
1210 _copyFromSrc(src);
1211
1212 src.currFrame = 0;
1213 src.nextFrame = 0;
1214 src.lastTime = 0.0f;
1215 src.maxTime = 0.0f;
1216 }
1217 };
1218}
1219
1220#endif//CSCI441_MD5_MODEL_TYPES_HPP