sent from android

This commit is contained in:
Alfie King 2025-07-30 13:14:22 +01:00
parent 15aa9d54ea
commit a03c7c85b8
25 changed files with 2243 additions and 203 deletions

BIN
assets/crate.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

38
assets/cube.obj Normal file
View File

@ -0,0 +1,38 @@
# Blender 4.5.0
# www.blender.org
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.875000 0.500000
vt 0.625000 1.000000
vt 0.875000 0.750000
s 0
f 2/1 3/2 1/3
f 4/4 7/5 3/2
f 8/6 5/7 7/5
f 6/8 1/9 5/7
f 7/5 1/10 3/11
f 4/12 6/8 8/6
f 2/1 4/4 3/2
f 4/4 8/6 7/5
f 8/6 6/8 5/7
f 6/8 2/13 1/9
f 7/5 5/7 1/10
f 4/12 2/14 6/8

BIN
assets/meow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

1479
assets/monkey.obj Normal file

File diff suppressed because it is too large Load Diff

45
include/geometry.hpp Normal file
View File

@ -0,0 +1,45 @@
#ifndef GEOMETRY_HPP
#define GEOMETRY_HPP
// Includes
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "graphics.hpp"
// Object class
class Object {
public:
Object(
float *vertices, unsigned int vertex_size,
unsigned int *indices, unsigned int index_size,
float *normals = nullptr, unsigned int normal_size = 0,
float *texcoords = nullptr, unsigned int texcoord_size = 0
);
~Object();
void draw();
private:
unsigned int VAO, VBO, EBO, NBO, TBO; // Vertex Array Object, Vertex Buffer Object, Element Buffer Object, Normal Buffer Object, Texture Buffer Object
unsigned int vertex_count;
unsigned int index_count;
};
class UntexturedObject {
public:
UntexturedObject(
float *vertices, unsigned int vertex_size,
unsigned int *indices, unsigned int index_size,
float *normals = nullptr, unsigned int normal_size = 0,
float *texcoords = nullptr, unsigned int texcoord_size = 0
);
~UntexturedObject();
void draw();
private:
unsigned int VAO, VBO, EBO, NBO, TBO; // Vertex Array Object, Vertex Buffer Object, Element Buffer Object, Normal Buffer Object, Texture Buffer Object
unsigned int vertex_count;
unsigned int index_count;
};
#endif

View File

@ -3,11 +3,11 @@
#define GL_GLEXT_PROTOTYPES
// Includes
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_opengl3.h"
#include <SDL3/SDL_opengl.h>
#include "window.hpp"
#include "shader.hpp"
#include "texture.hpp"
#include <iostream>
// Constants
const int open_gl_major_version = 3;
@ -21,25 +21,13 @@ extern float frame_time;
extern float fps;
extern float frame_time_graph[100];
extern SDL_GLContext gl_context;
extern ImGuiIO& io;
extern ImGuiStyle& style;
#define delta_time frame_time
// Functions
int initialize_opengl();
void cleanup_opengl();
// ImGui
int initialize_imgui();
void cleanup_imgui();
void new_frame_imgui();
void frame_time_ui();
// Frame time calculation
void calc_frame_time();
// Shader management
unsigned int compile_shader(const char* shader_source, GLenum shader_type);
unsigned int create_program(unsigned int vertex_shader, unsigned int fragment_shader);
#endif

23
include/gui.hpp Normal file
View File

@ -0,0 +1,23 @@
#ifndef GUI_HPP
#define GUI_HPP
// Includes
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_opengl3.h"
#include "window.hpp"
#include "graphics.hpp"
#include <iostream>
// Variables
extern ImGuiIO& io;
extern ImGuiStyle& style;
extern
// Functions
int initialize_imgui();
void cleanup_imgui();
void new_frame_imgui();
void frame_time_ui();
#endif

23
include/loader.hpp Normal file
View File

@ -0,0 +1,23 @@
#ifndef LOADER_HPP
#define LOADER_HPP
// Includes
#include <fstream>
#include <iostream>
// Obj struct
struct Obj {
float* vertices; // Pointer to vertex data
size_t vertex_count; // Number of vertices
float* normals; // Pointer to normal data
size_t normal_count; // Number of normals
float* texcoords; // Pointer to texture coordinate data
size_t texcoord_count; // Number of texture coordinates
unsigned int* indices; // Pointer to index data
size_t index_count; // Number of indices
};
// Function to load an OBJ file
Obj load_obj(const std::string& filename);
#endif // LOADER_HPP

