first commit

This commit is contained in:
DawidPietrykowski 2021-08-10 22:52:19 +02:00
commit 8d2af1dbda
25 changed files with 2456 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.vscode
lib
include
test
packages
.vs
bin
obj
build
makeP.bat

137
CMakeLists.txt Normal file
View File

@ -0,0 +1,137 @@
cmake_minimum_required(VERSION 3.10)
# So library linking is more sane.
cmake_policy(SET CMP0003 NEW)
# So syntax problems are errors.
cmake_policy(SET CMP0010 NEW)
# Input directories must have CMakeLists.txt
cmake_policy(SET CMP0014 NEW)
# Compile definitions.
cmake_policy(SET CMP0043 NEW)
# Use ROOT variables in find_package.
cmake_policy(SET CMP0074 NEW)
# Convert relative paths to absolute in target_sources()
cmake_policy(SET CMP0076 NEW)
# Copy files from source directory to destination directory, substituting any
# variables. Create destination directory if it does not exist.
macro(configure_files srcDir destDir)
message(STATUS "Configuring directory ${destDir}")
make_directory(${destDir})
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
foreach(templateFile ${templateFiles})
set(srcTemplatePath ${srcDir}/${templateFile})
if(NOT IS_DIRECTORY ${srcTemplatePath})
message(STATUS "Configuring file ${templateFile}")
configure_file(
${srcTemplatePath}
${destDir}/${templateFile}
@ONLY)
endif(NOT IS_DIRECTORY ${srcTemplatePath})
endforeach(templateFile)
endmacro(configure_files)
# Initialize project
project(ComputeEngine)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(default_build_type "Release")
# Add binary
add_library(${PROJECT_NAME} STATIC)
# Find GLFW
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
find_path(GLFW_INCLUDE_DIR GLFW/glfw3.h
HINTS
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/lib
${GLFW_ROOT}
${GLFW_ROOT}/include)
if(GLFW_INCLUDE_DIR)
message(STATUS "GLFW_INCLUDE_DIR: ${GLFW_INCLUDE_DIR}")
else()
message(FATAL_ERROR "glfw3.h not found")
endif()
find_path(GLFW_LIB_DIR glfw3.lib
HINTS
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/lib
${GLFW_ROOT}/lib
${GLFW_ROOT}/lib-vc2019
${GLFW_ROOT}/lib-vc2017
${GLFW_ROOT}/lib-vc2015)
if(GLFW_LIB_DIR)
message(STATUS "GLFW_LIB_DIR: ${GLFW_LIB_DIR}")
else()
message(FATAL_ERROR "glfw3.lib not found")
endif()
# Find GLEW
find_package(GLEW REQUIRED)
if(GLEW_FOUND)
set(GLEW_INCLUDE_DIR ${GLEW_INCLUDE_DIRS})
get_filename_component(GLEW_LIBRARIES ${GLEW_LIBRARIES} DIRECTORY)
message(STATUS "GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}")
message(STATUS "GLEW_LIBRARIES: ${GLEW_LIBRARIES}")
else()
message(FATAL_ERROR "GLEW not found")
endif()
# Find OpenGL
if(NOT WIN32)
find_package(OpenGL REQUIRED)
endif()
# Find stb_image
find_path(stb_image_INCLUDE_DIR stb_image.h
HINTS
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/include/stb
${CMAKE_CURRENT_SOURCE_DIR}/lib
${stb_image_ROOT})
if(stb_image_INCLUDE_DIR)
message(STATUS "stb_image_INCLUDE_DIR: ${stb_image_INCLUDE_DIR}")
else()
message(FATAL_ERROR "stb_image not found")
endif()
# Add source
add_subdirectory(src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src
${GLFW_INCLUDE_DIR}
${OPENGL_INCLUDE_DIR}
${stb_image_INCLUDE_DIR}
${GLEW_INCLUDE_DIR})
target_link_directories(${PROJECT_NAME} PUBLIC ${GLFW_LIB_DIR} ${GLEW_LIBRARIES})
target_link_libraries(${PROJECT_NAME} "glfw3.lib" "opengl32.lib" "glew32s.lib")
# Header files
file(COPY src/ComputeEngine.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/Timer.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/Texture.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/UBO.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/SSBO.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/Shader.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/Program.h DESTINATION ${CMAKE_BINARY_DIR}/include)
file(COPY src/GLUtils.h DESTINATION ${CMAKE_BINARY_DIR}/include)
#file(COPY src/Scene.h DESTINATION ${CMAKE_BINARY_DIR}/include)

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Dawid Pietrykowski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

79
README.md Normal file
View File

