diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed68aea --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.DS_Store +.vscode/ +build/ +thirdparty/ +CMakeFiles/ +CmakeCache.txt +cmake_install.cmake +Makefile +GSM_TEMPLATE \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..4a098b8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,113 @@ +# This cmake configuration was originally created by meemknight on github +# https://github.com/meemknight/cmakeSetup +# It has been modified for use in this repository by Colton Staiduhar + +cmake_minimum_required(VERSION 3.16) + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Release>") + +# Declare Project where "GSM_TEMPLATE" is the project name +project(GSM_TEMPLATE LANGUAGES C CXX) + +# Allow cmake to fetch web repositories +include(FetchContent) + +# Set the location for downloaded libraries +set(THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty") +set(FETCHCONTENT_BASE_DIR "${THIRDPARTY_DIR}") + +# Fetch the miniaudio Repository and install it +FetchContent_Declare( + miniaudio + GIT_REPOSITORY git@github.com:mackron/miniaudio.git + GIT_TAG "master" + GIT_SHALLOW TRUE + GIT_PROGRESS ON + SYSTEM +) +FetchContent_MakeAvailable(miniaudio) + +# Fetch the STB-Image Repository and install it +FetchContent_Declare( + stb_image + GIT_REPOSITORY git@github.com:arizotaz/cmake_stb_image + GIT_TAG "master" + GIT_SHALLOW TRUE + GIT_PROGRESS ON + SYSTEM +) +FetchContent_MakeAvailable(stb_image) + + +# Tell Cmake to find the locations of libraries +find_package(OpenGL REQUIRED) +find_package(GLUT REQUIRED) + +# Define MY_SOURCES to be a list of all the source files for my game +file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + + +add_executable("${CMAKE_PROJECT_NAME}") + +# Set the C++ standard to 17 +set_property(TARGET "${CMAKE_PROJECT_NAME}" PROPERTY CXX_STANDARD 17) + +#======================================================================================== +# CHANGE RESOURCES DEFINITION +#======================================================================================== +# You will change which line is commented depending +# on if the compiled binary is for development or +# production. +# +# Uncomment the line below when in development, this uses the resources folder +# in the CMake project for the RESOURCES_PATH definition +target_compile_definitions("${CMAKE_PROJECT_NAME}" PUBLIC RESOURCES_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/") +# +# Uncomment the line below when in production, this uses a folder in the same working +# directory of the binary called "resources". Effectively RESOURCES_PATH +# becomes ./resources/. You would copy the resources folder of the cmake project +# and ship it will the compiled binary +#target_compile_definitions("${CMAKE_PROJECT_NAME}" PUBLIC RESOURCES_PATH="./resources/") +# + + + + +# Add our sources +target_sources("${CMAKE_PROJECT_NAME}" PRIVATE ${MY_SOURCES} ) + +# If using the VS compiler +if(MSVC) + + target_compile_definitions("${CMAKE_PROJECT_NAME}" PUBLIC _CRT_SECURE_NO_WARNINGS) + + #remove console + #set_target_properties("${CMAKE_PROJECT_NAME}" PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") + + set_property(TARGET "${CMAKE_PROJECT_NAME}" PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDebug<$:Debug>") + set_property(TARGET "${CMAKE_PROJECT_NAME}" PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Release>") + +endif() + +# Add our include files +target_include_directories("${CMAKE_PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/") + +# Disable different warning (Glut is really old, we already know that) +target_compile_options("${CMAKE_PROJECT_NAME}" + PRIVATE + -Wno-deprecated-declarations + -Wdelete-incomplete + $<$:-Wno-pedantic -Wno-macro-redefined> +) + +# Include the libraries loaded earlier +target_link_libraries("${CMAKE_PROJECT_NAME}" + PRIVATE + OpenGL::GL + "-framework GLUT" + "-lpthread" + "-lm" + stb_image + miniaudio +) diff --git a/README.md b/README.md index 8da275b..5b88c4b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # GlutSTBMiniAudio-Template +To compile the project +``` +cmake .; make; ./GSM_TEMPLATE +``` \ No newline at end of file diff --git a/include/texture.h b/include/texture.h new file mode 100644 index 0000000..6bcd5b4 --- /dev/null +++ b/include/texture.h @@ -0,0 +1,37 @@ +//############################################################################# +//# texture.h +//############################################################################# +//# Written by Colton Staiduhar +//# Date Created: 02/05/2025 +//# Last Modification: 02/05/2025 +//############################################################################# +//# This file serves as simple, yet functional example of how to use the +//# include directory of this project +//############################################################################# +//# This header exposses the LoadTexture function of this project. +//# Usage: +//# unsigned int textureID = LoadTexture(fileURL); +//# +//# Where textureID is the returned OpenGL texture ID that can be bounded +//# +//############################################################################# +#ifndef TEXTURES_H +#define TEXTRUES_H + + +/** + * Loads a texture for use in OpenGL with STB + * + * Usage: + * unsigned int textureID = LoadTexture(fileURL) + * + * textureID - the generated OpenGL Texture ID + * + * Bind texture with + * glBindTexture(GL_TEXTURE_2D, textureID); + + */ +unsigned int LoadTexture(char *location); + + +#endif \ No newline at end of file diff --git a/resources/audio/CrazyLaPaint.mp3 b/resources/audio/CrazyLaPaint.mp3 new file mode 100644 index 0000000..0ca83f6 Binary files /dev/null and b/resources/audio/CrazyLaPaint.mp3 differ diff --git a/resources/container.jpg b/resources/container.jpg new file mode 100755 index 0000000..0b7c87f Binary files /dev/null and b/resources/container.jpg differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100755 index 0000000..3fa3dd4 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,377 @@ +//############################################################################# +//# 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 +#include +#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(); +void GlutLoopTimer(int); + +// 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; + +/** + * Main entry point of the application + */ +int main(int argc, char **argv) +{ + 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"); + + // 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); + + // Setup a timer to run the main loop at an interval + // (This call will call the GlutLoopTimer() function immediately) + glutTimerFunc(0, GlutLoopTimer, 0); + + // Start the Glut Loop (Calls the funtions above repeatedly) + glutMainLoop(); + + + return 0; +} + +/** + * 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 +} + +/** + * 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(); +} + +/** + * 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"); +} \ No newline at end of file diff --git a/src/texture.cpp b/src/texture.cpp new file mode 100644 index 0000000..bbc11d9 --- /dev/null +++ b/src/texture.cpp @@ -0,0 +1,70 @@ +//############################################################################# +//# texture.cpp +//############################################################################# +//# Written by Colton Staiduhar +//# Date Created: 02/05/2025 +//# Last Modification: 02/05/2025 +//############################################################################# +//# Super simple OpenGL texture loading using the stb_image.h library +//############################################################################# +//# This file provides sources of the functions listed in Texture.h +//############################################################################# + + +// Include STB +#include +#define STB_IMAGE_IMPLEMENTATION +#include + +// Header file for functions defined here +#include + +/** + * Loads a texture for use in OpenGL with STB + */ +unsigned int LoadTexture(char *location) +{ + // These will be filled with attributes of the file once loaded + int w, // Width of image + h, // Height of image + bpp; // Number of color channels in the image + + // Load the image and save raw pixel data as unsigned bytes + unsigned char *pixels = stbi_load(location, &w, &h, &bpp, 3); + + // Declare our texture, this will be filled with the texture ID + unsigned int texture; + + // Tell OpenGL to generate a texture slot and bind it to the current texture + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + // These are option values, but they are nice to set + { + // Set OpenGL texture Wrapping + // I prefer CLAMP_TO_EDGE but GL_REPEAT works too, look up the different OpenGL Texture Wrap Types + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // Set the type of Texture Filtering + // "GL_LINEAR" is default, I like GL_NEAREST. Again, look up all the options + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + // If the loaded pixel data is value + if (pixels) + { + // Load the texture data into the currently bound texture slot + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); + + // Generate the mipmap cause why not + glGenerateMipmap(GL_TEXTURE_2D); + } + + // Frees the image data stored in ram from stb + stbi_image_free(pixels); + + // Return the texture ID + return texture; +} \ No newline at end of file