View File

@ -6,11 +6,17 @@
#include "window.hpp"
#include "graphics.hpp"
#include "utils.hpp"
#include "gui.hpp"
#include "geometry.hpp"
#include "loader.hpp"
// Variables
extern bool running;
// Functions
int main(int argc, char* argv[]);
void init(); // Initialize SDL, OpenGL, and ImGui
void handle_events(); // Handle SDL events
void handle_keyboard_input(); // Handle keyboard input for camera movement
#endif

24
include/shader.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef SHADER_HPP
#define SHADER_HPP
#define GL_GLEXT_PROTOTYPES
// Includes
#include "utils.hpp"
#include <iostream>
#include <SDL3/SDL_opengl.h>
#include "geometry.hpp"
// Shader class
class Shader {
public:
unsigned int ID;
Shader(const char* vertexPath, const char* fragmentPath);
void use() const;
void setBool(const std::string &name, bool value) const;
void setInt(const std::string &name, int value) const;
void setFloat(const std::string &name, float value) const;
void setMat4(const std::string &name, const glm::mat4 &mat) const;
~Shader();
};
#endif

24
include/texture.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef TEXTURE_HPP
#define TEXTURE_HPP
#define GL_GLEXT_PROTOTYPES
// Includes
#include <SDL3_image/SDL_image.h>
#include <SDL3/SDL_opengl.h>
#include <iostream>
// Functions
void flip_surface(SDL_Surface* surface);
// Classes
class Texture {
public:
unsigned int ID;
Texture(const char* file_path);
~Texture();
void bind() const;
void bind(unsigned int unit) const;
void unbind() const;
};
#endif

View File

@ -2,18 +2,16 @@
#define WINDOW_HPP
// Includes
#include "iostream"
#include <iostream>
#include <SDL3/SDL.h>
// Constants
const int window_width = 800;
const int window_height = 600;
// Variables
const SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;
extern float main_scale;
extern SDL_Window* window;
extern SDL_Event event;
extern int window_width;
extern int window_height;
// Functions
int initialize_sdl();

View File

@ -10,10 +10,10 @@ IMGUI_DIR = imgui
CXX = g++
# Libs
LIBS = -lGL `pkg-config --libs sdl3`
LIBS = -lGL -lglm `pkg-config --libs sdl3 sdl3-image`
# Compiler and linker settings
CXXFLAGS = `pkg-config --cflags sdl3` -std=c++17 -I $(INCLUDE_DIR)
CXXFLAGS = -std=c++17 -I $(INCLUDE_DIR)
# If ImGui directory is set, include its source files
ifdef IMGUI_DIR
@ -51,6 +51,10 @@ dirs:
@mkdir -p $(BUILD_DIR)
@mkdir -p $(OBJ_DIR)
# Clear build directory
clear:
@find $(OBJ_DIR) -type f -name '*.o' ! -name 'imgui*.o' -exec rm -f {} +
# Pattern rule for source files in src directory
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
@ -64,7 +68,7 @@ $(OBJ_DIR)/%.o: $(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
endif
all: dirs $(BIN)
all: dirs clear $(BIN)
@echo Build complete
$(BIN): $(OBJS)

View File

@ -2,7 +2,11 @@
out vec4 FragColor;
in vec3 color; // Input color from the vertex shader
in vec2 TexCoord;
uniform sampler2D texture1; // Texture sampler
uniform sampler2D texture2; // Second texture sampler
void main() {
FragColor = vec4(color, 1.0); // Set the fragment color to the input color
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.3) * vec4(color, 1.0); // Mix the two textures and apply the color
}

View File

@ -1,9 +1,16 @@
#version 330 core
layout(location = 0) in vec3 position; // Vertex position
layout(location = 1) in vec2 texCoords; // Texture coordinates
out vec3 color; // Output color to the fragment shader
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
gl_Position = vec4(position, 1.0); // Set the position of the vertex
gl_Position = projection * view * model * vec4(position, 1.0); // Apply transformation matrices
color = position + vec3(0.5); // Set the color based on the vertex position
TexCoord = texCoords; // Pass texture coordinates to the fragment shader
}

View File

