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