CSCI441 OpenGL Library 5.17.0
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
OpenGLEngine.hpp
Go to the documentation of this file.
1
12#ifndef CSCI441_OPENGL_ENGINE_HPP
13#define CSCI441_OPENGL_ENGINE_HPP
14
15#include "constants.h"
16#include "OpenGLUtils.hpp"
17
18#ifdef CSCI441_USE_GLEW
19 #include <GL/glew.h>
20#else
21 #include <glad/gl.h>
22#endif
23
24#include <GLFW/glfw3.h>
25
26#include <cstdio>
27#include <cstring>
28#include <set>
29#include <string>
30
31namespace CSCI441 {
32
41 public:
45 OpenGLEngine(const OpenGLEngine&) = delete;
50
54 OpenGLEngine(OpenGLEngine&&) noexcept;
59 OpenGLEngine& operator=(OpenGLEngine&&) noexcept;
60
65 virtual ~OpenGLEngine();
66
74 virtual void initialize();
78 virtual void run() = 0;
86 virtual void shutdown();
87
92 [[maybe_unused]] virtual void turnDebuggingOn() noexcept final { DEBUG = true; }
97 virtual void turnDebuggingOff() noexcept final { DEBUG = false; }
101 [[maybe_unused]] [[nodiscard]] virtual bool isDebuggingEnabled() const noexcept final { return DEBUG; }
102
108 [[maybe_unused]] [[nodiscard]] virtual bool isExtensionEnabled(const std::string EXT) const noexcept final { return _extensions.find(EXT) != _extensions.end(); }
109
118 virtual void setCurrentWindowSize(const int WINDOW_WIDTH, const int WINDOW_HEIGHT) final { mWindowWidth = WINDOW_WIDTH; mWindowHeight = WINDOW_HEIGHT; }
122 [[maybe_unused]] [[nodiscard]] virtual int getWindowHeight() const noexcept final { return mWindowHeight; }
126 [[maybe_unused]] [[nodiscard]] virtual int getWindowWidth() const noexcept final { return mWindowWidth; }
130 [[maybe_unused]] [[nodiscard]] virtual GLFWwindow* getWindow() const noexcept final { return mpWindow; }
131
135 [[maybe_unused]] virtual void setWindowShouldClose() final { glfwSetWindowShouldClose(mpWindow, GLFW_TRUE); }
136
140 [[nodiscard]] virtual unsigned short getError() noexcept final {
141 const unsigned short storedErrorCode = mErrorCode; // store current error code
142 mErrorCode = OPENGL_ENGINE_ERROR_NO_ERROR; // reset error code
143 return storedErrorCode; // return previously stored error code
144 }
145
149 static constexpr unsigned short OPENGL_ENGINE_ERROR_NO_ERROR = 0;
153 static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_INIT = 1;
157 static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_WINDOW = 2;
161 static constexpr unsigned short OPENGL_ENGINE_ERROR_GLEW_INIT = 3;
165 static constexpr unsigned short OPENGL_ENGINE_ERROR_GLAD_INIT = 4;
169 static constexpr unsigned short OPENGL_ENGINE_ERROR_UNKNOWN = 5;
170 // note to developers: if more error codes are added, need to update LAST accordingly or
171 // update UNKNOWN to the last value and shift
176 static constexpr unsigned short OPENGL_ENGINE_ERROR_LAST = OPENGL_ENGINE_ERROR_UNKNOWN;
180 [[maybe_unused]] static constexpr unsigned short OPENGL_ENGINE_ERROR_SIZE = OPENGL_ENGINE_ERROR_LAST + 1;
181
182 protected:
194 OpenGLEngine(int OPENGL_MAJOR_VERSION, int OPENGL_MINOR_VERSION, int WINDOW_WIDTH, int WINDOW_HEIGHT, const char* WINDOW_TITLE, bool WINDOW_RESIZABLE = GLFW_FALSE);
195
200 bool DEBUG;
201
205 unsigned int mErrorCode;
206
239 GLFWwindow* mpWindow;
240
247 static void mErrorCallback(const int error, const char* DESCRIPTION) { fprintf(stderr, "[ERROR]: %d\n\t%s\n", error, DESCRIPTION ); }
248
252 static void APIENTRY mDebugMessageCallback(const GLenum source, const GLenum type, const GLuint id, const GLenum severity, const GLsizei length, const GLchar* message, const void* userParam) {
253 fprintf( stdout, "[VERBOSE]: Debug Message (%d): source = %s, type = %s, severity = %s, message = %s\n",
254 id,
255 CSCI441::OpenGLUtils::debugSourceToString(source),
256 CSCI441::OpenGLUtils::debugTypeToString(type),
257 CSCI441::OpenGLUtils::debugSeverityToString(severity),
258 message
259 );
260 }
261
269 static void mWindowResizeCallback(GLFWwindow* pWindow, int width, int height);
270
290 virtual void mSetupGLFW();
297 virtual void mSetupOpenGL() = 0;
304 virtual void mSetupShaders() {};
310 virtual void mSetupBuffers() {};
316 virtual void mSetupTextures() {}
322 virtual void mSetupScene() {};
323
328 virtual void mCleanupScene() {};
333 virtual void mCleanupTextures() {}
338 virtual void mCleanupBuffers() {};
343 virtual void mCleanupShaders() {};
348 virtual void mCleanupOpenGL() {};
355 virtual void mCleanupGLFW();
356
361 virtual void mReloadShaders() final;
362
363 private:
364 void _setupGLFunctions(); // initialize OpenGL functions
365 void _cleanupGLFunctions() {} // nothing to be done at this time
366
367 void _cleanupSelf(); // delete internal memory
368 void _moveFromSource(OpenGLEngine&);// move members from another instance
369
370 bool _isInitialized; // makes initialization a singleton process
371 bool _isCleanedUp; // makes cleanup a singleton process
372
373 std::set< std::string > _extensions;// set of all available OpenGL extensions
374 };
375}
376
378 const int OPENGL_MAJOR_VERSION,
379 const int OPENGL_MINOR_VERSION,
380 const int WINDOW_WIDTH,
381 const int WINDOW_HEIGHT,
382 const char* WINDOW_TITLE,
383 const bool WINDOW_RESIZABLE
384) : DEBUG(true),
385 mErrorCode(OPENGL_ENGINE_ERROR_NO_ERROR),
386 mOpenGLMajorVersion(OPENGL_MAJOR_VERSION),
387 mOpenGLMinorVersion(OPENGL_MINOR_VERSION),
388 mWindowWidth(WINDOW_WIDTH),
389 mWindowHeight(WINDOW_HEIGHT),
390 mWindowResizable(WINDOW_RESIZABLE),
391 mWindowTitle(nullptr),
392 mpWindow(nullptr),
393 _isInitialized(false),
394 _isCleanedUp(false)
395{
396 mWindowTitle = new char[ strlen(WINDOW_TITLE) ];
397 strcpy(mWindowTitle, WINDOW_TITLE);
398}
399
402) noexcept :
403 DEBUG(true),
404 mErrorCode(OPENGL_ENGINE_ERROR_NO_ERROR),
405 mOpenGLMajorVersion(0),
406 mOpenGLMinorVersion(0),
407 mWindowWidth(0),
408 mWindowHeight(0),
409 mWindowResizable(false),
410 mWindowTitle(nullptr),
411 mpWindow(nullptr),
412 _isInitialized(false),
413 _isCleanedUp(false)
414{
415 _moveFromSource(src);
416}
417
419 if (this != &src) {
420 _cleanupSelf();
421 _moveFromSource(src);
422 }
423 return *this;
424}
425
426
428 _cleanupSelf();
429}
430
431inline void CSCI441::OpenGLEngine::_cleanupSelf() {
432 delete[] mWindowTitle;
433 mWindowTitle = nullptr;
434}
435
436inline void CSCI441::OpenGLEngine::_moveFromSource(OpenGLEngine& src) {
437 DEBUG = src.DEBUG;
438 src.DEBUG = false;
439
440 mErrorCode = src.mErrorCode;
441 src.mErrorCode = OPENGL_ENGINE_ERROR_NO_ERROR;
442
443 mOpenGLMajorVersion = src.mOpenGLMajorVersion;
444 src.mOpenGLMajorVersion = 0;
445
446 mOpenGLMinorVersion = src.mOpenGLMinorVersion;
447 src.mOpenGLMinorVersion = 0;
448
449 mWindowWidth = src.mWindowWidth;
450 src.mWindowWidth = 0;
451
452 mWindowHeight = src.mWindowHeight;
453 src.mWindowHeight = 0;
454
455 mWindowResizable = src.mWindowResizable;
456 src.mWindowResizable = false;
457
458 mWindowTitle = src.mWindowTitle;
459 src.mWindowTitle = nullptr;
460
461 mpWindow = src.mpWindow;
462 src.mpWindow = nullptr;
463
464 _isInitialized = src._isInitialized;
465 src._isInitialized = false;
466
467 _isCleanedUp = src._isCleanedUp;
468 src._isCleanedUp = false;
469
470 _extensions = std::move(src._extensions);
471}
472
474 if( !_isInitialized ) {
475 if (DEBUG) {
476 fprintf(stdout, "[INFO]: Using CSCI441 Library v%d.%d.%d\n", CSCI441::VERSION_MAJOR, CSCI441::VERSION_MINOR, CSCI441::VERSION_PATCH);
477 }
478
479 mSetupGLFW(); // initialize GLFW and set up a window
480 _setupGLFunctions(); // create OpenGL function pointers
481 mSetupOpenGL(); // create the OpenGL context
482
483 // get OpenGL context information
484 if( DEBUG ) {
485 // if wanting debug information with Version 4.3 or higher
486 if( mOpenGLMajorVersion > 4 || (mOpenGLMajorVersion == 4 && mOpenGLMinorVersion >= 3) ) {
487 // check if debug context was created
488 int flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
489 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
490 // register callback to synchronously print any debug messages without having to call glGetError()
491 glEnable(GL_DEBUG_OUTPUT);
492 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
493 glDebugMessageCallback(mDebugMessageCallback, nullptr);
494 glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE );
495 }
496 }
497
498 CSCI441::OpenGLUtils::printOpenGLInfo();
499 }
500
501 mSetupShaders(); // transfer, compile, link shaders on GPU
502 mSetupBuffers(); // register Buffers on GPU
503 mSetupTextures(); // register Textures on GPU
504 mSetupScene(); // setup any scene specific information
505
506 _isInitialized = true;
507 _isCleanedUp = false;
508 if (DEBUG) fprintf(stdout, "\n[INFO]: Setup complete\n");
509 }
510}
511
513 // set what function to use when registering errors
514 // this is the ONLY GLFW function that can be called BEFORE GLFW is initialized
515 // all other GLFW calls must be performed after GLFW has been initialized
516 glfwSetErrorCallback(mErrorCallback);
517
518 // initialize GLFW
519 if( !glfwInit() ) {
520 fprintf( stderr, "[ERROR]: Could not initialize GLFW\n" );
521 mErrorCode = OPENGL_ENGINE_ERROR_GLFW_INIT;
522 } else {
523 if(DEBUG) fprintf( stdout, "[INFO]: GLFW %d.%d.%d initialized\n", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION );
524
525 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, mOpenGLMajorVersion ); // request OpenGL vX.
526 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, mOpenGLMinorVersion ); // request OpenGL v .X
527 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE ); // request forward compatible OpenGL context
528 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE ); // request OpenGL Core Profile context
529 glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE ); // request double buffering
530 glfwWindowHint(GLFW_RESIZABLE, mWindowResizable ); // set if our window should be able to be resized
531
532 // if wanting debug information with Version 4.3 or higher
533 if( DEBUG
534 && (mOpenGLMajorVersion > 4 || (mOpenGLMajorVersion == 4 && mOpenGLMinorVersion >= 3)) ) {
535 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true); // request a debug context
536 }
537
538 // create a window for a given size, with a given title
539 mpWindow = glfwCreateWindow(mWindowWidth, mWindowHeight, mWindowTitle, nullptr, nullptr );
540 if( !mpWindow ) { // if the window could not be created, NULL is returned
541 fprintf( stderr, "[ERROR]: GLFW Window could not be created\n" );
542 glfwTerminate();
543 mErrorCode = OPENGL_ENGINE_ERROR_GLFW_WINDOW;
544 } else {
545 if(DEBUG) fprintf( stdout, "[INFO]: GLFW Window created\n" );
546 glfwMakeContextCurrent(mpWindow); // make the created window the current window
547 glfwSwapInterval(1); // update our screen after at least 1 screen refresh
548 glfwSetInputMode(mpWindow, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // track state of Caps Lock and Num Lock keys
549 glfwSetWindowUserPointer(mpWindow, (void*)this);
550 glfwSetWindowSizeCallback(mpWindow, mWindowResizeCallback);
551 }
552 }
553}
554
555inline void CSCI441::OpenGLEngine::_setupGLFunctions() {
556
557#ifdef CSCI441_USE_GLEW
558 glewExperimental = GL_TRUE;
559 const GLenum glewResult = glewInit(); // initialize GLEW
560
561 // check for an error
562 if( glewResult != GLEW_OK ) {
563 fprintf( stderr, "[ERROR]: Error initializing GLEW\n");
564 fprintf( stderr, "[ERROR]: %s\n", reinterpret_cast<const char *>(glewGetErrorString(glewResult)) );
565 mErrorCode = OPENGL_ENGINE_ERROR_GLEW_INIT;
566 } else {
567 if(DEBUG) {
568 fprintf(stdout, "\n[INFO]: GLEW initialized\n");
569 fprintf(stdout, "[INFO]: Using GLEW %s\n", reinterpret_cast<const char *>(glewGetString(GLEW_VERSION)));
570 }
571 }
572#else
573 int version = gladLoadGL(glfwGetProcAddress);
574 if(version == 0) {
575 fprintf(stderr, "Failed to initialize GLAD\n" );
576 mErrorCode = OPENGL_ENGINE_ERROR_GLAD_INIT;
577 } else {
578 if(DEBUG) {
579 // Successfully loaded OpenGL
580 fprintf(stdout, "\n[INFO]: GLAD initialized\n");
581 fprintf(stdout, "[INFO]: Loaded OpenGL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
582 }
583 }
584#endif
585
586 if(mErrorCode == OPENGL_ENGINE_ERROR_NO_ERROR) {
587 GLint numExtensions = 0;
588 glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
589 for (int i = 0; i < numExtensions; i++) {
590 _extensions.insert(reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i)) );
591 }
592 }
593}
594
596 if(DEBUG) fprintf( stdout, "[INFO]: ...closing window...\n" );
597 glfwDestroyWindow(mpWindow ); // close our window
598 mpWindow = nullptr;
599 if(DEBUG) fprintf( stdout, "[INFO]: ...closing GLFW.....\n" );
600 glfwTerminate();
601}
602
604 if( !_isCleanedUp ) {
605 if (DEBUG) fprintf(stdout, "\n[INFO]: Shutting down.......\n");
606 mCleanupShaders(); // delete shaders from GPU
607 mCleanupBuffers(); // delete VAOs/VBOs from GPU
608 mCleanupTextures(); // delete textures from GPU
609 mCleanupScene(); // delete scene info from CPU
610 mCleanupOpenGL(); // cleanup anything OpenGL related
611 _cleanupGLFunctions(); // cleanup anything function pointer related
612 mCleanupGLFW(); // shut down GLFW to clean up our context
613 if (DEBUG) fprintf(stdout, "[INFO]: ..shut down complete!\n");
614 _isCleanedUp = true;
615 _isInitialized = false;
616 }
617}
618
619inline void CSCI441::OpenGLEngine::mWindowResizeCallback(GLFWwindow* pWindow, const int width, const int height) {
620 const auto pEngine = static_cast<OpenGLEngine *>(glfwGetWindowUserPointer(pWindow));
621 pEngine->setCurrentWindowSize(width, height);
622}
623
625 if (DEBUG) fprintf(stdout, "\n[INFO]: Removing old shaders...\n");
626 mCleanupShaders();
627 if (DEBUG) fprintf(stdout, "\n[INFO]: Reloading shaders...\n");
628 mSetupShaders();
629 if (DEBUG) fprintf(stdout, "\n[INFO]: Shaders reloaded\n");
630}
631
632#endif //CSCI441_OPENGL_ENGINE_HPP
Helper functions to work with OpenGL 3.0+.
Abstract Class to run an OpenGL application. The following methods must be overridden:
Definition: OpenGLEngine.hpp:40
virtual void mSetupOpenGL()=0
override to enable specific OpenGL features
virtual bool isExtensionEnabled(const std::string EXT) const noexcept final
Returns if OpenGL extension exists.
Definition: OpenGLEngine.hpp:108
bool DEBUG
if information should be printed to console while running
Definition: OpenGLEngine.hpp:200
OpenGLEngine & operator=(const OpenGLEngine &)=delete
do not allow engines to be copied
int mOpenGLMinorVersion
the minor version of the requested OpenGL context
Definition: OpenGLEngine.hpp:216
int mOpenGLMajorVersion
the major version of the requested OpenGL context
Definition: OpenGLEngine.hpp:211
static constexpr unsigned short OPENGL_ENGINE_ERROR_NO_ERROR
no error is present, everything is currently working
Definition: OpenGLEngine.hpp:149
virtual void setCurrentWindowSize(const int WINDOW_WIDTH, const int WINDOW_HEIGHT) final
Set the new window size.
Definition: OpenGLEngine.hpp:118
virtual void initialize()
Initialize everything needed for OpenGL Rendering. This includes in order: GLFW, function pointers,...
Definition: OpenGLEngine.hpp:473
virtual void shutdown()
Cleanup everything needed for OpenGL Rendering. This includes freeing memory for data used in: any Sc...
Definition: OpenGLEngine.hpp:603
virtual unsigned short getError() noexcept final
Return current value of error code and clear the error code back to no error.
Definition: OpenGLEngine.hpp:140
virtual void mSetupTextures()
override to register any textures with the GPU
Definition: OpenGLEngine.hpp:316
virtual int getWindowHeight() const noexcept final
Return the height of the window.
Definition: OpenGLEngine.hpp:122
virtual bool isDebuggingEnabled() const noexcept final
Returns if logging is enabled.
Definition: OpenGLEngine.hpp:101
static void mWindowResizeCallback(GLFWwindow *pWindow, int width, int height)
Definition: OpenGLEngine.hpp:619
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLAD_INIT
an error occurred while initializing GLAD
Definition: OpenGLEngine.hpp:165
virtual void mCleanupBuffers()
override to cleanup any buffer objects from the GPU
Definition: OpenGLEngine.hpp:338
virtual void mCleanupScene()
override to cleanup any scene specific information
Definition: OpenGLEngine.hpp:328
virtual void mCleanupShaders()
override to cleanup any shaders from the GPU
Definition: OpenGLEngine.hpp:343
virtual void mCleanupTextures()
override to cleanup any textures from the GPU
Definition: OpenGLEngine.hpp:333
bool mWindowResizable
if the GLFW window can be resized while open
Definition: OpenGLEngine.hpp:231
OpenGLEngine(const OpenGLEngine &)=delete
do not allow engines to be copied
virtual void turnDebuggingOn() noexcept final
Enable logging to command line.
Definition: OpenGLEngine.hpp:92
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLEW_INIT
an error occurred while initializing GLEW
Definition: OpenGLEngine.hpp:161
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_WINDOW
an error occurred while creating the GLFW window
Definition: OpenGLEngine.hpp:157
static void mErrorCallback(const int error, const char *DESCRIPTION)
We will register this function as GLFW's error callback. When an error within OpenGL occurs,...
Definition: OpenGLEngine.hpp:247
static constexpr unsigned short OPENGL_ENGINE_ERROR_LAST
stores the error code number of the last possible error, this corresponds to the max error code value...
Definition: OpenGLEngine.hpp:176
unsigned int mErrorCode
tracks the current status of the OpenGL engine via error codes
Definition: OpenGLEngine.hpp:205
virtual void run()=0
Initiate the draw loop.
static void APIENTRY mDebugMessageCallback(const GLenum source, const GLenum type, const GLuint id, const GLenum severity, const GLsizei length, const GLchar *message, const void *userParam)
callback called whenever a debug message is signaled
Definition: OpenGLEngine.hpp:252
char * mWindowTitle
the title of the GLFW window
Definition: OpenGLEngine.hpp:235
int mWindowHeight
the window height of the requested GLFW window
Definition: OpenGLEngine.hpp:226
virtual void setWindowShouldClose() final
Tell our engine's window to close.
Definition: OpenGLEngine.hpp:135
static constexpr unsigned short OPENGL_ENGINE_ERROR_SIZE
stores the number of unique error codes that can be generated
Definition: OpenGLEngine.hpp:180
virtual void mReloadShaders() final
calls mCleanupShaders() followed by mSetupShaders() to reload shader source code from file
Definition: OpenGLEngine.hpp:624
virtual void mSetupShaders()
override to register any shaders with the GPU
Definition: OpenGLEngine.hpp:304
GLFWwindow * mpWindow
pointer to the GLFW window object
Definition: OpenGLEngine.hpp:239
virtual void turnDebuggingOff() noexcept final
Disable logging to command line.
Definition: OpenGLEngine.hpp:97
virtual int getWindowWidth() const noexcept final
Return the width of the window.
Definition: OpenGLEngine.hpp:126
virtual void mSetupBuffers()
override to register any buffer objects with the GPU
Definition: OpenGLEngine.hpp:310
virtual ~OpenGLEngine()
cleans up our OpenGL Engine by destroying the OpenGL context, GLFW window, and cleaning up all GPU re...
Definition: OpenGLEngine.hpp:427
virtual void mCleanupGLFW()
Destroys the associated GLFW window and terminates the GLFW instance.
Definition: OpenGLEngine.hpp:595
int mWindowWidth
the window width of the requested GLFW window
Definition: OpenGLEngine.hpp:221
virtual void mCleanupOpenGL()
override to cleanup any specific OpenGL features
Definition: OpenGLEngine.hpp:348
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_INIT
an error occurred while initializing GLFW
Definition: OpenGLEngine.hpp:153
virtual void mSetupGLFW()
Used to setup everything GLFW related. This includes the OpenGL context and our window....
Definition: OpenGLEngine.hpp:512
virtual void mSetupScene()
override to setup any scene specific information
Definition: OpenGLEngine.hpp:322
static constexpr unsigned short OPENGL_ENGINE_ERROR_UNKNOWN
a new error that does not correspond to a predefined scenario has occurred
Definition: OpenGLEngine.hpp:169
virtual GLFWwindow * getWindow() const noexcept final
Return the window object.
Definition: OpenGLEngine.hpp:130
CSCI441 Helper Functions for OpenGL.
Definition: ArcballCam.hpp:17