@ -0,0 +1,8 @@
#version 330 core
out vec4 FragColor;
in vec3 color; // Input color from the vertex shader
void main() {
FragColor = vec4(color, 1.0); // Apply the color
}

View File

@ -0,0 +1,13 @@
#version 330 core
layout(location = 0) in vec3 position; // Vertex position
out vec3 color; // Output color to the fragment shader
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
gl_Position = projection * view * model * vec4(position, 1.0); // Apply transformation matrices
color = position + vec3(0.5); // Set the color based on the vertex position
}

120
src/geometry.cpp Normal file
View File

@ -0,0 +1,120 @@
#include "geometry.hpp"
Object::Object(
float *vertices, unsigned int vertex_size,
unsigned int *indices, unsigned int index_size,
float *normals, unsigned int normal_size,
float *texcoords, unsigned int texcoord_size
) {
glGenVertexArrays(1, &VAO); // Generate a vertex array object
glGenBuffers(1, &VBO); // Generate a vertex buffer object
glGenBuffers(1, &EBO); // Generate an element buffer object
glGenBuffers(1, &NBO); // Generate a normal buffer object
glGenBuffers(1, &TBO); // Generate a texture buffer object
glBindVertexArray(VAO); // Bind the vertex array object
glBindBuffer(GL_ARRAY_BUFFER, VBO); // Bind the vertex buffer object
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Bind the element buffer object
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW); // Upload vertex data to the buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, indices, GL_STATIC_DRAW); // Upload index data to the buffer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); // Set up vertex attributes
glEnableVertexAttribArray(0); // Enable vertex attribute 0
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); // Set up texture coordinates
glEnableVertexAttribArray(1); // Enable vertex attribute 1
if (normals && normal_size > 0) {
glBindBuffer(GL_ARRAY_BUFFER, NBO); // Bind the normal buffer object
glBufferData(GL_ARRAY_BUFFER, normal_size, normals, GL_STATIC_DRAW); // Upload normal data to the buffer
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // Set up normal attributes
glEnableVertexAttribArray(2); // Enable vertex attribute 2
}
if (texcoords && texcoord_size > 0) {
glBindBuffer(GL_ARRAY_BUFFER, TBO); // Bind the texture buffer object
glBufferData(GL_ARRAY_BUFFER, texcoord_size, texcoords, GL_STATIC_DRAW); // Upload texture coordinate data to the buffer
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); // Set up texture coordinate attributes
glEnableVertexAttribArray(3); // Enable vertex attribute 3
}
glBindVertexArray(0); // Unbind the vertex array object
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind the vertex buffer object
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind the element buffer object
this->vertex_count = vertex_size / (5 * sizeof(float)); // Calculate vertex count based on size
this->index_count = index_size / sizeof(unsigned int); // Calculate index count based on size
}
Object::~Object() {
glDeleteVertexArrays(1, &VAO); // Delete the vertex array object
glDeleteBuffers(1, &VBO); // Delete the vertex buffer object
glDeleteBuffers(1, &EBO); // Delete the element buffer object
glDeleteBuffers(1, &NBO); // Delete the normal buffer object
glDeleteBuffers(1, &TBO); // Delete the texture buffer object
}
void Object::draw() {
glBindVertexArray(VAO); // Bind the vertex array object
glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); // Draw the object using the element buffer
glBindVertexArray(0); // Unbind the vertex array object
}
UntexturedObject::UntexturedObject(
float *vertices, unsigned int vertex_size,
unsigned int *indices, unsigned int index_size,
float *normals, unsigned int normal_size,
float *texcoords, unsigned int texcoord_size
) {
glGenVertexArrays(1, &VAO); // Generate a vertex array object
glGenBuffers(1, &VBO); // Generate a vertex buffer object
glGenBuffers(1, &EBO); // Generate an element buffer object
glGenBuffers(1, &NBO); // Generate a normal buffer object
glGenBuffers(1, &TBO); // Generate a texture buffer object
glBindVertexArray(VAO); // Bind the vertex array object
glBindBuffer(GL_ARRAY_BUFFER, VBO); // Bind the vertex buffer object
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Bind the element buffer object
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW); // Upload vertex data to the buffer
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, indices, GL_STATIC_DRAW); // Upload index data to the buffer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // Set up vertex attributes
glEnableVertexAttribArray(0); // Enable vertex attribute 0
if (normals && normal_size > 0) {
glBindBuffer(GL_ARRAY_BUFFER, NBO); // Bind the normal buffer object
glBufferData(GL_ARRAY_BUFFER, normal_size, normals, GL_STATIC_DRAW); // Upload normal data to the buffer
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); // Set up normal attributes
glEnableVertexAttribArray(1); // Enable vertex attribute 1
}
if (texcoords && texcoord_size > 0) {
glBindBuffer(GL_ARRAY_BUFFER, TBO); // Bind the texture buffer object
glBufferData(GL_ARRAY_BUFFER, texcoord_size, texcoords, GL_STATIC_DRAW); // Upload texture coordinate data to the buffer
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); // Set up texture coordinate attributes
glEnableVertexAttribArray(2); // Enable vertex attribute 2
}
glBindVertexArray(0); // Unbind the vertex array object
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind the vertex buffer object
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind the element buffer object
this->vertex_count = vertex_size / (5 * sizeof(float)); // Calculate vertex count based on size
this->index_count = index_size / sizeof(unsigned int); // Calculate index count based on
}
UntexturedObject::~UntexturedObject() {
glDeleteVertexArrays(1, &VAO); // Delete the vertex array object
glDeleteBuffers(1, &VBO); // Delete the vertex buffer object
glDeleteBuffers(1, &EBO); // Delete the element buffer object
glDeleteBuffers(1, &NBO); // Delete the normal buffer object
glDeleteBuffers(1, &TBO); // Delete the texture buffer object
}
void UntexturedObject::draw() {
glBindVertexArray(VAO); // Bind the vertex array object
glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0); // Draw the object using the element buffer
glBindVertexArray(0); // Unbind the vertex array object
}