@ -0,0 +1,79 @@
# GPU Ray Tracer
GPU Ray Tracing application based on my OpenGL Compute Engine.
<p align="center">
<img src="screenshots/fox2.png">
</p>
## Dependencies
* OpenGL
* GLFW
* GLEW
* [stb_image](https://github.com/nothings/stb)
* [OpenGL Compute Engine](https://github.com/DawidPietrykowski/ComputeEngine)
## Build
Specify these root directories for dependencies in [make.bat](make.bat) script:
* GLFW_ROOT
* GLEW_ROOT
* stb_image_ROOT
* ComputeEngine_ROOT
Run [make.bat](make.bat) script.
## Config files
Each scene/configuration is described in a config file.
Example scenes are located in [/configs](configs) directory.
All available parameters are specified in [config_template.txt](config_template.txt).
## Usage
Pass chosen config file to the generated executable as an argument in command line.
If no argument given, *config.txt* is picked.
## Features
* Wavefront (.obj) file import
* PNG, JPG, HDR texture import
* Object can be an imported triangle mesh, sphere or infinite plane
* Each scene is saved in a separate file
* Specular and diffuse reflections
* Physics based refractions
* Camera movement
* Screenshot saving
## Example images
Mesh | Refraction
:-------------------------:|:-------------------------:
![](screenshots/fox2.png) | ![](screenshots/refraction1.png)
Multiple meshes 1 | Multiple meshes 2
![](screenshots/objects1.png) | ![](screenshots/objects4.jpg)
Solar system 1 | Solar system 2
![](screenshots/solar_system1.png) | ![](screenshots/solar_system2.png)
## Keys
Camera
* UP - SPACE
* DOWN - CTRL
* LEFT - A
* RIGHT - D
* FORWARD - W
* BACKWARD - S
Window
* Screenshot - L
* Disable input to window - P
* Close application - ESC
## License and copyright
© Dawid Pietrykowski
Licensed under the [MIT LICENSE](LICENSE)

8
make.bat Normal file
View File

@ -0,0 +1,8 @@
@echo off
set GLFW_ROOT=
set GLEW_ROOT=
set stb_image_ROOT=
cmake -B build -S . -DGLFW_ROOT=%GLFW_ROOT% -DGLEW_ROOT=%GLEW_ROOT% -Dstb_image_ROOT=%stb_image_ROOT%
cmake --build build --config Release

2
remake.bat Normal file
View File

@ -0,0 +1,2 @@
rmdir /s /q build
make.bat

21
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
target_sources(${PROJECT_NAME}
PUBLIC
GLUtils.cpp
GLUtils.h
ComputeEngine.cpp
ComputeEngine.h
Program.cpp
Program.h
#Scene.cpp
#Scene.h
Shader.cpp
Shader.h
SSBO.cpp
SSBO.h
UBO.cpp
UBO.h
Texture.cpp
Texture.h
Timer.cpp
Timer.h
)

379
src/ComputeEngine.cpp Normal file
View File

@ -0,0 +1,379 @@
#include <Windows.h>
#include "ComputeEngine.h"
#define STBI_MSC_SECURE_CRT
#define STB_IMAGE_WRITE_IMPLEMENTATION
#pragma warning(disable : 4996)
#include <stb_image_write.h>
#include <cstdlib>
#include <chrono>
#include <string>
#include <vector>
#include <iostream>
#include <math.h>
#include <array>
#include <cmath>
#include <vector>
#include <string>
#include <fileapi.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Texture.h"
#include "Program.h"
#include "Shader.h"
#include "Timer.h"
ComputeEngine* m_instance;
ComputeEngine::~ComputeEngine() {
m_TextureDisplay.~Program();
m_instance = nullptr;
glfwTerminate();
}
ComputeEngine::ComputeEngine(int w, int h, std::string name, bool focus, bool tonemapping)
{
m_instance = this;
m_width = w;
m_height = h;
m_window = InitWindow(m_width, m_height, name, focus);
LOG("GLFW initiated");
GLCall(glEnable(GL_DEBUG_OUTPUT));
glewExperimental = GL_FALSE;
glfwGetCursorPos(m_window, &m_xpos, &m_ypos);
Shader vertexShadrer(GL_VERTEX_SHADER);
Shader fragmentShader(GL_FRAGMENT_SHADER, tonemapping);
m_TextureDisplay = InitQuad(vertexShadrer, fragmentShader);
LOG("Texture display shader created");
for(int i = 0; i < 348; i++)
m_keys[i] = GLFW_RELEASE;
}
GLFWwindow* ComputeEngine::InitWindow(int width, int height, std::string name, bool focus) {
GLFWwindow* window;
if (!glfwInit())
LOG("Failed to initialize glfw");
window = glfwCreateWindow(width, height, name.c_str(), NULL, NULL);
if (!window)
{
glfwTerminate();
LOG("Failed to initialize window");
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, this->KeyCallback);
glfwSetMouseButtonCallback(window, this->MouseButtonCallback);
glfwSetFramebufferSizeCallback(window, this->FramebufferSizeCallback);
if (focus) {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
glfwSetWindowSizeLimits(window, 200, 200, m_fullscreen_width, m_fullscreen_height);
m_input = focus;
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
LOG("Error: " << glewGetErrorString(err));
}
LOG("Using GL " << glGetString(GL_VERSION));
LOG("Using GLEW " << glewGetString(GLEW_VERSION));
GLFWmonitor* primary = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(primary);
m_fullscreen_width = mode->width;
m_fullscreen_height = mode->height;
return window;
}
Program ComputeEngine::InitQuad(Shader& vertShader, Shader& fragShader) {
unsigned int buffer;
GLCall(glGenBuffers(1, &buffer));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, buffer));
float quad_vao[] = {
-1.0f, -1.0f, 0.0f, 0.0f, // bottom left corner
-1.0f, 1.0f, 0.0f, 1.0f, // top left corner
1.0f, -1.0f, 1.0f, 0.0f, // bottom right corner
1.0f, 1.0f, 1.0f, 1.0f // top right corner
};
GLCall(glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, quad_vao, GL_STATIC_DRAW));
GLuint vao = 0;
GLCall(glGenVertexArrays(1, &vao));
GLCall(glBindVertexArray(vao));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GLCall(glEnableVertexAttribArray(0));
GLCall(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)0));
GLCall(glEnableVertexAttribArray(1));
GLCall(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(sizeof(float) * 2)));
Program quad_program(vertShader, fragShader);
return quad_program;
}
void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
std::string sev = "";
if (severity == GL_DEBUG_SEVERITY_LOW)
sev = "low";
else if (severity == GL_DEBUG_SEVERITY_HIGH)
sev = "high";
else if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
return;
else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
sev = "medium";
fprintf(stderr, "GL CALLBACK: %s type = %x, severity = %s, message = %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
type, sev.c_str(), message);
}
void ComputeEngine::FramebufferSizeCallback(GLFWwindow* window, int w, int h) {
if(w != 0 && h != 0)
(*m_instance).UpdateSize(w, h);
}
void ComputeEngine::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
(*m_instance).m_keys[key] = action;
}
void ComputeEngine::MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
(*m_instance).m_mouse_buttons[button] = action;
}
void ComputeEngine::PollEvents() {
ResetKeys();
glfwPollEvents();
for (int i = 0; i < 348; i++) {
m_keys[i] = (m_keys[i] == GLFW_PRESS && m_prev_keys[i] == GLFW_PRESS) ? GLFW_REPEAT : m_keys[i];
}
for (int i = 0; i < 8; i++) {
m_mouse_buttons[i] = (m_mouse_buttons[i] == GLFW_PRESS && m_prev_mouse_buttons[i] == GLFW_PRESS) ? GLFW_REPEAT : m_mouse_buttons[i];
}
double x_p, y_p;
glfwGetCursorPos(m_window, &x_p, &y_p);
m_dx = (float)(m_xpos - x_p) * m_input;
m_dy = (float)(m_ypos - y_p) * m_input;
m_xpos = x_p;
m_ypos = y_p;
}
void ComputeEngine::ResetKeys() {
memcpy(m_prev_keys, m_keys, sizeof(int) * 348);
memcpy(m_prev_mouse_buttons, m_mouse_buttons, sizeof(int) * 8);
}
void ComputeEngine::SetFullscreen(bool fullscreen) {
m_fullscreen = fullscreen;
if (!m_fullscreen) {
m_width = m_windowed_width;
m_height = m_windowed_height;
glfwSetWindowMonitor(m_window, NULL, 200, 200, m_width, m_height, GLFW_DONT_CARE);
glViewport(0, 0, m_width, m_height);
}
else {
m_windowed_width = m_width;
m_windowed_height = m_height;
m_width = m_fullscreen_width;
m_height = m_fullscreen_height;
glfwSetWindowMonitor(m_window, NULL, 0, 0, m_width, m_height, GLFW_DONT_CARE);
glViewport(0, 0, m_width, m_height);
m_dx = 0;
m_dy = 0;
}
}
void ComputeEngine::SwitchFullScreen() {
SetFullscreen(!IsFullscreen());
}
void ComputeEngine::GetWindowSize(int& width, int& height) {
width = m_width;
height = m_height;
}
bool ComputeEngine::IsFullscreen() {
return m_fullscreen;
}
void ComputeEngine::SetInput(bool mode) {
m_input = mode;
if(!mode)
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
else
glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
void ComputeEngine::UpdateSize(int width, int height) {
m_width = width;
m_height = height;
glViewport(0, 0, m_width, m_height);
}
bool ComputeEngine::ShouldClose() {
return glfwWindowShouldClose(m_window);
}
void ComputeEngine::CloseWindow() {
glfwSetWindowShouldClose(m_window, GLFW_TRUE);
}
void ComputeEngine::SwitchInput() {
SetInput(!m_input);
}
void ComputeEngine::DrawTexture(Texture &texture){
m_TextureDisplay.Use();
GLCall(glMemoryBarrier(GL_ALL_BARRIER_BITS));
GLCall(glActiveTexture(GL_TEXTURE0));
GLuint boundTexture = 0;
GLCall(glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&boundTexture));
GLCall(glBindTexture(GL_TEXTURE_2D, texture.GetId()));
GLCall(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
GLCall(glBindTexture(GL_TEXTURE_2D, boundTexture));
GLCall(glfwSwapBuffers(m_window));
}
void ComputeEngine::UpdateFrametime() {
double ms = m_timer.GetMilis();
m_frametime = m_framecount > 0 ? ms : 1;
m_time_sum += m_frametime;
m_framecount++;
}
void ComputeEngine::SaveScreen(std::string name) {
bool found = true;
int i = 0;
while (found) {
i++;
std::string full_name_png = "screenshots\\" + name + std::to_string(i) + ".png";
std::string full_name_jpg = "screenshots\\" + name + std::to_string(i) + ".jpg";
found = FileExists(full_name_png) || FileExists(full_name_jpg);
}
const char* path = "screenshots";
CreateDirectoryA(path, NULL);
name = name + std::to_string(i) + ".png";
int img_size = 4 * m_width * m_height;
unsigned char* pixels = new unsigned char[img_size];
LOG("Saving screenshot: " + name);
GLCall(glReadBuffer(GL_FRONT));
GLCall(glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
stbi__flip_vertically_on_write = true;
stbi_write_png(("screenshots\\" + name).c_str(), m_width, m_height, 4, pixels, m_width * 4);
delete[] pixels;
};
void ComputeEngine::Finish() {
GLCall(glFinish());
}
bool ComputeEngine::IsKeyPressed(int key) {
int state = m_keys[key];
return state == GLFW_PRESS || state == GLFW_REPEAT;
}
bool ComputeEngine::IsKeyClicked(int key) {
return m_keys[key] == GLFW_PRESS;
}
bool ComputeEngine::IsMouseButtonPressed(int button) {
int state = m_mouse_buttons[button];
return state == GLFW_PRESS || state == GLFW_REPEAT;
}
bool ComputeEngine::IsMouseButtonClicked(int button) {
return m_prev_mouse_buttons[button] == GLFW_PRESS;
}
void ComputeEngine::GetMousePos(double& xpos, double& ypos) {
xpos = m_xpos;
ypos = m_ypos;
}
void ComputeEngine::GetMouseDelta(double& dx, double& dy) {
dx = m_dx;
dy = m_dy;
}
bool ComputeEngine::GetInput() {
return m_input;
}
double ComputeEngine::GetFrametime() {
return m_frametime;
}
int ComputeEngine::GetFramecount() {
return m_framecount;
}
double ComputeEngine::GetAverageFrametime() {
return m_time_sum / m_framecount;
}
int ComputeEngine::GetWidth() {
return m_width;
}
int ComputeEngine::GetHeight() {
return m_height;
}
float ComputeEngine::GetRand() {
return (float)((double)rand() / (RAND_MAX));
}
bool ComputeEngine::FileExists(const std::string& name) {
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
GLFWwindow* ComputeEngine::GetWindow() {
return m_window;
}

89
src/ComputeEngine.h Normal file
View File

@ -0,0 +1,89 @@
#pragma once
#define GLEW_STATIC
#include "UBO.h"
#include "GLUtils.h"
#include "SSBO.h"
#include "Texture.h"
#include "Program.h"
#include "Scene.h"
#include "Shader.h"
#include "Timer.h"
class ComputeEngine {
public:
ComputeEngine(int w, int h, std::string name, bool focus = true, bool tonemapping = false);
~ComputeEngine();
GLFWwindow* InitWindow(int width, int height, std::string name, bool focus);
void UpdateFrametime();
void CloseWindow();
void SwitchInput();
void SetInput(bool mode);
void PollEvents();
void GetMousePos(double& xpos, double& ypos);
void GetMouseDelta(double& dx, double& dy);
void SaveScreen(std::string name);
void ResetKeys();
void SetFullscreen(bool fullscreen);
void SwitchFullScreen();
void GetWindowSize(int& width, int& height);
void DrawTexture(Texture& texture);
void Finish();
bool IsFullscreen();
bool GetInput();
bool ShouldClose();
bool IsKeyPressed(int key);
bool IsKeyClicked(int key);
bool IsMouseButtonPressed(int button);
bool IsMouseButtonClicked(int button);
bool FileExists(const std::string& name);
double GetFrametime();
double GetAverageFrametime();
int GetWidth();
int GetHeight();
int GetFramecount();
float GetRand();
GLFWwindow* GetWindow();
private:
Program m_TextureDisplay;
Timer m_timer;
GLFWwindow* m_window;
Program InitQuad(Shader& vertShader, Shader& fragShader);
double m_frametime = 0;
double m_time_sum = 0;
int m_keys[348];
int m_prev_keys[348];
int m_mouse_buttons[8];
int m_prev_mouse_buttons[8];
bool m_fullscreen = false;
bool m_input = false;
int m_framecount = 0;
int m_width, m_height;
int m_windowed_width, m_windowed_height;
double m_xpos = 0, m_ypos = 0;
float m_dx = 0, m_dy = 0;
int m_fullscreen_width = 1920;
int m_fullscreen_height = 1080;
static void FramebufferSizeCallback(GLFWwindow* window, int width, int height);
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
static void MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
void UpdateSize(int w, int h);
};

75
src/GLUtils.cpp Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include "GLUtils.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <sys/stat.h>
using std::cout;
using std::endl;
bool glErrorCheck() {
bool no_err = true;
GLenum error = glGetError();
while (error) {
std::string err_str;
switch (error) {
case GL_NO_ERROR:
err_str = "GL_NO_ERROR";
break;
case GL_INVALID_ENUM:
err_str = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
err_str = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
err_str = "GL_INVALID_OPERATION";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
err_str = "GL_INVALID_FRAMEBUFFER_OPERATION";
break;
case GL_OUT_OF_MEMORY:
err_str = "GL_OUT_OF_MEMORY";
break;
default:
err_str = "GL_UNKNOWN_ERROR";
break;
}
cout << err_str << endl;
error = glGetError();
no_err = false;
return no_err;
}
return no_err;
}
void glClearError() {
while (glGetError() != GL_NO_ERROR);
}
void PrintSizeLimits() {
GLint size;
GLint size2;
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &size);
std::cout << "GL_MAX_TEXTURE_BUFFER_SIZE is " << ((float)size * 32.0f / 1073741824.0f) << " GB" << endl;
glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &size);
std::cout << "GL_MAX_SHADER_STORAGE_BLOCK_SIZE is " << ((float)size / 1073741824.0f) << " GB" << endl;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &size);
std::cout << "GL_MAX_UNIFORM_BLOCK_SIZE is " << ((float)size / 1024.0f) << " KB" << endl;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size);
std::cout << "GL_MAX_TEXTURE_SIZE is " << ((float)size / 1024.0f) << " MB" << endl;
glGetIntegerv(GL_MAX_IMAGE_UNITS, &size);
std::cout << "GL_MAX_IMAGE_UNITS is " << size << endl;
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &size);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &size2);
std::cout << "GL_MAX_COMPUTE_WORK_GROUP_SIZE is " << size << ", " << size2 << endl;
}

