#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/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 = 1.0f / (float)rows; for(int y = 0; y < rows; ++y) { for(int x = 0; x < columns; ++x) { vertices[i++] = { Vertex3D{x * div + 0.0f * div, y * div + 0.0f * div, 0.0f}, Vertex3D{x * div + 1.0f * div, y * div + 0.0f * div, 0.0f}, Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f} }; vertices[i++] = { Vertex3D{x * div + 1.0f * div, y * div + 1.0f * div, 0.0f}, Vertex3D{x * div + 0.0f * div, y * div + 1.0f * div, 0.0f}, Vertex3D{x * div + 0.0f * div, y * div + 0.0f * div, 0.0f} }; } } return vertices; } static void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *texture); static DeviceMemory* load_model(const char *filepath); int main() { initGlfw(); glfwSetErrorCallback(glfwErrorHandler); GLFWwindow *window = createWindow(); int window_width = 1; int window_height = 1; glfwGetWindowSize(window, &window_width, &window_height); glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); 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() }); ShaderFrame sand_frame = sand_shader_program->create_frame(); DeviceMemory *sand_triangles = sand_frame.get_input_by_name("position"); DeviceMemory *sand_texcoords = sand_frame.get_input_by_name("texcoord_vert"); Texture2D sand_texture; create_sand(sand_triangles, sand_texcoords, &sand_texture); Result sand_proj_uniform = sand_frame.get_uniform_by_name("proj"); Result sand_view_uniform = sand_frame.get_uniform_by_name("view"); Result sand_model_uniform = sand_frame.get_uniform_by_name("model"); //Result sand_time = sand_frame.get_uniform_by_name("time"); Result sand_heightmap_uniform = sand_frame.get_uniform_by_name("tex"); sand_proj_uniform->set(proj); sand_heightmap_uniform->set(sand_texture); 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() }); ShaderFrame model_frame = shader_program->create_frame(); std::vector triangles; std::vector texture_coords; Image *image; ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); DeviceMemory *gpuModel = model_frame.get_input_by_name("position"); gpuModel->set({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); Texture2D model_texture(image); DeviceMemory *model_gpu_texcoords = model_frame.get_input_by_name("texcoord_vert"); model_gpu_texcoords->set({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); Result proj_uniform = model_frame.get_uniform_by_name("proj"); Result view_uniform = model_frame.get_uniform_by_name("view"); Result model_uniform = model_frame.get_uniform_by_name("model"); Result tex_uniform = model_frame.get_uniform_by_name("tex"); proj_uniform->set(proj); 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); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); 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) ); model_uniform->set(model); glm::mat4 sand_model = glm::mat4(1.0f); sand_model = glm::rotate( sand_model, 0.0f, glm::vec3(0.0f, 0.0f, 1.0f) ); sand_model = glm::scale(sand_model, glm::vec3(50.0f, 50.0f, 50.0f)); sand_model_uniform->set(sand_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); model_frame.draw(); sand_frame.draw(); //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); } delete image; //glfwTerminate(); return 0; } void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *texture) { std::vector cpu_sand = generate_sand(); triangles->set({cpu_sand.data(), cpu_sand.size()}, DeviceMemory::StorageType::STATIC); Result height_map_image = Image::loadFromFile("heightmap.jpg"); if(!height_map_image) { fprintf(stderr, "Error: failed to load image: heightmap.jpg\n"); exit(1); } std::vector height_map_texcoord; for(const Triangle3D &triangle : cpu_sand) { height_map_texcoord.push_back(vec2f{ triangle.p1.x, triangle.p1.y }); height_map_texcoord.push_back(vec2f{ triangle.p2.x, triangle.p2.y }); height_map_texcoord.push_back(vec2f{ triangle.p3.x, triangle.p3.y }); } Texture2D height_map_texture(height_map_image.unwrap()); *texture = std::move(height_map_texture); texcoords->set({height_map_texcoord.data(), height_map_texcoord.size()}, DeviceMemory::StorageType::STATIC); } DeviceMemory* load_model(const char *filepath) { return nullptr; } 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()); }