View File

@ -6,7 +6,6 @@ Uint32 current_time;
float frame_time;
float fps;
float frame_time_graph[100];
SDL_GLContext gl_context;
// Functions
@ -44,91 +43,6 @@ void cleanup_opengl() {
std::cout << "OpenGL cleanup successful." << std::endl;
}
unsigned int compile_shader(const char* shader_source, GLenum shader_type) {
unsigned int shader = glCreateShader(shader_type);
if (shader == 0) {
std::cerr << "Failed to create shader." << std::endl;
return 0; // Shader creation failed
}
glShaderSource(shader, 1, &shader_source, nullptr);
glCompileShader(shader);
// Check for compilation errors
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char info_log[512];
glGetShaderInfoLog(shader, sizeof(info_log), nullptr, info_log);
std::cerr << "Shader compilation error: " << info_log << std::endl;
glDeleteShader(shader);
return 0; // Shader compilation failed
}
return shader; // Shader compiled successfully
}
unsigned int create_program(unsigned int vertex_shader, unsigned int fragment_shader) {
unsigned int program = glCreateProgram();
if (program == 0) {
std::cerr << "Failed to create shader program." << std::endl;
return 0; // Program creation failed
}
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Check for linking errors
int success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
char info_log[512];
glGetProgramInfoLog(program, sizeof(info_log), nullptr, info_log);
std::cerr << "Shader program linking error: " << info_log << std::endl;
glDeleteProgram(program);
return 0; // Program linking failed
}
return program; // Program created successfully
}
int initialize_imgui() {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale);
style.FontScaleDpi = main_scale;
if (!ImGui_ImplSDL3_InitForOpenGL(window, gl_context)) {
std::cerr << "ImGui_ImplSDL3_InitForOpenGL failed!" << std::endl;
return 1; // Initialization failed
}
char glsl_version[32];
snprintf(glsl_version, sizeof(glsl_version), "#version %d%d0", open_gl_major_version, open_gl_minor_version);
if (!ImGui_ImplOpenGL3_Init(glsl_version)) {
std::cerr << "ImGui_ImplOpenGL3_Init failed!" << std::endl;
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
return 1; // Initialization failed
}
return 0;
}
void cleanup_imgui() {
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
std::cout << "ImGui cleanup successful." << std::endl;
}
void calc_frame_time() {
// Calculate frame time
current_time = SDL_GetTicks();
@ -142,17 +56,3 @@ void calc_frame_time() {
}
frame_time_graph[0] = frame_time; // Add new frame time
}
void new_frame_imgui() {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
}
void frame_time_ui() {
ImGui::Begin("Frame Time");
ImGui::Text("Current FPS: %.2f", fps);
ImGui::Text("Current Frame Time: %.3f ms", frame_time * 1000.0f);
ImGui::PlotLines("##Frame Time Graph", frame_time_graph, 100, 0, "Frame Time (ms)", 0.0f, 0.1f, ImVec2(200, 80));
ImGui::End();
}