29
src/GLUtils.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define ASSERT(x) if(!(x)){ std::cout << "[ERROR] " << #x << '\n';\
__debugbreak();}
#define GLCall(x) \
glClearError();\
x;\
if(!(glErrorCheck())){ std::cout << "[ERROR] " << #x << '\n';\
__debugbreak();}
#if 1
#define LOG(msg) \
std::cout << '[' << __TIME__ << "] Renderer: " << msg << std::endl
#else
#define LOG(msg) \
std::cout << __FILENAME__ << "(" << __LINE__ << "): " << msg << std::endl
#endif
void PrintSizeLimits();
bool glErrorCheck();
void glClearError();

428
src/Program.cpp Normal file
View File

@ -0,0 +1,428 @@
#include "Program.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "GLUtils.h"
#include "Texture.h"
#include "Shader.h"
Program::Program() :
m_id(0)
{
}
Program::Program(unsigned int _id) :
m_id(_id)
{
}
Program::Program(Shader& vertShader, Shader& fragShader) {
unsigned int program;
GLCall(program = glCreateProgram());
GLCall(glAttachShader(program, vertShader.GetId()));
GLCall(glAttachShader(program, fragShader.GetId()));
GLCall(glLinkProgram(program));
GLCall(glValidateProgram(program));
m_id = program;
}
Program::~Program() {
Delete();
}
Program::Program(Program&& other) :
m_id(other.m_id)
{
other.m_id = 0;
}
Program& Program::operator=(Program&& other)
{
if (this != &other)
{
Delete();
std::swap(m_id, other.m_id);
}
return *this;
}
Program::Program(Shader& computeShader) {
unsigned int program;
GLCall(program = glCreateProgram());
GLCall(glAttachShader(program, computeShader.GetId()));
GLCall(glLinkProgram(program));
GLCall(glValidateProgram(program));
m_id = program;
}
void Program::Delete() {
if (m_id != 0) {
GLCall(glDeleteProgram(m_id));
}
m_id = 0;
}
void Program::DispatchCompute(int width, int height) {
Use();
int up_w = int(ceil((float)width / 8.0f));
int up_h = int(ceil((float)height / 8.0f));
GLCall(glDispatchCompute(up_w, up_h, 1));
}
void Program::DispatchCompute(int x) {
Use();
GLCall(glDispatchCompute(x, 1, 1));
}
void Program::Use() {
GLCall(glUseProgram(m_id));
}
void Program::BindTexture(Texture& texture, int slot) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, texture.GetName().c_str()));
ASSERT(location != -1);
Use();
GLCall(glUniform1i(location, slot));
texture.Bind(slot);
}
void Program::BindTexture(Texture* texture, int slot) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, texture->GetName().c_str()));
ASSERT(location != -1);
Use();
GLCall(glUniform1i(location, slot));
texture->Bind(slot);
}
void Program::BindTexture(Texture& texture, int slot, std::string name) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1i(location, slot));
texture.Bind(slot);
}
void Program::BindTextureImage(Texture& texture, int slot) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, texture.GetName().c_str()));
ASSERT(location != -1);
GLCall(glUniform1i(location, slot));
texture.BindImage(slot);
}
unsigned int Program::GetId() {
return m_id;
}
void Program::SetUniform1f(std::string name, float u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1f(location, u));
}
void Program::SetUniform2f(std::string name, float u1, float u2) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2f(location, u1, u2));
}
void Program::SetUniform3f(std::string name, float u1, float u2, float u3) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3f(location, u1, u2, u3));
}
void Program::SetUniform4f(std::string name, float u1, float u2, float u3, float u4) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4f(location, u1, u2, u3, u4));
}
void Program::SetUniform1i(std::string name, int u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1i(location, u));
}
void Program::SetUniform2i(std::string name, int u1, int u2) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2i(location, u1, u2));
}
void Program::SetUniform3i(std::string name, int u1, int u2, int u3) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3i(location, u1, u2, u3));
}
void Program::SetUniform4i(std::string name, int u1, int u2, int u3, int u4) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4i(location, u1, u2, u3, u4));
}
void Program::SetUniform1ui(std::string name, unsigned int u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1ui(location, u));
}
void Program::SetUniform2ui(std::string name, unsigned int u1, unsigned int u2) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2ui(location, u1, u2));
}
void Program::SetUniform3ui(std::string name, unsigned int u1, unsigned int u2, unsigned int u3) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3ui(location, u1, u2, u3));
}
void Program::SetUniform4ui(std::string name, unsigned int u1, unsigned int u2, unsigned int u3, unsigned int u4) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4ui(location, u1, u2, u3, u4));
}
void Program::SetUniform1fv(std::string name, int count, float* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1fv(location, count, u));
}
void Program::SetUniform2fv(std::string name, int count, float* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2fv(location, count, u));
}
void Program::SetUniform3fv(std::string name, int count, float* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3fv(location, count, u));
}
void Program::SetUniform4fv(std::string name, int count, float* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4fv(location, count, u));
}
void Program::SetUniform1iv(std::string name, int count, int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1iv(location, count, u));
}
void Program::SetUniform2iv(std::string name, int count, int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2iv(location, count, u));
}
void Program::SetUniform3iv(std::string name, int count, int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3iv(location, count, u));
}
void Program::SetUniform4iv(std::string name, int count, int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4iv(location, count, u));
}
void Program::SetUniform1uiv(std::string name, int count, unsigned int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform1uiv(location, count, u));
}
void Program::SetUniform2uiv(std::string name, int count, unsigned int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform2uiv(location, count, u));
}
void Program::SetUniform3uiv(std::string name, int count, unsigned int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform3uiv(location, count, u));
}
void Program::SetUniform4uiv(std::string name, int count, unsigned int* u) {
Use();
int location;
GLCall(location = glGetUniformLocation(m_id, name.c_str()));
ASSERT(location != -1);
GLCall(glUniform4uiv(location, count, u));
}

