Compare commits
10 Commits
e8e91e86c7
...
7b0c9aad02
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b0c9aad02 | ||
|
|
ffe7731f10 | ||
|
|
40b7639c66 | ||
|
|
651186f7bd | ||
|
|
aebd69a027 | ||
|
|
472d35497d | ||
|
|
9a38c557f0 | ||
|
|
6d8bf7c563 | ||
|
|
e5ba7474e6 | ||
|
|
06a9f74f2c |
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.default.cppStandard": "c++20",
|
||||||
|
"cmake.debugConfig": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,15 @@
|
|||||||
cmake_minimum_required(VERSION 3.31)
|
cmake_minimum_required(VERSION 3.31)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||||
|
|
||||||
project(Ugly)
|
project(Ugly)
|
||||||
|
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
|
||||||
add_subdirectory(./source/app)
|
add_subdirectory(./source/app)
|
||||||
|
add_subdirectory(./source/image)
|
||||||
|
add_subdirectory(./source/log)
|
||||||
|
add_subdirectory(./source/shader)
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
"generator": "Visual Studio 17 2022",
|
"generator": "Visual Studio 17 2022",
|
||||||
"architecture": "x64",
|
"architecture": "x64",
|
||||||
"binaryDir": "${sourceDir}/build",
|
"binaryDir": "${sourceDir}/build",
|
||||||
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
"toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_VS_DEBUGGER_WORKING_DIRECTORY": "${sourceDir}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
9
assets/shaders/shader.frag
Normal file
9
assets/shaders/shader.frag
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec3 color;
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(color, 1.0);
|
||||||
|
}
|
||||||
13
assets/shaders/shader.vert
Normal file
13
assets/shaders/shader.vert
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec3 inPosition;
|
||||||
|
in vec3 inColor;
|
||||||
|
|
||||||
|
out vec3 color;
|
||||||
|
|
||||||
|
uniform mat4 inTransformation;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
color = inColor;
|
||||||
|
gl_Position = inTransformation * vec4(inPosition, 1.0);
|
||||||
|
}
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
project(UglyMain)
|
project(UglyMain)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} main.c)
|
add_executable(${PROJECT_NAME}
|
||||||
|
./main.cpp
|
||||||
|
./src/App.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PRIVATE ./src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
GLEW::GLEW
|
||||||
|
glfw
|
||||||
|
glm::glm
|
||||||
|
stb_image
|
||||||
|
UglyLogLib
|
||||||
|
UglyShaderLib
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
printf("hello world!\n");
|
|
||||||
}
|
|
||||||
12
source/app/main.cpp
Normal file
12
source/app/main.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
auto args = std::vector<std::string>{};
|
||||||
|
std::copy_n(argv, argc, std::back_inserter(args));
|
||||||
|
return ugly::App::main(args);
|
||||||
|
}
|
||||||
197
source/app/src/App.cpp
Normal file
197
source/app/src/App.cpp
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#include "App.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include "LogUtils.hpp"
|
||||||
|
#include "ShaderProgramBuilder.hpp"
|
||||||
|
#include "stb_image.h"
|
||||||
|
#include "TimestampLog.hpp"
|
||||||
|
|
||||||
|
constexpr std::array<std::array<float, 6>, 36> getCubeVertices();
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
int App::main(std::vector<std::string> &args) {
|
||||||
|
// Initialize global log.
|
||||||
|
auto cerrLog = TimestampLog{"ugly::log", std::cerr};
|
||||||
|
log = LogAlias{&cerrLog};
|
||||||
|
log("hello, world! app started.");
|
||||||
|
|
||||||
|
// Initialize GLFW.
|
||||||
|
glfwSetErrorCallback(error_callback_s);
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
|
|
||||||
|
// Create GLFW window and OpenGL context for GLEW.
|
||||||
|
auto window = glfwCreateWindow(640, 480, "uGLy", NULL, NULL);
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
glewExperimental = GL_TRUE;
|
||||||
|
if(glewInit() != GLEW_OK) {
|
||||||
|
log("glewInit() failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run app.
|
||||||
|
auto app = App{window};
|
||||||
|
app.game_loop();
|
||||||
|
|
||||||
|
// Clean up.
|
||||||
|
glfwTerminate();
|
||||||
|
glfwSetErrorCallback(NULL);
|
||||||
|
log("app quitting.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void App::error_callback_s(int error, const char *description)
|
||||||
|
{
|
||||||
|
log("(glfw error): {}", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void App::key_callback_s(GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||||
|
auto app = static_cast<App*>(glfwGetWindowUserPointer(window));
|
||||||
|
app->key_callback(key, scancode, action, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
App::App(GLFWwindow *window):
|
||||||
|
mpWindow{window},
|
||||||
|
mShaderProgram{} {
|
||||||
|
// To allow key_callback_s to access member functions
|
||||||
|
glfwSetWindowUserPointer(mpWindow, this);
|
||||||
|
glfwSetKeyCallback(mpWindow, key_callback_s);
|
||||||
|
|
||||||
|
// Prepare shader
|
||||||
|
mShaderProgram = ShaderProgramBuilder{}
|
||||||
|
.attachFromFile(GL_VERTEX_SHADER, "assets/shaders/shader.vert")
|
||||||
|
.attachFromFile(GL_FRAGMENT_SHADER, "assets/shaders/shader.frag")
|
||||||
|
.link();
|
||||||
|
GLint posAttrib = glGetAttribLocation(mShaderProgram, "inPosition");
|
||||||
|
GLint colorAttrib = glGetAttribLocation(mShaderProgram, "inColor");
|
||||||
|
|
||||||
|
glCreateVertexArrays(1, &mVAO);
|
||||||
|
glBindVertexArray(mVAO);
|
||||||
|
|
||||||
|
// Upload vertice attributes (position and color)
|
||||||
|
const auto vertices = getCubeVertices();
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), (void*)(&vertices), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Vertex format = { x, y, z, r, g, b }
|
||||||
|
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), 0);
|
||||||
|
glVertexAttribPointer(colorAttrib, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(posAttrib);
|
||||||
|
glEnableVertexAttribArray(colorAttrib);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void App::game_loop() {
|
||||||
|
// Generate view and projection tranforms
|
||||||
|
int width, height;
|
||||||
|
glfwGetWindowSize(mpWindow, &width, &height);
|
||||||
|
auto projMatrix = glm::perspective(glm::radians(60.0f), float(width) / height, 0.01f, 1000.f);
|
||||||
|
auto viewMatrix = glm::lookAt(
|
||||||
|
glm::vec3{0.f, 0.f, 0.f},
|
||||||
|
glm::vec3{0.f, 0.f, 1.f},
|
||||||
|
glm::vec3{0.f, 1.f, 0.f}
|
||||||
|
);
|
||||||
|
|
||||||
|
GLint matrixUniform = glGetUniformLocation(mShaderProgram, "inTransformation");
|
||||||
|
float startTime = glfwGetTime();
|
||||||
|
while(!glfwWindowShouldClose(mpWindow)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
// Rotate the cube each frame
|
||||||
|
float dt = glfwGetTime() - startTime;
|
||||||
|
auto modelMatrix = glm::identity<glm::mat4>();
|
||||||
|
modelMatrix = glm::translate(modelMatrix, glm::vec3{0.f, 0.f, 2.f});
|
||||||
|
modelMatrix = glm::rotate(modelMatrix, glm::radians(20.f * dt), glm::vec3{1.f, 1.f, 0.f});
|
||||||
|
auto finalMatrix = projMatrix * viewMatrix * modelMatrix;
|
||||||
|
|
||||||
|
// Draw logic
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glUseProgram(mShaderProgram);
|
||||||
|
glBindVertexArray(mVAO);
|
||||||
|
|
||||||
|
glUniformMatrix4fv(matrixUniform, 1, GL_FALSE, glm::value_ptr(finalMatrix));
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(0);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glfwSwapBuffers(mpWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void App::key_callback(int key, int scancode, int action, int mods) {
|
||||||
|
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||||
|
glfwSetWindowShouldClose(mpWindow, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr std::array<std::array<float, 6>, 36> getCubeVertices() {
|
||||||
|
// The eight vertices of a cube
|
||||||
|
const float cubeVertices[8][3] = {
|
||||||
|
{ -0.5f, -0.5f, -0.5f },
|
||||||
|
{ -0.5f, +0.5f, -0.5f },
|
||||||
|
{ +0.5f, +0.5f, -0.5f },
|
||||||
|
{ +0.5f, -0.5f, -0.5f },
|
||||||
|
{ -0.5f, -0.5f, +0.5f },
|
||||||
|
{ -0.5f, +0.5f, +0.5f },
|
||||||
|
{ +0.5f, +0.5f, +0.5f },
|
||||||
|
{ +0.5f, -0.5f, +0.5f }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Color for each of the six faces
|
||||||
|
const float cubeColors[6][3] = {
|
||||||
|
{ 1.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 1.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, 1.0f },
|
||||||
|
{ 1.0f, 1.0f, 0.0f },
|
||||||
|
{ 1.0f, 0.0f, 1.0f },
|
||||||
|
{ 0.0f, 1.0f, 1.0f }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Each face consists of two triangles, so 36 unique vertices total
|
||||||
|
const int vertexIndices[36] = {
|
||||||
|
0, 1, 2, 2, 3, 0, // B
|
||||||
|
4, 5, 1, 1, 0, 4, // L
|
||||||
|
7, 6, 5, 5, 4, 7, // F
|
||||||
|
3, 2, 6, 6, 7, 3, // R
|
||||||
|
0, 3, 7, 7, 4, 0, // D
|
||||||
|
2, 1, 5, 5, 6, 2 // U
|
||||||
|
};
|
||||||
|
|
||||||
|
// Construct an array suitable for OpenGL - concatenates position and color for each vertex
|
||||||
|
// { x, y, z, r, g, b }
|
||||||
|
std::array<std::array<float, 6>, 36> vertices;
|
||||||
|
for(int i = 0; i < 36; i++) {
|
||||||
|
vertices[i][0] = cubeVertices[vertexIndices[i]][0];
|
||||||
|
vertices[i][1] = cubeVertices[vertexIndices[i]][1];
|
||||||
|
vertices[i][2] = cubeVertices[vertexIndices[i]][2];
|
||||||
|
vertices[i][3] = cubeColors[i/6][0];
|
||||||
|
vertices[i][4] = cubeColors[i/6][1];
|
||||||
|
vertices[i][5] = cubeColors[i/6][2];
|
||||||
|
}
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
28
source/app/src/App.hpp
Normal file
28
source/app/src/App.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
class App {
|
||||||
|
public:
|
||||||
|
static int main(std::vector<std::string> &args);
|
||||||
|
private:
|
||||||
|
static void error_callback_s(int error, const char *description);
|
||||||
|
static void key_callback_s(GLFWwindow *window, int key, int scancode, int action, int mods);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLFWwindow *mpWindow;
|
||||||
|
unsigned int mShaderProgram;
|
||||||
|
unsigned int mVAO;
|
||||||
|
|
||||||
|
private:
|
||||||
|
App(GLFWwindow *window);
|
||||||
|
void game_loop();
|
||||||
|
void key_callback(int key, int scancode, int action, int mods);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
9
source/image/CMakeLists.txt
Normal file
9
source/image/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
project(stb_image)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME}
|
||||||
|
./src/stb_image.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC ./include
|
||||||
|
)
|
||||||
37
source/image/LICENSE.txt
Normal file
37
source/image/LICENSE.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
This software is available under 2 licenses -- choose whichever you prefer.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE A - MIT License
|
||||||
|
Copyright (c) 2017 Sean Barrett
|
||||||
|
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.
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||||
|
software dedicate any and all copyright interest in the software to the public
|
||||||
|
domain. We make this dedication for the benefit of the public at large and to
|
||||||
|
the detriment of our heirs and successors. We intend this dedication to be an
|
||||||
|
overt act of relinquishment in perpetuity of all present and future rights to
|
||||||
|
this software under copyright law.
|
||||||
|
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 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.
|
||||||
7988
source/image/include/stb_image.h
Normal file
7988
source/image/include/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
2
source/image/src/stb_image.c
Normal file
2
source/image/src/stb_image.c
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
11
source/log/CMakeLists.txt
Normal file
11
source/log/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
project(UglyLogLib)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME}
|
||||||
|
./src/globals.cpp
|
||||||
|
./src/TimestampLog.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC ./include
|
||||||
|
PRIVATE ./src
|
||||||
|
)
|
||||||
22
source/log/include/ILogFacility.hpp
Normal file
22
source/log/include/ILogFacility.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Interface for a generic log-like object.
|
||||||
|
*/
|
||||||
|
class ILogFacility {
|
||||||
|
public:
|
||||||
|
~ILogFacility() = default;
|
||||||
|
/**
|
||||||
|
* \brief Put a message into the log, \c std::vformat -style.
|
||||||
|
* \param fmt Format string.
|
||||||
|
* \param args Format arguments.
|
||||||
|
*/
|
||||||
|
virtual void vlog(std::string_view fmt, std::format_args args) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
32
source/log/include/LogUtils.hpp
Normal file
32
source/log/include/LogUtils.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ILogFacility.hpp"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Provides \c std::format -style variadic template functions for \ref ILogFacility.
|
||||||
|
*/
|
||||||
|
class LogAlias {
|
||||||
|
public:
|
||||||
|
ILogFacility *mpLog;
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
LogAlias &operator()(std::format_string<Args...> fmt, Args &&...args) {
|
||||||
|
if(mpLog) {
|
||||||
|
mpLog->vlog(fmt.get(), std::make_format_args(args...));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Globally-shared log.
|
||||||
|
*
|
||||||
|
* Should be assigned to by the user, defaults to a null log.
|
||||||
|
*/
|
||||||
|
extern LogAlias log;
|
||||||
|
|
||||||
|
}
|
||||||
31
source/log/include/TimestampLog.hpp
Normal file
31
source/log/include/TimestampLog.hpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ILogFacility.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <format>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string_view>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Log that automatically annotates messages with time and name.
|
||||||
|
*/
|
||||||
|
class TimestampLog: virtual public ILogFacility {
|
||||||
|
private:
|
||||||
|
std::chrono::high_resolution_clock::time_point mStartTime;
|
||||||
|
std::ostream &mrOutputStream;
|
||||||
|
std::string mDescription;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \param description Name of the log to appear in the messages.
|
||||||
|
* \param os Output stream.
|
||||||
|
*/
|
||||||
|
TimestampLog(std::string_view description, std::ostream &os);
|
||||||
|
void vlog(std::string_view fmt, std::format_args args) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
23
source/log/src/TimestampLog.cpp
Normal file
23
source/log/src/TimestampLog.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "TimestampLog.hpp"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
TimestampLog::TimestampLog(std::string_view description, std::ostream &os):
|
||||||
|
mStartTime{std::chrono::high_resolution_clock::now()},
|
||||||
|
mrOutputStream{os},
|
||||||
|
mDescription{description} {}
|
||||||
|
|
||||||
|
|
||||||
|
void TimestampLog::vlog(std::string_view fmt, std::format_args args) {
|
||||||
|
// Format message as "[123.4567] Name: User Message\n"
|
||||||
|
using namespace std::chrono;
|
||||||
|
auto now = high_resolution_clock::now();
|
||||||
|
auto timestamp = duration_cast<duration<float>>(now - mStartTime).count();
|
||||||
|
auto message = std::vformat(fmt, args);
|
||||||
|
mrOutputStream << std::format("[{:9.4f}] {}: {}\n", timestamp, mDescription, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
source/log/src/globals.cpp
Normal file
7
source/log/src/globals.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "LogUtils.hpp"
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
LogAlias log{nullptr};
|
||||||
|
|
||||||
|
}
|
||||||
15
source/shader/CMakeLists.txt
Normal file
15
source/shader/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
project(UglyShaderLib)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME}
|
||||||
|
./src/ShaderProgramBuilder.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC ./include
|
||||||
|
PRIVATE ./src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
GLEW::GLEW
|
||||||
|
UglyLogLib
|
||||||
|
)
|
||||||
55
source/shader/include/ShaderProgramBuilder.hpp
Normal file
55
source/shader/include/ShaderProgramBuilder.hpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
namespace ugly{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Builder class for OpenGL shader and programs.
|
||||||
|
*
|
||||||
|
* On initialization, creates a new OpenGL program. Attach and compile shader
|
||||||
|
* sources using `attachFrom*`. Link and get the program with `link()`. User is
|
||||||
|
* responsible of managing returned program's lifetime, including destroying it.
|
||||||
|
*/
|
||||||
|
class ShaderProgramBuilder {
|
||||||
|
private:
|
||||||
|
GLuint mProgram;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderProgramBuilder();
|
||||||
|
~ShaderProgramBuilder();
|
||||||
|
/**
|
||||||
|
* \brief Deletes program and starts from scratch.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
/**
|
||||||
|
* \brief Creates, compiles, and attaches a shader.
|
||||||
|
* \param type Specifies the type of shader to be created. Must be one of
|
||||||
|
* \c GL_VERTEX_SHADER, \c GL_GEOMETRY_SHADER or
|
||||||
|
* \c GL_FRAGMENT_SHADER .
|
||||||
|
* \param string Shader source code.
|
||||||
|
* \param length Bytes to read from \p string, \c 0 reads until NUL byte.
|
||||||
|
* \returns *this
|
||||||
|
*/
|
||||||
|
ShaderProgramBuilder &attachFromMemory(GLenum type, const GLchar *string, GLint length = 0);
|
||||||
|
/**
|
||||||
|
* \brief Creates, compiles, and attaches a shader. Reads source from file.
|
||||||
|
* \param type Specifies the type of shader to be created. Must be one of
|
||||||
|
* \c GL_VERTEX_SHADER, \c GL_GEOMETRY_SHADER or
|
||||||
|
* \c GL_FRAGMENT_SHADER .
|
||||||
|
* \param filename Shader source code file.
|
||||||
|
* \returns \c *this
|
||||||
|
*/
|
||||||
|
ShaderProgramBuilder &attachFromFile(GLenum type, const char *filename);
|
||||||
|
/**
|
||||||
|
* \brief Links OpenGL program after attaching sources.
|
||||||
|
*
|
||||||
|
* After this function is called the builder object is reset.
|
||||||
|
* \return OpenGL object name. User is reponsible for managing it.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] GLuint link();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
87
source/shader/src/ShaderProgramBuilder.cpp
Normal file
87
source/shader/src/ShaderProgramBuilder.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "ShaderProgramBuilder.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "LogUtils.hpp"
|
||||||
|
|
||||||
|
namespace ugly {
|
||||||
|
|
||||||
|
ShaderProgramBuilder::ShaderProgramBuilder():
|
||||||
|
mProgram{glCreateProgram()} {}
|
||||||
|
|
||||||
|
|
||||||
|
ShaderProgramBuilder::~ShaderProgramBuilder() {
|
||||||
|
// link() sets mProgram=0 to prevent it from being deleted after being given to the user.
|
||||||
|
if(mProgram != 0) {
|
||||||
|
glDeleteProgram(mProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ShaderProgramBuilder::reset() {
|
||||||
|
using namespace std;
|
||||||
|
ShaderProgramBuilder newBuilder;
|
||||||
|
swap(*this, newBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShaderProgramBuilder &ShaderProgramBuilder::attachFromMemory(GLenum type, const GLchar *string, GLint length) {
|
||||||
|
auto shader = glCreateShader(type);
|
||||||
|
glShaderSource(shader, 1, &string, length != 0 ? &length : NULL);
|
||||||
|
glCompileShader(shader);
|
||||||
|
|
||||||
|
// Check for shader compilation errors
|
||||||
|
GLint status;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||||
|
if(status != GL_TRUE) {
|
||||||
|
char buf[512];
|
||||||
|
glGetShaderInfoLog(shader, 512, NULL, buf);
|
||||||
|
glDeleteShader(shader);
|
||||||
|
log("failed to compile shader:\n\t{}", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the shader is attached, it can safely be marked for deletion and OpenGL will handle it.
|
||||||
|
glAttachShader(mProgram, shader);
|
||||||
|
glDeleteShader(shader);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShaderProgramBuilder &ShaderProgramBuilder::attachFromFile(GLenum type, const char *filename) {
|
||||||
|
// Load entire file to memory then let attachFromMemory handle it.
|
||||||
|
auto file = std::filebuf{};
|
||||||
|
auto ss = std::ostringstream{};
|
||||||
|
|
||||||
|
log("loading shader from file {}", filename);
|
||||||
|
file.open(filename, std::ios_base::in);
|
||||||
|
if(!file.is_open()) {
|
||||||
|
log("couldn't open file {}", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << &file;
|
||||||
|
return attachFromMemory(type, ss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLuint ShaderProgramBuilder::link() {
|
||||||
|
glLinkProgram(mProgram);
|
||||||
|
|
||||||
|
// Check for program linking errors
|
||||||
|
GLint status;
|
||||||
|
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
||||||
|
if(status != GL_TRUE) {
|
||||||
|
char buf[512];
|
||||||
|
glGetProgramInfoLog(mProgram, 512, NULL, buf);
|
||||||
|
log("failed to link program:\n\t{}", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset() this object but take care of not deleting the program returned to the caller.
|
||||||
|
auto result = mProgram;
|
||||||
|
mProgram = 0;
|
||||||
|
reset();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user