Files
GlutSTBMiniAudio-Template/src/main.cpp
Colton Staiduhar 6aba4de2f0 Fixed Linux Support
2026-03-25 16:39:11 -04:00

410 lines
10 KiB
C++
Executable File

// #############################################################################
// # 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 <glad/glad.h>
#define FREEGLUT_STATIC
#include <GL/freeglut.h>
#else
#include <GLUT/glut.h>
#endif
#include <miniaudio.h>
// STD
#include <iostream>
#include <math.h>
#include <stdio.h>
// Custom includes
#include <texture.h>
/**
* 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");
}