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