61
src/Program.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include "Shader.h"
#include "Texture.h"
class Program {
private:
unsigned int m_id = 0;
public:
Program();
~Program();
Program(unsigned int id);
Program(Shader& vertShader, Shader& fragShader);
Program(Shader& computeShader);
Program& operator=(Program&& other);
Program(Program&& other);
Program(const Program&) = delete;
Program& operator=(const Program&) = delete;
void Delete();
void Use();
void DispatchCompute(int width, int height);
void DispatchCompute(int x);
void BindTexture(Texture& texture, int slot);
void BindTexture(Texture* texture, int slot);
void BindTexture(Texture& texture, int slot, std::string name);
void BindTextureImage(Texture& texture, int slot);
unsigned int GetId();
void SetUniform1f(std::string name, float u);
void SetUniform2f(std::string name, float u1, float u2);
void SetUniform3f(std::string name, float u1, float u2, float u3);
void SetUniform4f(std::string name, float u1, float u2, float u3, float u4);
void SetUniform1i(std::string name, int u);
void SetUniform2i(std::string name, int u1, int u2);
void SetUniform3i(std::string name, int u1, int u2, int u3);
void SetUniform4i(std::string name, int u1, int u2, int u3, int u4);
void SetUniform1ui(std::string name, unsigned int u);
void SetUniform2ui(std::string name, unsigned int u1, unsigned int u2);
void SetUniform3ui(std::string name, unsigned int u1, unsigned int u2, unsigned int u3);
void SetUniform4ui(std::string name, unsigned int u1, unsigned int u2, unsigned int u3, unsigned int u4);
void SetUniform1fv(std::string name, int count, float* u);
void SetUniform2fv(std::string name, int count, float* u);
void SetUniform3fv(std::string name, int count, float* u);
void SetUniform4fv(std::string name, int count, float* u);
void SetUniform1iv(std::string name, int count, int* u);
void SetUniform2iv(std::string name, int count, int* u);
void SetUniform3iv(std::string name, int count, int* u);
void SetUniform4iv(std::string name, int count, int* u);
void SetUniform1uiv(std::string name, int count, unsigned int* u);
void SetUniform2uiv(std::string name, int count, unsigned int* u);
void SetUniform3uiv(std::string name, int count, unsigned int* u);
void SetUniform4uiv(std::string name, int count, unsigned int* u);
};

