// ############################################################################# // # main.cpp // ############################################################################# // # Written by Colton Staiduhar // # Date Created: 02/03/2025 // # Last Modification: 02/05/2025 // ############################################################################# // # Main Entry point for Cmake project, declare by the int main() function // ############################################################################# // # // # This is a simple demonstration of GLUT functioning using STB_Image.H for // # loading images and MiniAudio.h for playing audio. The repositories for // # these libraries can be found below. // # // # Miniaudio // # https://github.com/mackron/miniaudio // # // # STB_Image.h // # https://github.com/arizotaz/cmake_stb_image // # // ############################################################################# // # // # For GLUT/OpenGL, the operating system should have GLUT in some form already // # installed. However, freeglut exists as the modern implementation of GLUT. // # // # GLUT // # You're on your own for this, but here are some helpful implementation docs // # MacOS: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_drawing/opengl_drawing.html // # Windows & Linux: https://www.opengl.org/resources/libraries/glut/glut_downloads.php // # // # FreeGLUT: // # https://freeglut.sourceforge.net/docs/api.php // # // ############################################################################# // # // # This file will setup much of GLUT. Getting some output to the screen // # The following is executed: // # Create a windows with GLUT's API // # Create a display update timer // # Create Keyboard Interrupts // # Load textures the included Texture.H file // # Setup the audio engine from MiniAudio // # Declare the Main Loop funcitons // # Draw a sprite to the screen // # Texture said sprite with an image // # Rotate, move, and scale the sprite // # Apply translations via user keyboard input // # // ############################################################################# // Libraries #if defined(use_freeglut) #include #define FREEGLUT_STATIC #include #else #include #endif #include // STD #include #include #include // Custom includes #include /** * Function Prototypes */ // Basic Glut void ProcessKeys(unsigned char, int, int); void ProcessSpecialKeys(int, int, int); void MainLoop(); // Extended Functionality void UpdateViewPort(); void DrawSprite(); void LoadUserTextures(); // Miniaudio Engine Declaration void CreateAudioEngine(); ma_engine engine; // Miniaudio engine // Demo Program Variables float rotX, rotY, rotZ; float moveX, moveY; float scale = 1; bool rotPressed, movePressed, scalePressed; unsigned int texID; ma_sound musicSound; // Miniaudio sound object int lastWinW = 0, lastWinH = 0; bool running = true; void CloseCallBack() { running = false; } /** * Main Loop Timer * Wait 16.7ms then generate next frame (~60FPS) */ void GlutLoopTimer(int v) { // Runs the function specified in glutDisplayFunc glutPostRedisplay(); // Call the timer again in 16.7 seconds ~ 60 times per second glutTimerFunc(16.7, GlutLoopTimer, v); // Creates a frame delay that is counted in miliseconds } /** * Main entry point of the application */ int main(int argc, char** argv) { std::cout << "Starting"; fflush(stdout); int winW = 1280; int winH = 720; // Initialize GLUT glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB); // RGB mode // Setup then create the window glutInitWindowSize(winW, winH); // window size glutInitWindowPosition(0, 0); glutCreateWindow("Transform Example - Using Native Glut"); // This line only needs to run when glad is in use #if defined(use_freeglut) glutSetWindowTitle("Transform Example - using FreeGLUT"); if (!gladLoadGL()) { } #endif // Clear screen glClearColor(0.0, 0.0, 0.0, 1.0); // clear the window screen // Sets up the viewport UpdateViewPort(); // Calls the texture load method LoadUserTextures(); // Setup Audio Engine CreateAudioEngine(); // Play the music ma_sound_start(&musicSound); // Deplare the Main Loop Function // (Will be executed when glutPostRedisplay() is called in the timer) glutDisplayFunc(MainLoop); // Declare Keyboard Interupts glutKeyboardFunc(ProcessKeys); // Declare Special Keys Keyboard Interrupt glutSpecialFunc(ProcessSpecialKeys); #ifndef use_freeglut // Setup a timer to run the main loop at an interval // (This call will call the GlutLoopTimer() function immediately) glutTimerFunc(0, GlutLoopTimer, 0); #endif std::cout << "Started" << std::endl; fflush(stdout); // Start the Glut Loop (Calls the funtions above repeatedly) #if defined(use_freeglut) // FreeGlut allows for manual updating of the main loop // So we can call the main loop in a while loop and tell the loop when to stop // Tell FreeGlut to do nothing on window X press glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); // Run callback when window X is pressed glutCloseFunc(CloseCallBack); // Our loop, calls the funtion in glutDisplayFunc repeatedly until running = false while (running) glutMainLoopEvent(); #else // Start the Glut Loop (Calls the funtions above repeatedly) glutMainLoop(); #endif std::cout << "exited" << std::endl; fflush(stdout); return 0; } /** * Function to update the viewport to the size of the window */ void UpdateViewPort() { // Gets the window size int winW = glutGet(GLUT_WINDOW_WIDTH); int winH = glutGet(GLUT_WINDOW_HEIGHT); // Sets up OpenGL Matrix Mode glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Create projection type (Orthographic with size of window) glOrtho(-winW / 2, winW / 2, winH / 2, -winH / 2, -1000.0f, 1000.0f); // Clipping plane is set to 1000 behind camera and 1000 infront, this works because ortho is cool // Set last size to the new size lastWinW = winW; lastWinH = winH; } /** * The function set as the Keyboard Interrupt of GLUT * This function will be called whenever a keystrke is pressed by the user * This function suffers from key repeat */ void ProcessSpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_LEFT) { moveX = -10; movePressed = true; } if (key == GLUT_KEY_RIGHT) { moveX = 10; movePressed = true; } if (key == GLUT_KEY_UP) { moveY = 10; movePressed = true; } if (key == GLUT_KEY_DOWN) { moveY = -10; movePressed = true; } } /** * Processes Keys as characters instead of keys * IE when a is pressed, "key" is set to "a" instead of 65 */ void ProcessKeys(unsigned char key, int x, int y) { switch (key) { case 'q': rotX += 1; break; case 'w': rotY += 1; break; case 'e': rotZ += 1; break; case 'a': rotX -= 1; break; case 's': rotY -= 1; break; case 'd': rotZ -= 1; break; case 'p': scale += .1; break; case 'l': scale -= .1; break; case 27: // escape exit(0); } rotPressed = true; scalePressed = true; } /** * Creates the miniaudio engine * (Bare minimum to play a sound) */ void CreateAudioEngine() { ma_result result = ma_engine_init(NULL, &engine); if (result != MA_SUCCESS) { std::cout << "Failed to setup the miniaudio engine\n"; fflush(stdout); } // Play Test Sound ma_sound_init_from_file( &engine, RESOURCES_PATH "audio/CrazyLaPaint.mp3", 0, NULL, NULL, &musicSound); } /** * This is the main loop functions that was declared during window creation */ void MainLoop() { // Get the window size int winW = glutGet(GLUT_WINDOW_WIDTH); int winH = glutGet(GLUT_WINDOW_HEIGHT); // If Changed, update the view port if (winW != lastWinW || winH != lastWinH) { UpdateViewPort(); } // Clear the screen glClear(GL_COLOR_BUFFER_BIT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // If scale oneshot is set, scale the image if (scalePressed) { glScalef(scale, scale, scale); scalePressed = false; scale = 1; } // If rotation oneshot is set, rotate the image if (rotPressed) { glRotatef((GLfloat)rotX, 1.0, 0.0, 0.0); glRotatef((GLfloat)rotY, 0.0, 1.0, 0.0); glRotatef((GLfloat)rotZ, 0.0, 0.0, 1.0); rotPressed = false; rotX = rotY = rotZ = 0; } // If move oneshot is set, move the image and set move back to 0 if (movePressed) { glTranslatef(moveX, moveY, 0); movePressed = false; moveX = moveY = 0; } // Draws the image DrawSprite(); glFlush(); // Swap buffers to display the new frame glutSwapBuffers(); // With freeglut, we can trigger screen update right after we are done #if defined(use_freeglut) glutPostRedisplay(); #endif } /** * Our function to draw the image */ void DrawSprite() { // Set texture enviorment glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // Enable textures so OpenGL will apply the textures to the created object glEnable(GL_TEXTURE_2D); // Bind our texture glBindTexture(GL_TEXTURE_2D, texID); // Which texture // Create a polygon and apply textures to it glBegin(GL_POLYGON); { glTexCoord2f(0.0, 0.0); glVertex3f(-50, -50, 0); glTexCoord2f(1.0, 0.0); glVertex3f(50, -50, 0); glTexCoord2f(1.0, 1.0); glVertex3f(50, 50, 0); glTexCoord2f(0.0, 1.0); glVertex3f(-50, 50, 0); } glEnd(); // Disable textures so you dont continue adding textures to other objects glDisable(GL_TEXTURE_2D); // Turn texturing off } /** * Just loads a bunch of textures */ void LoadUserTextures() { /* We add RESOURCES_PATH to the front of the filename RESOURCES_PATH is the absolute path of the resources folder on the computer when the application is build for production it turns into a relative path */ texID = LoadTexture(RESOURCES_PATH "container.jpg"); }