51
src/gui.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "gui.hpp"
int initialize_imgui() {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale);
style.FontScaleDpi = main_scale;
if (!ImGui_ImplSDL3_InitForOpenGL(window, gl_context)) {
std::cerr << "ImGui_ImplSDL3_InitForOpenGL failed!" << std::endl;
return 1; // Initialization failed
}
char glsl_version[32];
snprintf(glsl_version, sizeof(glsl_version), "#version %d%d0", open_gl_major_version, open_gl_minor_version);
if (!ImGui_ImplOpenGL3_Init(glsl_version)) {
std::cerr << "ImGui_ImplOpenGL3_Init failed!" << std::endl;
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
return 1; // Initialization failed
}
return 0;
}
void cleanup_imgui() {
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
std::cout << "ImGui cleanup successful." << std::endl;
}
void new_frame_imgui() {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
}
void frame_time_ui() {
ImGui::Begin("Frame Time");
ImGui::Text("Current FPS: %.2f", fps);
ImGui::Text("Current Frame Time: %.3f ms", frame_time * 1000.0f);
ImGui::PlotLines("##Frame Time Graph", frame_time_graph, 100, 0, "Frame Time (ms)", 0.0f, 0.1f, ImVec2(200, 80));
ImGui::End();
}

48
src/loader.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "loader.hpp"
Obj load_obj(const std::string& filename) {
Obj obj;
obj.vertices = nullptr;
obj.vertex_count = 0;
obj.indices = nullptr;
obj.index_count = 0;
obj.normals = nullptr;
obj.normal_count = 0;
obj.texcoords = nullptr;
obj.texcoord_count = 0;
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "Failed to open OBJ file: " << filename << std::endl;
return obj;
}
// Read the file and populate the obj structure
std::string line;
while (std::getline(file, line)) {
// Parse the line and extract vertex, normal, and index data
if (line.substr(0, 2) == "v ") {
// Vertex position
obj.vertex_count++;
obj.vertices = (float*)realloc(obj.vertices, obj.vertex_count * 3 * sizeof(float));
sscanf(line.c_str() + 2, "%f %f %f", &obj.vertices[(obj.vertex_count - 1) * 3], &obj.vertices[(obj.vertex_count - 1) * 3 + 1], &obj.vertices[(obj.vertex_count - 1) * 3 + 2]);
} else if (line.substr(0, 2) == "f ") {
// Face indices
unsigned int index1,
} else if (line.substr(0, 2) == "vn") {
// Vertex normal
obj.normal_count++;
obj.normals = (float*)realloc(obj.normals, obj.normal_count * 3 * sizeof(float));
sscanf(line.c_str() + 3, "%f %f %f", &obj.normals[(obj.normal_count - 1) * 3], &obj.normals[(obj.normal_count - 1) * 3 + 1], &obj.normals[(obj.normal_count - 1) * 3 + 2]);
} else if (line.substr(0, 2) == "vt") {
// Vertex texture coordinate
obj.texcoord_count++;
obj.texcoords = (float*)realloc(obj.texcoords, obj.texcoord_count * 2 * sizeof(float));
sscanf(line.c_str() + 3, "%f %f", &obj.texcoords[(obj.texcoord_count - 1) * 2], &obj.texcoords[(obj.texcoord_count - 1) * 2 + 1]);
}
}
file.close();
return obj;
}

View File

@ -1,22 +1,33 @@
#include "main.hpp"
#include <GL/glu.h>
// Variables
bool running = true;
float fov = 45.0f; // Field of view
float camera_move_speed = 10.0f; // Camera movement speed
bool wireframe_mode = false; // Wireframe mode toggle
glm::mat4 viewMatrix = glm::mat4(1.0f); // View matrix
glm::mat4 projectionMatrix = glm::perspective(glm::radians(fov), (float)window_width / (float)window_height, 0.1f, 100.0f); // Perspective projection matrix
// Main
int main(int argc, char* argv[]) {
glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f); // Initial camera position
glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); // Camera front vector
glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); // Camera up vector
float camera_pitch = 0.0f; // Pitch angle
float camera_yaw = -90.0f; // Yaw angle
float camera_turn_speed = 1.0f; // Camera turn speed
// Init
void init() {
// Initialize SDL
if (initialize_sdl() != 0) {
std::cerr << "SDL initialization failed." << std::endl;
return 1; // SDL initialization failed
return;
}
// Initialize OpenGL
if (initialize_opengl() != 0) {
std::cerr << "OpenGL initialization failed." << std::endl;
cleanup_sdl();
return 1; // OpenGL initialization failed
return;
}
// Initialize ImGui
@ -24,92 +35,159 @@ int main(int argc, char* argv[]) {
std::cerr << "ImGui initialization failed." << std::endl;
cleanup_opengl();
cleanup_sdl();
return 1; // ImGui initialization failed
return;
}
// Triangle vertices
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
glEnable(GL_DEPTH_TEST);
}
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
// Event handling
void handle_events() {
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL3_ProcessEvent(&event); // Process ImGui events
switch (event.type) {
case SDL_EVENT_QUIT:
running = false; // Exit loop on quit event
break;
case SDL_EVENT_WINDOW_RESIZED:
// Handle window resize
SDL_GetWindowSize(window, &window_width, &window_height);
glViewport(0, 0, window_width, window_height); // Update OpenGL
break;
// Vertex buffer object (VBO) and vertex array object (VAO) and element buffer object (EBO)
unsigned int VBO, VAO, EBO;
default:
break;
}
}
}
glGenVertexArrays(1, &VAO); // Generate a vertex array object
glGenBuffers(1, &VBO); // Generate a vertex buffer object
glGenBuffers(1, &EBO); // Generate an element buffer object
// Handle keyboard input
void handle_keyboard_input() {
const bool *keyboard_state = SDL_GetKeyboardState(NULL);
glBindVertexArray(VAO); // Bind the vertex array object
glBindBuffer(GL_ARRAY_BUFFER, VBO); // Bind the vertex buffer object
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Bind the element buffer object
// Handle keyboard input for camera movement
if (keyboard_state[SDL_SCANCODE_W]) {
camera_position += camera_move_speed * delta_time * camera_front; // Move forward
}
if (keyboard_state[SDL_SCANCODE_S]) {
camera_position -= camera_move_speed * delta_time * camera_front; // Move backward
}
if (keyboard_state[SDL_SCANCODE_A]) {
camera_position -= glm::normalize(glm::cross(camera_front, camera_up)) * camera_move_speed * delta_time; // Move left
}
if (keyboard_state[SDL_SCANCODE_D]) {
camera_position += glm::normalize(glm::cross(camera_front, camera_up)) * camera_move_speed * delta_time; // Move right
}
if (keyboard_state[SDL_SCANCODE_SPACE]) {
camera_position += camera_up * camera_move_speed * delta_time; // Move up
}
if (keyboard_state[SDL_SCANCODE_LCTRL]) {
camera_position -= camera_up * camera_move_speed * delta_time; // Move down
}
if (keyboard_state[SDL_SCANCODE_LEFT]) {
camera_yaw -= camera_turn_speed; // Turn left
if (camera_yaw < -180.0f) camera_yaw += 360.0f; // Wrap yaw
}
if (keyboard_state[SDL_SCANCODE_RIGHT]) {
camera_yaw += camera_turn_speed; // Turn right
if (camera_yaw > 180.0f) camera_yaw -= 360.0f; // Wrap yaw
}
if (keyboard_state[SDL_SCANCODE_UP]) {
camera_pitch += camera_turn_speed; // Look up
if (camera_pitch > 89.0f) camera_pitch = 89.0f; // Clamp pitch
}
if (keyboard_state[SDL_SCANCODE_DOWN]) {
camera_pitch -= camera_turn_speed; // Look down
if (camera_pitch < -89.0f) camera_pitch = -89.0f; // Clamp pitch
}
}
// Upload vertex data to the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// ImGui frame
void imgui_frame() {
new_frame_imgui();
// Set up vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
frame_time_ui();
glBindVertexArray(0); // Unbind the vertex array object
ImGui::Begin("Control Panel");
ImGui::Text("Camera Position: (%.2f, %.2f, %.2f)", camera_position.x, camera_position.y, camera_position.z);
ImGui::Text("Camera Front: (%.2f, %.2f, %.2f)", camera_front.x, camera_front.y, camera_front.z);
ImGui::Text("Camera Up: (%.2f, %.2f, %.2f)", camera_up.x, camera_up.y, camera_up.z);
ImGui::Text("Camera Pitch: %.2f degrees", camera_pitch);
ImGui::Text("Camera Yaw: %.2f degrees", camera_yaw);
ImGui::SliderFloat("Field of View", &fov, 1.0f, 120.0f, "%.1f degrees");
ImGui::SliderFloat("Camera Speed", &camera_move_speed, 0.1f, 10.0f, "%.1f units/s");
ImGui::SliderFloat("Camera Turn Speed", &camera_turn_speed, 1.0f, 5.0f, "%.2f units/s");
ImGui::Checkbox("Wireframe Mode", &wireframe_mode);
if (wireframe_mode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Enable wireframe mode
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Disable wireframe mode
}
ImGui::End();
}
// Load shaders
const char* vertex_shader_source = read_file("shaders/triangle.vert");
const char* fragment_shader_source = read_file("shaders/triangle.frag");
// Main
int main(int argc, char* argv[]) {
// Initialize SDL, OpenGL, and ImGui
init();
unsigned int vertex_shader = compile_shader(vertex_shader_source, GL_VERTEX_SHADER);
unsigned int fragment_shader = compile_shader(fragment_shader_source, GL_FRAGMENT_SHADER);
unsigned int shader_program = create_program(vertex_shader, fragment_shader);
// Load shader program
Shader shader_program("shaders/triangle_untextured.vert", "shaders/triangle_untextured.frag");
// Set the shader program
glUseProgram(shader_program);
// Generate and set up textures
Texture texture1("assets/crate.jpg");
Texture texture2("assets/meow.png");
shader_program.use();
shader_program.setInt("texture1", 0);
shader_program.setInt("texture2", 1);
// Wireframe toggle
bool wireframe_mode = false;
// Load an OBJ file
Obj obj = load_obj("assets/cube.obj");
// print vertex and index counts
std::cout << "Loaded OBJ file: " << obj.vertex_count << " vertices, " << obj.index_count << " indices." << std::endl;
// Create the object and set up its geometry
UntexturedObject object(
obj.vertices, obj.vertex_count * 3 * sizeof(float),
obj.indices, obj.index_count * sizeof(unsigned int)
);
glm::mat4 modelMatrix = glm::mat4(1.0f);
// Main loop
while (running) {
// Handle events
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL3_ProcessEvent(&event); // Process ImGui events
if (event.type == SDL_EVENT_QUIT) {
running = false; // Exit loop on quit event
}
}
handle_events();
handle_keyboard_input();
// Start the ImGui frame
new_frame_imgui();
// ImGui frame
imgui_frame();
// Frame time UI
frame_time_ui();
// Toggle wireframe mode ui
ImGui::Begin("Wireframe Mode");
if (ImGui::Checkbox("Enable Wireframe Mode", &wireframe_mode)) {
if (wireframe_mode) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Enable wireframe mode
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // Disable wireframe mode
}
}
ImGui::End();
// Update the projection and view matrices
projectionMatrix = glm::perspective(glm::radians(fov), (float)window_width / (float)window_height, 0.1f, 100.0f);
camera_front = glm::vec3(
cos(glm::radians(camera_yaw)) * cos(glm::radians(camera_pitch)),
sin(glm::radians(camera_pitch)),
sin(glm::radians(camera_yaw)) * cos(glm::radians(camera_pitch))
);
viewMatrix = glm::lookAt(camera_position, camera_position + camera_front, camera_up);
// Render
ImGui::Render();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO); // Bind the vertex array object
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Draw the triangles
// Use the shader program
shader_program.use();
shader_program.setMat4("view", viewMatrix); // Set the view matrix
shader_program.setMat4("projection", projectionMatrix); // Set the projection matrix
shader_program.setMat4("model", modelMatrix); // Set the model matrix
texture1.bind(0); // Bind texture 1 to unit 0
texture2.bind(1); // Bind texture 2 to unit 1
object.draw(); // Draw the object
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(window);
@ -119,14 +197,6 @@ int main(int argc, char* argv[]) {
}
// Cleanup
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shader_program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
free((void*)vertex_shader_source);
free((void*)fragment_shader_source);
cleanup_imgui();
cleanup_opengl();
cleanup_sdl();

97
src/shader.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "shader.hpp"
Shader::Shader(const char* vertexPath, const char* fragmentPath) {
// Load and compile vertex shader
unsigned int shader = glCreateShader(GL_VERTEX_SHADER);
if (shader == 0) {
std::cerr << "Failed to create shader." << std::endl;
}
const char* vertex_shader_source = read_file(vertexPath);
glShaderSource(shader, 1, &vertex_shader_source, nullptr);
glCompileShader(shader);
// Check for vertex shader compilation errors
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char info_log[512];
glGetShaderInfoLog(shader, sizeof(info_log), nullptr, info_log);
std::cerr << "Vertex shader compilation error: " << info_log << std::endl;
glDeleteShader(shader);
}
// Load and compile fragment shader
unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
if (fragment_shader == 0) {
std::cerr << "Failed to create shader." << std::endl;
}
const char* fragment_shader_source = read_file(fragmentPath);
glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
glCompileShader(fragment_shader);
// Check for fragment shader compilation errors
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success) {
char info_log[512];
glGetShaderInfoLog(fragment_shader, sizeof(info_log), nullptr, info_log);
std::cerr << "Fragment shader compilation error: " << info_log << std::endl;
glDeleteShader(fragment_shader);
}
// Create shader program
ID = glCreateProgram();
if (ID == 0) {
std::cerr << "Failed to create shader program." << std::endl;
}
glAttachShader(ID, shader);
glAttachShader(ID, fragment_shader);
glLinkProgram(ID);
// Check for linking errors
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success) {
char info_log[512];
glGetProgramInfoLog(ID, sizeof(info_log), nullptr, info_log);
std::cerr << "Shader program linking error: " << info_log << std::endl;
glDeleteProgram(ID);
ID = 0; // Reset ID to indicate failure
}
// Clean up shaders as they are no longer needed
glDeleteShader(shader);
glDeleteShader(fragment_shader);
}
void Shader::use() const {
if (ID != 0) {
glUseProgram(ID);
} else {
std::cerr << "Shader program not initialized." << std::endl;
}
}
void Shader::setBool(const std::string &name, bool value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setMat4(const std::string &name, const glm::mat4 &mat) const {
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
Shader::~Shader() {
if (ID != 0) {
glDeleteProgram(ID);
ID = 0; // Reset ID to indicate the shader program has been deleted
}
}

68
src/texture.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "texture.hpp"
void flip_surface(SDL_Surface* surface) {
if (!surface) {
std::cerr << "Surface is null, cannot flip" << std::endl;
return;
}
int pitch = surface->pitch;
Uint8* pixels = static_cast<Uint8*>(surface->pixels);
int height = surface->h;
for (int y = 0; y < height / 2; ++y) {
Uint8* top_row = pixels + y * pitch;
Uint8* bottom_row = pixels + (height - y - 1) * pitch;
for (int x = 0; x < pitch; ++x) {
std::swap(top_row[x], bottom_row[x]);
}
}
}
Texture::Texture(const char* file_path) {
ID = 0;
SDL_Surface* surface = IMG_Load(file_path);
if (!surface) {
std::cerr << "Failed to load texture: " << SDL_GetError() << std::endl;
return; // Texture loading failed
}
GLenum format = (surface->format == SDL_PIXELFORMAT_RGBA32) ? GL_RGBA : GL_RGB;
flip_surface(surface); // Flip the surface vertically
glGenTextures(1, &ID);
glBindTexture(GL_TEXTURE_2D, ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, format, surface->w, surface->h, 0, format, GL_UNSIGNED_BYTE, surface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
SDL_DestroySurface(surface); // Free the surface after uploading texture data
}
Texture::~Texture() {
if (ID != 0) {
glDeleteTextures(1, &ID);
}
}
void Texture::bind() const {
glBindTexture(GL_TEXTURE_2D, ID);
}
void Texture::bind(unsigned int unit) const {
if (unit >= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) {
std::cerr << "Texture unit out of range: " << unit << std::endl;
return; // Invalid texture unit
}
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, ID);
}
void Texture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@ -4,6 +4,8 @@
float main_scale;
SDL_Window* window;
SDL_Event event;
int window_width = 850; // Default window width
int window_height = 850; // Default window height
// Functions
int initialize_sdl() {