From e29a9115d185d0b752868a36c8d56f6020bc4134 Mon Sep 17 00:00:00 2001 From: Loic Guegan Date: Sun, 5 Jul 2020 18:55:39 +0200 Subject: [PATCH] Create basics source files --- CMakeLists.txt | 41 ++++++++++ resources/shaders/square.glsl | 29 +++++++ src/opengl/renderer.cpp | 88 ++++++++++++++++++++ src/opengl/renderer.hpp | 54 ++++++++++++ src/opengl/shaders.cpp | 149 ++++++++++++++++++++++++++++++++++ src/opengl/shaders.hpp | 21 +++++ src/rms.cpp | 45 ++++++++++ tools/shader_watcher.sh | 50 ++++++++++++ 8 files changed, 477 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 resources/shaders/square.glsl create mode 100644 src/opengl/renderer.cpp create mode 100644 src/opengl/renderer.hpp create mode 100644 src/opengl/shaders.cpp create mode 100644 src/opengl/shaders.hpp create mode 100644 src/rms.cpp create mode 100755 tools/shader_watcher.sh diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2032208 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.17) +project(rms) +set(CMAKE_BUILD_TYPE Debug) + +# SFML (window system) +find_package(SFML 2.5 COMPONENTS window) +link_libraries(sfml-window) + +# GLEW (OpenglGL dependecies manager) +find_package(GLEW REQUIRED) +include_directories(${GLEW_INCLUDE_DIRS}) +link_libraries(${GLEW_LIBRARIES}) + +# OpenGL +find_package(OpenGL REQUIRED) +include_directories( ${OPENGL_INCLUDE_DIRS}) +link_libraries(${OPENGL_LIBRARIES}) + +# GLM for mathematics +find_package(glm 0.9 REQUIRED) +include_directories( ${GLM_INCLUDE_DIRS}) + +# Source files +file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS src/*.cpp src/*.hpp) +file(GLOB_RECURSE SHADERS_SRC_FILES CONFIGURE_DEPENDS resources/shaders/*) + +# Build +include_directories(${CMAKE_SOURCE_DIR}/src/) +add_executable(rms ${SRC_FILES}) + + +# Shaders +add_custom_target(shaders + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/resources/shaders ${CMAKE_BINARY_DIR}/resources/shaders + SOURCES ${SHADERS_SRC_FILES}) + +# Build shaders each time we build rms +add_dependencies(rms shaders) + + diff --git a/resources/shaders/square.glsl b/resources/shaders/square.glsl new file mode 100644 index 0000000..200215c --- /dev/null +++ b/resources/shaders/square.glsl @@ -0,0 +1,29 @@ +// ----- Vertex Shader ----- +#version 330 core + +layout(location = 0) in vec3 position; +uniform mat4 projection; +uniform mat4 model; + + +void main(){ + + gl_Position = projection * model * vec4(position,1); + +} + +// ----- Fragment Shader ----- + +#version 330 core + +uniform vec2 resolution; +uniform float time; + +out vec3 color; + +void main(){ + vec2 coord=gl_FragCoord.xy/resolution; + coord-=0.5; + float d=length(coord); + color=vec3(d,1,1); +} diff --git a/src/opengl/renderer.cpp b/src/opengl/renderer.cpp new file mode 100644 index 0000000..1898753 --- /dev/null +++ b/src/opengl/renderer.cpp @@ -0,0 +1,88 @@ +#include "renderer.hpp" +#include + + +void GLAPIENTRY MessageCallback( GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam ) +{ + std::cerr << "GL CALLBACK" << + (type == GL_DEBUG_TYPE_ERROR ? "(ERROR):" : "(UNKNOWN):") << + " type="<< std::showbase << std::hex << type << + " severity="<< severity << " message=" << message << std::endl; + + +} + +Renderer::Renderer(short width,short height): Width(width),Height(height), ClockStart(steady_clock::now()){ + // Init OpenGl + glewInit(); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glEnable ( GL_DEBUG_OUTPUT ); + glDebugMessageCallback( MessageCallback, 0 ); + + // Create screen quad + glGenVertexArrays(1,&VAO); + glBindVertexArray(VAO); + GLuint vertexbuffer; + glGenBuffers(1, &vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); + float square[]{ + -1,1,0, + 1,1,0, + -1,-1,0, + + -1,-1,0, + 1,1,0, + 1,-1,0 + + }; + glBufferData(GL_ARRAY_BUFFER, 6*3*sizeof(float), square, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0); + glBindVertexArray(0); + LoadShader("square.glsl"); +} + +void Renderer::Render(){ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(RayMarchingShader); + MProjection=glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.f,100.0f); + MModel=glm::scale(glm::mat4(1.0f),glm::vec3(10,10,1)); + glUniformMatrix4fv(UProjection, 1, GL_FALSE, &MProjection[0][0]); + glUniformMatrix4fv(UModel, 1, GL_FALSE, &MModel[0][0]); + ClockCurrent = std::chrono::steady_clock::now(); + duration time_span = duration_cast>(ClockCurrent - ClockStart); + glUniform1f(UTime, time_span.count()); + + glUniform2f(UResolution,Width,Height); + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES,0,6); + glBindVertexArray(0); + glUseProgram(0); +} + +void Renderer::UpdateShader(std::string name){ + glDeleteProgram(RayMarchingShader); + LoadShader(name); +} + +void Renderer::LoadShader(std::string name){ + RayMarchingShader = CompileShader("square.glsl"); + RayMarchingShader = CompileShader("square.glsl"); + UProjection = glGetUniformLocation(RayMarchingShader, "projection"); + UModel = glGetUniformLocation(RayMarchingShader, "model"); + UResolution = glGetUniformLocation(RayMarchingShader, "resolution"); + UTime = glGetUniformLocation(RayMarchingShader, "time"); +} + +void Renderer::AjustViewport(short width,short height){ + glViewport(0, 0, width,height); + this->Width=width; + this->Height=height; +} diff --git a/src/opengl/renderer.hpp b/src/opengl/renderer.hpp new file mode 100644 index 0000000..157ceb3 --- /dev/null +++ b/src/opengl/renderer.hpp @@ -0,0 +1,54 @@ +#pragma once +#include +#include "shaders.hpp" +#include +#include +#include "glm/gtc/matrix_transform.hpp" + +using namespace std::chrono; + +/** + * Bind this fonction with the following for debugging: + * glEnable ( GL_DEBUG_OUTPUT ); + * glDebugMessageCallback( MessageCallback, 0 ); + * @param source + * @param type + * @param id + * @param severity + * @param length + * @param message + * @param userParam + */ +void GLAPIENTRY MessageCallback( GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam); + +/** + * Main renderer class + */ +class Renderer { +private: + GLuint VAO; + GLuint RayMarchingShader; + GLuint UProjection; + GLuint UResolution; + GLuint UModel; + GLuint UTime; + glm::mat4 MProjection; + glm::mat4 MModel; + short Width,Height; + steady_clock::time_point ClockStart; + steady_clock::time_point ClockCurrent; + + void LoadShader(std::string name); + +public: + Renderer(short width,short height); + void Render(); + void AjustViewport(short with,short height); + void UpdateShader(std::string name); +}; diff --git a/src/opengl/shaders.cpp b/src/opengl/shaders.cpp new file mode 100644 index 0000000..34d4e8f --- /dev/null +++ b/src/opengl/shaders.cpp @@ -0,0 +1,149 @@ +#include "shaders.hpp" + +GLuint CompileShader(std::string shader_name){ + std::ifstream shader_file; + shader_file.open(std::string(SHADERS_RESOURCES) + "/" + shader_name); + if(!shader_file.is_open()) { + std::cout << "Failed to open: " << shader_name << std::endl; + exit(EXIT_FAILURE); + } + + std::string line; + char type='\0'; + std::stringstream ss[2]; + while(getline(shader_file, line)) { + if(line.find("- Vertex Shader -") != std::string::npos){ + type='v'; + } else if(line.find("- Fragment Shader -") != std::string::npos){ + type='f'; + } + + if(type=='v') + ss[0] << line << std::endl; + else if(type=='f') + ss[1] << line << std::endl; + } + + // Create ids + GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + // Compile vertex shader + std::string vsrc=ss[0].str(); + char const * vsrc_c = vsrc.c_str(); + glShaderSource(VertexShaderID, 1, &vsrc_c, NULL); + glCompileShader(VertexShaderID); + + // Compile fragment shader + std::string fsrc=ss[1].str(); + char const * fsrc_c = fsrc.c_str(); + glShaderSource(FragmentShaderID, 1, &fsrc_c, NULL); + glCompileShader(FragmentShaderID); + + // Link programs + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, FragmentShaderID); + glLinkProgram(ProgramID); + + // Cleaning + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + return ProgramID; +} + + +GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ + + // Create the shaders + GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + // Read the Vertex Shader code from the file + std::string VertexShaderCode; + std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); + if(VertexShaderStream.is_open()){ + std::stringstream sstr; + sstr << VertexShaderStream.rdbuf(); + VertexShaderCode = sstr.str(); + VertexShaderStream.close(); + }else{ + printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); + getchar(); + return 0; + } + + // Read the Fragment Shader code from the file + std::string FragmentShaderCode; + std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); + if(FragmentShaderStream.is_open()){ + std::stringstream sstr; + sstr << FragmentShaderStream.rdbuf(); + FragmentShaderCode = sstr.str(); + FragmentShaderStream.close(); + } + + GLint Result = GL_FALSE; + int InfoLogLength; + + + // Compile Vertex Shader + printf("Compiling shader : %s\n", vertex_file_path); + char const * VertexSourcePointer = VertexShaderCode.c_str(); + glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); + glCompileShader(VertexShaderID); + + // Check Vertex Shader + glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector VertexShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + } + + + + // Compile Fragment Shader + printf("Compiling shader : %s\n", fragment_file_path); + char const * FragmentSourcePointer = FragmentShaderCode.c_str(); + glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); + glCompileShader(FragmentShaderID); + + // Check Fragment Shader + glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector FragmentShaderErrorMessage(InfoLogLength+1); + glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); + printf("%s\n", &FragmentShaderErrorMessage[0]); + } + + // Link the program + printf("Linking program\n"); + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, FragmentShaderID); + glLinkProgram(ProgramID); + + // Check the program + glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); + glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); + if ( InfoLogLength > 0 ){ + std::vector ProgramErrorMessage(InfoLogLength+1); + glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); + printf("%s\n", &ProgramErrorMessage[0]); + } + + + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + return ProgramID; +} diff --git a/src/opengl/shaders.hpp b/src/opengl/shaders.hpp new file mode 100644 index 0000000..ba7da09 --- /dev/null +++ b/src/opengl/shaders.hpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include // ifstream +#include // stringstream +#include + +# ifndef NDEBUG +#define SHADERS_RESOURCES "../resources/shaders/" +#else +#define SHADERS_RESOURCES "resources/shaders/" +#endif +/** + * Compile a shader: + * - Shader should contains both vertex and fragment code + * - Vertex code should begin with: // ----- Vertex Shader ----- + * - Fragment code should begin with: // ----- Fragment Shader ----- + * @param shader_path + * @return The generated program id + */ +GLuint CompileShader(std::string shader_path); diff --git a/src/rms.cpp b/src/rms.cpp new file mode 100644 index 0000000..d2c6136 --- /dev/null +++ b/src/rms.cpp @@ -0,0 +1,45 @@ +#include +#include "opengl/renderer.hpp" + +#define WIDTH 1200 +#define HEIGHT 800 + +int main(int argc, char *argv[]) +{ + // Init SFML + sf::ContextSettings settings; + settings.depthBits = 24; + settings.stencilBits = 8; + settings.antialiasingLevel = 3; + settings.attributeFlags=sf::ContextSettings::Core; + sf::Window window(sf::VideoMode(WIDTH, HEIGHT,32), "SFML/OpenGL Ray Marching", sf::Style::Close, settings); + window.setFramerateLimit(60); // Limit to 60 frames per second + + // Init Renderer/OpenGL + Renderer renderer(WIDTH,HEIGHT); + + // Main loop + bool running=true; + while (running) + { + // gestion des évènements + sf::Event event; + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + running=false; + else if (event.type == sf::Event::Resized) + renderer.AjustViewport(event.size.width,event.size.height); + else if (event.key.code == sf::Keyboard::R) + renderer.UpdateShader("square.glsl"); + } + + renderer.Render(); + window.display(); // Refresh screen + } + + return 0; +} + + + diff --git a/tools/shader_watcher.sh b/tools/shader_watcher.sh new file mode 100755 index 0000000..d32285d --- /dev/null +++ b/tools/shader_watcher.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# ____ _ _ _ ____ _____ ____ +# / ___|| | | | / \ | _ \| ____| _ \ +# \___ \| |_| | / _ \ | | | | _| | |_) | +# ___) | _ |/ ___ \| |_| | |___| _ < +# |____/|_| |_/_/ \_\____/|_____|_| \_\ +# +# __ ___ _____ ____ _ _ _____ ____ +# \ \ / / \|_ _/ ___| | | | ____| _ \ +# \ \ /\ / / _ \ | || | | |_| | _| | |_) | +# \ V V / ___ \| || |___| _ | |___| _ < +# \_/\_/_/ \_\_| \____|_| |_|_____|_| \_\ +# +# This program require xdotool to communicate +# with the window. + +wai=$(dirname $(readlink -f "$0")) # Current script directory + + +refresh() { + wid=$(xdotool search --name 'SFML/OpenGL Ray Marching') + [ ! -z "$wid" ] && xdotool key --window "$wid" R +} + +usage() { + echo "Usage: $0 [options]" + echo "Options:" + echo " --every