FreeGlut MacOS Support

This commit is contained in:
Colton Staiduhar
2026-02-17 21:22:16 -05:00
parent a3bac40258
commit ad2175b9a6
2 changed files with 342 additions and 271 deletions

View File

@@ -10,6 +10,9 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# Declare Project where "GSM_TEMPLATE" is the project name # Declare Project where "GSM_TEMPLATE" is the project name
project(GSM_TEMPLATE LANGUAGES C CXX) project(GSM_TEMPLATE LANGUAGES C CXX)
# Use FreeGlut on Macos (Requires X11 to be installed, but doesn't use it)
option(USE_FREEGLUT "Use FreeGLUT on Mac (ignored on Windows)" ON)
# Allow cmake to fetch web repositories # Allow cmake to fetch web repositories
include(FetchContent) include(FetchContent)
@@ -41,13 +44,28 @@ FetchContent_MakeAvailable(stb_image)
# If using the Windows compiler # If using the Windows compiler
if (MSVC) if (MSVC OR USE_FREEGLUT)
if (APPLE)
find_path(XQUARTZ_INCLUDE_DIR X11/Xlib.h
PATHS /opt/X11/include
NO_DEFAULT_PATH
)
if(NOT XQUARTZ_INCLUDE_DIR)
message(FATAL_ERROR "To use FreeGLUT on Mac, you need XQuartz installed. Please install it from https://www.xquartz.org/ or set the USE_FREEGLUT cache option to OFF")
endif()
endif()
set(CMAKE_POLICY_VERSION_MINIMUM 3.16)
# Download freeglut # Download freeglut
FetchContent_Declare( FetchContent_Declare(
freeglut freeglut
GIT_REPOSITORY https://github.com/freeglut/freeglut.git GIT_REPOSITORY https://github.com/freeglut/freeglut.git
GIT_TAG "master" GIT_TAG "v3.8.0"
GIT_SHALLOW TRUE GIT_SHALLOW TRUE
GIT_PROGRESS ON GIT_PROGRESS ON
) )
@@ -56,6 +74,11 @@ if (MSVC)
set(FREEGLUT_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(FREEGLUT_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(FREEGLUT_BUILD_STATIC_LIBS ON CACHE BOOL "" FORCE) set(FREEGLUT_BUILD_STATIC_LIBS ON CACHE BOOL "" FORCE)
# Force Cocca on Mac
if(APPLE)
set(FREEGLUT_USE_X11 OFF CACHE BOOL "" FORCE)
set(FREEGLUT_COCOA ON CACHE BOOL "" FORCE)
endif()
FetchContent_MakeAvailable(freeglut) FetchContent_MakeAvailable(freeglut)
@@ -76,8 +99,8 @@ endif()
# Tell Cmake to find the locations of libraries # Tell Cmake to find the locations of libraries
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
# Only require glut if on macos # Only require glut if on macos and not using freeglut
if (APPLE) if (APPLE AND NOT USE_FREEGLUT)
find_package(GLUT REQUIRED) find_package(GLUT REQUIRED)
endif() endif()
# Define MY_SOURCES to be a list of all the source files for my game # Define MY_SOURCES to be a list of all the source files for my game
@@ -117,6 +140,37 @@ target_sources("${CMAKE_PROJECT_NAME}" PRIVATE ${MY_SOURCES})
# If on mac # If on mac
if (APPLE) if (APPLE)
# FreeGlut for mac
if (USE_FREEGLUT)
target_sources("${CMAKE_PROJECT_NAME}" PRIVATE "${glad_SOURCE_DIR}/src/glad.c")
target_include_directories("${CMAKE_PROJECT_NAME}" PUBLIC "${glad_SOURCE_DIR}/include")
# Add our include files
target_include_directories("${CMAKE_PROJECT_NAME}" PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include/"
"${freeglut_SOURCE_DIR}/include"
"${glad_SOURCE_DIR}/include"
)
target_compile_definitions("${CMAKE_PROJECT_NAME}" PUBLIC use_freeglut=TRUE)
target_link_libraries("${CMAKE_PROJECT_NAME}"
PRIVATE
OpenGL::GL
freeglut_static
"-framework Cocoa"
"-framework IOKit"
"-framework CoreVideo"
"-lpthread"
stb_image
miniaudio
)
# Native GLUT for Mac
else()
# Add our include files # Add our include files
target_include_directories("${CMAKE_PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/") target_include_directories("${CMAKE_PROJECT_NAME}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/")
@@ -138,6 +192,7 @@ target_link_libraries("${CMAKE_PROJECT_NAME}"
stb_image stb_image
miniaudio miniaudio
) )
endif()
# If on windows # If on windows

View File

@@ -1,68 +1,66 @@
//############################################################################# // #############################################################################
//# main.cpp // # main.cpp
//############################################################################# // #############################################################################
//# Written by Colton Staiduhar // # Written by Colton Staiduhar
//# Date Created: 02/03/2025 // # Date Created: 02/03/2025
//# Last Modification: 02/05/2025 // # Last Modification: 02/05/2025
//############################################################################# // #############################################################################
//# Main Entry point for Cmake project, declare by the int main() function // # 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 // # This is a simple demonstration of GLUT functioning using STB_Image.H for
//# loading images and MiniAudio.h for playing audio. The repositories for // # loading images and MiniAudio.h for playing audio. The repositories for
//# these libraries can be found below. // # these libraries can be found below.
//# // #
//# Miniaudio // # Miniaudio
//# https://github.com/mackron/miniaudio // # https://github.com/mackron/miniaudio
//# // #
//# STB_Image.h // # STB_Image.h
//# https://github.com/arizotaz/cmake_stb_image // # https://github.com/arizotaz/cmake_stb_image
//# // #
//############################################################################# // #############################################################################
//# // #
//# For GLUT/OpenGL, the operating system should have GLUT in some form already // # For GLUT/OpenGL, the operating system should have GLUT in some form already
//# installed. However, freeglut exists as the modern implementation of GLUT. // # installed. However, freeglut exists as the modern implementation of GLUT.
//# // #
//# GLUT // # GLUT
//# You're on your own for this, but here are some helpful implementation docs // # 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 // # 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 // # Windows & Linux: https://www.opengl.org/resources/libraries/glut/glut_downloads.php
//# // #
//# FreeGLUT: // # FreeGLUT:
//# https://freeglut.sourceforge.net/docs/api.php // # https://freeglut.sourceforge.net/docs/api.php
//# // #
//############################################################################# // #############################################################################
//# // #
//# This file will setup much of GLUT. Getting some output to the screen // # This file will setup much of GLUT. Getting some output to the screen
//# The following is executed: // # The following is executed:
//# Create a windows with GLUT's API // # Create a windows with GLUT's API
//# Create a display update timer // # Create a display update timer
//# Create Keyboard Interrupts // # Create Keyboard Interrupts
//# Load textures the included Texture.H file // # Load textures the included Texture.H file
//# Setup the audio engine from MiniAudio // # Setup the audio engine from MiniAudio
//# Declare the Main Loop funcitons // # Declare the Main Loop funcitons
//# Draw a sprite to the screen // # Draw a sprite to the screen
//# Texture said sprite with an image // # Texture said sprite with an image
//# Rotate, move, and scale the sprite // # Rotate, move, and scale the sprite
//# Apply translations via user keyboard input // # Apply translations via user keyboard input
//# // #
//############################################################################# // #############################################################################
// Libraries // Libraries
#if defined(use_freeglut) #if defined(use_freeglut)
# include <glad/glad.h> #include <glad/glad.h>
# define FREEGLUT_STATIC #define FREEGLUT_STATIC
# include <gl/freeglut.h> #include <gl/freeglut.h>
#else #else
# include <GLUT/glut.h> #include <GLUT/glut.h>
#endif #endif
#include <miniaudio.h> #include <miniaudio.h>
// STD // STD
#include <math.h>
#include <iostream> #include <iostream>
#include <math.h>
#include <stdio.h> #include <stdio.h>
// Custom includes // Custom includes
@@ -76,14 +74,12 @@
void ProcessKeys(unsigned char, int, int); void ProcessKeys(unsigned char, int, int);
void ProcessSpecialKeys(int, int, int); void ProcessSpecialKeys(int, int, int);
void MainLoop(); void MainLoop();
void GlutLoopTimer(int);
// Extended Functionality // Extended Functionality
void UpdateViewPort(); void UpdateViewPort();
void DrawSprite(); void DrawSprite();
void LoadUserTextures(); void LoadUserTextures();
// Miniaudio Engine Declaration // Miniaudio Engine Declaration
void CreateAudioEngine(); void CreateAudioEngine();
ma_engine engine; // Miniaudio engine ma_engine engine; // Miniaudio engine
@@ -97,10 +93,29 @@ unsigned int texID;
ma_sound musicSound; // Miniaudio sound object ma_sound musicSound; // Miniaudio sound object
int lastWinW = 0, lastWinH = 0; 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 * Main entry point of the application
*/ */
int main(int argc, char **argv) int main(int argc, char** argv)
{ {
std::cout << "Starting"; std::cout << "Starting";
fflush(stdout); fflush(stdout);
@@ -115,12 +130,13 @@ int main(int argc, char **argv)
// Setup then create the window // Setup then create the window
glutInitWindowSize(winW, winH); // window size glutInitWindowSize(winW, winH); // window size
glutInitWindowPosition(0, 0); glutInitWindowPosition(0, 0);
glutCreateWindow("Transform Example"); glutCreateWindow("Transform Example - Using Native Glut");
// This line only needs to run when glad is in use // This line only needs to run when glad is in use
#if defined(use_freeglut) #if defined(use_freeglut)
if (!gladLoadGL()) {} glutSetWindowTitle("Transform Example - using FreeGLUT");
#endif if (!gladLoadGL()) { }
#endif
// Clear screen // Clear screen
glClearColor(0.0, 0.0, 0.0, 1.0); // clear the window screen glClearColor(0.0, 0.0, 0.0, 1.0); // clear the window screen
@@ -147,33 +163,40 @@ int main(int argc, char **argv)
// Declare Special Keys Keyboard Interrupt // Declare Special Keys Keyboard Interrupt
glutSpecialFunc(ProcessSpecialKeys); glutSpecialFunc(ProcessSpecialKeys);
#ifndef use_freeglut
// Setup a timer to run the main loop at an interval // Setup a timer to run the main loop at an interval
// (This call will call the GlutLoopTimer() function immediately) // (This call will call the GlutLoopTimer() function immediately)
glutTimerFunc(0, GlutLoopTimer, 0); glutTimerFunc(0, GlutLoopTimer, 0);
#endif
std::cout << "Started"; std::cout << "Started" << std::endl;
fflush(stdout); fflush(stdout);
// Start the Glut Loop (Calls the funtions above repeatedly) // Start the Glut Loop (Calls the funtions above repeatedly)
glutMainLoop();
std::cout << "exited"; #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); fflush(stdout);
return 0; 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 * Function to update the viewport to the size of the window
*/ */
@@ -202,26 +225,22 @@ void UpdateViewPort()
*/ */
void ProcessSpecialKeys(int key, int x, int y) void ProcessSpecialKeys(int key, int x, int y)
{ {
if (key == GLUT_KEY_LEFT) if (key == GLUT_KEY_LEFT) {
{
moveX = -10; moveX = -10;
movePressed = true; movePressed = true;
} }
if (key == GLUT_KEY_RIGHT) if (key == GLUT_KEY_RIGHT) {
{
moveX = 10; moveX = 10;
movePressed = true; movePressed = true;
} }
if (key == GLUT_KEY_UP) if (key == GLUT_KEY_UP) {
{
moveY = 10; moveY = 10;
movePressed = true; movePressed = true;
} }
if (key == GLUT_KEY_DOWN) if (key == GLUT_KEY_DOWN) {
{
moveY = -10; moveY = -10;
movePressed = true; movePressed = true;
} }
@@ -233,8 +252,7 @@ void ProcessSpecialKeys(int key, int x, int y)
*/ */
void ProcessKeys(unsigned char key, int x, int y) void ProcessKeys(unsigned char key, int x, int y)
{ {
switch (key) switch (key) {
{
case 'q': case 'q':
rotX += 1; rotX += 1;
break; break;
@@ -274,8 +292,7 @@ void ProcessKeys(unsigned char key, int x, int y)
void CreateAudioEngine() void CreateAudioEngine()
{ {
ma_result result = ma_engine_init(NULL, &engine); ma_result result = ma_engine_init(NULL, &engine);
if (result != MA_SUCCESS) if (result != MA_SUCCESS) {
{
std::cout << "Failed to setup the miniaudio engine\n"; std::cout << "Failed to setup the miniaudio engine\n";
fflush(stdout); fflush(stdout);
} }
@@ -287,8 +304,7 @@ void CreateAudioEngine()
0, 0,
NULL, NULL,
NULL, NULL,
&musicSound &musicSound);
);
} }
/** /**
@@ -302,8 +318,7 @@ void MainLoop()
int winH = glutGet(GLUT_WINDOW_HEIGHT); int winH = glutGet(GLUT_WINDOW_HEIGHT);
// If Changed, update the view port // If Changed, update the view port
if (winW != lastWinW || winH != lastWinH) if (winW != lastWinW || winH != lastWinH) {
{
UpdateViewPort(); UpdateViewPort();
} }
@@ -313,16 +328,14 @@ void MainLoop()
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// If scale oneshot is set, scale the image // If scale oneshot is set, scale the image
if (scalePressed) if (scalePressed) {
{
glScalef(scale, scale, scale); glScalef(scale, scale, scale);
scalePressed = false; scalePressed = false;
scale = 1; scale = 1;
} }
// If rotation oneshot is set, rotate the image // If rotation oneshot is set, rotate the image
if (rotPressed) if (rotPressed) {
{
glRotatef((GLfloat)rotX, 1.0, 0.0, 0.0); glRotatef((GLfloat)rotX, 1.0, 0.0, 0.0);
glRotatef((GLfloat)rotY, 0.0, 1.0, 0.0); glRotatef((GLfloat)rotY, 0.0, 1.0, 0.0);
glRotatef((GLfloat)rotZ, 0.0, 0.0, 1.0); glRotatef((GLfloat)rotZ, 0.0, 0.0, 1.0);
@@ -330,8 +343,7 @@ void MainLoop()
rotX = rotY = rotZ = 0; rotX = rotY = rotZ = 0;
} }
// If move oneshot is set, move the image and set move back to 0 // If move oneshot is set, move the image and set move back to 0
if (movePressed) if (movePressed) {
{
glTranslatef(moveX, moveY, 0); glTranslatef(moveX, moveY, 0);
movePressed = false; movePressed = false;
moveX = moveY = 0; moveX = moveY = 0;
@@ -344,6 +356,11 @@ void MainLoop()
// Swap buffers to display the new frame // Swap buffers to display the new frame
glutSwapBuffers(); glutSwapBuffers();
// With freeglut, we can trigger screen update right after we are done
#if defined(use_freeglut)
glutPostRedisplay();
#endif
} }
/** /**
@@ -364,7 +381,6 @@ void DrawSprite()
glBegin(GL_POLYGON); glBegin(GL_POLYGON);
{ {
glTexCoord2f(0.0, 0.0); glTexCoord2f(0.0, 0.0);
glVertex3f(-50, -50, 0); glVertex3f(-50, -50, 0);
glTexCoord2f(1.0, 0.0); glTexCoord2f(1.0, 0.0);