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

@@ -48,8 +48,6 @@
// # // #
// ############################################################################# // #############################################################################
// Libraries // Libraries
#if defined(use_freeglut) #if defined(use_freeglut)
#include <glad/glad.h> #include <glad/glad.h>
@@ -61,8 +59,8 @@
#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,6 +93,25 @@ 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
*/ */
@@ -115,10 +130,11 @@ 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)
glutSetWindowTitle("Transform Example - using FreeGLUT");
if (!gladLoadGL()) { } if (!gladLoadGL()) { }
#endif #endif
@@ -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);