CSCI441 OpenGL Library 6.1.0.0
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
MD5Camera.hpp
Go to the documentation of this file.
1
12#ifndef CSCI441_MD5_CAMERA_HPP
13#define CSCI441_MD5_CAMERA_HPP
14
15#include "Camera.hpp"
16#include "LogUtils.hpp"
17
18#include <ctime>
19#include <fstream>
20#include <string>
21
22namespace CSCI441 {
23
29 class MD5Camera final : public CSCI441::Camera {
30 public:
53 };
54
58 MD5Camera() = delete;
59
73 explicit MD5Camera(const char* MD5CAMERA_FILE, AdvancementStrategy advancementStrategy, GLuint firstCutToRun = 0, GLfloat aspectRatio = 1.0f, GLfloat fovy = glm::half_pi<GLfloat>(), GLfloat nearClipPlane = 0.001f, GLfloat farClipPlane = 1000.0f, GLboolean INFO = true, GLboolean ERRORS = true);
74
78 MD5Camera(const MD5Camera&);
84
88 MD5Camera(MD5Camera&&) noexcept;
93 MD5Camera& operator=(MD5Camera&&) noexcept;
94
98 ~MD5Camera() override;
99
100 void recomputeOrientation() override {}
101 void moveForward(GLfloat unused) override;
102 void moveBackward(GLfloat unused) override;
103
104 private:
105 bool _loadMD5CameraFromFile(const char * MD5CAMERA_FILE, GLboolean INFO = true, GLboolean ERRORS = true);
106 void _copy(const MD5Camera&);
107 void _moveFromSource(MD5Camera&);
108 void _free();
109
110 bool _isInitialized;
111
112 struct Frame {
113 glm::vec3 cameraPosition;
114 glm::vec3 cameraQuaternion;
115 GLfloat fieldOfView;
116 };
117
118 GLuint _frameRate;
119 GLuint _numFrames;
120 GLuint _numCuts;
121 GLuint* _cutPositions;
122 Frame* _frames;
123 GLuint _currentFrameIndex;
124 GLuint _currentCutIndex;
125 AdvancementStrategy _advancementStrategy;
126
127 void _updateCameraAttributesForCurrentFrame();
128
129 // vertical field of view stored in degrees
130 GLfloat _fovy;
131 GLfloat _aspectRatio;
132 GLfloat _nearClipPlane;
133 GLfloat _farClipPlane;
134 };
135}
136
138 const char * const MD5CAMERA_FILE,
139 const AdvancementStrategy advancementStrategy,
140 const GLuint firstCutToRun,
141 const GLfloat aspectRatio,
142 const GLfloat fovy,
143 const GLfloat nearClipPlane,
144 const GLfloat farClipPlane,
145 const GLboolean INFO,
146 const GLboolean ERRORS
147) : _isInitialized(false),
148 _frameRate(60),
149 _numFrames(0),
150 _numCuts(0),
151 _cutPositions(nullptr),
152 _frames(nullptr),
153 _currentFrameIndex(0),
154 _currentCutIndex(firstCutToRun),
155 _advancementStrategy(advancementStrategy),
156 _fovy(fovy),
157 _aspectRatio(aspectRatio),
158 _nearClipPlane(nearClipPlane),
159 _farClipPlane(farClipPlane)
160{
161 mProjectionMatrix = glm::perspective(_fovy, _aspectRatio, _nearClipPlane, _farClipPlane);
162
163 _isInitialized = _loadMD5CameraFromFile(MD5CAMERA_FILE, INFO, ERRORS);
164}
165
166[[maybe_unused]]
168 const MD5Camera& OTHER
169) : Camera(OTHER),
170 _isInitialized(false),
171 _frameRate(60),
172 _numFrames(0),
173 _numCuts(0),
174 _cutPositions(nullptr),
175 _frames(nullptr),
176 _currentFrameIndex(0),
177 _currentCutIndex(0),
178 _advancementStrategy(AdvancementStrategy::RUN_SINGLE_CUT),
179 _fovy(45.0f),
180 _aspectRatio(1.0f),
181 _nearClipPlane(0.001f),
182 _farClipPlane(1000.0f)
183{
184 this->_copy(OTHER);
185}
186
188 MD5Camera&& src
189) noexcept : Camera(std::move(src)),
190 _isInitialized(false),
191 _frameRate(60),
192 _numFrames(0),
193 _numCuts(0),
194 _cutPositions(nullptr),
195 _frames(nullptr),
196 _currentFrameIndex(0),
197 _currentCutIndex(0),
198 _advancementStrategy(AdvancementStrategy::RUN_SINGLE_CUT),
199 _fovy(45.0f),
200 _aspectRatio(1.0f),
201 _nearClipPlane(0.001f),
202 _farClipPlane(1000.0f)
203{
204 this->_moveFromSource(src);
205}
206
208 // call parent assignment operator
210
211 // guard against self-assignment
212 if(this != &OTHER) {
213 this->_free();
214 this->_copy(OTHER);
215 }
216 return *this;
217}
218
220 // guard against self-move
221 if (this != &src) {
222 this->_free();
223 this->_moveFromSource(src);
224 }
225
226 // call parent move operator
227 CSCI441::Camera::operator=(std::move(src));
228
229 return *this;
230}
231
232
234 this->_free();
235}
236
237inline void CSCI441::MD5Camera::_copy(const MD5Camera& OTHER) {
238 _fovy = OTHER._fovy;
239 _aspectRatio = OTHER._aspectRatio;
240 _nearClipPlane = OTHER._nearClipPlane;
241 _farClipPlane = OTHER._farClipPlane;
242 _frameRate = OTHER._frameRate;
243 _currentFrameIndex = OTHER._currentFrameIndex;
244 _currentCutIndex = OTHER._currentCutIndex;
245 _advancementStrategy = OTHER._advancementStrategy;
246 mProjectionMatrix = OTHER.mProjectionMatrix;
247 _isInitialized = OTHER._isInitialized;
248
249 _numCuts = OTHER._numCuts;
250 _cutPositions = new GLuint[_numCuts];
251 for(unsigned int i = 0; i < _numCuts; i++) {
252 _cutPositions[i] = OTHER._cutPositions[i];
253 }
254
255 _numFrames = OTHER._numFrames;
256 _frames = new Frame[_numFrames];
257 for(unsigned int i = 0; i < _numFrames; i++) {
258 _frames[i] = OTHER._frames[i];
259 }
260}
261
262inline void CSCI441::MD5Camera::_moveFromSource(CSCI441::MD5Camera& src) {
263 _fovy = src._fovy;
264 src._fovy = 0.0f;
265
266 _aspectRatio = src._aspectRatio;
267 src._aspectRatio = 0.0f;
268
269 _nearClipPlane = src._nearClipPlane;
270 src._nearClipPlane = 0.0f;
271
272 _farClipPlane = src._farClipPlane;
273 src._farClipPlane = 0.0f;
274
275 _frameRate = src._frameRate;
276 src._frameRate = 0;
277
278 _currentFrameIndex = src._currentFrameIndex;
279 src._currentFrameIndex = 0;
280;
281 _currentCutIndex = src._currentCutIndex;
282 src._currentCutIndex = 0;
283
284 _advancementStrategy = src._advancementStrategy;
285
286 _isInitialized = src._isInitialized;
287 src._isInitialized = false;
288
289 _numCuts = src._numCuts;
290 src._numCuts = 0;
291
292 _cutPositions = src._cutPositions;
293 src._cutPositions = nullptr;
294
295 _numFrames = src._numFrames;
296 src._numFrames = 0;
297
298 _frames = src._frames;
299 src._frames = nullptr;
300}
301
302inline void CSCI441::MD5Camera::_free() {
303 delete[] _frames;
304 _frames = nullptr;
305
306 delete[] _cutPositions;
307 _cutPositions = nullptr;
308}
309
310
311inline bool CSCI441::MD5Camera::_loadMD5CameraFromFile(
312 const char * const MD5CAMERA_FILE,
313 const GLboolean INFO,
314 const GLboolean ERRORS
315) {
316 if ( INFO ) CSCI441::LogUtils::log("[.md5camera]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=- \n", MD5CAMERA_FILE );
317
318 time_t start, end;
319 time(&start);
320
321 std::ifstream md5CameraFile(MD5CAMERA_FILE);
322 if( !md5CameraFile.is_open() ) {
323 if (ERRORS) CSCI441::LogUtils::logError("[.md5camera]: [ERROR]: Could not open \"%s\"\n", MD5CAMERA_FILE );
324 if ( INFO ) CSCI441::LogUtils::log("[.md5camera]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n", MD5CAMERA_FILE );
325 return false;
326 }
327
328 std::string sectionLabel, commandLineStr, brace;
329 int md5version;
330 Frame frame = { glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), 45.0f };
331
332 // MD5Version 10
333 md5CameraFile >> sectionLabel >> md5version;
334 if(sectionLabel != "MD5Version" || md5version != 10) {
335 if (ERRORS) fprintf (stderr, "[.md5camera]: [ERROR]: improper MD5Camera version found \"%s %d\"\n", sectionLabel.c_str(), md5version );
336 if ( INFO ) CSCI441::LogUtils::log("[.md5camera]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n", MD5CAMERA_FILE );
337 return false;
338 }
339
340 // commandline "string"
341 md5CameraFile >> sectionLabel;
342 getline(md5CameraFile, commandLineStr);
343
344 for(unsigned short i = 0; i < 5; i++) {
345 md5CameraFile >> sectionLabel;
346 if(sectionLabel == "numFrames") {
347 // numFrames <integer>
348 md5CameraFile >> _numFrames;
349 _frames = new Frame[_numFrames];
350 } else if(sectionLabel == "frameRate") {
351 // frameRate <integer>
352 md5CameraFile >> _frameRate;
353 } else if(sectionLabel == "numCuts") {
354 // numCuts <integer>
355 md5CameraFile >> _numCuts;
356 _cutPositions = new GLuint[_numCuts];
357 } else if(sectionLabel == "cuts") {
358 // cuts {
359 // [frameNumber]
360 // [frameNumber]
361 // }
362 md5CameraFile >> brace;
363 if (_cutPositions == nullptr) {
364 if (ERRORS) CSCI441::LogUtils::logError("[.md5camera]: [ERROR]: malformed md5camera file. numCuts not previously defined in file\n" );
365 return false;
366 }
367 for(unsigned int cutNumber = 0; cutNumber < _numCuts; cutNumber++) {
368 md5CameraFile >> _cutPositions[cutNumber];
369 }
370 md5CameraFile >> brace;
371 _currentFrameIndex = _cutPositions[_currentCutIndex];
372 } else if(sectionLabel == "camera") {
373 // camera {
374 // ( [x] [y] [z] ) ( [orientation] ) [FOV]
375 // }
376 md5CameraFile >> brace;
377 for(unsigned int frameNumber = 0; frameNumber < _numFrames; frameNumber++) {
378 md5CameraFile >> brace >> frame.cameraPosition.x >> frame.cameraPosition.y >> frame.cameraPosition.z >> brace;
379 md5CameraFile >> brace >> frame.cameraQuaternion.x >> frame.cameraQuaternion.y >> frame.cameraQuaternion.z >> brace;
380 md5CameraFile >> frame.fieldOfView;
381 }
382 md5CameraFile >> brace;
383 } else {
384 if (ERRORS) CSCI441::LogUtils::logError("[.md5camera]: [ERROR]: unknown section label found \"%s\"\n", sectionLabel.c_str() );
385 if ( INFO ) CSCI441::LogUtils::log("[.md5camera]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n", MD5CAMERA_FILE );
386 return false;
387 }
388 }
389
390 if (INFO) {
391 CSCI441::LogUtils::log("[.md5camera]: Camera Stats:\n" );
392 CSCI441::LogUtils::log("[.md5camera]: Num Frames:\t%u\tFrame Rate:\t%u\tNum Cuts: \t%u\n", _numFrames, _frameRate, _numCuts );
393 }
394
395 time(&end);
396 double seconds = difftime( end, start );
397
398 if (INFO) {
399 CSCI441::LogUtils::log("[.md5camera]: Completed in %.3fs\n", seconds );
400 CSCI441::LogUtils::log("[.md5camera]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n\n", MD5CAMERA_FILE );
401 }
402
403 return true;
404}
405
406inline void CSCI441::MD5Camera::moveForward(const GLfloat unused) {
407 // prevent memory errors by checking if file loaded correctly
408 if( !_isInitialized ) return;
409
410 // clamp to current cut ? loop ? advance ?
411
412 // check if current frame is at end of overall list of frames
413 if( _currentFrameIndex == _numFrames - 1) {
414 switch(_advancementStrategy) {
415 case AdvancementStrategy::LOOP_ALL_CUTS:
416 // go back to start of all cuts
417 _currentCutIndex = 0;
418 case AdvancementStrategy::LOOP_SINGLE_CUT:
419 // go to start of current cut
420 _currentFrameIndex = _cutPositions[ _currentCutIndex ];
421 break;
422
423 case AdvancementStrategy::RUN_SINGLE_CUT:
424 case AdvancementStrategy::RUN_ALL_CUTS:
425 // do nothing, at end and not looping
426 return;
427 }
428 }
429 // check if in last cut, but can't be at the end of the last cut because then we'd be at the end of the overall frames
430 else if( _currentCutIndex == _numCuts - 1 ) {
431 // in the middle of the last cut, move forward
432 _currentFrameIndex++;
433 }
434 // otherwise not on final overall frame and not in the last cut
435 else {
436 // check if at end of current cut
437 if( _currentFrameIndex == _cutPositions[_currentCutIndex + 1] - 1 ) {
438 switch(_advancementStrategy) {
439 case AdvancementStrategy::RUN_ALL_CUTS:
440 case AdvancementStrategy::LOOP_ALL_CUTS:
441 // go to next cut
442 _currentCutIndex++;
443 case AdvancementStrategy::LOOP_SINGLE_CUT:
444 // go to start of current cut
445 _currentFrameIndex = _cutPositions[ _currentCutIndex ];
446 break;
447
448 case AdvancementStrategy::RUN_SINGLE_CUT:
449 // do nothing, at end and not looping nor advancing
450 return;
451 }
452 } else {
453 // in the middle of a cut, move forward
454 _currentFrameIndex++;
455 }
456 }
457 _updateCameraAttributesForCurrentFrame();
458}
459
460inline void CSCI441::MD5Camera::moveBackward(const GLfloat unused) {
461 // prevent memory errors by checking if file loaded correctly
462 if( !_isInitialized ) return;
463
464 // clamp to current cut ? loop ? advance ?
465
466 // check if current frame is at beginning of overall list of frames
467 if( _currentFrameIndex == 0) {
468 switch(_advancementStrategy) {
469 case AdvancementStrategy::LOOP_ALL_CUTS:
470 // go back to end of all frames
471 _currentCutIndex = _numFrames-1;
472 break;
473
474 case AdvancementStrategy::LOOP_SINGLE_CUT:
475 if( _numCuts == 1 ) {
476 // go back to end of all frames
477 _currentCutIndex = _numFrames-1;
478 } else {
479 // go to end of current cut, which is the frame before the next cut
480 _currentFrameIndex = _cutPositions[ _currentCutIndex+1 ] - 1;
481 }
482 break;
483
484 case AdvancementStrategy::RUN_SINGLE_CUT:
485 case AdvancementStrategy::RUN_ALL_CUTS:
486 // do nothing, at end and not looping
487 return;
488 }
489 }
490 // check if in first cut, but can't be at the end of the first cut because then we'd be at the end of the overall frames
491 else if( _currentCutIndex == 0 ) {
492 // in the middle of the first cut, move backward
493 _currentFrameIndex--;
494 }
495 // otherwise not on initial overall frame and not in the first cut
496 else {
497 // check if at beginning of current cut
498 if( _currentFrameIndex == _cutPositions[_currentCutIndex] ) {
499 switch(_advancementStrategy) {
500 case AdvancementStrategy::RUN_ALL_CUTS:
501 case AdvancementStrategy::LOOP_ALL_CUTS:
502 // go to previous cut
503 _currentCutIndex--;
504 case AdvancementStrategy::LOOP_SINGLE_CUT:
505 // go to end of current cut, which is the frame before the next cut
506 _currentFrameIndex = _cutPositions[ _currentCutIndex+1 ] - 1;
507 break;
508
509 case AdvancementStrategy::RUN_SINGLE_CUT:
510 // do nothing, at end and not looping nor advancing
511 return;
512 }
513 } else {
514 // in the middle of a cut, move backward
515 _currentFrameIndex--;
516 }
517 }
518 _updateCameraAttributesForCurrentFrame();
519}
520
521inline void CSCI441::MD5Camera::_updateCameraAttributesForCurrentFrame() {
522 // get and set camera position for current frame
523 mCameraPosition = _frames[_currentFrameIndex].cameraPosition;
524
525 // get and set camera orientation for current frame
526 // compute W of quaternion
527 glm::vec4 q(_frames[_currentFrameIndex].cameraQuaternion, 0.0f);
528 GLfloat t = 1.0f - (q.x * q.x) - (q.y * q.y) - (q.z * q.z);
529 if (t < 0.0f)
530 q.w = 0.0f;
531 else
532 q.w = -glm::sqrt(t);
533
534 // set direction and look at point
535 glm::vec3 defaultCameraDirection(0.0f, 0.0f, -1.0f);
536 glm::vec4 inverseQ(-q.x, -q.y, -q.z, q.w);
537 inverseQ = glm::normalize(inverseQ);
538
539 glm::vec4 tmp( (q.w * defaultCameraDirection.x) + (q.y * defaultCameraDirection.z) - (q.z * defaultCameraDirection.y),
540 (q.w * defaultCameraDirection.y) + (q.z * defaultCameraDirection.x) - (q.x * defaultCameraDirection.z),
541 (q.w * defaultCameraDirection.z) + (q.x * defaultCameraDirection.y) - (q.y * defaultCameraDirection.x),
542 -(q.w * defaultCameraDirection.x) - (q.y * defaultCameraDirection.y) - (q.z * defaultCameraDirection.z) );
543 glm::vec4 rotatedCameraDirection((tmp.x * inverseQ.w) + (tmp.w * inverseQ.x) + (tmp.y * inverseQ.z) - (tmp.z * inverseQ.y),
544 (tmp.y * inverseQ.w) + (tmp.w * inverseQ.y) + (tmp.z * inverseQ.x) - (tmp.x * inverseQ.z),
545 (tmp.z * inverseQ.w) + (tmp.w * inverseQ.z) + (tmp.x * inverseQ.y) - (tmp.y * inverseQ.x),
546 (tmp.w * inverseQ.w) - (tmp.x * inverseQ.x) - (tmp.y * inverseQ.y) - (tmp.z * inverseQ.z) );
547 mCameraDirection = glm::vec3( rotatedCameraDirection.x, rotatedCameraDirection.y, rotatedCameraDirection.z );
548 mCameraLookAtPoint = mCameraPosition + mCameraDirection;
549
550 // set up vector
551 glm::vec3 defaultCameraUpVector(0.0f, 1.0f, 0.0f);
552 glm::vec4 tmp2( (q.w * defaultCameraUpVector.x) + (q.y * defaultCameraUpVector.z) - (q.z * defaultCameraUpVector.y),
553 (q.w * defaultCameraUpVector.y) + (q.z * defaultCameraUpVector.x) - (q.x * defaultCameraUpVector.z),
554 (q.w * defaultCameraUpVector.z) + (q.x * defaultCameraUpVector.y) - (q.y * defaultCameraUpVector.x),
555 -(q.w * defaultCameraUpVector.x) - (q.y * defaultCameraUpVector.y) - (q.z * defaultCameraUpVector.z) );
556 glm::vec4 rotatedCameraUpVector((tmp2.x * inverseQ.w) + (tmp2.w * inverseQ.x) + (tmp2.y * inverseQ.z) - (tmp2.z * inverseQ.y),
557 (tmp2.y * inverseQ.w) + (tmp2.w * inverseQ.y) + (tmp2.z * inverseQ.x) - (tmp2.x * inverseQ.z),
558 (tmp2.z * inverseQ.w) + (tmp2.w * inverseQ.z) + (tmp2.x * inverseQ.y) - (tmp2.y * inverseQ.x),
559 (tmp2.w * inverseQ.w) - (tmp2.x * inverseQ.x) - (tmp2.y * inverseQ.y) - (tmp2.z * inverseQ.z) );
560 mCameraUpVector = glm::vec3(rotatedCameraUpVector.x, rotatedCameraUpVector.y, rotatedCameraUpVector.z);
561
562 // compute and set view matrix
563 computeViewMatrix();
564
565 // get and set field of view for perspective projection matrix
566 _fovy = _frames[_currentFrameIndex].fieldOfView;
567 mProjectionMatrix = glm::perspective(_fovy, _aspectRatio, _nearClipPlane, _farClipPlane);
568}
569
570#endif//CSCI441_MD5_CAMERA_HPP
Abstract Camera class to be placed (position and orientation) within our scene.
Abstract Class to represent a synthetic camera. The following methods must be overridden:
Definition: Camera.hpp:39
glm::mat4 mProjectionMatrix
stores the Projection Matrix
Definition: Camera.hpp:191
Camera & operator=(const Camera &)=default
assign a copy of an existing camera
A camera that implements the MD5Camera specification.
Definition: MD5Camera.hpp:29
MD5Camera & operator=(const MD5Camera &)
deep copy another MD5Camera
Definition: MD5Camera.hpp:207
~MD5Camera() override
delete cuts and frames
Definition: MD5Camera.hpp:233
AdvancementStrategy
what to do when the end of a cut is reached
Definition: MD5Camera.hpp:34
@ LOOP_SINGLE_CUT
run through just the initial specified cut, looping back to the beginning when the end is reached
@ LOOP_ALL_CUTS
run through all cuts beginning at initial specified cut, advancing to next cut when the end of the cu...
@ RUN_ALL_CUTS
run through all cuts beginning at initial specified cut, advancing to next cut when the end of the cu...
@ RUN_SINGLE_CUT
run through just the initial specified cut, stop when end is reached
void moveBackward(GLfloat unused) override
steps backward along the camera's view
Definition: MD5Camera.hpp:460
void recomputeOrientation() override
Uses theta, phi, & radius to update the camera's view matrix parameters. The camera orientation is co...
Definition: MD5Camera.hpp:100
void moveForward(GLfloat unused) override
steps forward along the camera's view
Definition: MD5Camera.hpp:406
MD5Camera()=delete
must create camera object from parameterized constructor
void log(const char *MSG,...)
log a message to both the standard output stream and file
Definition: LogUtils.hpp:116
void logError(const char *MSG,...)
log a message to both the standard error stream and file
Definition: LogUtils.hpp:128
CSCI441 Helper Functions for OpenGL.
Definition: ArcballCam.hpp:17