58
src/SSBO.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "SSBO.h"
#include "GLUtils.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
SSBO::SSBO(int bind) :
m_id(0), m_binding(bind), m_last_size(0)
{
GLCall(glGenBuffers(1, &m_id));
}
SSBO::SSBO() :
m_id(0), m_binding(0), m_last_size(0)
{
}
SSBO::SSBO(unsigned int i, int bind) :
m_id(i), m_binding(bind), m_last_size(0)
{}
SSBO::~SSBO() {
Delete();
}
int SSBO::GetId()
{
return m_id;
}
SSBO::SSBO(SSBO&& other) :
m_id(other.m_id), m_binding(other.m_binding), m_last_size(other.m_last_size)
{
other.m_id = 0;
}
SSBO& SSBO::operator=(SSBO&& other)
{
if (this != &other)
{
Delete();
std::swap(m_id, other.m_id);
m_binding = other.m_binding;
m_last_size = other.m_last_size;
}
return *this;
}
void SSBO::Delete() {
if (m_id != 0) {
GLCall(glDeleteBuffers(1, &m_id));
}
m_id = 0;
}
void SSBO::Bind() {
GLCall(glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_id));
}

76
src/SSBO.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <vector>
#include "GLUtils.h"
class SSBO {
private:
unsigned int m_id;
int m_binding;
int m_last_size;
public:
SSBO(int bind);
SSBO();
SSBO(unsigned int i, int bind);
SSBO& operator=(SSBO&& other);
SSBO(SSBO&& other);
SSBO(const SSBO&) = delete;
SSBO& operator=(const SSBO&) = delete;
~SSBO();
int GetId();
void Delete();
void Bind();
template<typename T>
void Set(T shader_data) {
int size = sizeof(shader_data);
m_last_size = size;
Bind();
GLCall(glBufferData(GL_SHADER_STORAGE_BUFFER, size, size > 0 ? &shader_data : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, m_binding, m_id));
}
template<typename T>
void Set(std::vector<T>* shader_data) {
int size = sizeof(T) * (int)shader_data->size();
m_last_size = size;
Bind();
GLCall(glBufferData(GL_SHADER_STORAGE_BUFFER, size, size > 0 ? shader_data->data() : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, m_binding, m_id));
}
template<typename T>
void Update(T shader_data) {
int size = sizeof(shader_data);
Bind();
if (size == m_last_size) {
GLCall(glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size, &shader_data));
}
else {
m_last_size = size;
GLCall(glBufferData(GL_SHADER_STORAGE_BUFFER, size, &shader_data, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, m_binding, m_id));
}
}
template<typename T>
void Update(std::vector<T>* shader_data) {
int size = sizeof(T) * shader_data->size();
Bind();
if (size == m_last_size) {
GLCall(glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size, size > 0 ? shader_data->data() : nullptr));
}
else {
m_last_size = size;
GLCall(glBufferData(GL_SHADER_STORAGE_BUFFER, size, size > 0 ? shader_data->data() : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, m_binding, m_id));
}
}
};

311
src/Scene.cpp Normal file
View File

