From a00022523f5862105c3d1170ea960bb32b8de2cb Mon Sep 17 00:00:00 2001 From: lukas Date: Sat, 5 Feb 2022 21:44:31 +0100 Subject: [PATCH] init --- CMakeLists.txt | 34 +++++++ blocks/BaseBlock.cpp | 27 ++++++ blocks/BaseBlock.h | 23 +++++ blocks/BlockRenderer.cpp | 89 +++++++++++++++++++ blocks/BlockRenderer.h | 26 ++++++ blocks/GrasBlock.cpp | 8 ++ blocks/GrasBlock.h | 18 ++++ blocks/RenderBase.cpp | 48 ++++++++++ blocks/RenderBase.h | 61 +++++++++++++ blocks/fragment.shader | 20 +++++ blocks/geometry.shader | 25 ++++++ blocks/vertex.shader | 16 ++++ cmake/FindGLFW3.cmake | 49 +++++++++++ cmake/FindGLM.cmake | 57 ++++++++++++ gl/Camera.cpp | 95 ++++++++++++++++++++ gl/Camera.h | 30 +++++++ gl/IndexBuffer.cpp | 28 ++++++ gl/IndexBuffer.h | 26 ++++++ gl/Renderer.cpp | 15 ++++ gl/Renderer.h | 19 ++++ gl/Shader.cpp | 136 ++++++++++++++++++++++++++++ gl/Shader.h | 45 ++++++++++ gl/VertexArray.cpp | 26 ++++++ gl/VertexArray.h | 24 +++++ gl/VertexBuffer.cpp | 25 ++++++ gl/VertexBuffer.h | 23 +++++ main.cpp | 185 +++++++++++++++++++++++++++++++++++++++ 27 files changed, 1178 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 blocks/BaseBlock.cpp create mode 100644 blocks/BaseBlock.h create mode 100644 blocks/BlockRenderer.cpp create mode 100644 blocks/BlockRenderer.h create mode 100644 blocks/GrasBlock.cpp create mode 100644 blocks/GrasBlock.h create mode 100644 blocks/RenderBase.cpp create mode 100644 blocks/RenderBase.h create mode 100644 blocks/fragment.shader create mode 100644 blocks/geometry.shader create mode 100644 blocks/vertex.shader create mode 100644 cmake/FindGLFW3.cmake create mode 100644 cmake/FindGLM.cmake create mode 100644 gl/Camera.cpp create mode 100644 gl/Camera.h create mode 100644 gl/IndexBuffer.cpp create mode 100644 gl/IndexBuffer.h create mode 100644 gl/Renderer.cpp create mode 100644 gl/Renderer.h create mode 100644 gl/Shader.cpp create mode 100644 gl/Shader.h create mode 100644 gl/VertexArray.cpp create mode 100644 gl/VertexArray.h create mode 100644 gl/VertexBuffer.cpp create mode 100644 gl/VertexBuffer.h create mode 100644 main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ffb030d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.21) +project(opengltest) + +set(CMAKE_CXX_STANDARD 14) + + +# We need a CMAKE_DIR with some code to find external dependencies +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") + +# OpenGL +find_package(OpenGL REQUIRED) + +# GLM +find_package(GLM REQUIRED) +message(STATUS "GLM included at ${GLM_INCLUDE_DIR}") + +# GLFW +find_package(GLFW3 REQUIRED) +message(STATUS "Found GLFW3 in ${GLFW3_INCLUDE_DIR}") + +SET(srcs main.cpp gl/Shader.cpp gl/Shader.h + gl/IndexBuffer.cpp gl/IndexBuffer.h + gl/VertexBuffer.cpp gl/VertexBuffer.h + gl/VertexArray.cpp gl/VertexArray.h + gl/Renderer.cpp gl/Renderer.h + blocks/BaseBlock.cpp blocks/BaseBlock.h + blocks/GrasBlock.cpp blocks/GrasBlock.h + blocks/BlockRenderer.cpp blocks/BlockRenderer.h + blocks/RenderBase.cpp blocks/RenderBase.h + gl/Camera.cpp gl/Camera.h) + +add_executable(opengltest ${srcs}) + +target_link_libraries(opengltest ${GLFW3_LIBRARY} ${OPENGL_LIBRARY} ) diff --git a/blocks/BaseBlock.cpp b/blocks/BaseBlock.cpp new file mode 100644 index 0000000..a96953a --- /dev/null +++ b/blocks/BaseBlock.cpp @@ -0,0 +1,27 @@ +// +// Created by lukas on 04.02.22. +// + +#define GL_GLEXT_PROTOTYPES + +#include +#include +#include +#include +#include "BaseBlock.h" +#include "BlockRenderer.h" + +void BaseBlock::render() { + glUniform3f(BlockRenderer::getInstance()->getUniformhandle("u_color"), r, g, b); + + glm::mat4 position = glm::translate(glm::mat4(1.0f), glm::vec3((float) xpos * 2, (float) ypos * 2, (float) zpos * 2)); + glUniformMatrix4fv(BlockRenderer::getInstance()->getUniformhandle("translation"), 1, GL_FALSE, &position[0][0]); + + BlockRenderer::getInstance()->render(); +} + +BaseBlock::BaseBlock(float r, float g, float b, uint xpos, uint ypos, uint zpos) : r(r), g(g), b(b), xpos(xpos), ypos(ypos), zpos(zpos) { + // BlockRenderer::init(); + // this->getrenderer().init(); + +} \ No newline at end of file diff --git a/blocks/BaseBlock.h b/blocks/BaseBlock.h new file mode 100644 index 0000000..4fb8d8b --- /dev/null +++ b/blocks/BaseBlock.h @@ -0,0 +1,23 @@ +// +// Created by lukas on 04.02.22. +// + +#ifndef OPENGLTEST_BASEBLOCK_H +#define OPENGLTEST_BASEBLOCK_H + + +#include "BlockRenderer.h" + +class BaseBlock { +private: + + float r,g,b; + uint xpos,ypos,zpos; +public: + BaseBlock(float r, float g, float b, uint xpos, uint ypos, uint zpos); + + void render(); +}; + + +#endif //OPENGLTEST_BASEBLOCK_H diff --git a/blocks/BlockRenderer.cpp b/blocks/BlockRenderer.cpp new file mode 100644 index 0000000..576a808 --- /dev/null +++ b/blocks/BlockRenderer.cpp @@ -0,0 +1,89 @@ +// +// Created by lukas on 05.02.22. +// + +#include "BlockRenderer.h" + +#define GL_GLEXT_PROTOTYPES + +#include + +VertexArray *BlockRenderer::setVertexArray() { + float cube_vertices[] = { + // front + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, 1.0, 1.0, + -1.0, 1.0, 1.0, + // back + -1.0, -1.0, -1.0, + 1.0, -1.0, -1.0, + 1.0, 1.0, -1.0, + -1.0, 1.0, -1.0 + }; + + GLfloat cube_colors[] = { + // front colors + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, + 1.0, 1.0, 1.0, + // back colors + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, + 1.0, 1.0, 1.0 + }; + + // Generate a vertex buffer + auto *vb = new VertexBuffer(cube_vertices, sizeof(cube_vertices)); + + // + return new VertexArray(*vb); +} + +IndexBuffer *BlockRenderer::setIndexBuffer() { + unsigned cube_elements[] = { + // front + 0, 1, 2, + 2, 3, 0, + // right + 1, 5, 6, + 6, 2, 1, + // back + 7, 6, 5, + 5, 4, 7, + // left + 4, 0, 3, + 3, 7, 4, + // bottom + 4, 5, 1, + 1, 0, 4, + // top + 3, 2, 6, + 6, 7, 3 + }; + + return new IndexBuffer(cube_elements, 36);; +} + +Shader BlockRenderer::setShader() { + const std::string vertsrc = + +#include "vertex.shader" + + const std::string geosrc = + +#include "geometry.shader" + + const std::string fragsrc = + +#include "fragment.shader" + + Shader s; + s.loadShader(vertsrc, geosrc, fragsrc); + s.Bind(); + return s; +} + +BlockRenderer::BlockRenderer() {} diff --git a/blocks/BlockRenderer.h b/blocks/BlockRenderer.h new file mode 100644 index 0000000..714d7ca --- /dev/null +++ b/blocks/BlockRenderer.h @@ -0,0 +1,26 @@ +// +// Created by lukas on 05.02.22. +// + +#ifndef OPENGLTEST_BLOCKRENDERER_H +#define OPENGLTEST_BLOCKRENDERER_H + +#include "../gl/Renderer.h" +#include "../gl/Shader.h" +#include "RenderBase.h" +#include + +class BlockRenderer : public RenderBase { + +public: + BlockRenderer(); + + VertexArray* setVertexArray() override; + + Shader setShader() override; + + IndexBuffer *setIndexBuffer() override; +}; + + +#endif //OPENGLTEST_BLOCKRENDERER_H diff --git a/blocks/GrasBlock.cpp b/blocks/GrasBlock.cpp new file mode 100644 index 0000000..4d39f76 --- /dev/null +++ b/blocks/GrasBlock.cpp @@ -0,0 +1,8 @@ +// +// Created by lukas on 04.02.22. +// + +#include "GrasBlock.h" + +GrasBlock::GrasBlock(const uint &xpos, const uint &ypos, const uint &zpos) : BaseBlock(0.0f, 1.0f, 0.0f, xpos, ypos, zpos) { +} diff --git a/blocks/GrasBlock.h b/blocks/GrasBlock.h new file mode 100644 index 0000000..b668e5d --- /dev/null +++ b/blocks/GrasBlock.h @@ -0,0 +1,18 @@ +// +// Created by lukas on 04.02.22. +// + +#ifndef OPENGLTEST_GRASBLOCK_H +#define OPENGLTEST_GRASBLOCK_H + + +#include +#include "BaseBlock.h" + +class GrasBlock : public BaseBlock { +public: + GrasBlock(const uint &xpos, const uint &ypos, const uint &zpos); +}; + + +#endif //OPENGLTEST_GRASBLOCK_H diff --git a/blocks/RenderBase.cpp b/blocks/RenderBase.cpp new file mode 100644 index 0000000..589c56c --- /dev/null +++ b/blocks/RenderBase.cpp @@ -0,0 +1,48 @@ +// +// Created by lukas on 05.02.22. +// + +#include "RenderBase.h" + + + +//template +//RenderBase::RenderBase() { +// +//} + +//template +//void RenderBase::render() { +// r.render(*va, *ib); +//} + +//template +//void RenderBase::init() { +// s = setShader(); +// va = setVertexArray(); +// ib = setIndexBuffer(); +//} + +//template +//void RenderBase::deinit() { +// +//} + +//template +//unsigned RenderBase::getMVPhandle() { +// return s.getUniformHandle("MVP"); +//} + +//template +//unsigned RenderBase::getUniformhandle(std::string name) { +// return s.getUniformHandle(std::move(name)); +//} + +//template +//T *RenderBase::getInstance() { +// if (instance == nullptr) { +// instance = new T(); +// } +// return instance; +// +//} diff --git a/blocks/RenderBase.h b/blocks/RenderBase.h new file mode 100644 index 0000000..4d108d7 --- /dev/null +++ b/blocks/RenderBase.h @@ -0,0 +1,61 @@ +// +// Created by lukas on 05.02.22. +// + +#ifndef OPENGLTEST_RENDERBASE_H +#define OPENGLTEST_RENDERBASE_H + + +#include "../gl/Renderer.h" +#include "../gl/Shader.h" + +template +class RenderBase { +public: + virtual VertexArray* setVertexArray() = 0; + virtual Shader setShader() = 0; + virtual IndexBuffer* setIndexBuffer() = 0; + + static RenderBase* getInstance() { + if (instance == nullptr) { + instance = new T(); + instance->init(); + } + return instance; + + } + +private: + static RenderBase* instance; + + +private: + Renderer r; + VertexArray* va; + IndexBuffer* ib; + Shader s; + +public: + RenderBase(){}; + void render(){ + r.render(*va, *ib, s); + } + void init() { + s = setShader(); + va = setVertexArray(); + ib = setIndexBuffer(); + } + void deinit(){} + + unsigned getMVPhandle(){ + return s.getUniformHandle("MVP"); + } + unsigned getUniformhandle(std::string name){ + return s.getUniformHandle(std::move(name)); + } +}; + +template +RenderBase *RenderBase::instance = nullptr; + +#endif //OPENGLTEST_RENDERBASE_H diff --git a/blocks/fragment.shader b/blocks/fragment.shader new file mode 100644 index 0000000..273ce43 --- /dev/null +++ b/blocks/fragment.shader @@ -0,0 +1,20 @@ +R"(#version 330 core +out vec4 color; +uniform vec3 u_color; + +in vec3 normal; +in vec4 pos; + +void main() +{ + vec3 norm = normalize(normal); + vec3 lightDir = normalize(vec3(4.0,3.0,3.0) - pos.xyz); + + float diff = max(dot(norm, lightDir), 0.0); + + // set light color + vec3 diffuse = diff * vec3(1.0,1.0,1.0); + + vec3 result = (diffuse) * u_color; + color = vec4(result,0.0); +})"; \ No newline at end of file diff --git a/blocks/geometry.shader b/blocks/geometry.shader new file mode 100644 index 0000000..e3eab01 --- /dev/null +++ b/blocks/geometry.shader @@ -0,0 +1,25 @@ +R"(#version 330 + +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +out vec3 normal; + +out vec4 pos; + +void main( void ) +{ + vec3 a = ( gl_in[1].gl_Position - gl_in[0].gl_Position ).xyz; + vec3 b = ( gl_in[2].gl_Position - gl_in[0].gl_Position ).xyz; + vec3 N = normalize( cross( b, a ) ); + + for( int i=0; i/glm/glm.hpp OR +# /include/glm/glm.hpp +# This variable can either be a cmake or environment +# variable. Note however that changing the value +# of the environment varible will NOT result in +# re-running the header search and therefore NOT +# adjust the variables set by this module. +#============================================================================= +# Copyright 2012 Carsten Neumann +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) +# default search dirs + +SET(_glm_HEADER_SEARCH_DIRS + "/usr/include" + "/usr/local/include" + "${CMAKE_SOURCE_DIR}/include" + "C:/Program Files (x86)/glm" ) +# check environment variable +SET(_glm_ENV_ROOT_DIR "$ENV{GLM_ROOT_DIR}") +IF(NOT GLM_ROOT_DIR AND _glm_ENV_ROOT_DIR) + SET(GLM_ROOT_DIR "${_glm_ENV_ROOT_DIR}") +ENDIF(NOT GLM_ROOT_DIR AND _glm_ENV_ROOT_DIR) +# put user specified location at beginning of search +IF(GLM_ROOT_DIR) + SET(_glm_HEADER_SEARCH_DIRS "${GLM_ROOT_DIR}" + "${GLM_ROOT_DIR}/include" + ${_glm_HEADER_SEARCH_DIRS}) +ENDIF(GLM_ROOT_DIR) +# locate header +FIND_PATH(GLM_INCLUDE_DIR "glm/glm.hpp" + PATHS ${_glm_HEADER_SEARCH_DIRS}) +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLM DEFAULT_MSG + GLM_INCLUDE_DIR) +IF(GLM_FOUND) + SET(GLM_INCLUDE_DIRS "${GLM_INCLUDE_DIR}") + MESSAGE(STATUS "GLM_INCLUDE_DIR = ${GLM_INCLUDE_DIR}") +ENDIF(GLM_FOUND) \ No newline at end of file diff --git a/gl/Camera.cpp b/gl/Camera.cpp new file mode 100644 index 0000000..9eb66dd --- /dev/null +++ b/gl/Camera.cpp @@ -0,0 +1,95 @@ +// +// Created by lukas on 05.02.22. +// +#define GL_GLEXT_PROTOTYPES +#include +#include +#include +#include +#include +#include "Camera.h" +#include "../blocks/BlockRenderer.h" + +void Camera::setPos(double x, double y, double z) { + this->x = x; + this->y = y; + this->z = z; + + updateCameraPos(); +} + +void Camera::setRotation(double rotx, double roty) { + rx = rotx; + ry = roty; + + updateCameraPos(); +} + +void Camera::updateCameraPos() { + // Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units + glm::mat4 Projection = glm::perspective(glm::radians(45.0f), (float) width / (float) height, 0.1f, 100.0f); + + // Or, for an ortho camera : + //glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates + // + // float rotation = M_PI; + // + // float x = cos(rotation); + // float y = sin(rotation); + + const float radius = 5.0f; + double camX = sin(rx) * radius; + double camZ = cos(rx) * radius; + double camY = sin(ry) * radius; + + glm::mat4 View = glm::lookAt( + glm::vec3(2.0f, 2.0f, 3.0f), // and looks at the origin + glm::vec3(camX, camZ, camY), // Camera is at (4,3,3), in World Space + glm::vec3(0, 0, 1) // Head is up (set to 0,-1,0 to look upside-down) + ); + + auto View2 = glm::translate(View, glm::vec3(x, -y, -z)); + + // Model matrix : an identity matrix (model will be at the origin) + glm::mat4 Model = glm::mat4(1.0f); + // Our ModelViewProjection : multiplication of our 3 matrices + glm::mat4 mvp = Projection * View2 * Model; // Remember, matrix multiplication is the other way around + + // todo not really generic if we call blockrenderer here + glUniformMatrix4fv((int) BlockRenderer::getInstance()->getMVPhandle(), 1, GL_FALSE, &mvp[0][0]); +} + +Camera::Camera(double width, double height) : width(width), height(height) {} + +void Camera::setWindowSize(double width, double height) { + this->width = width; + this->height = height; +} + +void Camera::addRotaion(double rotx, double roty) { + rx -= rotx / 300; + ry -= roty / 300; + + + // limit to 2pi + rx = std::fmod(rx, (2 * M_PI)); + ry = std::fmod(ry, (2 * M_PI)); + + updateCameraPos(); +} + +void Camera::addPos(double x, double y, double z) { + this->x += x; + this->y += y; + this->z += z; + + updateCameraPos(); +} + +double Camera::getxangle() const { + return rx; +} + +double Camera::getyangle() const { + return ry; +} diff --git a/gl/Camera.h b/gl/Camera.h new file mode 100644 index 0000000..50f08c8 --- /dev/null +++ b/gl/Camera.h @@ -0,0 +1,30 @@ +// +// Created by lukas on 05.02.22. +// + +#ifndef OPENGLTEST_CAMERA_H +#define OPENGLTEST_CAMERA_H + + +class Camera { +private: + double x, y, z, rx, ry, width, height; + + void updateCameraPos(); +public: + Camera(double width, double height); + + void setWindowSize(double width, double height); + + void setPos(double x, double y, double z); + void addPos(double x, double y, double z); + + void setRotation(double rotx, double roty); + void addRotaion(double rotx, double roty); + + double getxangle() const; + double getyangle() const; +}; + + +#endif //OPENGLTEST_CAMERA_H diff --git a/gl/IndexBuffer.cpp b/gl/IndexBuffer.cpp new file mode 100644 index 0000000..1503478 --- /dev/null +++ b/gl/IndexBuffer.cpp @@ -0,0 +1,28 @@ +// +// Created by lukas on 03.02.22. +// + +#include "IndexBuffer.h" +#include + +IndexBuffer::IndexBuffer(const unsigned *data, unsigned count): count(count) { + glGenBuffers(1, &handle); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned) * count , data, GL_STATIC_DRAW); +} + +IndexBuffer::~IndexBuffer() { + glDeleteBuffers(1, &handle); +} + +void IndexBuffer::Bind() const { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); +} + +void IndexBuffer::UnBind() const { + glBindVertexArray(0); +} + +unsigned IndexBuffer::getcount() const { + return count; +} diff --git a/gl/IndexBuffer.h b/gl/IndexBuffer.h new file mode 100644 index 0000000..816ea79 --- /dev/null +++ b/gl/IndexBuffer.h @@ -0,0 +1,26 @@ +// +// Created by lukas on 03.02.22. +// + +#ifndef OPENGLTEST_INDEXBUFFER_H +#define OPENGLTEST_INDEXBUFFER_H + +#define GL_GLEXT_PROTOTYPES + +class IndexBuffer { +private: + unsigned handle; + unsigned count; +public: + IndexBuffer(const unsigned *data, unsigned count); + + virtual ~IndexBuffer(); + + void Bind() const; + void UnBind() const; + + unsigned getcount() const; +}; + + +#endif //OPENGLTEST_INDEXBUFFER_H diff --git a/gl/Renderer.cpp b/gl/Renderer.cpp new file mode 100644 index 0000000..94ca78a --- /dev/null +++ b/gl/Renderer.cpp @@ -0,0 +1,15 @@ +// +// Created by lukas on 04.02.22. +// +#define GL_GLEXT_PROTOTYPES + +#include +#include "Renderer.h" + +void Renderer::render(const VertexArray& va, const IndexBuffer& ib, const Shader& s) { + va.Bind(); + ib.Bind(); + s.Bind(); + + glDrawElements(GL_TRIANGLES, ib.getcount(), GL_UNSIGNED_INT, nullptr); +} diff --git a/gl/Renderer.h b/gl/Renderer.h new file mode 100644 index 0000000..759cb2f --- /dev/null +++ b/gl/Renderer.h @@ -0,0 +1,19 @@ +// +// Created by lukas on 04.02.22. +// + +#ifndef OPENGLTEST_RENDERER_H +#define OPENGLTEST_RENDERER_H + + +#include "VertexArray.h" +#include "IndexBuffer.h" +#include "Shader.h" + +class Renderer { +public: + void render(const VertexArray& va, const IndexBuffer& ib, const Shader& s); +}; + + +#endif //OPENGLTEST_RENDERER_H diff --git a/gl/Shader.cpp b/gl/Shader.cpp new file mode 100644 index 0000000..95e7014 --- /dev/null +++ b/gl/Shader.cpp @@ -0,0 +1,136 @@ +// +// Created by lukas on 03.02.22. +// + +#include "Shader.h" + +#define GL_GLEXT_PROTOTYPES + +#include +#include +#include +#include +#include +#include + +unsigned int Shader::compileShader(const char *source, unsigned int type) const { + unsigned int shaderid = glCreateShader(type); + + // Compile Shader + glShaderSource(shaderid, 1, &source, NULL); + glCompileShader(shaderid); + + // Check Shader + int Result = GL_FALSE; + int InfoLogLength; + + glGetShaderiv(shaderid, GL_COMPILE_STATUS, &Result); + glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &InfoLogLength); + if (InfoLogLength > 0) { + std::vector VertexShaderErrorMessage(InfoLogLength + 1); + glGetShaderInfoLog(shaderid, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + + return 0; + } + + return shaderid; +} + +void Shader::Bind() const { + glUseProgram(mProgHandle); +} + +unsigned Shader::getHandle() const { + return mProgHandle; +} + +unsigned Shader::getUniformHandle(std::string name) { + if(uniformhandles.find(name) != uniformhandles.end()){ + return uniformhandles[name]; + }else{ + const unsigned id = glGetUniformLocation(mProgHandle, name.c_str()); + uniformhandles[name] = id; + return id; + } +} + +std::string Shader::readFile(std::string path) { + // Read the Vertex Shader code from the file + std::string VertexShaderCode; + std::ifstream VertexShaderStream(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", path.c_str()); + getchar(); + return ""; + } + return VertexShaderCode; +} + +unsigned int Shader::loadShaderFromFile(const std::string vertex_file_path, const std::string geometry_file_path, const std::string fragment_file_path) { + // Read the Vertex Shader code from the file + std::string VertexShaderCode = readFile(vertex_file_path); + std::string FragmentShaderCode = readFile(fragment_file_path); + std::string GeometryShaderCode = readFile("../geometry.shader"); + + return loadShader(VertexShaderCode, GeometryShaderCode, FragmentShaderCode); +} + +unsigned int Shader::loadShader(const std::string vertex_src, const std::string geometry_src, const std::string fragment_src) { + // Compile Vertex Shader + printf("Compiling vertex shader\n"); + uint VertexShaderID = compileShader(vertex_src.c_str(), GL_VERTEX_SHADER); + if (VertexShaderID == 0) { + printf("Error Compiling shader\n"); + return 0; + } + + printf("Compiling geometry shader\n"); + uint GeometryShaderID = compileShader(geometry_src.c_str(), GL_GEOMETRY_SHADER); + if (GeometryShaderID == 0) { + printf("Error Compiling shader\n"); + return 0; + } + + printf("Compiling fragment shader\n"); + uint FragmentShaderID = compileShader(fragment_src.c_str(), GL_FRAGMENT_SHADER); + if (FragmentShaderID == 0) { + printf("Error Compiling shader\n"); + return 0; + } + + // Link the program + GLint Result = GL_FALSE; + int InfoLogLength; + + printf("Linking shader program\n"); + GLuint ProgramID = glCreateProgram(); + glAttachShader(ProgramID, VertexShaderID); + glAttachShader(ProgramID, GeometryShaderID); + 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]); + } + + // cleanup shaders + glDetachShader(ProgramID, VertexShaderID); + glDetachShader(ProgramID, FragmentShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + + mProgHandle = ProgramID; + return ProgramID; +} diff --git a/gl/Shader.h b/gl/Shader.h new file mode 100644 index 0000000..1bc93e1 --- /dev/null +++ b/gl/Shader.h @@ -0,0 +1,45 @@ +// +// Created by lukas on 03.02.22. +// + +#ifndef OPENGLTEST_SHADER_H +#define OPENGLTEST_SHADER_H + +#include +#include + +class Shader { +private: + unsigned mProgHandle; + + std::unordered_map uniformhandles; +public: + /** + * load the compiled shader pipeline + * @param vertex_file_path path to vertex source file + * @param fragment_file_path path to fragment source file + * @return program id + */ + unsigned int loadShaderFromFile(const std::string vertex_file_path, const std::string geometry_file_path, const std::string fragment_file_path); + + unsigned int loadShader(const std::string vertex_src, const std::string geometry_src, const std::string fragment_src); + + /** + * comile a specific shader source + * @param source source string + * @param type shader tpye + * @return id of copiled shader + */ + unsigned int compileShader(const char *source, unsigned int type) const; + + std::string readFile(std::string path); + + void Bind() const; + + unsigned getHandle() const; + + unsigned getUniformHandle(std::string name); + +}; + +#endif //OPENGLTEST_SHADER_H diff --git a/gl/VertexArray.cpp b/gl/VertexArray.cpp new file mode 100644 index 0000000..48df8e4 --- /dev/null +++ b/gl/VertexArray.cpp @@ -0,0 +1,26 @@ +// +// Created by lukas on 04.02.22. +// +#define GL_GLEXT_PROTOTYPES +#include +#include "VertexArray.h" + +void VertexArray::Bind() const { + glBindVertexArray(handle); +} + +VertexArray::VertexArray(const VertexBuffer& buff) { + buff.Bind(); + + // generate new vertex array object + glGenVertexArrays(1, &handle); + Bind(); + + // specify syntax of my data + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) nullptr); + glEnableVertexAttribArray(0); +} + +unsigned VertexArray::getHandle() const { + return handle; +} diff --git a/gl/VertexArray.h b/gl/VertexArray.h new file mode 100644 index 0000000..a4806bb --- /dev/null +++ b/gl/VertexArray.h @@ -0,0 +1,24 @@ +// +// Created by lukas on 04.02.22. +// + +#ifndef OPENGLTEST_VERTEXARRAY_H +#define OPENGLTEST_VERTEXARRAY_H + + +#include +#include "VertexBuffer.h" + +class VertexArray { +private: + unsigned handle; +public: + VertexArray(const VertexBuffer& buff); + + void Bind() const; + + unsigned getHandle() const; +}; + + +#endif //OPENGLTEST_VERTEXARRAY_H diff --git a/gl/VertexBuffer.cpp b/gl/VertexBuffer.cpp new file mode 100644 index 0000000..5f57ef6 --- /dev/null +++ b/gl/VertexBuffer.cpp @@ -0,0 +1,25 @@ +// +// Created by lukas on 03.02.22. +// + +#include "VertexBuffer.h" + +#include + +VertexBuffer::VertexBuffer(const void* data, const unsigned size) { + glGenBuffers(1, &handle); + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); +} + +VertexBuffer::~VertexBuffer() { + glDeleteBuffers(1, &handle); +} + +void VertexBuffer::Bind() const { + glBindBuffer(GL_ARRAY_BUFFER, handle); +} + +void VertexBuffer::UnBind() const { + glBindVertexArray(0); +} diff --git a/gl/VertexBuffer.h b/gl/VertexBuffer.h new file mode 100644 index 0000000..8be43a2 --- /dev/null +++ b/gl/VertexBuffer.h @@ -0,0 +1,23 @@ +// +// Created by lukas on 03.02.22. +// + +#ifndef OPENGLTEST_VERTEXBUFFER_H +#define OPENGLTEST_VERTEXBUFFER_H + +#define GL_GLEXT_PROTOTYPES + +class VertexBuffer { +private: + unsigned handle; +public: + VertexBuffer(const void* data, const unsigned size); + + virtual ~VertexBuffer(); + + void Bind() const; + void UnBind() const; +}; + + +#endif //OPENGLTEST_VERTEXBUFFER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..cfeda65 --- /dev/null +++ b/main.cpp @@ -0,0 +1,185 @@ +#include + +#define GL_GLEXT_PROTOTYPES + +#include +#include +#include +#include "gl/Shader.h" +#include "gl/IndexBuffer.h" +#include "gl/VertexArray.h" +#include "gl/Renderer.h" +#include "blocks/GrasBlock.h" +#include "blocks/BlockRenderer.h" +#include "gl/Camera.h" +#include + +#include + +//#define WIREFRAME + +void framebuffer_size_callback(GLFWwindow *window, int width, int height); + +void processInput(GLFWwindow *window); + +int width = 1920; +int height = 1080; + +Camera cam(width, height); + +double oldx = 0; +double oldy = 0; + +bool menuopen = false; + +void cursor_position_callback(GLFWwindow *window, double xpos, double ypos) { + if (menuopen)return; + + double xdiff = oldx - xpos; + oldx = xpos; + + double ydiff = oldy - ypos; + oldy = ypos; + + cam.addRotaion(xdiff, ydiff); +} + +GLFWwindow *initWindow() { + + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + // create new window + GLFWwindow *window = glfwCreateWindow(width, height, "LearnOpenGL", NULL, NULL); + if (window == NULL) { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + exit(-1); + } + glfwMakeContextCurrent(window); + + // limit frame rate + glfwSwapInterval(1); + + // set window viewport + glViewport(0, 0, width, height); + + // callback when window was resized + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + + glfwSetCursorPosCallback(window, cursor_position_callback); + + if (glfwRawMouseMotionSupported()) + glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); + + + std::cout << "[GLFW] " << glfwGetVersionString() << std::endl; + std::cout << "[GL] " << glGetString(GL_VERSION) << std::endl; + + return window; +} + + +int main() { + GLFWwindow *window = initWindow(); + +#ifdef WIREFRAME + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); +#endif + + glEnable(GL_DEPTH_TEST); + + GrasBlock gb(0, 0, 0); + BaseBlock bb(0.0f, (float) rand() / RAND_MAX, 1.0f, 1, 0, 0); + + // BlockRenderer::getInstance()->init(); + + std::vector blocks; + + blocks.push_back(gb); + blocks.push_back(bb); + blocks.emplace_back(1.0f, .0f, 1.0f, 0, 0, 1); + + for (int i = 0; i < 5; i++) { + blocks.push_back(GrasBlock(i, i, 0)); + } + + cam.setPos(0, 0, 0); + cam.setRotation(0,0); + + while (!glfwWindowShouldClose(window)) { + // process user input events + processInput(window); + + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + for (auto b: blocks) { + b.render(); + } + + // swap buffer to calc and show + glfwSwapBuffers(window); + // poll for and execute events + glfwPollEvents(); + } + + // glDeleteProgram(shaderProgram); + BlockRenderer::getInstance()->deinit(); + glfwTerminate(); + return 0; +} + +// callback when user resizes image +void framebuffer_size_callback(GLFWwindow *window, int width, int height) { + glViewport(0, 0, width, height); + cam.setWindowSize(width, height); +} + +void processInput(GLFWwindow *window) { + // 45c view range + double viewrange = M_PI / 8; + + if (!menuopen) { + + if (glfwGetKey(window, GLFW_KEY_W)) { + cam.addPos(-sin(cam.getxangle() - viewrange) * 0.1, cos(cam.getxangle() + viewrange) * 0.1, 0.0); + } + + if (glfwGetKey(window, GLFW_KEY_S)) { + cam.addPos(sin(cam.getxangle() + viewrange) * 0.1, -cos(cam.getxangle() - viewrange) * 0.1, 0.0); + } + + if (glfwGetKey(window, GLFW_KEY_D)) { + cam.addPos(sin(cam.getxangle() - M_PI / 2) * 0.1, -cos(cam.getxangle() - M_PI / 2) * 0.1, 0.0); + } + + if (glfwGetKey(window, GLFW_KEY_A)) { + cam.addPos(sin(cam.getxangle() + M_PI / 2) * 0.1, -cos(cam.getxangle() + M_PI / 2) * 0.1, 0.0); + } + + if (glfwGetKey(window, GLFW_KEY_SPACE)) { + cam.addPos(0.0,0.0,0.1); + } + + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) { + cam.addPos(0.0,0.0,-0.1); + } + } + + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + menuopen = !menuopen; + + glfwSetInputMode(window, GLFW_CURSOR, menuopen ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_DISABLED); + + // reset old cursor pos to new one to avoid a jump + glfwGetCursorPos(window, &oldx, &oldy); + } + // glfwSetWindowShouldClose(window, true); +} \ No newline at end of file