12#ifndef CSCI441_OPENGL_ENGINE_HPP
13#define CSCI441_OPENGL_ENGINE_HPP
18#ifdef CSCI441_USE_GLEW
24#include <GLFW/glfw3.h>
26#ifdef CSCI441_SCREENSHOT_IMPLEMENTATION
27#define STB_IMAGE_WRITE_IMPLEMENTATION
29#include <stb_image_write.h>
87 virtual
void run() = 0;
100 [[maybe_unused]] virtual
bool saveScreenshot(const
char* FILENAME) noexcept final;
122 [[maybe_unused]] [[nodiscard]]
virtual bool isExtensionEnabled(
const std::string EXT)
const noexcept final {
return _extensions.find(EXT) != _extensions.end(); }
144 [[maybe_unused]] [[nodiscard]]
virtual GLFWwindow*
getWindow() const noexcept final {
return mpWindow; }
154 [[nodiscard]]
virtual unsigned short getError() noexcept final {
155 const unsigned short storedErrorCode =
mErrorCode;
160 return storedErrorCode;
223 OpenGLEngine(
int OPENGL_MAJOR_VERSION,
int OPENGL_MINOR_VERSION,
int WINDOW_WIDTH,
int WINDOW_HEIGHT,
const char* WINDOW_TITLE,
bool WINDOW_RESIZABLE = GLFW_FALSE);
276 static void mErrorCallback(
const int error,
const char* DESCRIPTION) { fprintf(stderr,
"[ERROR]: %d\n\t%s\n", error, DESCRIPTION ); }
281 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) {
282 fprintf( stdout,
"[VERBOSE]: Debug Message (%d): source = %s, type = %s, severity = %s, message = %s\n",
284 CSCI441::OpenGLUtils::debugSourceToString(source),
285 CSCI441::OpenGLUtils::debugTypeToString(type),
286 CSCI441::OpenGLUtils::debugSeverityToString(severity),
393 void _setupGLFunctions();
394 void _cleanupGLFunctions() {}
397 void _moveFromSource(OpenGLEngine&);
402 std::set< std::string > _extensions;
408 const int OPENGL_MAJOR_VERSION,
409 const int OPENGL_MINOR_VERSION,
410 const int WINDOW_WIDTH,
411 const int WINDOW_HEIGHT,
412 const char* WINDOW_TITLE,
413 const bool WINDOW_RESIZABLE
415 mErrorCode(OPENGL_ENGINE_ERROR_NO_ERROR),
416 mOpenGLMajorVersion(OPENGL_MAJOR_VERSION),
417 mOpenGLMinorVersion(OPENGL_MINOR_VERSION),
418 mWindowWidth(WINDOW_WIDTH),
419 mWindowHeight(WINDOW_HEIGHT),
420 mWindowResizable(WINDOW_RESIZABLE),
421 mWindowTitle(nullptr),
423 _isInitialized(false),
435 mErrorCode(OPENGL_ENGINE_ERROR_NO_ERROR),
436 mOpenGLMajorVersion(0),
437 mOpenGLMinorVersion(0),
440 mWindowResizable(
false),
441 mWindowTitle(
nullptr),
443 _isInitialized(
false),
446 _moveFromSource(src);
456 _moveFromSource(src);
469void CSCI441::OpenGLEngine::_cleanupSelf()
471 delete[] mWindowTitle;
472 mWindowTitle =
nullptr;
476void CSCI441::OpenGLEngine::_moveFromSource(
482 mErrorCode = src.mErrorCode;
483 src.mErrorCode = OPENGL_ENGINE_ERROR_NO_ERROR;
485 mOpenGLMajorVersion = src.mOpenGLMajorVersion;
486 src.mOpenGLMajorVersion = 0;
488 mOpenGLMinorVersion = src.mOpenGLMinorVersion;
489 src.mOpenGLMinorVersion = 0;
491 mWindowWidth = src.mWindowWidth;
492 src.mWindowWidth = 0;
494 mWindowHeight = src.mWindowHeight;
495 src.mWindowHeight = 0;
497 mWindowResizable = src.mWindowResizable;
498 src.mWindowResizable =
false;
500 mWindowTitle = src.mWindowTitle;
501 src.mWindowTitle =
nullptr;
503 mpWindow = src.mpWindow;
504 src.mpWindow =
nullptr;
506 _isInitialized = src._isInitialized;
507 src._isInitialized =
false;
509 _isCleanedUp = src._isCleanedUp;
510 src._isCleanedUp =
false;
512 _extensions = std::move(src._extensions);
518 if( !_isInitialized ) {
520 fprintf(stdout,
"[INFO]: Using CSCI441 Library v%d.%d.%d.%d\n", CSCI441::VERSION_MAJOR, CSCI441::VERSION_MINOR, CSCI441::VERSION_REVISION, CSCI441::VERSION_PATCH);
530 if( mOpenGLMajorVersion > 4 || (mOpenGLMajorVersion == 4 && mOpenGLMinorVersion >= 3) ) {
532 int flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
533 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
535 glEnable(GL_DEBUG_OUTPUT);
536 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
537 glDebugMessageCallback(mDebugMessageCallback,
nullptr);
538 glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0,
nullptr, GL_TRUE );
542 CSCI441::OpenGLUtils::printOpenGLInfo();
550 _isInitialized =
true;
551 _isCleanedUp =
false;
552 if (DEBUG) fprintf(stdout,
"\n[INFO]: Setup complete\n");
558 const unsigned short ERROR_CODE
560 switch (ERROR_CODE) {
561 case OPENGL_ENGINE_ERROR_NO_ERROR:
return "No error";
562 case OPENGL_ENGINE_ERROR_GLFW_INIT:
return "Error initializing GLFW";
563 case OPENGL_ENGINE_ERROR_GLFW_WINDOW:
return "Error initializing GLFW window";
564 case OPENGL_ENGINE_ERROR_GLEW_INIT:
return "Error initializing GLEW";
565 case OPENGL_ENGINE_ERROR_GLAD_INIT:
return "Error initializing GLAD";
566 case OPENGL_ENGINE_ERROR_TAKE_SCREENSHOT:
return "Error saving screenshot";
567 default:
return "Unknown error code";
576 const std::string filename =
579 ?
"Screenshot_" + std::to_string(time(
nullptr)) +
".png"
585 glGetIntegerv(GL_VIEWPORT, viewport);
586 const GLsizei x = viewport[0], y = viewport[1], width = viewport[2], height = viewport[3];
589 constexpr int CHANNELS = 4;
590 const auto bytes =
new GLubyte[width*height*CHANNELS];
591 glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
593 stbi_flip_vertically_on_write(
true);
595 if( !stbi_write_png(filename.c_str(), width, height, CHANNELS, bytes, width*CHANNELS) ) {
596 fprintf(stderr,
"[ERROR]: Could not save screenshot\n");
597 mErrorCode = OPENGL_ENGINE_ERROR_TAKE_SCREENSHOT;
599 fprintf(stdout,
"[INFO]: Screenshot saved to %s\n", filename.c_str());
604 return (mErrorCode == OPENGL_ENGINE_ERROR_NO_ERROR);
613 glfwSetErrorCallback(mErrorCallback);
617 fprintf( stderr,
"[ERROR]: Could not initialize GLFW\n" );
618 mErrorCode = OPENGL_ENGINE_ERROR_GLFW_INIT;
620 if(DEBUG) fprintf( stdout,
"[INFO]: GLFW %d.%d.%d initialized\n", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION );
622 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, mOpenGLMajorVersion );
623 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, mOpenGLMinorVersion );
624 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
625 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
626 glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE );
627 glfwWindowHint(GLFW_RESIZABLE, mWindowResizable );
631 && (mOpenGLMajorVersion > 4 || (mOpenGLMajorVersion == 4 && mOpenGLMinorVersion >= 3)) ) {
632 glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT,
true);
636 mpWindow = glfwCreateWindow(mWindowWidth, mWindowHeight, mWindowTitle,
nullptr,
nullptr );
638 fprintf( stderr,
"[ERROR]: GLFW Window could not be created\n" );
640 mErrorCode = OPENGL_ENGINE_ERROR_GLFW_WINDOW;
642 if(DEBUG) fprintf( stdout,
"[INFO]: GLFW Window created\n" );
643 glfwMakeContextCurrent(mpWindow);
645 glfwSetInputMode(mpWindow, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
646 glfwSetWindowUserPointer(mpWindow, (
void*)
this);
647 glfwSetWindowSizeCallback(mpWindow, mWindowResizeCallback);
653void CSCI441::OpenGLEngine::_setupGLFunctions()
656#ifdef CSCI441_USE_GLEW
657 glewExperimental = GL_TRUE;
658 const GLenum glewResult = glewInit();
661 if( glewResult != GLEW_OK ) {
662 fprintf( stderr,
"[ERROR]: Error initializing GLEW\n");
663 fprintf( stderr,
"[ERROR]: %s\n",
reinterpret_cast<const char *
>(glewGetErrorString(glewResult)) );
664 mErrorCode = OPENGL_ENGINE_ERROR_GLEW_INIT;
667 fprintf(stdout,
"\n[INFO]: GLEW initialized\n");
668 fprintf(stdout,
"[INFO]: Using GLEW %s\n",
reinterpret_cast<const char *
>(glewGetString(GLEW_VERSION)));
672 int version = gladLoadGL(glfwGetProcAddress);
674 fprintf(stderr,
"Failed to initialize GLAD\n" );
675 mErrorCode = OPENGL_ENGINE_ERROR_GLAD_INIT;
679 fprintf(stdout,
"\n[INFO]: GLAD initialized\n");
680 fprintf(stdout,
"[INFO]: Loaded OpenGL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
685 if(mErrorCode == OPENGL_ENGINE_ERROR_NO_ERROR) {
686 GLint numExtensions = 0;
687 glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
688 for (
int i = 0; i < numExtensions; i++) {
689 _extensions.insert(
reinterpret_cast<const char *
>(glGetStringi(GL_EXTENSIONS, i)) );
697 if(DEBUG) fprintf( stdout,
"[INFO]: ...closing window...\n" );
698 glfwDestroyWindow(mpWindow );
700 if(DEBUG) fprintf( stdout,
"[INFO]: ...closing GLFW.....\n" );
707 if( !_isCleanedUp ) {
708 if (DEBUG) fprintf(stdout,
"\n[INFO]: Shutting down.......\n");
714 _cleanupGLFunctions();
716 if (DEBUG) fprintf(stdout,
"[INFO]: ..shut down complete!\n");
718 _isInitialized =
false;
728 const auto pEngine =
static_cast<OpenGLEngine *
>(glfwGetWindowUserPointer(pWindow));
735 if (DEBUG) fprintf(stdout,
"\n[INFO]: Removing old shaders...\n");
737 if (DEBUG) fprintf(stdout,
"\n[INFO]: Reloading shaders...\n");
739 if (DEBUG) fprintf(stdout,
"\n[INFO]: Shaders reloaded\n");
Helper functions to work with OpenGL 3.0+.
Abstract Class to run an OpenGL application. The following methods must be overridden:
Definition: OpenGLEngine.hpp:49
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:122
bool DEBUG
if information should be printed to console while running
Definition: OpenGLEngine.hpp:229
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:245
int mOpenGLMajorVersion
the major version of the requested OpenGL context
Definition: OpenGLEngine.hpp:240
static constexpr unsigned short OPENGL_ENGINE_ERROR_NO_ERROR
no error is present, everything is currently working
Definition: OpenGLEngine.hpp:166
virtual bool saveScreenshot(const char *FILENAME) noexcept final
Save a PNG screenshot of the viewport.
Definition: OpenGLEngine.hpp:572
virtual void setCurrentWindowSize(const int WINDOW_WIDTH, const int WINDOW_HEIGHT) final
Set the new window size.
Definition: OpenGLEngine.hpp:132
virtual void initialize()
Initialize everything needed for OpenGL Rendering. This includes in order: GLFW, function pointers,...
Definition: OpenGLEngine.hpp:516
virtual void shutdown()
Cleanup everything needed for OpenGL Rendering. This includes freeing memory for data used in: any Sc...
Definition: OpenGLEngine.hpp:705
virtual unsigned short getError() noexcept final
Return current value of error code and clear the error code back to no error.
Definition: OpenGLEngine.hpp:154
virtual void mSetupTextures()
override to register any textures with the GPU
Definition: OpenGLEngine.hpp:345
virtual int getWindowHeight() const noexcept final
Return the height of the window.
Definition: OpenGLEngine.hpp:136
virtual bool isDebuggingEnabled() const noexcept final
Returns if logging is enabled.
Definition: OpenGLEngine.hpp:115
static void mWindowResizeCallback(GLFWwindow *pWindow, int width, int height)
Definition: OpenGLEngine.hpp:723
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLAD_INIT
an error occurred while initializing GLAD
Definition: OpenGLEngine.hpp:182
virtual void mCleanupBuffers()
override to cleanup any buffer objects from the GPU
Definition: OpenGLEngine.hpp:367
virtual void mCleanupScene()
override to cleanup any scene specific information
Definition: OpenGLEngine.hpp:357
virtual void mCleanupShaders()
override to cleanup any shaders from the GPU
Definition: OpenGLEngine.hpp:372
virtual void mCleanupTextures()
override to cleanup any textures from the GPU
Definition: OpenGLEngine.hpp:362
bool mWindowResizable
if the GLFW window can be resized while open
Definition: OpenGLEngine.hpp:260
OpenGLEngine(const OpenGLEngine &)=delete
do not allow engines to be copied
static constexpr unsigned short OPENGL_ENGINE_ERROR_TAKE_SCREENSHOT
an error occurred while taking a screenshot
Definition: OpenGLEngine.hpp:186
virtual void turnDebuggingOn() noexcept final
Enable logging to command line.
Definition: OpenGLEngine.hpp:106
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLEW_INIT
an error occurred while initializing GLEW
Definition: OpenGLEngine.hpp:178
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_WINDOW
an error occurred while creating the GLFW window
Definition: OpenGLEngine.hpp:174
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:276
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:198
unsigned int mErrorCode
tracks the current status of the OpenGL engine via error codes
Definition: OpenGLEngine.hpp:234
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:281
char * mWindowTitle
the title of the GLFW window
Definition: OpenGLEngine.hpp:264
int mWindowHeight
the window height of the requested GLFW window
Definition: OpenGLEngine.hpp:255
virtual void setWindowShouldClose() final
Tell our engine's window to close.
Definition: OpenGLEngine.hpp:149
static constexpr unsigned short OPENGL_ENGINE_ERROR_SIZE
stores the number of unique error codes that can be generated
Definition: OpenGLEngine.hpp:202
virtual void mReloadShaders() final
calls mCleanupShaders() followed by mSetupShaders() to reload shader source code from file
Definition: OpenGLEngine.hpp:733
virtual void mSetupShaders()
override to register any shaders with the GPU
Definition: OpenGLEngine.hpp:333
GLFWwindow * mpWindow
pointer to the GLFW window object
Definition: OpenGLEngine.hpp:268
virtual void turnDebuggingOff() noexcept final
Disable logging to command line.
Definition: OpenGLEngine.hpp:111
static const char * getErrorStringDescription(unsigned short ERROR_CODE) noexcept
Returns a string describing what the error code corresponds to.
Definition: OpenGLEngine.hpp:557
virtual int getWindowWidth() const noexcept final
Return the width of the window.
Definition: OpenGLEngine.hpp:140
virtual void mSetupBuffers()
override to register any buffer objects with the GPU
Definition: OpenGLEngine.hpp:339
virtual ~OpenGLEngine()
cleans up our OpenGL Engine by destroying the OpenGL context, GLFW window, and cleaning up all GPU re...
Definition: OpenGLEngine.hpp:463
virtual void mCleanupGLFW()
Destroys the associated GLFW window and terminates the GLFW instance.
Definition: OpenGLEngine.hpp:695
int mWindowWidth
the window width of the requested GLFW window
Definition: OpenGLEngine.hpp:250
virtual void mCleanupOpenGL()
override to cleanup any specific OpenGL features
Definition: OpenGLEngine.hpp:377
static constexpr unsigned short OPENGL_ENGINE_ERROR_GLFW_INIT
an error occurred while initializing GLFW
Definition: OpenGLEngine.hpp:170
virtual void mSetupGLFW()
Used to setup everything GLFW related. This includes the OpenGL context and our window....
Definition: OpenGLEngine.hpp:608
virtual void mSetupScene()
override to setup any scene specific information
Definition: OpenGLEngine.hpp:351
static constexpr unsigned short OPENGL_ENGINE_ERROR_UNKNOWN
a new error that does not correspond to a predefined scenario has occurred
Definition: OpenGLEngine.hpp:190
virtual GLFWwindow * getWindow() const noexcept final
Return the window object.
Definition: OpenGLEngine.hpp:144
CSCI441 Helper Functions for OpenGL.
Definition: ArcballCam.hpp:17