@ -0,0 +1,311 @@
#include "Scene.h"
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
void IndexArray::AddVertex(int x, int y, int z) {
m_array.push_back(x - 1);
m_array.push_back(y - 1);
m_array.push_back(z - 1);
m_array.push_back(0);
m_array.push_back(0);
m_array.push_back(0);
}
void IndexArray::AddVertex(int x, int y, int z, int tx, int ty, int tz) {
m_array.push_back(x - 1);
m_array.push_back(y - 1);
m_array.push_back(z - 1);
m_array.push_back(tx - 1);
m_array.push_back(ty - 1);
m_array.push_back(tz - 1);
}
int IndexArray::GetSize() {
return (int)m_array.size();
}
int IndexArray::GetByteSize() {
return (int)m_array.size() * (int)sizeof(int);
}
std::vector<int>* IndexArray::GetPointer() {
return &m_array;
}
std::vector<int> IndexArray::GetVector() {
return m_array;
}
void IndexArray::MoveIndices(int offset) {
int size = (int)m_array.size();
const int block_size = 6;
for (int i = 0; i < size / block_size; i++) {
m_array[block_size *i] += offset;
m_array[block_size *i + 1] += offset;
m_array[block_size *i + 2] += offset;
}
}
void IndexArray::MoveTextureIndices(int offset){
int size = (int)m_array.size();
const int block_size = 6;
for (int i = 0; i < size / block_size; i++) {
m_array[block_size * i + 3] += offset;
m_array[block_size * i + 4] += offset;
m_array[block_size * i + 5] += offset;
}
}
void VertexArray::AddVertex(float x, float y, float z) {
m_array.push_back(x);
m_array.push_back(y);
m_array.push_back(z);
}
int VertexArray::GetSize() {
return (int)m_array.size();
}
int VertexArray::GetByteSize() {
return (int)m_array.size() * (int)sizeof(float);
}
std::vector<float>* VertexArray::GetPointer() {
return &m_array;
}
std::vector<float> VertexArray::GetVector() {
return m_array;
}
void TextureVertexArray::AddVertex(float u, float v) {
m_array.push_back(u);
m_array.push_back(v);
}
int TextureVertexArray::GetSize() {
return (int)m_array.size();
}
int TextureVertexArray::GetByteSize() {
return (int)m_array.size() * (int)sizeof(float);
}
std::vector<float>* TextureVertexArray::GetPointer() {
return &m_array;
}
std::vector<float> TextureVertexArray::GetVector() {
return m_array;
}
void SceneVertices::AddModel(Model3D* model) {
int size = model->GetIndexArrayPtr()->GetSize() / 6;
m_offsets.push_back(size + m_index_count);
m_models.push_back(model);
}
void SceneVertices::FillBuffers() {
int size = (int)m_models.size();
for (int i = 0; i < size; i++) {
m_models[i]->GetIndexArrayPtr()->MoveIndices(m_vertex_count);
m_models[i]->GetIndexArrayPtr()->MoveTextureIndices(m_texture_vertex_count);
m_models[i]->SetIndexOffset(m_index_count);
m_vertex_buffer.insert(m_vertex_buffer.end(),
m_models[i]->GetVertexArrayPtr()->GetPointer()->begin(),
m_models[i]->GetVertexArrayPtr()->GetPointer()->end());
m_texture_buffer.insert(m_texture_buffer.end(),
m_models[i]->GetTextureArrayPtr()->GetPointer()->begin(),
m_models[i]->GetTextureArrayPtr()->GetPointer()->end());
m_index_buffer.insert(m_index_buffer.end(),
m_models[i]->GetIndexArrayPtr()->GetPointer()->begin(),
m_models[i]->GetIndexArrayPtr()->GetPointer()->end());
m_vertex_count += m_models[i]->GetVertexArrayPtr()->GetSize() / 3;
m_texture_vertex_count += m_models[i]->GetTextureArrayPtr()->GetSize() / 2;
m_index_count += m_models[i]->GetIndexArrayPtr()->GetSize() / 6;
}
}
std::vector<float>* SceneVertices::GetVertexBuffer() {
return &m_vertex_buffer;
}
std::vector<float>* SceneVertices::GetTextureBuffer() {
return &m_texture_buffer;
}
std::vector<int>* SceneVertices::GetIndexBuffer() {
return &m_index_buffer;
}
int SceneVertices::GetFaceCount() {
return m_index_count;
}
int SceneVertices::GetTextureVertsCount() {
return m_texture_vertex_count;
}
int SceneVertices::GetVertexCount() {
return m_vertex_count;
}
void Model3D::Load(std::string path) {
std::fstream file(path);
std::string line;
std::stringstream str;
std::string prefix;
int vertex_id = 0;
float x, y, z;
while (std::getline(file, line)) {
str.clear();
str.str(line);
str >> prefix;
if (prefix == "v") {
str >> x >> y >> z;
if (m_vertex_arr.GetSize() == 0)
m_lowest_point = y;
else
m_lowest_point = std::min(m_lowest_point, y);
m_vertex_arr.AddVertex(x, y, z);
}
else if (prefix == "vt") {
str >> x >> y;
m_texture_arr.AddVertex(x, y);
}
else if (prefix == "f") {
int f;
int v1 = 0;
int v2 = 0;
int v3 = 0;
int v4 = 0;
int vt1 = 0;
int vt2 = 0;
int vt3 = 0;
int vt4 = 0;
int type_counter = 0;
int id_counter = 0;
while (str >> f) {
if (type_counter == 0) {
if (id_counter == 0) {
v1 = f;
}
else if (id_counter == 1) {
v2 = f;
}
else if (id_counter == 2) {
v3 = f;
}
else if (id_counter == 3) {
v4 = f;
}
}
else if (type_counter == 1) {
if (id_counter == 0) {
vt1 = f;
}
else if (id_counter == 1) {
vt2 = f;
}
else if (id_counter == 2) {
vt3 = f;
}
else if (id_counter == 3) {
vt4 = f;
}
}
while (str.peek() == '/') {
type_counter++;
type_counter %= 3;
str.ignore(1, '/');
}
while (str.peek() == ' ') {
id_counter++;
type_counter = 0;
str.ignore(1, ' ');
}
}
if (id_counter == 2)
m_index_arr.AddVertex(v1, v2, v3, vt1, vt2, vt3);
else {
m_index_arr.AddVertex(v1, v2, v3, vt1, vt2, vt3);
m_index_arr.AddVertex(v1, v3, v4, vt1, vt3, vt4);
}
}
}
// shift vertices to level the vertices to ground
const int block_size = 3;
for (int i = 0; i < m_vertex_arr.GetSize()/ block_size; i++)
(*m_vertex_arr.GetPointer())[block_size * i + 1] -= (m_lowest_point - 0.001f);
}
void Model3D::SetId(int id) {
m_id = id;
}
void Model3D::SetIndexOffset(int offset) {
m_index_offset = offset;
}
int Model3D::GetIndexOffset() {
return m_index_offset;
}
int Model3D::GetFaceCount() {
return m_index_arr.GetSize() / 6;
}
int Model3D::GetId() {
return m_id;
}
float Model3D::GetLowestPoint() {
return m_lowest_point;
}
VertexArray Model3D::GetVertexArray() {
return m_vertex_arr;
}
IndexArray Model3D::GetIndexArray() {
return m_index_arr;
}
TextureVertexArray Model3D::GetTextureArray() {
return m_texture_arr;
}
VertexArray* Model3D::GetVertexArrayPtr() {
return &m_vertex_arr;
}
IndexArray* Model3D::GetIndexArrayPtr() {
return &m_index_arr;
}
TextureVertexArray* Model3D::GetTextureArrayPtr() {
return &m_texture_arr;
}

93
src/Scene.h Normal file
View File

@ -0,0 +1,93 @@
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include "Texture.h"
class IndexArray {
public:
void AddVertex(int x, int y, int z, int tx, int ty, int tz);
void AddVertex(int x, int y, int z);
int GetSize();
int GetByteSize();
std::vector<int>* GetPointer();
std::vector<int> GetVector();
void MoveIndices(int offset);
void MoveTextureIndices(int offset);
private:
std::vector<int> m_array;
};
class VertexArray {
public:
void AddVertex(float x, float y, float z);
int GetSize();
int GetByteSize();
std::vector<float>* GetPointer();
std::vector<float> GetVector();
private:
std::vector<float> m_array;
};
class TextureVertexArray {
public:
void AddVertex(float u, float v);
int GetSize();
int GetByteSize();
std::vector<float>* GetPointer();
std::vector<float> GetVector();
private:
std::vector<float> m_array;
};
class Model3D {
public:
void Load(std::string path);
void SetId(int id);
void SetIndexOffset(int offset);
int GetIndexOffset();
int GetFaceCount();
float GetLowestPoint();
int GetId();
VertexArray GetVertexArray();
IndexArray GetIndexArray();
TextureVertexArray GetTextureArray();
VertexArray* GetVertexArrayPtr();
IndexArray* GetIndexArrayPtr();
TextureVertexArray* GetTextureArrayPtr();
private:
VertexArray m_vertex_arr;
IndexArray m_index_arr;
TextureVertexArray m_texture_arr;
int m_id = -1;
int m_index_offset = 0;
float m_lowest_point = 0;
};
class SceneVertices {
public:
void AddModel(Model3D* model);
void FillBuffers();
std::vector<float>* GetVertexBuffer();
std::vector<float>* GetTextureBuffer();
std::vector<int>* GetIndexBuffer();
int GetFaceCount();
int GetTextureVertsCount();
int GetVertexCount();
private:
std::vector<Model3D*> m_models;
int m_index_count = 0;
int m_vertex_count = 0;
int m_texture_vertex_count = 0;
std::vector<int> m_offsets;
std::vector<float> m_vertex_buffer;
std::vector<float> m_texture_buffer;
std::vector<int> m_index_buffer;
};

