Skip to content

Instantly share code, notes, and snippets.

@luke10x
Last active October 4, 2024 04:23
Show Gist options
  • Save luke10x/cb640b1189e552444406747903092cac to your computer and use it in GitHub Desktop.
Save luke10x/cb640b1189e552444406747903092cac to your computer and use it in GitHub Desktop.
Gamedev examples
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
// Screen dimensions
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const char* HELLO_VERTEX_SHADER =
#ifdef __EMSCRIPTEN__
"#version 300 es"
#else
"#version 330 core"
#endif
R"(
layout(location = 0) in vec3 aPos;
void main() {
gl_Position = vec4(aPos, 1.0);
}
)";
const char* HELLO_FRAGMENT_SHADER =
#ifdef __EMSCRIPTEN__
"#version 300 es"
#else
"#version 330 core"
#endif
R"(
precision mediump float;
out vec4 FragColor;
void main() {
FragColor = vec4(1.0, 0.5, 0.0, 1.0); // Orange color
}
)";
// 1. OpenGL init subsystem
bool initVideo();
void initBuffers();
// 2. OpenGL shader subsystem
GLuint createShaderProgram(
const char* vertexShader,
const char* fragmentShader
);
GLuint compileShader(GLenum type, const char* source);
// 3. OpenGL diagnostic utils
void printShaderVersions();
void checkOpenGLError();
// 4. Main loop subsystem
void performOneCycle();
void close();
int main(int argc, char* argv[]);
//
// Global state context
//
typedef struct {
bool shouldContinue;
GLFWwindow* window;
GLuint triangleProgramId;
bool quit;
GLuint VAO, VBO;
} GameContext;
GameContext ctx;
// Implementation ///////////////////
// **************************
// 1. OpenGL init subsystem
// **************************
bool initVideo() {
// Initialize GLFW
if (!glfwInit()) {
printf("Failed to initialize GLFW\n");
return -1;
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4); // enable multisampling
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL ES 3.0", NULL, NULL);
if (window == NULL) {
printf("Failed to create window\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW to load OpenGL functions
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
printf("Error initializing GLEW\n");
return -1;
}
printf("OpenGL Version: %s\n", glGetString(GL_VERSION));
printf("GLSL Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
ctx.window = window;
return true;
}
void initBuffers() {
GameContext* ctx_ = &ctx;
float vertices[] = {
-0.5f, -0.5f, 0.0f, // Bottom left
0.5f, -0.5f, 0.0f, // Bottom right
0.0f, 0.5f, 0.0f // Top
};
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
ctx.VAO = VAO;
ctx.VBO = VBO;
};
// ****************************
// 2. OpenGL shader subsystem
// ****************************
GLuint createShaderProgram(
const char* vertexShaderSource,
const char* fragmentShaderSource
) {
GLuint vertexShader = compileShader(
GL_VERTEX_SHADER, vertexShaderSource
);
GLuint fragmentShader = compileShader(
GL_FRAGMENT_SHADER, fragmentShaderSource
);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
}
GLuint compileShader(
GLenum type,
const char* source
) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
std::cerr
<< "ERROR::SHADER::COMPILATION_FAILED\n"
<< "SHADER SOURCE:\n"
<< source
<< "\nSHADER TYPE: "
<< (type == GL_VERTEX_SHADER ? "Vertex Shader" : "")
<< (type == GL_FRAGMENT_SHADER ? "Fragment Shader" : "")
<< "\nSHADER COMPILATION ERROR:\n"
<< infoLog
<< std::endl;
exit(1);
}
return shader;
}
// ****************************
// 3. OpenGL diagnostic utils
// ****************************
void printShaderVersions() {
// Get OpenGL version
const GLubyte* glVersion = glGetString(GL_VERSION);
printf("OpenGL Version: %s\n", glVersion);
// Get GLSL (shader language) version
const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
printf("GLSL (Shader) Version: %s\n", glslVersion);
// You can also get OpenGL vendor and renderer information
const GLubyte* vendor = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
printf("Vendor: %s\n", vendor);
printf("Renderer: %s\n", renderer);
}
void checkOpenGLError() {
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL error: " << err << std::endl;
}
}
// ************************
// 4. Main loop subsystem
// ************************
void performOneCycle() {
ctx.shouldContinue = true;
if (glfwWindowShouldClose(ctx.window)) {
close();
ctx.shouldContinue = false;
return;
}
// SDL_Event event;
// while (SDL_PollEvent(&event) != 0) {
// if (event.type == SDL_QUIT) {
// quit = true;
// }
// }
glClearColor(0.1f, 0.4f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(ctx.triangleProgramId);
glBindVertexArray(ctx.VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwPollEvents();
// checkOpenGLError();
glfwSwapBuffers(ctx.window);
}
void close() {
glfwDestroyWindow(ctx.window);
glfwTerminate();
}
// Clean up resources
// void close(SDL_Window* window, SDL_GLContext context) {
// SDL_GL_DeleteContext(context);
// SDL_DestroyWindow(window);
// SDL_Quit();
// }
int main(int argc, char* argv[]) {
ctx.shouldContinue = true;
if (!initVideo()) {
std::cerr << "Failed to initialize!" << std::endl;
return -1;
}
initBuffers();
ctx.triangleProgramId = createShaderProgram(
HELLO_VERTEX_SHADER,
HELLO_FRAGMENT_SHADER
);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(performOneCycle, 0, 1);
#else
while (ctx.shouldContinue) performOneCycle();
#endif
return 0;
// Should be no code beyond this point!
// singleLoopCycle() performs the cleanup
// when it detects that it should quit.
// The reason for this is that in Emscripten build
// this coude would be reached before
// singleLoopCycle() is even called,
// and the native code would reach here only
// after the main loop.
//
// The End.
}
#include <GL/glew.h>
#ifdef __USE_SDL
#include <SDL2/SDL.h>
#elif defined(__USE_GLFW)
#include <GLFW/glfw3.h>
#endif
#include <iostream>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
// ***********
// Constants
// ***********
// Screen dimensions
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const char* HELLO_VERTEX_SHADER =
#ifdef __EMSCRIPTEN__
"#version 300 es"
#else
"#version 330 core"
#endif
R"(
layout(location = 0) in vec3 aPos;
void main() {
gl_Position = vec4(aPos, 1.0);
}
)";
const char* HELLO_FRAGMENT_SHADER =
#ifdef __EMSCRIPTEN__
"#version 300 es"
#else
"#version 330 core"
#endif
R"(
precision mediump float;
out vec4 FragColor;
void main() {
FragColor = vec4(1.0, 0.5, 0.0, 1.0); // Orange color
}
)";
// *******************************
// Declarations of all functions
// *******************************
// 1. OpenGL init subsystem
bool initVideo();
void initBuffers();
// 2. OpenGL shader subsystem
GLuint createShaderProgram(
const char* vertexShader,
const char* fragmentShader
);
GLuint compileShader(GLenum type, const char* source);
// 3. OpenGL diagnostic utils
void printShaderVersions();
void checkOpenGLError();
// 4. Main loop subsystem
void performOneCycle();
void close();
int main(int argc, char* argv[]);
// **********************
// Global state context
// **********************
typedef struct {
bool shouldContinue;
#ifdef __USE_SDL
SDL_Window* sdlWindow;
SDL_GLContext sdlContext;
#elif defined(__USE_GLFW)
GLFWwindow* glfwWindow;
#endif
GLuint triangleProgramId;
bool quit;
GLuint VAO, VBO;
} GameContext;
GameContext ctx;
// **************************
// 1. OpenGL init subsystem
// **************************
bool initVideo() {
#ifdef __USE_SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL Error: " << SDL_GetError() << std::endl;
return false;
}
#ifdef __EMSCRIPTEN__
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
#endif
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_Window* window = SDL_CreateWindow(
"SDL2 OpenGL Home",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
if (window == nullptr) {
std::cerr << "Window could not be created! SDL Error: " << SDL_GetError() << std::endl;
return false;
}
std::cerr << " will create cont now " << std::endl;
SDL_GLContext context = SDL_GL_CreateContext(window);
if (context == nullptr) {
std::cerr << "OpenGL context could not be created! SDL Error: " << SDL_GetError() << std::endl;
return false;
}
std::cerr << " will make cont active now " << std::endl;
if (SDL_GL_MakeCurrent(window, context) < 0) {
std::cerr << "Could not make OpenGL context current: " << SDL_GetError() << std::endl;
SDL_Quit();
}
std::cerr << " will create swap " << std::endl;
SDL_GL_SetSwapInterval(1); // Use V-Sync
#elif defined(__USE_GLFW)
if (!glfwInit()) {
printf("Failed to initialize GLFW\n");
return -1;
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4); // enable multisampling
GLFWwindow* window = glfwCreateWindow(
SCREEN_WIDTH,
SCREEN_HEIGHT,
"GLFW OpenGL program",
NULL, NULL
);
if (window == nullptr) {
printf("Failed to create window\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // V-Sync
#endif
std::cerr << "creating glewn " << std::endl;
// Loading Glew is necessary no matter which graphics library you use
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK) {
std::cerr << "Error initializing GLEW! " << glewGetErrorString(err) << std::endl;
return false;
}
std::cerr << "glewn created " << std::endl;
int width, height;
#ifdef __USE_SDL
SDL_GL_GetDrawableSize(window, &width, &height);
ctx.sdlContext = context;
ctx.sdlWindow = window;
#elif defined(__USE_GLFW)
glfwGetFramebufferSize(window, &width, &height);
ctx.glfwWindow = window;
#endif
glViewport(0, 0, width, height);
std::cerr<<"Status: Using GLEW"<< glewGetString(GLEW_VERSION)<<'\n';
printf("OpenGL Version: %s\n", glGetString(GL_VERSION));
printf("GLSL Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
printShaderVersions();
return true;
}
void initBuffers() {
GameContext* ctx_ = &ctx;
float vertices[] = {
-0.5f, -0.5f, 0.0f, // Bottom left
0.5f, -0.5f, 0.0f, // Bottom right
0.0f, 0.5f, 0.0f // Top
};
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
ctx.VAO = VAO;
ctx.VBO = VBO;
};
// ****************************
// 2. OpenGL shader subsystem
// ****************************
GLuint createShaderProgram(
const char* vertexShaderSource,
const char* fragmentShaderSource
) {
GLuint vertexShader = compileShader(
GL_VERTEX_SHADER, vertexShaderSource
);
GLuint fragmentShader = compileShader(
GL_FRAGMENT_SHADER, fragmentShaderSource
);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
}
GLuint compileShader(
GLenum type,
const char* source
) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
std::cerr
<< "ERROR::SHADER::COMPILATION_FAILED\n"
<< "SHADER SOURCE:\n"
<< source
<< "\nSHADER TYPE: "
<< (type == GL_VERTEX_SHADER ? "Vertex Shader" : "")
<< (type == GL_FRAGMENT_SHADER ? "Fragment Shader" : "")
<< "\nSHADER COMPILATION ERROR:\n"
<< infoLog
<< std::endl;
exit(1);
}
return shader;
}
// ****************************
// 3. OpenGL diagnostic utils
// ****************************
void printShaderVersions() {
// Get OpenGL version
const GLubyte* glVersion = glGetString(GL_VERSION);
printf("OpenGL Version: %s\n", glVersion);
// Get GLSL (shader language) version
const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
printf("GLSL (Shader) Version: %s\n", glslVersion);
// You can also get OpenGL vendor and renderer information
const GLubyte* vendor = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
printf("Vendor: %s\n", vendor);
printf("Renderer: %s\n", renderer);
}
void checkOpenGLError() {
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL error: " << err << std::endl;
}
}
// ************************
// 4. Main loop subsystem
// ************************
void performOneCycle() {
ctx.shouldContinue = true;
#ifdef __USE_SDL
SDL_Event event;
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT) {
close();
ctx.shouldContinue = false;
return;
}
if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
close();
ctx.shouldContinue = false;
return;
}
}
}
#elif defined(__USE_GLFW)
if (glfwWindowShouldClose(ctx.glfwWindow)) {
close();
ctx.shouldContinue = false;
return;
}
if (glfwGetKey(ctx.glfwWindow, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(ctx.glfwWindow, true); // Mark window to close
}
#endif
glClearColor(0.1f, 0.4f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(ctx.triangleProgramId);
glBindVertexArray(ctx.VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
checkOpenGLError();
#ifdef __USE_GLFW
glfwPollEvents();
#endif
#ifdef __USE_SDL
SDL_GL_SwapWindow(ctx.sdlWindow);
#elif defined(__USE_GLFW)
glfwSwapBuffers(ctx.glfwWindow);
#endif
}
void close() {
#ifdef __USE_SDL
SDL_GL_DeleteContext(ctx.sdlContext);
SDL_DestroyWindow(ctx.sdlWindow);
SDL_Quit();
#elif defined(__USE_GLFW)
glfwDestroyWindow(ctx.glfwWindow);
glfwTerminate();
#endif
}
int main(int argc, char* argv[]) {
ctx.shouldContinue = true;
if (!initVideo()) {
std::cerr << "Failed to initialize!" << std::endl;
return -1;
}
initBuffers();
ctx.triangleProgramId = createShaderProgram(
HELLO_VERTEX_SHADER,
HELLO_FRAGMENT_SHADER
);
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(performOneCycle, 0, 1);
#else
while (ctx.shouldContinue) performOneCycle();
#endif
return 0;
// Should be no code beyond this point!
// singleLoopCycle() performs the cleanup
// when it detects that it should quit.
// The reason for this is that in Emscripten build
// this coude would be reached before
// singleLoopCycle() is even called,
// and the native code would reach here only
// after the main loop.
//
// The End.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment