#include "../include/RenderBackend/OpenGL/opengl.hpp" #include "../include/RenderBackend/OpenGL/Shader.hpp" #include "../include/RenderBackend/OpenGL/ShaderProgram.hpp" #include "../include/RenderBackend/OpenGL/DeviceMemory.hpp" #include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" #include "../include/RenderBackend/OpenGL/Texture2D.hpp" #include "../include/Image.hpp" #include "../include/Triangle.hpp" #include "../include/model_loader/ObjModelLoader.hpp" #include #include // TODO: Creating buffers etc should be somehow created/drawn using the window object, since they are associated with the window // opengl context using namespace amalgine; using namespace std; static void glfwErrorHandler(int errorCode, const char *errorDescription); static void initGlfw(); static void initGlew(); static GLFWwindow *createWindow(); static std::unique_ptr load_shader_from_file(const char *filepath, Shader::Type shader_type); static std::unique_ptr build_shader_program_from_shaders(const std::vector &shaders); struct Userdata { float cam_dist; }; static std::vector generate_sand() { const int rows = 50; const int columns = 50; std::vector vertices(rows * columns * 2); int i = 0; float div = 0.3f; for(int y = 0; y < rows; ++y) { for(int x = 0; x < columns; ++x) { vertices[i++] = { Vertex3D{x * div + 0.0f, y * div + 0.0f, 0.0f}, Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} }; vertices[i++] = { Vertex3D{x * div + 1.0f * div, y * div + 0.0f, 0.0f}, Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f}, Vertex3D{x * div + 0.0f, y * div + 1.0f * div, 0.0f} }; } } return vertices; } int main() { initGlfw(); glfwSetErrorCallback(glfwErrorHandler); GLFWwindow *window = createWindow(); int window_width = 1; int window_height = 1; glfwGetWindowSize(window, &window_width, &window_height); DeviceFrame frame; std::vector cpu_sand = generate_sand(); DeviceMemory *gpuSand = frame.alloc(); gpuSand->copy({cpu_sand.data(), cpu_sand.size()}, DeviceMemory::StorageType::STATIC); std::unique_ptr sand_vertex_shader = load_shader_from_file("shaders/sand_vertex.vert", Shader::Type::VERTEX); std::unique_ptr sand_pixel_shader = load_shader_from_file("shaders/sand_fragment.frag", Shader::Type::PIXEL); std::unique_ptr sand_shader_program = build_shader_program_from_shaders({ sand_vertex_shader.get(), sand_pixel_shader.get() }); std::vector triangles; std::vector texture_coords; Image *image; ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); DeviceMemory *gpuModel = frame.alloc(); gpuModel->copy({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); Texture2D model_texture(image); DeviceMemory *model_gpu_texture = frame.alloc(); model_gpu_texture->copy({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); std::unique_ptr vertex_shader = load_shader_from_file("shaders/vertex.vert", Shader::Type::VERTEX); std::unique_ptr pixel_shader = load_shader_from_file("shaders/fragment.frag", Shader::Type::PIXEL); std::unique_ptr shader_program = build_shader_program_from_shaders({ vertex_shader.get(), pixel_shader.get() }); glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); vec3f triangle_color = { 1.0f, 0.0f, 0.0f }; Result sand_proj_uniform = sand_shader_program->get_uniform_by_name("proj"); Result sand_view_uniform = sand_shader_program->get_uniform_by_name("view"); Result sand_model_uniform = sand_shader_program->get_uniform_by_name("model"); Result sand_time = sand_shader_program->get_uniform_by_name("time"); Result sand_triangle_color_uniform = sand_shader_program->get_uniform_by_name("triangle_color"); Result proj_uniform = shader_program->get_uniform_by_name("proj"); Result view_uniform = shader_program->get_uniform_by_name("view"); Result model_uniform = shader_program->get_uniform_by_name("model"); Result tex_uniform = shader_program->get_uniform_by_name("tex"); sand_proj_uniform->set(proj); sand_triangle_color_uniform->set(triangle_color); proj_uniform->set(proj); shader_program->set_input_data("texcoord_vert", *model_gpu_texture); tex_uniform->set(model_texture); Userdata userdata; userdata.cam_dist = 3.0f; glm::vec3 character_pos(0.0f, 0.0f, userdata.cam_dist); auto t_start = std::chrono::high_resolution_clock::now(); glfwSetWindowUserPointer(window, &userdata); glfwSetScrollCallback(window, [](GLFWwindow *window, double xoffset, double yoffset){ Userdata *userdata = (Userdata*)glfwGetWindowUserPointer(window); userdata->cam_dist += yoffset; }); glEnable(GL_CULL_FACE); float time = 0.0f; while(!glfwWindowShouldClose(window)) { glfwPollEvents(); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); auto t_now = std::chrono::high_resolution_clock::now(); float time_delta = std::chrono::duration_cast>(t_now - t_start).count(); t_start = t_now; time += time_delta; float move_speed = time_delta * 3.0f; if(glfwGetKey(window, GLFW_KEY_W)) character_pos.y -= move_speed; if(glfwGetKey(window, GLFW_KEY_S)) character_pos.y += move_speed; if(glfwGetKey(window, GLFW_KEY_A)) character_pos.x += move_speed; if(glfwGetKey(window, GLFW_KEY_D)) character_pos.x -= move_speed; character_pos.z = userdata.cam_dist; glm::mat4 view = glm::lookAt( character_pos, character_pos - glm::vec3(0.0f, 3.0f, 3.0f), glm::vec3(0.0f, 0.0f, 1.0f) ); sand_view_uniform->set(view); view_uniform->set(view); glm::mat4 model = glm::mat4(1.0f); model = glm::rotate( model, 0.0f, glm::vec3(0.0f, 0.0f, 1.0f) ); sand_model_uniform->set(model); model_uniform->set(model); //printf("now: %f\n", time); sand_time->set(time); // Set color for clearing glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Do the actual screen clearing, using the color set using glClearColor glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); shader_program->set_input_data("position", *gpuModel); frame.draw(shader_program.get()); sand_shader_program->set_input_data("position", *gpuSand); frame.draw(sand_shader_program.get()); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); } delete image; //glfwTerminate(); return 0; } void glfwErrorHandler(int errorCode, const char *errorDescription) { printf("GLFW error code: %d, description: %s\n", errorCode, errorDescription); } void initGlfw() { if(!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW\n"); exit(-1); } glfwWindowHint(GLFW_SAMPLES, 4); // anti aliasing glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); } void initGlew() { glewExperimental = true; if(glewInit() != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW\n"); glfwTerminate(); exit(-1); } } GLFWwindow* createWindow() { GLFWwindow *window = glfwCreateWindow(1920, 1080, "Amalgine", nullptr, nullptr); if(!window) { fprintf(stderr, "Failed to open GLFW window\n"); glfwTerminate(); exit(10); } glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_FALSE); glfwMakeContextCurrent(window); glfwSwapInterval(1); // 1 = enable vsync initGlew(); return window; } static int file_read_all(const char *filepath, std::string &result) { FILE *file = fopen(filepath, "rb"); if(!file) { perror("file_read_all"); return errno; } fseek(file, 0, SEEK_END); size_t file_size = ftell(file); fseek(file, 0, SEEK_SET); result.resize(file_size); fread(&result[0], 1, result.size(), file); fclose(file); return 0; } std::unique_ptr load_shader_from_file(const char *filepath, Shader::Type shader_type) { std::string file_content; if(file_read_all(filepath, file_content) != 0) exit(13); Result> vertex_shader_result = Shader::compile(shader_type, file_content.data(), file_content.size()); if(!vertex_shader_result) { fprintf(stderr, "Failed to compile shader, error: %s\n", vertex_shader_result.getErrorMsg().c_str()); exit(12); } return std::move(vertex_shader_result.unwrap()); } std::unique_ptr build_shader_program_from_shaders(const std::vector &shaders) { Result> shader_program_result = ShaderProgram::build(shaders); if(!shader_program_result) { fprintf(stderr, "Failed to link shaders, error: %s\n", shader_program_result.getErrorMsg().c_str()); exit(13); } return std::move(shader_program_result.unwrap()); }