169
src/Shader.cpp Normal file
View File

@ -0,0 +1,169 @@
#include "Shader.h"
#include "GLUtils.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
std::string vert_source =
"#version 330 core\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"void main(){\n"
"gl_Position = position;\n"
"TexCoord = aTexCoord;\n"
"}";
std::string frag_source_tonemapped =
"#version 330 core\n"
"layout(location = 0) out vec4 color;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D img_output;\n"
"void main(){\n"
"const float gamma = 2.2;\n"
"vec3 hdrColor = texture(img_output, TexCoord).xyz;\n"
"vec3 mapped = vec3(1.0) - exp(-hdrColor * 1.0);\n"
"mapped = pow(mapped, vec3(1.0 / gamma));\n"
"color = vec4(mapped, 1.0);\n"
"}";
std::string frag_source =
"#version 330 core\n"
"layout(location = 0) out vec4 color;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D img_output;\n"
"void main(){\n"
"color = texture(img_output, TexCoord);\n"
"}";
Shader::Shader(std::string path, unsigned int type) {
std::string source;
LoadShader(path, source);
m_id = CompileShader(source, type);
}
Shader::Shader(std::string path, unsigned int type, bool tonemapping)
{
std::string source;
LoadShader(path, source);
m_id = CompileShader(source, type);
}
Shader::Shader(std::string path) {
std::string source;
LoadShader(path, source);
m_id = CompileShader(source, GL_COMPUTE_SHADER);
}
//Shader::Shader(unsigned int type) {
// switch (type) {
// case GL_VERTEX_SHADER:
// m_id = CompileShader(vert_source, type);
// break;
// case GL_FRAGMENT_SHADER:
// m_id = CompileShader(frag_source, type);
// break;
// default:
// __debugbreak();
// break;
// }
//}
Shader::Shader(unsigned int type, bool tonemapped) {
switch (type) {
case GL_VERTEX_SHADER:
m_id = CompileShader(vert_source, type);
break;
case GL_FRAGMENT_SHADER:
if(!tonemapped)
m_id = CompileShader(frag_source, type);
else
m_id = CompileShader(frag_source_tonemapped, type);
break;
default:
__debugbreak();
break;
}
}
Shader::~Shader() {
Delete();
}
Shader::Shader(Shader&& other) :
m_id(other.m_id)
{
other.m_id = 0;
}
Shader& Shader::operator=(Shader&& other)
{
if (this != &other)
{
Delete();
std::swap(m_id, other.m_id);
}
return *this;
}
void Shader::Delete() {
if (m_id != 0) {
GLCall(glDeleteShader(m_id));
}
m_id = 0;
}
int Shader::CompileShader(std::string _source, unsigned int type){
unsigned int id = glCreateShader(type);
const char* src = _source.c_str();
GLCall(glShaderSource(id, 1, &src, nullptr));
m_source = _source;
GLCall(glCompileShader(id));
int result;
GLCall(glGetShaderiv(id, GL_COMPILE_STATUS, &result));
if (result == GL_FALSE) {
m_compilation_success = false;
int length;
GLCall(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
char* message = (char*)alloca(length * sizeof(char));
GLCall(glGetShaderInfoLog(id, length, &length, message));
if (type == GL_COMPUTE_SHADER) {
LOG("Compilation failed of compute shader");
LOG(message);
}
GLCall(glDeleteShader(id));
return 0;
}
else {
m_compilation_success = true;
if (type == GL_COMPUTE_SHADER)
LOG("Compilation successfull of compute shader");
}
return id;
}
void Shader::LoadShader(std::string name, std::string& Shader){
std::ifstream v(name);
std::stringstream buffer;
buffer << v.rdbuf();
Shader = buffer.str();
}
int Shader::GetId() {
return m_id;
}
bool Shader::Compiled()
{
return m_compilation_success;
}

28
src/Shader.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#define _USE_MATH_DEFINES
#include <string>
#include <vector>
class Shader {
public:
Shader(std::string path);
Shader(std::string path, unsigned int type);
Shader(std::string path, unsigned int type, bool tonemapping);
Shader(unsigned int type, bool tonemapped = false);
~Shader();
Shader& operator=(Shader&& other);
Shader(Shader&& other);
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
void Delete();
int CompileShader(std::string _source, unsigned int type);
void LoadShader(std::string name, std::string& Shader);
int GetId();
bool Compiled();
private:
bool m_compilation_success = false;
unsigned int m_id = 0;
std::string m_source;
};

146
src/Texture.cpp Normal file
View File

@ -0,0 +1,146 @@
#include "Texture.h"
#include "GLUtils.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
Texture::Texture(std::string name, std::string path) :
m_width(0), m_height(0), m_name(name), m_image(false),
m_bpp(0), m_id(0), m_buffer(nullptr)
{
GLCall(glGenTextures(1, &m_id));
GLCall(glBindTexture(GL_TEXTURE_2D, m_id));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
Load(path);
}
Texture::Texture(std::string name, int width, int height) :
m_width(width), m_height(height), m_name(name), m_image(true),
m_bpp(0), m_id(0), m_buffer(nullptr)
{
GLCall(glGenTextures(1, &m_id));
GLCall(glBindTexture(GL_TEXTURE_2D, m_id));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_width, m_height, 0, GL_RGBA, GL_FLOAT, NULL));
}
void Texture::Resize(int width, int height) {
m_width = width;
m_height = height;
GLuint boundTexture = 0;
GLCall(glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&boundTexture));
Bind();
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_width, m_height, 0, GL_RGBA, GL_FLOAT, NULL));
GLCall(glBindTexture(GL_TEXTURE_2D, boundTexture));
}
void Texture::Load(std::string path) {
stbi_set_flip_vertically_on_load(1);
std::string extension = path.substr(path.length() - 3, 3);
if (extension != "hdr") {
m_buffer = stbi_load(path.c_str(), &m_width, &m_height, &m_bpp, 4);
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_buffer));
}
else {
m_buffer = (unsigned char*)stbi_loadf(path.c_str(), &m_width, &m_height, &m_bpp, 4);
GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, m_width, m_height, 0, GL_RGBA, GL_FLOAT, m_buffer));
}
if (m_buffer)
delete[] m_buffer;
}
void Texture::Bind(unsigned int slot) {
GLCall(glActiveTexture(GL_TEXTURE0 + slot));
GLCall(glBindTexture(GL_TEXTURE_2D, m_id));
}
void Texture::BindImage(unsigned int slot) {
GLCall(glBindImageTexture(slot, m_id, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F));
}
bool Texture::IsImg() {
return m_image;
}
std::string Texture::GetName()
{
return m_name;
}
Texture::Texture() :
m_width(0), m_height(0), m_name(""), m_image(false),
m_bpp(0), m_id(0), m_buffer(nullptr) {}
Texture::~Texture() {
Delete();
}
Texture::Texture(Texture&& other) :
m_width(other.m_width), m_height(other.m_height), m_name(other.m_name), m_image(other.m_image),
m_bpp(other.m_bpp), m_id(other.m_id), m_buffer(other.m_buffer)
{
other.m_id = 0;
}
Texture& Texture::operator=(Texture&& other)
{
if (this != &other)
{
Delete();
std::swap(m_id, other.m_id);
std::swap(m_width, other.m_width);
std::swap(m_height, other.m_height);
std::swap(m_name, other.m_name);
std::swap(m_image, other.m_image);
std::swap(m_bpp, other.m_bpp);
std::swap(m_buffer, other.m_buffer);
}
return *this;
}
void Texture::Delete() {
if (m_id != 0) {
Unbind();
GLCall(glDeleteTextures(1, &m_id));
}
}
void Texture::Bind() {
GLCall(glBindTexture(GL_TEXTURE_2D, m_id));
}
void Texture::Unbind() {
GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
unsigned int Texture::GetId() {
return m_id;
}
int Texture::GetWidth() {
return m_width;
}
int Texture::GetHeight() {
return m_height;
}

39
src/Texture.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#define _USE_MATH_DEFINES
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
class Texture {
private:
unsigned int m_id;
std::string m_name;
bool m_image;
unsigned char* m_buffer;
int m_width;
int m_height;
int m_bpp;
public:
Texture(std::string name, std::string path);
Texture(std::string name, int width, int height);
void Resize(int width, int height);
Texture();
~Texture();
Texture& operator=(Texture&& other);
Texture(Texture&& other);
Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete;
void Load(std::string path);
void Bind(unsigned int slot);
void BindImage(unsigned int slot);
void Bind();
void Unbind();
void Delete();
unsigned int GetId();
int GetWidth();
int GetHeight();
bool IsImg();
std::string GetName();
};

37
src/Timer.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "Timer.h"
Timer::Timer() {
m_start = std::chrono::high_resolution_clock::now();
m_s = std::chrono::microseconds(0);
m_e = std::chrono::microseconds(0);
m_duration = std::chrono::microseconds(0);
}
void Timer::Start() {
m_start = std::chrono::high_resolution_clock::now();
}
void Timer::Stop() {
m_end = std::chrono::high_resolution_clock::now();
}
double Timer::TimeSinceLast() {
m_end = std::chrono::high_resolution_clock::now();
m_s = std::chrono::time_point_cast<std::chrono::microseconds>(m_start).time_since_epoch();
m_e = std::chrono::time_point_cast<std::chrono::microseconds>(m_end).time_since_epoch();
m_start = std::chrono::high_resolution_clock::now();
m_duration = m_e - m_s;
return (double)m_duration.count();
}
double Timer::GetMicro() {
return Timer::TimeSinceLast();
}
double Timer::GetMilis() {
return Timer::TimeSinceLast() * 0.001;
}
double Timer::GetSec() {
return Timer::TimeSinceLast() * 0.000001;
}
double Timer::TimeAfterStop() {
m_s = std::chrono::time_point_cast<std::chrono::microseconds>(m_start).time_since_epoch();
m_e = std::chrono::time_point_cast<std::chrono::microseconds>(m_end).time_since_epoch();
m_duration = m_e - m_s;
return m_duration.count() * 0.001;
}

24
src/Timer.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#define _USE_MATH_DEFINES
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
class Timer {
public:
Timer();
void Stop();
void Start();
double TimeSinceLast();
double TimeAfterStop();
double GetMicro();
double GetMilis();
double GetSec();
private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_start, m_end;
std::chrono::microseconds m_s, m_e;
std::chrono::microseconds m_duration;
};

56
src/UBO.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "UBO.h"
#include "GLUtils.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
UBO::UBO(int bind) :
m_id(0), m_binding(bind), m_last_size(0)
{
GLCall(glGenBuffers(1, &m_id));
}
UBO::UBO() :
m_id(0), m_binding(0), m_last_size(0)
{
}
UBO::~UBO() {
Delete();
}
int UBO::GetId()
{
return m_id;
}
UBO::UBO(UBO&& other) :
m_id(other.m_id), m_binding(other.m_binding), m_last_size(other.m_last_size)
{
other.m_id = 0;
}
UBO& UBO::operator=(UBO&& other)
{
if (this != &other)
{
Delete();
std::swap(m_id,other.m_id);
m_binding = other.m_binding;
m_last_size = other.m_last_size;
}
return *this;
}
void UBO::Delete() {
if (m_id != 0) {
GLCall(glDeleteBuffers(1, &m_id));
}
m_id = 0;
}
void UBO::Bind() {
GLCall(glBindBuffer(GL_UNIFORM_BUFFER, m_id));
}

76
src/UBO.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <vector>
#include "GLUtils.h"
class UBO {
private:
unsigned int m_id = 0;
int m_binding = 0;
size_t m_last_size = 0;
public:
UBO(int bind);
UBO();
UBO& operator=(UBO&& other);
UBO(UBO&& other);
UBO(const UBO&) = delete;
UBO& operator=(const UBO&) = delete;
~UBO();
int GetId();
void Delete();
void Bind();
template<typename T>
void Set(T* shader_data) {
size_t size = sizeof(*shader_data);
m_last_size = size;
Bind();
GLCall(glBufferData(GL_UNIFORM_BUFFER, size, size > 0 ? shader_data : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, m_binding, m_id));
}
template<typename T>
void Set(std::vector<T>* shader_data) {
size_t size = sizeof(T) * shader_data->size();
m_last_size = size;
Bind();
GLCall(glBufferData(GL_UNIFORM_BUFFER, size, size > 0 ? shader_data->data() : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, m_binding, m_id));
}
template<typename T>
void Update(T* shader_data) {
size_t size = sizeof(*shader_data);
Bind();
if (size == m_last_size) {
GLCall(glBufferSubData(GL_UNIFORM_BUFFER, 0, size, shader_data));
}
else {
m_last_size = size;
GLCall(glBufferData(GL_UNIFORM_BUFFER, size, shader_data, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, m_binding, m_id));
}
}
template<typename T>
void Update(std::vector<T>* shader_data) {
size_t size = sizeof(T) * shader_data->size();
Bind();
if (size == m_last_size) {
GLCall(glBufferSubData(GL_UNIFORM_BUFFER, 0, size, size > 0 ? shader_data->data() : nullptr));
}
else {
m_last_size = size;
GLCall(glBufferData(GL_UNIFORM_BUFFER, size, size > 0 ? shader_data->data() : nullptr, GL_DYNAMIC_DRAW));
GLCall(glBindBufferBase(GL_UNIFORM_BUFFER, m_binding, m_id));
}
}
};