gpu, csg
This commit is contained in:
parent
3be9178126
commit
0aea51b594
@ -1,10 +0,0 @@
|
||||
((nil . (
|
||||
(projectile-project-name . "hyporo")
|
||||
(projectile-project-compilation-dir . "")
|
||||
(projectile-enable-caching . t)
|
||||
(projectile-project-configure-cmd . "cmake -S . -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=DEBUG")
|
||||
(projectile-project-compilation-cmd . "cmake --build build ")
|
||||
(projectile-project-test-cmd . "ctest --test-dir build")
|
||||
(projectile-project-run-cmd . "cd build/source/creator && ./hyporo")
|
||||
(cmake-ide-build-dir . "build")
|
||||
)))
|
69
.vscode/settings.json
vendored
69
.vscode/settings.json
vendored
@ -1,69 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
cmake_minimum_required (VERSION 3.16)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
set(USE_SYSTEM_OCCT ON CACHE INTERNAL "")
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/glad.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/stb.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/imgui.cmake)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/occt.cmake)
|
||||
|
||||
|
||||
project(
|
||||
hyporo
|
||||
@ -23,7 +30,7 @@ endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
add_definitions(-DPRECISION_FLOAT)
|
||||
add_definitions(-DPRECISION_DOUBLE)
|
||||
|
||||
add_subdirectory(source)
|
||||
|
||||
|
73
cmake/occt.cmake
Normal file
73
cmake/occt.cmake
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
if(USE_SYSTEM_OCCT)
|
||||
find_package(OpenCASCADE REQUIRED)
|
||||
|
||||
if(OpenCASCADE_FOUND)
|
||||
message(STATUS "Found OCCT")
|
||||
endif()
|
||||
else()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME occt
|
||||
GIT_REPOSITORY https://github.com/Open-Cascade-SAS/OCCT.git
|
||||
GIT_TAG V7_6_2
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
if(occt_ADDED)
|
||||
# Freaks are using CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR for the project root, fix it
|
||||
file(READ ${occt_SOURCE_DIR}/CMakeLists.txt filedata_)
|
||||
string(FIND "${filedata_}" "CMAKE_SOURCE_DIR" need_patch)
|
||||
|
||||
if(NOT ${need_patch} EQUAL -1)
|
||||
string(REPLACE "CMAKE_SOURCE_DIR" "OCCT_SOURCE_DIR" filedata_ "${filedata_}")
|
||||
string(REPLACE "CMAKE_BINARY_DIR" "OCCT_BINARY_DIR" filedata_ "${filedata_}")
|
||||
string(REPLACE "project (OCCT)" "" filedata_ "${filedata_}")
|
||||
string(PREPEND filedata_ "project(OCCT)\nset(OCCT_BINARY_DIR $\{_OCCT_BINARY_DIR\})\n")
|
||||
endif()
|
||||
file(WRITE ${occt_SOURCE_DIR}/CMakeLists.txt "${filedata_}")
|
||||
|
||||
file(GLOB_RECURSE files_to_patch ${occt_SOURCE_DIR}/adm/cmake "occt_*")
|
||||
|
||||
foreach(file_path ${files_to_patch})
|
||||
file(READ ${file_path} filedata_)
|
||||
string(REPLACE "CMAKE_SOURCE_DIR" "OCCT_SOURCE_DIR" filedata_ "${filedata_}")
|
||||
string(REPLACE "CMAKE_BINARY_DIR" "OCCT_BINARY_DIR" filedata_ "${filedata_}")
|
||||
file(WRITE ${file_path} "${filedata_}")
|
||||
endforeach()
|
||||
|
||||
project(OCCT)
|
||||
# should be better way to pass build directory
|
||||
set(_OCCT_BINARY_DIR ${occt_BINARY_DIR})
|
||||
set(INSTALL_DIR ${occt_BINARY_DIR} CACHE BOOL "" FORCE)
|
||||
|
||||
set(USE_TK OFF CACHE BOOL "" FORCE)
|
||||
set(USE_FREETYPE OFF CACHE BOOL "" FORCE)
|
||||
set(USE_TCL OFF CACHE INTERNAL "" FORCE)
|
||||
|
||||
set(BUILD_MODULE_Visualization OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_MODULE_ApplicationFramework OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_MODULE_Draw OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(${occt_SOURCE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(OCCT_LIBRARIES
|
||||
TKernel
|
||||
TKService
|
||||
TKV3d
|
||||
TKOpenGl
|
||||
TKBRep
|
||||
TKBool
|
||||
TKFillet
|
||||
TKGeomBase
|
||||
TKGeomAlgo
|
||||
TKG3d
|
||||
TKG2d
|
||||
TKTopAlgo
|
||||
TKPrim
|
||||
TKSTEP
|
||||
)
|
||||
set(OCCT_INCLUDE_DIRS ${OpenCASCADE_INCLUDE_DIR})
|
49
cmake/stb.cmake
Normal file
49
cmake/stb.cmake
Normal file
@ -0,0 +1,49 @@
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME stb_external
|
||||
GIT_REPOSITORY https://github.com/nothings/stb.git
|
||||
GIT_TAG af1a5bc352164740c1cc1354942b1c6b72eacb8a
|
||||
DOWNLOAD_ONLY TRUE
|
||||
)
|
||||
|
||||
if(stb_external_ADDED)
|
||||
project(stb)
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE)
|
||||
add_library(stb::stb ALIAS ${PROJECT_NAME})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${stb_external_SOURCE_DIR}>
|
||||
)
|
||||
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME stb
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME}Targets
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT ${PROJECT_NAME}Targets
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${stb_external_SOURCE_DIR}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
|
||||
COMPONENT devel
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN "*.hpp"
|
||||
)
|
||||
endif()
|
@ -1,2 +1,3 @@
|
||||
add_subdirectory(hyporo)
|
||||
add_subdirectory(creator)
|
||||
add_subdirectory(applications)
|
1
source/applications/CMakeLists.txt
Normal file
1
source/applications/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(periodic)
|
10
source/applications/periodic/CMakeLists.txt
Normal file
10
source/applications/periodic/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
add_executable(periodic
|
||||
periodic.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(periodic
|
||||
hyporo-hyplib
|
||||
hyporo-csg
|
||||
)
|
||||
|
239
source/applications/periodic/periodic.cpp
Normal file
239
source/applications/periodic/periodic.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
#include "../../hyporo/hyplib/scalar/scalar.hpp"
|
||||
#include "../../hyporo/hyplib/vector/vector.hpp"
|
||||
#include "../../hyporo/hyplib/array/array.hpp"
|
||||
#include "../../hyporo/csg/csg.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace hpr;
|
||||
|
||||
void print(vec3 vs)
|
||||
{
|
||||
for (auto& v : vs)
|
||||
std::cout << v << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
class Periodic
|
||||
{
|
||||
protected:
|
||||
scalar p_alpha;
|
||||
scalar p_initialRadius;
|
||||
scalar p_sideLength;
|
||||
scalar p_filletScale;
|
||||
vec3 p_direction;
|
||||
|
||||
public:
|
||||
Periodic() :
|
||||
p_alpha {0.1},
|
||||
p_initialRadius {1},
|
||||
p_filletScale {0.8},
|
||||
p_direction {}
|
||||
{}
|
||||
|
||||
Periodic(scalar alpha, scalar initialRadius, scalar filletScale, const vec3& direction) :
|
||||
p_alpha {alpha},
|
||||
p_initialRadius {initialRadius},
|
||||
p_filletScale {filletScale},
|
||||
p_direction {direction}
|
||||
{}
|
||||
|
||||
virtual
|
||||
~Periodic() = default;
|
||||
|
||||
scalar& alpha()
|
||||
{
|
||||
return p_alpha;
|
||||
}
|
||||
|
||||
scalar& initialRadius()
|
||||
{
|
||||
return p_initialRadius;
|
||||
}
|
||||
|
||||
virtual
|
||||
scalar sideLength() = 0;
|
||||
|
||||
virtual
|
||||
scalar gamma() = 0;
|
||||
|
||||
scalar& filletScale()
|
||||
{
|
||||
return p_filletScale;
|
||||
}
|
||||
|
||||
scalar radius() const
|
||||
{
|
||||
return p_initialRadius / (1. - p_alpha);
|
||||
}
|
||||
|
||||
scalar filletRadius()
|
||||
{
|
||||
scalar analytical = p_initialRadius * sqrt(2) / sqrt(1 - cos(gamma())) - radius();
|
||||
return analytical * p_filletScale;
|
||||
}
|
||||
|
||||
vec3& direction()
|
||||
{
|
||||
return p_direction;
|
||||
}
|
||||
|
||||
virtual
|
||||
void build() = 0;
|
||||
};
|
||||
|
||||
class Simple : public Periodic, public csg::Shape
|
||||
{
|
||||
public:
|
||||
|
||||
Simple() :
|
||||
csg::Shape {},
|
||||
Periodic {0.01, 1, 0.8, vec3(1., 0., 0.)}
|
||||
{}
|
||||
|
||||
Simple(scalar alpha, const vec3& direction, scalar filletScale = 0.8) :
|
||||
Simple {}
|
||||
{
|
||||
p_alpha = alpha;
|
||||
p_direction = direction;
|
||||
p_filletScale = filletScale;
|
||||
}
|
||||
|
||||
Simple(scalar alpha, scalar initialRadius, scalar filletScale, const vec3& direction) :
|
||||
Periodic {alpha, initialRadius, filletScale, direction}
|
||||
{}
|
||||
|
||||
~Simple() override = default;
|
||||
|
||||
scalar sideLength() override
|
||||
{
|
||||
return 2 * initialRadius();
|
||||
}
|
||||
|
||||
scalar gamma() override
|
||||
{
|
||||
return hpr::PI - 2 * 0.5 * 0.5 * hpr::PI;
|
||||
}
|
||||
|
||||
csg::Shape lattice()
|
||||
{
|
||||
csg::Shape lattice;
|
||||
darray<csg::Shape> spheres;
|
||||
|
||||
for (int zn = 0; zn < 3; ++zn)
|
||||
{
|
||||
scalar z = zn * sideLength();
|
||||
for (int yn = 0; yn < 3; ++yn)
|
||||
{
|
||||
scalar y = yn * sideLength();
|
||||
for (int xn = 0; xn < 3; ++xn)
|
||||
{
|
||||
scalar x = xn * sideLength();
|
||||
spheres.push(csg::sphere(vec3(x, y, z), radius()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lattice = csg::fuse({spheres.front()}, spheres.slice(spheres.begin() + 1, spheres.end()));
|
||||
|
||||
if (filletScale() > 0)
|
||||
{
|
||||
lattice = lattice.scale({0, 0, 0}, 1e+2);
|
||||
lattice = lattice.fillet(lattice.edges(), filletRadius() * 1e+2);
|
||||
lattice = lattice.scale({0, 0, 0}, 1e-2);
|
||||
}
|
||||
|
||||
return lattice;
|
||||
}
|
||||
|
||||
csg::Shape boxCell()
|
||||
{
|
||||
scalar length = sideLength() * sqrt(2);
|
||||
scalar width = sideLength() * sqrt(2);
|
||||
scalar height = sideLength();
|
||||
scalar xl = sqrt(pow(length, 2) * 0.5);
|
||||
scalar yw = xl;
|
||||
scalar zh = height;
|
||||
darray<Shape> edges {
|
||||
csg::Edge({xl, 0, 0}, {0, yw, 0}),
|
||||
csg::Edge({0, yw, 0}, {0, yw, zh}),
|
||||
csg::Edge({0, yw, zh}, {xl, 0, zh}),
|
||||
csg::Edge({xl, 0, zh}, {xl, 0, 0})
|
||||
};
|
||||
csg::Face plgm {edges};
|
||||
|
||||
vec3 localX {csg::Surface(plgm).normal(0, 0)};
|
||||
vec3 localZ = vec3(0, 0, 1);
|
||||
vec3 localY = cross(localX, localZ);
|
||||
csg::Shape cell = plgm.extrude(localX, width);
|
||||
|
||||
scalar angle;
|
||||
hpr::vec3 normal;
|
||||
|
||||
for (auto& face : cell.faces())
|
||||
{
|
||||
normal = csg::Surface(csg::Face(face)).normal(0, 0);
|
||||
angle = hpr::angle(localX, normal);
|
||||
|
||||
if (face.tshape().Orientation() == TopAbs_FORWARD)
|
||||
{
|
||||
normal = -normal;
|
||||
angle = hpr::angle(localX, normal);
|
||||
}
|
||||
|
||||
if (equal(angle, 0.))
|
||||
face.label("periodic-south");
|
||||
else if (equal(angle, hpr::PI))
|
||||
face.label("periodic-north");
|
||||
|
||||
angle = hpr::angle(localY, normal);
|
||||
if (equal(angle, 0.))
|
||||
face.label("periodic-east");
|
||||
else if (equal(angle, hpr::PI))
|
||||
face.label("periodic-west");
|
||||
|
||||
angle = hpr::angle(localZ, normal);
|
||||
if (equal(angle, hpr::PI))
|
||||
face.label("periodic-down");
|
||||
else if (equal(angle, 0.))
|
||||
face.label("periodic-up");
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
csg::Shape hexagonalPrismCell()
|
||||
{
|
||||
return csg::Shape();
|
||||
}
|
||||
|
||||
void build() override
|
||||
{
|
||||
if (direction() == vec3(1., 0., 0.) || direction() == vec3(1., 0., 0.) || direction() == vec3(0., 0., 1.))
|
||||
p_shape = csg::cut(boxCell(), lattice()).tshape();
|
||||
else if (direction() == vec3(1., 1., 1.))
|
||||
p_shape = csg::cut(hexagonalPrismCell(), lattice()).tshape();
|
||||
else
|
||||
throw std::runtime_error("Undefined cell for passed direction");
|
||||
|
||||
|
||||
p_shape = this->translate(-this->center()).tshape();
|
||||
p_shape = this->rotate(this->center(), {0, 0, 1}, 45).tshape();
|
||||
|
||||
for (auto& face : faces())
|
||||
if (face.label() == "default")
|
||||
face.label("wall");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Simple simple {0.01, {1., 0., 0.}};
|
||||
simple.build();
|
||||
|
||||
//simple.dump("simpleTest.step", csg::Shape::Format::STEP);
|
||||
return 0;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
|
||||
include_directories(
|
||||
../hyporo/hyplib/vector
|
||||
../hyporo/hyplib/scalar
|
||||
../hyporo/hyplib/integer
|
||||
../hyporo/hyplib/matrix
|
||||
../hyporo/hyplib
|
||||
../hyporo/window_system
|
||||
../hyporo/gpu
|
||||
../hyporo/hmesh
|
||||
)
|
||||
|
||||
add_executable(hyporo
|
||||
@ -14,5 +14,9 @@ add_executable(hyporo
|
||||
|
||||
target_link_libraries(hyporo
|
||||
PUBLIC
|
||||
hyporo-hyplib
|
||||
hyporo-window-system
|
||||
hyporo-gpu
|
||||
imgui)
|
||||
hyporo-mesh
|
||||
imgui
|
||||
)
|
||||
|
@ -1,14 +1,142 @@
|
||||
#include "../hyporo/gpu/window_system.hpp"
|
||||
#include "../hyporo/gpu/glfw/window.hpp"
|
||||
#include "../window_system/window_system.hpp"
|
||||
#include "../window_system/glfw/window.hpp"
|
||||
#include "../gpu/device.hpp"
|
||||
#include "../gpu/opengl/device.hpp"
|
||||
#include "../hmesh/mesh.hpp"
|
||||
#include "../hyplib/matrix/matrix.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(void)
|
||||
struct ConstantBuffer {
|
||||
hpr::mat4 World;
|
||||
hpr::mat4 View;
|
||||
hpr::mat4 Projection;
|
||||
|
||||
hpr::vec4 Eye;
|
||||
|
||||
float Color[4];
|
||||
float Offset[4];
|
||||
|
||||
float Scale;
|
||||
int AllWhiteLight;
|
||||
|
||||
int Pad[2];
|
||||
};
|
||||
|
||||
struct ObjectBuffer {
|
||||
hpr::mat4 ObjectTransform;
|
||||
|
||||
hpr::vec4 DiffuseColor;
|
||||
|
||||
hpr::vec4 FalloffColor;
|
||||
float FalloffPower;
|
||||
|
||||
int UseDiffuseMap;
|
||||
int UseSpecularMap;
|
||||
int UseNormalMap;
|
||||
int UseFalloff;
|
||||
int UseAlpha;
|
||||
int UseReflectMap;
|
||||
|
||||
float Specular;
|
||||
float SpecularPower;
|
||||
float ReflectPower;
|
||||
|
||||
float Ambient;
|
||||
|
||||
int Lit;
|
||||
int LightExclusion[3];
|
||||
|
||||
int Pad[1];
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
hpr::gpu::WindowSystem* ws = hpr::gpu::WindowSystem::create(hpr::gpu::WindowContext::Provider::GLFW);
|
||||
hpr::gpu::Window* w = ws->newWindow();
|
||||
w->init("test", hpr::gpu::Window::Style::Windowed, 0, 0, 600, 400, nullptr, nullptr);
|
||||
using namespace hpr;
|
||||
|
||||
gpu::WindowSystem* ws = gpu::WindowSystem::create(gpu::WindowContext::Provider::GLFW);
|
||||
gpu::Window* w = ws->newWindow();
|
||||
w->init("test", gpu::Window::Style::Windowed, 0, 0, 600, 400, nullptr, nullptr);
|
||||
|
||||
if (gpu::opengl::Device::loadLoader())
|
||||
std::cerr << "Load gl loader error" << std::endl;
|
||||
|
||||
gpu::Device* device;
|
||||
gpu::Device::create(&device, gpu::Device::DeviceAPI::OpenGL);
|
||||
device->initialize();
|
||||
gpu::Shader* vertexShader;
|
||||
device->createVertexShader(&vertexShader, "shaders/base.vert.glsl", "VS");
|
||||
gpu::Shader* fragmentShader;
|
||||
device->createFragmentShader(&fragmentShader, "shaders/base.frag.glsl", "FS");
|
||||
gpu::ShaderProgram* shaderProgram;
|
||||
device->createShaderProgram(&shaderProgram);
|
||||
device->attachShader(shaderProgram, vertexShader);
|
||||
device->attachShader(shaderProgram, fragmentShader);
|
||||
device->linkProgram(shaderProgram);
|
||||
|
||||
mesh::Mesh mesh;
|
||||
mesh.addVertex(-1, 1, 0.5);
|
||||
mesh.addVertex(1, 1, 0.5);
|
||||
mesh.addVertex(1, -1, 0.5);
|
||||
mesh.addVertex(-1, -1, 0.5);
|
||||
mesh.addEdge(mesh.vertex(0), mesh.vertex(1));
|
||||
mesh.addEdge(mesh.vertex(1), mesh.vertex(2));
|
||||
mesh.addEdge(mesh.vertex(2), mesh.vertex(3));
|
||||
mesh.addEdge(mesh.vertex(3), mesh.vertex(0));
|
||||
mesh.addEdge(mesh.vertex(0), mesh.vertex(2));
|
||||
mesh.addFace(mesh.edge(0), mesh.edge(1), mesh.edge(4));
|
||||
mesh.addFace(mesh.edge(2), mesh.edge(3), mesh.edge(4));
|
||||
|
||||
darray<float> data (3 * 6, 0.f);
|
||||
auto arr = mesh.face(0)->vertices() + mesh.face(1)->vertices();
|
||||
for (auto n = 0; n < arr.size(); ++n)
|
||||
for (auto k = 0; k < 3; ++k)
|
||||
data[k + 3 * n] = *(arr[n]->data() + k);
|
||||
darray<unsigned short> indices (6, 0);
|
||||
for (auto n = 0; n < arr.size(); ++n)
|
||||
indices[n] = mesh.indexOf(arr[n]);
|
||||
|
||||
gpu::Buffer* vertexBuffer;
|
||||
device->createVertexBuffer(&vertexBuffer, sizeof(float) * data.size(), (char*)data.data());
|
||||
gpu::Buffer* indexBuffer;
|
||||
device->createIndexBuffer(&indexBuffer, sizeof(unsigned short) * indices.size(), (char*)indices.data());
|
||||
|
||||
gpu::Buffer* constantBuffer;
|
||||
device->createUniformBuffer(&constantBuffer, sizeof(ConstantBuffer), nullptr);
|
||||
gpu::Buffer* objectBuffer;
|
||||
device->createUniformBuffer(&objectBuffer, sizeof(ObjectBuffer), nullptr);
|
||||
|
||||
ConstantBuffer constantData;
|
||||
constantData.Color[0] = 1;
|
||||
constantData.Color[1] = 0;
|
||||
constantData.Color[2] = 0;
|
||||
constantData.Color[3] = 1;
|
||||
constantData.Offset[0] = 0;
|
||||
constantData.Offset[1] = 0;
|
||||
constantData.Offset[2] = 0;
|
||||
constantData.Offset[3] = 1;
|
||||
constantData.Scale = 1;
|
||||
ObjectBuffer objectData;
|
||||
objectData.Lit = 1;
|
||||
objectData.DiffuseColor = vec4(1, 1, 1, 1);
|
||||
objectData.Specular = 0.25;
|
||||
objectData.SpecularPower = 1;
|
||||
objectData.UseDiffuseMap = 0;
|
||||
objectData.UseSpecularMap = 0;
|
||||
objectData.UseNormalMap = 0;
|
||||
objectData.UseFalloff = 0;
|
||||
objectData.FalloffColor = vec4(1, 1, 1, 1);
|
||||
objectData.FalloffPower = 1;
|
||||
objectData.Ambient = 1;
|
||||
objectData.UseAlpha = 0;
|
||||
objectData.UseReflectMap = 0;
|
||||
|
||||
device->useShaderProgram(shaderProgram);
|
||||
device->useUniformBuffer(constantBuffer, 0);
|
||||
device->useUniformBuffer(objectBuffer, 1);
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
@ -19,13 +147,16 @@ int main(void)
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(dynamic_cast<hpr::gpu::glfw::Window*>(w)->instance(), true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330");
|
||||
ImGui_ImplGlfw_InitForOpenGL(dynamic_cast<gpu::glfw::Window*>(w)->instance(), true);
|
||||
ImGui_ImplOpenGL3_Init("#version 420");
|
||||
|
||||
while (w->isOpen())
|
||||
{
|
||||
dynamic_cast<hpr::gpu::glfw::Window*>(w)->pollEvents();
|
||||
|
||||
dynamic_cast<gpu::glfw::Window*>(w)->pollEvents();
|
||||
device->useShaderProgram(shaderProgram);
|
||||
device->useVertexBuffer(vertexBuffer, 0, 0);
|
||||
device->useIndexBuffer(indexBuffer, 0);
|
||||
dynamic_cast<gpu::opengl::Device*>(device)->Draw(2, 0, 0);
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
@ -33,24 +164,33 @@ int main(void)
|
||||
bool yes = true;
|
||||
ImGui::ShowDemoWindow(&yes);
|
||||
|
||||
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
|
||||
ImGui::Begin("Hello, world!");
|
||||
{
|
||||
if (ImGui::Button("Exit")) // Buttons return true when clicked (most widgets return true when edited/activated)
|
||||
w->state(hpr::gpu::Window::State::Closed);
|
||||
if (ImGui::Button("Exit"))
|
||||
w->state(gpu::Window::State::Closed);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
dynamic_cast<hpr::gpu::glfw::Window*>(w)->swapBuffers();
|
||||
dynamic_cast<gpu::glfw::Window*>(w)->swapBuffers();
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
device->destroyShaderProgram(shaderProgram, false);
|
||||
device->destroyShader(vertexShader);
|
||||
device->destroyShader(fragmentShader);
|
||||
device->destroyBuffer(vertexBuffer);
|
||||
device->destroyBuffer(indexBuffer);
|
||||
device->destroyBuffer(constantBuffer);
|
||||
device->destroyBuffer(objectBuffer);
|
||||
delete dynamic_cast<gpu::opengl::Device*>(device);
|
||||
|
||||
ws->destroyWindow(w);
|
||||
hpr::gpu::WindowSystem::destroy(ws);
|
||||
gpu::WindowSystem::destroy(ws);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
|
||||
include_directories(
|
||||
.
|
||||
../hyplib/integer
|
||||
../hyplib/scalar
|
||||
../hyplib/vector
|
||||
)
|
||||
|
||||
add_library(hyporo-csg STATIC
|
||||
|
||||
# Header files
|
||||
shape.hpp
|
||||
|
||||
# Source files
|
||||
shape.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(hyporo-csg
|
||||
hyporo-hyplib
|
||||
${OCCT_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(hyporo-csg
|
||||
PUBLIC
|
||||
${OCCT_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
if(WITH_GTESTS)
|
||||
add_executable(hyporo-csg-test
|
||||
tests/csg-test.cpp
|
||||
shape.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(hyporo-csg-test
|
||||
GTest::gtest_main
|
||||
${OCCT_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(hyporo-csg-test
|
||||
PUBLIC
|
||||
${OCCT_INCLUDE_DIRS}
|
||||
)
|
||||
gtest_add_tests(TARGET hyporo-csg-test)
|
||||
endif()
|
45
source/hyporo/csg/compound.hpp
Normal file
45
source/hyporo/csg/compound.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "solid.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Compound : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Compound() = default;
|
||||
|
||||
~Compound() override = default;
|
||||
|
||||
explicit
|
||||
Compound(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Compound ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Compound(const darray<Shape>& shapes) :
|
||||
Shape {}
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
for (auto& shape : shapes)
|
||||
builder.Add(compound, shape.tshape());
|
||||
|
||||
p_shape = compound;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Compound tcast() const
|
||||
{
|
||||
return TopoDS::Compound(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
16
source/hyporo/csg/csg.hpp
Normal file
16
source/hyporo/csg/csg.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "vertex.hpp"
|
||||
#include "edge.hpp"
|
||||
#include "wire.hpp"
|
||||
#include "face.hpp"
|
||||
#include "shell.hpp"
|
||||
#include "solid.hpp"
|
||||
#include "compound.hpp"
|
||||
#include "geometry.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{}
|
39
source/hyporo/csg/edge.hpp
Normal file
39
source/hyporo/csg/edge.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "vertex.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Edge : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Edge() = default;
|
||||
|
||||
~Edge() override = default;
|
||||
|
||||
explicit
|
||||
Edge(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Edge ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
Edge(const vec3& p1, const vec3& p2) :
|
||||
Shape {BRepBuilderAPI_MakeEdge(gp_Pnt(p1[0], p1[1], p1[2]), gp_Pnt(p2[0], p2[1], p2[2])).Shape()}
|
||||
{}
|
||||
|
||||
Edge(const Vertex& v1, const Vertex& v2) :
|
||||
Shape {BRepBuilderAPI_MakeEdge(v1.tcast(), v2.tcast()).Shape()}
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Edge tcast() const
|
||||
{
|
||||
return TopoDS::Edge(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
42
source/hyporo/csg/face.hpp
Normal file
42
source/hyporo/csg/face.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "wire.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Face : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Face() = default;
|
||||
|
||||
~Face() override = default;
|
||||
|
||||
explicit
|
||||
Face(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Face ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Face(const Wire& wire) :
|
||||
Shape {BRepBuilderAPI_MakeFace(wire.tcast()).Shape()}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Face(const darray<Shape>& edges) :
|
||||
Face {Wire(edges)}
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Face tcast() const
|
||||
{
|
||||
return TopoDS::Face(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
21
source/hyporo/csg/geometry.hpp
Normal file
21
source/hyporo/csg/geometry.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Geometry
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Geometry() = default;
|
||||
|
||||
virtual
|
||||
~Geometry() = default;
|
||||
|
||||
};
|
||||
|
||||
}
|
27
source/hyporo/csg/shape.cpp
Normal file
27
source/hyporo/csg/shape.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "shape.hpp"
|
||||
|
||||
|
||||
bool std::less<hpr::csg::Shape>::operator()(const hpr::csg::Shape& s1, const hpr::csg::Shape& s2) const
|
||||
{
|
||||
return s1.tshape().HashCode(std::numeric_limits<Standard_Integer>::max()) <
|
||||
s2.tshape().HashCode(std::numeric_limits<Standard_Integer>::max());
|
||||
}
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
std::map<Shape, Shape::Metadata> Shape::metadata;
|
||||
|
||||
|
||||
Shape sphere(vec3 center, double radius)
|
||||
{
|
||||
BRepPrimAPI_MakeSphere prim {gp_Pnt(center[0], center[1], center[2]), radius};
|
||||
return Shape {prim.Shape()};
|
||||
}
|
||||
|
||||
Shape box(vec3 corner, double dx, double dy, double dz)
|
||||
{
|
||||
BRepPrimAPI_MakeBox prim {gp_Pnt(corner[0], corner[1], corner[2]), dx, dy, dz};
|
||||
return Shape {prim.Shape()};
|
||||
}
|
||||
|
||||
}
|
489
source/hyporo/csg/shape.hpp
Normal file
489
source/hyporo/csg/shape.hpp
Normal file
@ -0,0 +1,489 @@
|
||||
#pragma once
|
||||
|
||||
#include "../hyplib/scalar/scalar.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <Geom_Surface.hxx>
|
||||
#include <GeomLProp_SLProps.hxx>
|
||||
#include <Poly_Triangle.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <TopoDS_CompSolid.hxx>
|
||||
#include <TopoDS_Shell.hxx>
|
||||
#include <TopoDS_Solid.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <BRepBndLib.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <ShapeUpgrade_UnifySameDomain.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepFilletAPI_MakeFillet.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeSphere.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
|
||||
#include <STEPControl_Writer.hxx>
|
||||
#include <Interface_Static.hxx>
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <Poly_PolygonOnTriangulation.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
#include <ShapeFix_Shell.hxx>
|
||||
#include <ShapeFix_Face.hxx>
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
class Shape;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct less<hpr::csg::Shape>
|
||||
{
|
||||
bool operator() (const hpr::csg::Shape& s1, const hpr::csg::Shape& s2) const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
// Forward declaration of friend functions
|
||||
|
||||
double distance(const Shape& lhs, const Shape& rhs);
|
||||
|
||||
Shape fuse(const Shape& lhs, const Shape& rhs);
|
||||
|
||||
Shape fuse(const darray<Shape>& args, const darray<Shape>& tools);
|
||||
|
||||
Shape common(const Shape& lhs, const Shape& rhs);
|
||||
|
||||
Shape cut(const Shape& lhs, const Shape& rhs);
|
||||
|
||||
|
||||
// Class declaration
|
||||
|
||||
class Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Compound,
|
||||
Compsolid,
|
||||
Solid,
|
||||
Shell,
|
||||
Face,
|
||||
Wire,
|
||||
Edge,
|
||||
Vertex,
|
||||
Shape,
|
||||
Unknown
|
||||
};
|
||||
|
||||
enum class Format
|
||||
{
|
||||
Unknown,
|
||||
STEP
|
||||
};
|
||||
|
||||
class Metadata
|
||||
{
|
||||
public:
|
||||
std::string label;
|
||||
public:
|
||||
Metadata() :
|
||||
label {"default"}
|
||||
{}
|
||||
void merge(const Metadata& data)
|
||||
{
|
||||
if (label == "default" && data.label != "default")
|
||||
label = data.label;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// TODO: clean up map
|
||||
static
|
||||
std::map<Shape, Shape::Metadata> metadata;
|
||||
|
||||
protected:
|
||||
|
||||
TopoDS_Shape p_shape;
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Shape tshape() const { return p_shape; }
|
||||
|
||||
Shape(const TopoDS_Shape& s) :
|
||||
p_shape {s}
|
||||
{}
|
||||
|
||||
Shape(TopoDS_Shape&& s) noexcept:
|
||||
p_shape {std::forward<TopoDS_Shape>(s)}
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
Shape() :
|
||||
p_shape {}
|
||||
{}
|
||||
|
||||
virtual
|
||||
~Shape() = default;
|
||||
//{
|
||||
//if (metadata.contains(*this))
|
||||
// metadata.erase(*this);
|
||||
//}
|
||||
|
||||
[[nodiscard]]
|
||||
Type type() const
|
||||
{
|
||||
switch (p_shape.ShapeType())
|
||||
{
|
||||
case TopAbs_VERTEX:
|
||||
return Type::Vertex;
|
||||
case TopAbs_EDGE:
|
||||
return Type::Edge;
|
||||
case TopAbs_FACE:
|
||||
return Type::Face;
|
||||
case TopAbs_WIRE:
|
||||
return Type::Wire;
|
||||
case TopAbs_SHELL:
|
||||
return Type::Shell;
|
||||
case TopAbs_SOLID:
|
||||
return Type::Solid;
|
||||
case TopAbs_COMPOUND:
|
||||
return Type::Compound;
|
||||
case TopAbs_COMPSOLID:
|
||||
return Type::Compsolid;
|
||||
case TopAbs_SHAPE:
|
||||
return Type::Shape;
|
||||
default:
|
||||
return Type::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
vec3 center() const
|
||||
{
|
||||
GProp_GProps props;
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case Type::Solid:
|
||||
case Type::Compsolid:
|
||||
case Type::Compound:
|
||||
BRepGProp::VolumeProperties(p_shape, props);
|
||||
case Type::Shell:
|
||||
case Type::Face:
|
||||
BRepGProp::SurfaceProperties(p_shape, props);
|
||||
default:
|
||||
BRepGProp::LinearProperties(p_shape, props);
|
||||
}
|
||||
|
||||
gp_Pnt center {props.CentreOfMass()};
|
||||
|
||||
return vec3 {center.X(), center.Y(), center.Z()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
double length() const
|
||||
{
|
||||
GProp_GProps props;
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case Type::Vertex:
|
||||
return 0;
|
||||
default:
|
||||
BRepGProp::LinearProperties(p_shape, props);
|
||||
return props.Mass();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
double area() const
|
||||
{
|
||||
GProp_GProps props;
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case Type::Vertex:
|
||||
case Type::Edge:
|
||||
case Type::Wire:
|
||||
return 0;
|
||||
default:
|
||||
BRepGProp::SurfaceProperties(p_shape, props);
|
||||
return props.Mass();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
double volume() const
|
||||
{
|
||||
GProp_GProps props;
|
||||
|
||||
switch (type())
|
||||
{
|
||||
case Type::Compsolid:
|
||||
case Type::Solid:
|
||||
BRepGProp::VolumeProperties(p_shape, props);
|
||||
return props.Mass();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void label(const std::string& label) const
|
||||
{
|
||||
metadata[*this].label = label;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string label() const
|
||||
{
|
||||
return metadata[*this].label;
|
||||
}
|
||||
|
||||
void dump(const std::string& filename, Format format) const
|
||||
{
|
||||
if (p_shape.IsNull())
|
||||
throw std::runtime_error("Trying to export null shape");
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case Format::STEP:
|
||||
{
|
||||
STEPControl_Writer writer;
|
||||
Interface_Static::SetCVal("xstep.cascade.unit", "MM");
|
||||
Interface_Static::SetCVal("write.step.unit", "MM");
|
||||
Interface_Static::SetIVal("write.step.nonmanifold", 1);
|
||||
|
||||
writer.Transfer(p_shape, STEPControl_AsIs);
|
||||
writer.Write(filename.c_str());
|
||||
break;
|
||||
}
|
||||
case Format::Unknown:
|
||||
default:
|
||||
throw std::invalid_argument("Unknown export format");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
[[nodiscard]]
|
||||
sarray<vec3, 2> boundingBox() const
|
||||
{
|
||||
Bnd_Box bbox;
|
||||
BRepBndLib::Add(p_shape, bbox, true);
|
||||
gp_Pnt p1 {bbox.CornerMin()};
|
||||
gp_Pnt p2 {bbox.CornerMax()};
|
||||
|
||||
return sarray<vec3, 2> {{p1.X(), p1.Y(), p1.Z()}, {p2.X(), p2.Y(), p2.Z()}};
|
||||
}
|
||||
|
||||
void incrementalMesh(double deflection)
|
||||
{
|
||||
BRepTools::Clean(p_shape);
|
||||
BRepMesh_IncrementalMesh(p_shape, deflection, true);
|
||||
}
|
||||
|
||||
darray<Shape> subShapes(Type type) const
|
||||
{
|
||||
darray<Shape> subshapes;
|
||||
for (TopExp_Explorer exp(p_shape, static_cast<TopAbs_ShapeEnum>(type)); exp.More(); exp.Next())
|
||||
subshapes.push(Shape(exp.Current()));
|
||||
return subshapes;
|
||||
}
|
||||
|
||||
darray<Shape> edges() const
|
||||
{
|
||||
return subShapes(Type::Edge);
|
||||
}
|
||||
|
||||
darray<Shape> faces() const
|
||||
{
|
||||
return subShapes(Type::Face);
|
||||
}
|
||||
|
||||
darray<Shape> shells() const
|
||||
{
|
||||
return subShapes(Type::Shell);
|
||||
}
|
||||
|
||||
// Member functions: transformations
|
||||
|
||||
Shape translate(const vec3& dir)
|
||||
{
|
||||
gp_Trsf transform;
|
||||
transform.SetTranslation(gp_Vec(dir[0], dir[1], dir[2]));
|
||||
BRepBuilderAPI_Transform builder {p_shape, transform, true};
|
||||
|
||||
return builder.Shape();
|
||||
}
|
||||
|
||||
Shape rotate(const vec3& pos, const vec3& axis, double angle)
|
||||
{
|
||||
gp_Trsf transform;
|
||||
transform.SetRotation(gp_Ax1({pos[0], pos[1], pos[2]}, {axis[0], axis[1], axis[2]}), radians(angle));
|
||||
BRepBuilderAPI_Transform builder {p_shape, transform, true};
|
||||
|
||||
return builder.Shape();
|
||||
}
|
||||
|
||||
Shape scale(const vec3& center, double scale)
|
||||
{
|
||||
gp_Trsf transform;
|
||||
transform.SetScale(gp_Pnt(center[0], center[1], center[2]), scale);
|
||||
BRepBuilderAPI_Transform builder {p_shape, transform, true};
|
||||
|
||||
return builder.Shape();
|
||||
}
|
||||
|
||||
Shape& scaled(const vec3& center, double scale)
|
||||
{
|
||||
p_shape = this->scale(center, scale).p_shape;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Shape extrude(const vec3& dir, double length)
|
||||
{
|
||||
BRepPrimAPI_MakePrism builder {p_shape, length * gp_Vec(dir[0], dir[1], dir[2]), true};
|
||||
|
||||
for (auto& type : { Type::Solid, Type::Face, Type::Edge, Type::Vertex })
|
||||
for (TopExp_Explorer exp {p_shape, static_cast<TopAbs_ShapeEnum>(type)}; exp.More(); exp.Next())
|
||||
{
|
||||
auto data = metadata[Shape(exp.Current())];
|
||||
|
||||
for (auto& mod : builder.Generated(exp.Current()))
|
||||
metadata[Shape(mod)].merge(data);
|
||||
}
|
||||
|
||||
return builder.Shape();
|
||||
}
|
||||
|
||||
Shape fillet(darray<Shape> edges, double radius)
|
||||
{
|
||||
BRepFilletAPI_MakeFillet fillet {p_shape};
|
||||
|
||||
for (auto& e : edges)
|
||||
fillet.Add(radius, TopoDS::Edge(e.p_shape));
|
||||
fillet.Build();
|
||||
|
||||
return fillet.Shape();
|
||||
}
|
||||
|
||||
// Friend functions
|
||||
|
||||
friend
|
||||
double distance(const Shape& lhs, const Shape& rhs)
|
||||
{
|
||||
return BRepExtrema_DistShapeShape(lhs.tshape(), rhs.tshape()).Value();
|
||||
}
|
||||
|
||||
friend
|
||||
Shape fuse(const Shape& lhs, const Shape& rhs)
|
||||
{
|
||||
BRepAlgoAPI_Fuse builder {lhs.p_shape, rhs.p_shape};
|
||||
builder.Build();
|
||||
return Shape {builder.Shape()};
|
||||
}
|
||||
|
||||
friend
|
||||
Shape fuse(const darray<Shape>& args, const darray<Shape>& tools)
|
||||
{
|
||||
BRepAlgoAPI_Fuse builder;
|
||||
NCollection_List<TopoDS_Shape> args_, tools_;
|
||||
for (auto& arg : args)
|
||||
args_.Append(arg.tshape());
|
||||
for (auto& tool : tools)
|
||||
tools_.Append(tool.tshape());
|
||||
builder.SetArguments(args_);
|
||||
builder.SetTools(tools_);
|
||||
builder.Build();
|
||||
return Shape {builder.Shape()};
|
||||
}
|
||||
|
||||
friend
|
||||
Shape common(const Shape& lhs, const Shape& rhs)
|
||||
{
|
||||
BRepAlgoAPI_Common builder {lhs.p_shape, rhs.p_shape};
|
||||
builder.Build();
|
||||
return Shape {builder.Shape()};
|
||||
}
|
||||
|
||||
friend
|
||||
Shape cut(const Shape& lhs, const Shape& rhs)
|
||||
{
|
||||
BRepAlgoAPI_Cut builder {lhs.p_shape, rhs.p_shape};
|
||||
builder.Build();
|
||||
for (auto& type : { Type::Solid, Type::Face, Type::Edge, Type::Vertex })
|
||||
for (TopExp_Explorer exp {lhs.p_shape, static_cast<TopAbs_ShapeEnum>(type)}; exp.More(); exp.Next())
|
||||
{
|
||||
auto data = metadata[Shape(exp.Current())];
|
||||
|
||||
for (auto& mod : builder.Modified(exp.Current()))
|
||||
metadata[Shape(mod)].merge(data);
|
||||
}
|
||||
for (auto& type : { Type::Solid, Type::Face, Type::Edge, Type::Vertex })
|
||||
for (TopExp_Explorer exp {rhs.p_shape, static_cast<TopAbs_ShapeEnum>(type)}; exp.More(); exp.Next())
|
||||
{
|
||||
auto data = metadata[Shape(exp.Current())];
|
||||
|
||||
for (auto& mod : builder.Modified(exp.Current()))
|
||||
metadata[Shape(mod)].merge(data);
|
||||
}
|
||||
return Shape {builder.Shape()};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Global functions: primitives
|
||||
|
||||
Shape sphere(vec3 center, double radius);
|
||||
|
||||
Shape box(vec3 corner, double dx, double dy, double dz);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
52
source/hyporo/csg/shell.hpp
Normal file
52
source/hyporo/csg/shell.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Shell : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Shell() = default;
|
||||
|
||||
~Shell() override = default;
|
||||
|
||||
explicit
|
||||
Shell(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Shell ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Shell(const darray<Shape>& faces) :
|
||||
Shape {}
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Shell shell;
|
||||
builder.MakeShell(shell);
|
||||
|
||||
for (auto& shape : faces)
|
||||
switch (shape.type())
|
||||
{
|
||||
case Type::Face:
|
||||
builder.Add(shell, Face(shape).tcast());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
|
||||
p_shape = shell;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Shell tcast() const
|
||||
{
|
||||
return TopoDS::Shell(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
45
source/hyporo/csg/solid.hpp
Normal file
45
source/hyporo/csg/solid.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "shell.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Solid : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Solid() = default;
|
||||
|
||||
~Solid() override = default;
|
||||
|
||||
explicit
|
||||
Solid(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Solid ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Solid(const Shell& shell) :
|
||||
Shape {}
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Solid solid;
|
||||
|
||||
builder.MakeSolid(solid);
|
||||
builder.Add(solid, shell.tcast());
|
||||
|
||||
p_shape = solid;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Solid tcast() const
|
||||
{
|
||||
return TopoDS::Solid(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
64
source/hyporo/csg/surface.hpp
Normal file
64
source/hyporo/csg/surface.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "geometry.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Surface : public Geometry
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
Handle(Geom_Surface) p_surface;
|
||||
|
||||
public:
|
||||
|
||||
Surface() = default;
|
||||
|
||||
~Surface() override = default;
|
||||
|
||||
explicit
|
||||
Surface(const Face& face) :
|
||||
Geometry {},
|
||||
p_surface {BRep_Tool::Surface(face.tcast())}
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
Handle(Geom_Surface) tcast() const
|
||||
{
|
||||
return p_surface;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
vec3 value(double u, double v) const
|
||||
{
|
||||
gp_Pnt p {p_surface->Value(u, v)};
|
||||
|
||||
return vec3 {p.X(), p.Y(), p.Z()};
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
vec3 normal(double u, double v) const
|
||||
{
|
||||
GeomLProp_SLProps props {p_surface, u, v, 1, 1e-8};
|
||||
gp_Dir dir {props.Normal()};
|
||||
|
||||
return vec3 {dir.X(), dir.Y(), dir.Z()};
|
||||
}
|
||||
|
||||
vec3 normal()
|
||||
{
|
||||
gp_Vec du, dv;
|
||||
gp_Pnt p;
|
||||
p_surface->D1(0, 0, p, du, dv);
|
||||
gp_Vec dir {du ^ dv};
|
||||
return vec3 {dir.X(), dir.Y(), dir.Z()};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
24
source/hyporo/csg/tests/csg-test.cpp
Normal file
24
source/hyporo/csg/tests/csg-test.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "../csg.hpp"
|
||||
|
||||
TEST(csgTest, Shape)
|
||||
{
|
||||
using namespace hpr;
|
||||
double radius = 1.;
|
||||
double volume = 4. / 3. * PI;
|
||||
auto sphere = csg::sphere({0, 0, 0}, radius);
|
||||
EXPECT_TRUE(equal(sphere.volume(), volume, 1e-6));
|
||||
auto box = csg::box({0, 0, 0}, 1, 1, 1);
|
||||
EXPECT_TRUE(equal(box.volume(), 1));
|
||||
auto edge = csg::Edge();
|
||||
int n = 0;
|
||||
for (auto& face : box.subShapes(csg::Shape::Type::Face))
|
||||
{
|
||||
std::stringstream name;
|
||||
name << "face" << n;
|
||||
csg::Face(face).label(name.str());
|
||||
++n;
|
||||
}
|
||||
box.scale(box.center(), 5);
|
||||
EXPECT_EQ(box.subShapes(csg::Shape::Type::Face)[2].label(), "face2");
|
||||
}
|
43
source/hyporo/csg/vertex.hpp
Normal file
43
source/hyporo/csg/vertex.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Vertex : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Vertex() = default;
|
||||
|
||||
~Vertex() override = default;
|
||||
|
||||
explicit
|
||||
Vertex(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Vertex ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Vertex(const vec3& point) :
|
||||
Shape {BRepBuilderAPI_MakeVertex(gp_Pnt(point[0], point[1], point[2])).Shape()}
|
||||
{}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Vertex tcast() const
|
||||
{
|
||||
return TopoDS::Vertex(p_shape);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
vec3 cast() const
|
||||
{
|
||||
gp_Pnt point = BRep_Tool::Pnt(tcast());
|
||||
return vec3 {point.X(), point.Y(), point.Z()};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
53
source/hyporo/csg/wire.hpp
Normal file
53
source/hyporo/csg/wire.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "edge.hpp"
|
||||
|
||||
|
||||
namespace hpr::csg
|
||||
{
|
||||
|
||||
class Wire : public Shape
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Wire() = default;
|
||||
|
||||
~Wire() override = default;
|
||||
|
||||
explicit
|
||||
Wire(const Shape& shape) :
|
||||
Shape {shape.type() == Type::Wire ? shape : throw std::runtime_error("")}
|
||||
{}
|
||||
|
||||
explicit
|
||||
Wire(const darray<Shape>& edges) :
|
||||
Shape {}
|
||||
{
|
||||
BRepBuilderAPI_MakeWire builder;
|
||||
|
||||
for (auto& shape : edges)
|
||||
switch (shape.type())
|
||||
{
|
||||
case Type::Edge:
|
||||
builder.Add(Edge(shape).tcast());
|
||||
break;
|
||||
case Type::Wire:
|
||||
builder.Add(Wire(shape).tcast());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
|
||||
p_shape = builder.Shape();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
TopoDS_Wire tcast() const
|
||||
{
|
||||
return TopoDS::Wire(p_shape);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -36,5 +36,6 @@ add_library(hyporo-gpu STATIC
|
||||
|
||||
target_link_libraries(hyporo-gpu
|
||||
glad
|
||||
stb
|
||||
hyporo-hyplib
|
||||
)
|
@ -19,8 +19,7 @@ Buffer::Buffer(DeviceAPI api) :
|
||||
p_stride {0}
|
||||
{}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{}
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
// Member functions
|
||||
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
Undefined,
|
||||
Vertex,
|
||||
Index,
|
||||
Uniform,
|
||||
BufferTypeCount
|
||||
};
|
||||
|
||||
@ -34,14 +35,17 @@ public:
|
||||
|
||||
Buffer();
|
||||
|
||||
explicit
|
||||
Buffer(DeviceAPI api);
|
||||
|
||||
virtual ~Buffer();
|
||||
~Buffer() override;
|
||||
|
||||
// Member functions
|
||||
|
||||
[[nodiscard]]
|
||||
int size() const;
|
||||
|
||||
[[nodiscard]]
|
||||
BufferType type() const;
|
||||
};
|
||||
|
||||
|
@ -13,8 +13,7 @@ Context::Context(DeviceAPI api) :
|
||||
p_api {api}
|
||||
{}
|
||||
|
||||
Context::~Context()
|
||||
{}
|
||||
Context::~Context() = default;
|
||||
|
||||
bool Context::checkCompability(const Context* ctx) const
|
||||
{
|
||||
|
@ -26,6 +26,7 @@ public:
|
||||
|
||||
Context();
|
||||
|
||||
explicit
|
||||
Context(DeviceAPI api);
|
||||
|
||||
virtual
|
||||
|
@ -10,6 +10,7 @@ Device::Device() :
|
||||
Context {DeviceAPI::Unknown},
|
||||
p_currentVertexBuffer {},
|
||||
p_currentIndexBuffer {},
|
||||
p_currentUniformBuffer {},
|
||||
p_currentShaderProgram {}
|
||||
{}
|
||||
|
||||
@ -17,11 +18,21 @@ Device::Device(DeviceAPI api) :
|
||||
Context {api},
|
||||
p_currentVertexBuffer {},
|
||||
p_currentIndexBuffer {},
|
||||
p_currentUniformBuffer {},
|
||||
p_currentShaderProgram {}
|
||||
{}
|
||||
|
||||
Device::~Device()
|
||||
{}
|
||||
{
|
||||
for (auto& shader : p_shaders)
|
||||
delete shader;
|
||||
for (auto& buffer : p_buffers)
|
||||
delete buffer;
|
||||
for (auto& shaderProgram : p_shaderPrograms)
|
||||
delete shaderProgram;
|
||||
for (auto& texture : p_textures)
|
||||
delete texture;
|
||||
}
|
||||
|
||||
// Global functions
|
||||
|
||||
@ -52,7 +63,7 @@ void Device::useVertexBuffer(Buffer* buffer, int stride, int offset)
|
||||
p_currentVertexBuffer->p_stride = stride;
|
||||
}
|
||||
else
|
||||
throw "Incompatible buffer";
|
||||
throw std::runtime_error("Incompatible buffer");
|
||||
}
|
||||
else
|
||||
p_currentVertexBuffer = nullptr;
|
||||
@ -67,34 +78,70 @@ void Device::useIndexBuffer(Buffer* buffer, int offset)
|
||||
p_currentIndexBuffer = buffer;
|
||||
}
|
||||
else
|
||||
throw "Incompatible buffer";
|
||||
throw std::runtime_error("Incompatible buffer");
|
||||
}
|
||||
else
|
||||
p_currentIndexBuffer = nullptr;
|
||||
}
|
||||
|
||||
void Device::useUniformBuffer(Buffer* buffer, int slot)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer->p_type == Buffer::BufferType::Uniform)
|
||||
p_currentUniformBuffer = buffer;
|
||||
else
|
||||
throw std::runtime_error("Incompatible buffer");
|
||||
}
|
||||
else
|
||||
p_currentUniformBuffer = nullptr;
|
||||
}
|
||||
|
||||
void Device::destroyBuffer(Buffer*& buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
throw "Invalid parameter";
|
||||
throw std::runtime_error("Invalid parameter");
|
||||
|
||||
for (auto iter = p_buffers.begin(); iter != p_buffers.end(); ++iter)
|
||||
if (&*iter == &*buffer)
|
||||
p_buffers.erase(iter);
|
||||
if (*iter == buffer)
|
||||
{
|
||||
delete buffer;
|
||||
buffer = nullptr;
|
||||
p_buffers.remove(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer* Device::activeBuffer(Buffer::BufferType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Buffer::BufferType::Vertex:
|
||||
return p_currentVertexBuffer;
|
||||
case Buffer::BufferType::Index:
|
||||
return p_currentIndexBuffer;
|
||||
case Buffer::BufferType::Uniform:
|
||||
return p_currentUniformBuffer;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Shaders
|
||||
|
||||
void Device::destroyShader(Shader *&shader)
|
||||
void Device::destroyShader(Shader* shader)
|
||||
{
|
||||
if (shader == nullptr)
|
||||
throw "Invalid parameter";
|
||||
throw std::runtime_error("Invalid parameter");
|
||||
|
||||
for (auto iter = p_shaders.begin(); iter != p_shaders.end(); ++iter)
|
||||
if (&*iter == &*shader)
|
||||
p_shaders.erase(iter);
|
||||
if (*iter == shader)
|
||||
{
|
||||
delete shader;
|
||||
shader = nullptr;
|
||||
p_shaders.remove(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Shader programs
|
||||
@ -102,9 +149,9 @@ void Device::destroyShader(Shader *&shader)
|
||||
void Device::attachShader(ShaderProgram *program, Shader *shader)
|
||||
{
|
||||
if (program == nullptr || shader == nullptr)
|
||||
throw "Invalid parameter";
|
||||
throw std::runtime_error("Invalid parameter");
|
||||
if (program->p_isLinked)
|
||||
throw "Shader program already linked";
|
||||
throw std::runtime_error("Shader program already linked");
|
||||
|
||||
program->p_slots[(int)shader->p_type] = shader;
|
||||
}
|
||||
@ -112,9 +159,9 @@ void Device::attachShader(ShaderProgram *program, Shader *shader)
|
||||
void Device::linkProgram(ShaderProgram *program)
|
||||
{
|
||||
if (program == nullptr)
|
||||
throw "Invalid parameter";
|
||||
throw std::runtime_error("Invalid parameter");
|
||||
if (program->p_isLinked)
|
||||
throw "Shader program already linked";
|
||||
throw std::runtime_error("Shader program already linked");
|
||||
|
||||
program->p_isLinked = true;
|
||||
}
|
||||
@ -123,7 +170,7 @@ void Device::useShaderProgram(ShaderProgram *program)
|
||||
{
|
||||
if (program != nullptr)
|
||||
if (!program->p_isLinked)
|
||||
throw "Shader program is not linked";
|
||||
throw std::runtime_error("Shader program is not linked");
|
||||
|
||||
p_currentShaderProgram = program;
|
||||
}
|
||||
@ -136,7 +183,15 @@ void Device::destroyShaderProgram(ShaderProgram *&program, bool withShaders)
|
||||
if (withShaders)
|
||||
for (size_t n = 0; n < (size_t)Shader::ShaderType::ShaderTypeCount; n++)
|
||||
destroyShader(program->p_slots[n]);
|
||||
|
||||
for (auto iter = p_shaderPrograms.begin(); iter != p_shaderPrograms.end(); ++iter)
|
||||
if (*iter == program)
|
||||
{
|
||||
delete program;
|
||||
program = nullptr;
|
||||
p_shaderPrograms.remove(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Textures
|
||||
@ -144,9 +199,13 @@ void Device::destroyShaderProgram(ShaderProgram *&program, bool withShaders)
|
||||
void Device::destroyTexture(Texture *&texture)
|
||||
{
|
||||
for (auto iter = p_textures.begin(); iter != p_textures.end(); ++iter)
|
||||
if (&*iter == &*texture)
|
||||
p_textures.erase(iter);
|
||||
if (*iter == texture)
|
||||
{
|
||||
delete texture;
|
||||
texture = nullptr;
|
||||
p_textures.remove(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include "shader.hpp"
|
||||
#include "shader_program.hpp"
|
||||
#include "texture.hpp"
|
||||
#include "render_target.hpp"
|
||||
|
||||
#include "../hyplib/array/array.hpp"
|
||||
|
||||
@ -27,13 +28,14 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
darray<Buffer> p_buffers;
|
||||
darray<Shader> p_shaders;
|
||||
darray<ShaderProgram> p_shaderPrograms;
|
||||
darray<Texture> p_textures;
|
||||
darray<Buffer*> p_buffers;
|
||||
darray<Shader*> p_shaders;
|
||||
darray<ShaderProgram*> p_shaderPrograms;
|
||||
darray<Texture*> p_textures;
|
||||
|
||||
Buffer* p_currentVertexBuffer;
|
||||
Buffer* p_currentIndexBuffer;
|
||||
Buffer* p_currentUniformBuffer;
|
||||
ShaderProgram* p_currentShaderProgram;
|
||||
|
||||
protected:
|
||||
@ -42,55 +44,87 @@ protected:
|
||||
|
||||
Device();
|
||||
|
||||
explicit
|
||||
Device(DeviceAPI api);
|
||||
|
||||
virtual ~Device();
|
||||
~Device() override;
|
||||
|
||||
public:
|
||||
|
||||
// Global functions
|
||||
|
||||
static void create(Device** device, DeviceAPI api);
|
||||
static
|
||||
void create(Device** device, DeviceAPI api);
|
||||
|
||||
// Member functions
|
||||
|
||||
// Setup
|
||||
|
||||
virtual bool initialize() = 0;
|
||||
virtual bool destroy() = 0;
|
||||
virtual
|
||||
bool initialize() = 0;
|
||||
virtual
|
||||
bool destroy() = 0;
|
||||
|
||||
// State
|
||||
|
||||
virtual void faceCulling(bool enableFaceCulling, CullMode faceCullingMode = CullMode::None) = 0;
|
||||
virtual
|
||||
void faceCulling(bool enableFaceCulling, CullMode faceCullingMode) = 0;
|
||||
|
||||
// Buffers
|
||||
|
||||
virtual void createVertexBuffer(Buffer **buffer, int size, char* data) = 0;
|
||||
virtual void createIndexBuffer(Buffer **buffer, int size, char* data) = 0;
|
||||
virtual void useVertexBuffer(Buffer* buffer, int stride, int offset);
|
||||
virtual void useIndexBuffer(Buffer* buffer, int offset);
|
||||
virtual void destroyBuffer(Buffer*& buffer);
|
||||
virtual
|
||||
void createVertexBuffer(Buffer **buffer, int size, char* data) = 0;
|
||||
virtual
|
||||
void createIndexBuffer(Buffer **buffer, int size, char* data) = 0;
|
||||
virtual
|
||||
void createUniformBuffer(Buffer **buffer, int size, char* data) = 0;
|
||||
virtual
|
||||
void useVertexBuffer(Buffer* buffer, int stride, int offset);
|
||||
virtual
|
||||
void useIndexBuffer(Buffer* buffer, int offset);
|
||||
virtual
|
||||
void useUniformBuffer(Buffer* buffer, int slot);
|
||||
virtual
|
||||
void editBuffer(Buffer* buffer, char* data, int size, int offset) = 0;
|
||||
virtual
|
||||
void editBuffer(Buffer* buffer, char* data) = 0;
|
||||
virtual
|
||||
void destroyBuffer(Buffer*& buffer);
|
||||
Buffer* activeBuffer(Buffer::BufferType type);
|
||||
|
||||
|
||||
// Shaders
|
||||
|
||||
virtual void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual void destroyShader(Shader*& shader);
|
||||
virtual
|
||||
void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual
|
||||
void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual
|
||||
void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) = 0;
|
||||
virtual
|
||||
void destroyShader(Shader* shader);
|
||||
|
||||
// Shader programs
|
||||
|
||||
virtual void createShaderProgram(ShaderProgram** program) = 0;
|
||||
virtual void attachShader(ShaderProgram* program, Shader* shader);
|
||||
virtual void linkProgram(ShaderProgram* program);
|
||||
virtual void useShaderProgram(ShaderProgram* program);
|
||||
virtual void destroyShaderProgram(ShaderProgram*& program, bool withShaders = false);
|
||||
virtual
|
||||
void createShaderProgram(ShaderProgram** program) = 0;
|
||||
virtual
|
||||
void attachShader(ShaderProgram* program, Shader* shader);
|
||||
virtual
|
||||
void linkProgram(ShaderProgram* program);
|
||||
virtual
|
||||
void useShaderProgram(ShaderProgram* program);
|
||||
virtual
|
||||
void destroyShaderProgram(ShaderProgram*& program, bool withShaders);
|
||||
|
||||
// Textures
|
||||
|
||||
virtual void createTexture(Texture** texture, const std::string& filename) = 0;
|
||||
virtual void useTexture(Texture* texture, int slot) = 0;
|
||||
virtual void destroyTexture(Texture*& texture);
|
||||
virtual
|
||||
void createTexture(Texture** texture, const std::string& filename) = 0;
|
||||
virtual
|
||||
void useTexture(Texture* texture, int slot) = 0;
|
||||
virtual
|
||||
void destroyTexture(Texture*& texture);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ Buffer::Buffer() :
|
||||
p_vertexArrayIndex {0}
|
||||
{}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{}
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
int Buffer::target() const
|
||||
{
|
||||
|
@ -4,12 +4,17 @@
|
||||
#include "shader.hpp"
|
||||
#include "shader_program.hpp"
|
||||
#include "texture.hpp"
|
||||
#include "render_target.hpp"
|
||||
|
||||
#include "io/io.hpp"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
|
||||
namespace hpr::gpu::opengl
|
||||
{
|
||||
@ -19,8 +24,7 @@ Device::Device() :
|
||||
p_isInitialized {false}
|
||||
{}
|
||||
|
||||
Device::~Device()
|
||||
{}
|
||||
Device::~Device() = default;
|
||||
|
||||
// Setup
|
||||
|
||||
@ -34,6 +38,11 @@ bool Device::destroy()
|
||||
return p_isInitialized = false;
|
||||
}
|
||||
|
||||
bool Device::loadLoader()
|
||||
{
|
||||
return !gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
||||
}
|
||||
|
||||
// State
|
||||
|
||||
void Device::faceCulling(bool enableFaceCulling, CullMode faceCullingMode)
|
||||
@ -60,14 +69,19 @@ void Device::faceCulling(bool enableFaceCulling, CullMode faceCullingMode)
|
||||
}
|
||||
}
|
||||
|
||||
// Render targets
|
||||
|
||||
// Buffers
|
||||
|
||||
|
||||
void Device::createVertexBuffer(gpu::Buffer **buffer, int size, char *data)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*buffer = nullptr;
|
||||
p_buffers.emplace_back(opengl::Buffer());
|
||||
opengl::Buffer* newBuffer = dynamic_cast<opengl::Buffer*>(&p_buffers.back());
|
||||
p_buffers.push(new opengl::Buffer());
|
||||
auto* newBuffer = dynamic_cast<opengl::Buffer*>(p_buffers.back());
|
||||
|
||||
newBuffer->p_type = Buffer::BufferType::Vertex;
|
||||
newBuffer->p_size = size;
|
||||
@ -88,10 +102,10 @@ void Device::createIndexBuffer(gpu::Buffer **buffer, int size, char *data)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*buffer = nullptr;
|
||||
p_buffers.emplace_back(opengl::Buffer());
|
||||
opengl::Buffer* newBuffer = dynamic_cast<opengl::Buffer*>(&p_buffers.back());
|
||||
p_buffers.push(new opengl::Buffer());
|
||||
auto* newBuffer = dynamic_cast<opengl::Buffer*>(p_buffers.back());
|
||||
|
||||
newBuffer->p_type = Buffer::BufferType::Vertex;
|
||||
newBuffer->p_type = Buffer::BufferType::Index;
|
||||
newBuffer->p_size = size;
|
||||
|
||||
glGenVertexArrays(1, &newBuffer->p_vertexArrayIndex);
|
||||
@ -104,6 +118,25 @@ void Device::createIndexBuffer(gpu::Buffer **buffer, int size, char *data)
|
||||
*buffer = static_cast<gpu::Buffer*>(newBuffer);
|
||||
}
|
||||
|
||||
void Device::createUniformBuffer(gpu::Buffer** buffer, int size, char* data)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*buffer = nullptr;
|
||||
p_buffers.push(new opengl::Buffer());
|
||||
auto* newBuffer = dynamic_cast<opengl::Buffer*>(p_buffers.back());
|
||||
|
||||
newBuffer->p_type = Buffer::BufferType::Uniform;
|
||||
newBuffer->p_size = size;
|
||||
|
||||
glGenBuffers(1, &newBuffer->p_bufferIndex);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, newBuffer->p_bufferIndex);
|
||||
glBufferData(GL_UNIFORM_BUFFER, size, (void*)data, GL_DYNAMIC_DRAW);
|
||||
|
||||
*buffer = static_cast<gpu::Buffer*>(newBuffer);
|
||||
}
|
||||
|
||||
void Device::useVertexBuffer(gpu::Buffer *buffer, int stride, int offset)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
@ -113,14 +146,14 @@ void Device::useVertexBuffer(gpu::Buffer *buffer, int stride, int offset)
|
||||
}
|
||||
else
|
||||
{
|
||||
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
auto* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
|
||||
if (curBuffer->p_type == Buffer::BufferType::Vertex && p_currentVertexBuffer != buffer)
|
||||
{
|
||||
glBindVertexArray(curBuffer->p_vertexArrayIndex);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, curBuffer->p_bufferIndex);
|
||||
|
||||
opengl::Buffer* curIndexBuffer = dynamic_cast<opengl::Buffer*>(p_currentIndexBuffer);
|
||||
auto* curIndexBuffer = dynamic_cast<opengl::Buffer*>(p_currentIndexBuffer);
|
||||
|
||||
if (curIndexBuffer != nullptr)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, curIndexBuffer->p_bufferIndex);
|
||||
@ -138,7 +171,7 @@ void Device::useIndexBuffer(gpu::Buffer *buffer, int offset)
|
||||
}
|
||||
else
|
||||
{
|
||||
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
auto* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
|
||||
if (curBuffer->p_type == Buffer::BufferType::Index && p_currentVertexBuffer != buffer)
|
||||
{
|
||||
@ -149,12 +182,51 @@ void Device::useIndexBuffer(gpu::Buffer *buffer, int offset)
|
||||
gpu::Device::useIndexBuffer(buffer, offset);
|
||||
}
|
||||
|
||||
void Device::useUniformBuffer(gpu::Buffer* buffer, int slot)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, slot, curBuffer->p_bufferIndex, 0, buffer->size());
|
||||
}
|
||||
gpu::Device::useUniformBuffer(buffer, slot);
|
||||
}
|
||||
|
||||
void Device::editBuffer(gpu::Buffer* buffer, char* data, int size, int offset)
|
||||
{
|
||||
if (!checkCompability(buffer))
|
||||
throw std::runtime_error("Incompatible platform");
|
||||
if (buffer == nullptr || data == nullptr)
|
||||
throw std::invalid_argument("Invalid argument");
|
||||
if (size + offset > buffer->size() || size < 0 || offset < 0)
|
||||
throw std::out_of_range("Out of bounds");
|
||||
|
||||
auto* prevBuffer = dynamic_cast<opengl::Buffer*>(activeBuffer(buffer->type()));
|
||||
|
||||
auto* buffer_ = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
glBindBuffer(buffer_->target(), buffer_->p_bufferIndex);
|
||||
glBufferSubData(buffer_->target(), offset, size, data);
|
||||
|
||||
if (prevBuffer != buffer_)
|
||||
glBindBuffer(buffer_->target(), prevBuffer ? prevBuffer->p_bufferIndex : 0);
|
||||
|
||||
}
|
||||
|
||||
void Device::editBuffer(gpu::Buffer* buffer, char* data)
|
||||
{
|
||||
editBuffer(buffer, data, buffer->size(), 0);
|
||||
}
|
||||
|
||||
void Device::destroyBuffer(gpu::Buffer *&buffer)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
opengl::Buffer* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
auto* curBuffer = dynamic_cast<opengl::Buffer*>(buffer);
|
||||
glDeleteBuffers(1, &curBuffer->p_bufferIndex);
|
||||
|
||||
if (curBuffer->p_type == Buffer::BufferType::Vertex)
|
||||
@ -195,8 +267,8 @@ void Device::createVertexShader(gpu::Shader **shader, const std::string &filenam
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
p_shaders.emplace_back(opengl::Shader());
|
||||
opengl::Shader* newShader = dynamic_cast<opengl::Shader*>(&p_shaders.back());
|
||||
p_shaders.push(new opengl::Shader());
|
||||
auto* newShader = dynamic_cast<opengl::Shader*>(p_shaders.back());
|
||||
newShader->p_type = Shader::ShaderType::Vertex;
|
||||
newShader->p_filename = filename;
|
||||
newShader->p_shaderIndex = shaderIndex;
|
||||
@ -205,4 +277,251 @@ void Device::createVertexShader(gpu::Shader **shader, const std::string &filenam
|
||||
*shader = static_cast<Shader*>(newShader);
|
||||
}
|
||||
|
||||
|
||||
void Device::createFragmentShader(gpu::Shader **shader, const std::string &filename, const std::string &label)
|
||||
{
|
||||
if (shader == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*shader = nullptr;
|
||||
|
||||
unsigned int shaderIndex = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
if (shaderIndex == 0)
|
||||
throw std::runtime_error("Could not create shader");
|
||||
|
||||
File file;
|
||||
file.open(filename, File::Binary | File::Read);
|
||||
std::string content = file.read().str();
|
||||
const char* shaderSource = content.c_str();
|
||||
|
||||
glShaderSource(shaderIndex, 1, &shaderSource, nullptr);
|
||||
GLenum result = glGetError();
|
||||
glCompileShader(shaderIndex);
|
||||
|
||||
int shaderStatus;
|
||||
glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus);
|
||||
if (!shaderStatus)
|
||||
{
|
||||
char error[2048 + 1];
|
||||
glGetShaderInfoLog(shaderIndex, 2048, nullptr, error);
|
||||
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
p_shaders.push(new opengl::Shader());
|
||||
auto* newShader = dynamic_cast<opengl::Shader*>(p_shaders.back());
|
||||
newShader->p_type = Shader::ShaderType::Fragment;
|
||||
newShader->p_filename = filename;
|
||||
newShader->p_shaderIndex = shaderIndex;
|
||||
newShader->p_label = "FragmentShader";
|
||||
|
||||
*shader = static_cast<Shader*>(newShader);
|
||||
}
|
||||
|
||||
|
||||
void Device::createGeometryShader(gpu::Shader **shader, const std::string &filename, const std::string &label)
|
||||
{
|
||||
if (shader == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*shader = nullptr;
|
||||
|
||||
unsigned int shaderIndex = glCreateShader(GL_GEOMETRY_SHADER);
|
||||
if (shaderIndex == 0)
|
||||
throw std::runtime_error("Could not create shader");
|
||||
|
||||
File file;
|
||||
file.open(filename, File::Binary | File::Read);
|
||||
std::string content = file.read().str();
|
||||
const char* shaderSource = content.c_str();
|
||||
|
||||
glShaderSource(shaderIndex, 1, &shaderSource, nullptr);
|
||||
GLenum result = glGetError();
|
||||
glCompileShader(shaderIndex);
|
||||
|
||||
int shaderStatus;
|
||||
glGetShaderiv(shaderIndex, GL_COMPILE_STATUS, &shaderStatus);
|
||||
if (!shaderStatus)
|
||||
{
|
||||
char error[2048 + 1];
|
||||
glGetShaderInfoLog(shaderIndex, 2048, nullptr, error);
|
||||
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
p_shaders.push(new opengl::Shader());
|
||||
auto* newShader = dynamic_cast<opengl::Shader*>(p_shaders.back());
|
||||
newShader->p_type = Shader::ShaderType::Geometry;
|
||||
newShader->p_filename = filename;
|
||||
newShader->p_shaderIndex = shaderIndex;
|
||||
newShader->p_label = "FragmentShader";
|
||||
|
||||
*shader = static_cast<gpu::Shader*>(newShader);
|
||||
}
|
||||
|
||||
void Device::destroyShader(gpu::Shader* shader)
|
||||
{
|
||||
if (shader == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
auto* shader_ = dynamic_cast<opengl::Shader*>(shader);
|
||||
glDeleteShader(shader_->p_shaderIndex);
|
||||
|
||||
gpu::Device::destroyShader(shader);
|
||||
}
|
||||
|
||||
void Device::createShaderProgram(gpu::ShaderProgram** program)
|
||||
{
|
||||
if (program == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*program = nullptr;
|
||||
|
||||
p_shaderPrograms.push(new opengl::ShaderProgram());
|
||||
auto* newProgram = dynamic_cast<opengl::ShaderProgram*>(p_shaderPrograms.back());
|
||||
newProgram->p_shaderProgramIndex = glCreateProgram();
|
||||
|
||||
*program = static_cast<gpu::ShaderProgram*>(newProgram);
|
||||
}
|
||||
|
||||
void Device::attachShader(gpu::ShaderProgram* program, gpu::Shader* shader)
|
||||
{
|
||||
gpu::Device::attachShader(program, shader);
|
||||
auto* program_ = dynamic_cast<opengl::ShaderProgram*>(program);
|
||||
auto* shader_ = dynamic_cast<opengl::Shader*>(shader);
|
||||
glAttachShader(program_->p_shaderProgramIndex, shader_->p_shaderIndex);
|
||||
}
|
||||
|
||||
|
||||
void Device::linkProgram(gpu::ShaderProgram* program)
|
||||
{
|
||||
gpu::Device::linkProgram(program);
|
||||
auto* program_ = dynamic_cast<opengl::ShaderProgram*>(program);
|
||||
glLinkProgram(program_->p_shaderProgramIndex);
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program_->p_shaderProgramIndex, GL_LINK_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
throw std::runtime_error("Shader program link error");
|
||||
}
|
||||
|
||||
void Device::useShaderProgram(gpu::ShaderProgram* program)
|
||||
{
|
||||
gpu::ShaderProgram* currentProgram = p_currentShaderProgram;
|
||||
gpu::Device::useShaderProgram(program);
|
||||
|
||||
if (currentProgram == program)
|
||||
return;
|
||||
if (program == nullptr)
|
||||
glUseProgram(0);
|
||||
else
|
||||
{
|
||||
auto* program_ = dynamic_cast<opengl::ShaderProgram*>(program);
|
||||
glUseProgram(program_->p_shaderProgramIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::destroyShaderProgram(gpu::ShaderProgram*& program, bool withShaders)
|
||||
{
|
||||
if (program == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
auto* program_ = dynamic_cast<opengl::ShaderProgram*>(program);
|
||||
|
||||
for (int n = 0; n < static_cast<int>(Shader::ShaderType::ShaderTypeCount); ++n)
|
||||
{
|
||||
auto* shader = dynamic_cast<opengl::Shader*>(program_->p_slots[n]);
|
||||
if (shader != nullptr)
|
||||
glDetachShader(program_->p_shaderProgramIndex, shader->p_shaderIndex);
|
||||
}
|
||||
glDeleteProgram(program_->p_shaderProgramIndex);
|
||||
gpu::Device::destroyShaderProgram(program, withShaders);
|
||||
}
|
||||
|
||||
void Device::createTexture(gpu::Texture** texture, const std::string& filename)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
if (filename.empty())
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
*texture = nullptr;
|
||||
bool alphaChannel = true;
|
||||
int internalFormat = GL_RGBA;
|
||||
int imageFormat = GL_RGBA;
|
||||
int width;
|
||||
int height;
|
||||
int channelsCount;
|
||||
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
unsigned char* source = stbi_load(filename.c_str(), &width, &height, &channelsCount, 0);
|
||||
|
||||
if (!source)
|
||||
throw std::runtime_error("Failed to load texture source");
|
||||
else
|
||||
{
|
||||
p_textures.push(new opengl::Texture());
|
||||
auto* texture_ = dynamic_cast<opengl::Texture*>(p_textures.back());
|
||||
texture_->p_filename = filename;
|
||||
texture_->p_width = width;
|
||||
texture_->p_height = height;
|
||||
|
||||
glGenTextures(1, &texture_->p_textureIndex);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_->p_textureIndex);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
if (alphaChannel)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
else
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, imageFormat, GL_UNSIGNED_BYTE, source);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
*texture = static_cast<gpu::Texture*>(texture_);
|
||||
}
|
||||
|
||||
stbi_image_free(source);
|
||||
}
|
||||
|
||||
void Device::useTexture(gpu::Texture* texture, int slot)
|
||||
{
|
||||
//gpu::Device::useTexture(texture, slot);
|
||||
|
||||
if (texture == nullptr)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* texture_ = dynamic_cast<opengl::Texture*>(texture);
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_->p_textureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::destroyTexture(gpu::Texture*& texture)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
throw std::invalid_argument("Invalid parameter");
|
||||
|
||||
auto* texture_ = dynamic_cast<opengl::Texture*>(texture);
|
||||
|
||||
glDeleteTextures(1, &texture_->p_textureIndex);
|
||||
gpu::Device::destroyTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
void Device::Draw(int numFaces, int indexOffset, int vertexOffset)
|
||||
{
|
||||
if (p_currentVertexBuffer != nullptr)
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, numFaces * 3, GL_UNSIGNED_SHORT, (void*)(indexOffset * 2), vertexOffset);
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "../device.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace hpr::gpu::opengl
|
||||
{
|
||||
@ -29,16 +31,28 @@ public:
|
||||
bool initialize() override;
|
||||
bool destroy() override;
|
||||
|
||||
static
|
||||
bool loadLoader();
|
||||
|
||||
// State
|
||||
|
||||
void faceCulling(bool enableFaceCulling, CullMode faceCullingMode = CullMode::None) override;
|
||||
void faceCulling(bool enableFaceCulling, CullMode faceCullingMode) override;
|
||||
|
||||
// Render targets
|
||||
|
||||
virtual
|
||||
void createScreenRenderTarget(RenderTarget** target);
|
||||
|
||||
// Buffers
|
||||
|
||||
void createVertexBuffer(Buffer **buffer, int size, char* data) override;
|
||||
void createIndexBuffer(Buffer **buffer, int size, char* data) override;
|
||||
void createUniformBuffer(Buffer **buffer, int size, char* data) override;
|
||||
void useVertexBuffer(Buffer* buffer, int stride, int offset) override;
|
||||
void useIndexBuffer(Buffer* buffer, int offset) override;
|
||||
void useUniformBuffer(Buffer* buffer, int slot) override;
|
||||
void editBuffer(Buffer* buffer, char* data, int size, int offset) override;
|
||||
void editBuffer(Buffer* buffer, char* data) override;
|
||||
void destroyBuffer(Buffer*& buffer) override;
|
||||
|
||||
// Shaders
|
||||
@ -46,21 +60,25 @@ public:
|
||||
void createVertexShader(Shader** shader, const std::string& filename, const std::string& label) override;
|
||||
void createFragmentShader(Shader** shader, const std::string& filename, const std::string& label) override;
|
||||
void createGeometryShader(Shader** shader, const std::string& filename, const std::string& label) override;
|
||||
void destroyShader(Shader*& shader) override;
|
||||
void destroyShader(Shader* shader) override;
|
||||
|
||||
// Shader programs
|
||||
|
||||
virtual void createShaderProgram(ShaderProgram** program);
|
||||
virtual void attachShader(ShaderProgram* program, Shader* shader);
|
||||
virtual void linkProgram(ShaderProgram* program);
|
||||
virtual void useShaderProgram(ShaderProgram* program);
|
||||
virtual void destroyShaderProgram(ShaderProgram*& program, bool withShaders = false);
|
||||
void createShaderProgram(ShaderProgram** program) override;
|
||||
void attachShader(ShaderProgram* program, Shader* shader) override;
|
||||
void linkProgram(ShaderProgram* program) override;
|
||||
void useShaderProgram(ShaderProgram* program) override;
|
||||
void destroyShaderProgram(ShaderProgram*& program, bool withShaders) override;
|
||||
|
||||
// Textures
|
||||
|
||||
virtual void createTexture(Texture** texture, const std::string& filename);
|
||||
virtual void useTexture(Texture* texture, int slot);
|
||||
virtual void destroyTexture(Texture*& texture);
|
||||
void createTexture(Texture** texture, const std::string& filename) override;
|
||||
void useTexture(Texture* texture, int slot) override;
|
||||
void destroyTexture(Texture*& texture) override;
|
||||
|
||||
//
|
||||
|
||||
void Draw(int numFaces, int indexOffset, int vertexOffset);
|
||||
};
|
||||
|
||||
}
|
15
source/hyporo/gpu/opengl/render_target.cpp
Normal file
15
source/hyporo/gpu/opengl/render_target.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "render_target.hpp"
|
||||
|
||||
|
||||
namespace hpr::gpu::opengl
|
||||
{
|
||||
|
||||
RenderTarget::RenderTarget() :
|
||||
gpu::RenderTarget {DeviceAPI::OpenGL}
|
||||
{}
|
||||
|
||||
RenderTarget::~RenderTarget() = default;
|
||||
|
||||
}
|
42
source/hyporo/gpu/opengl/render_target.hpp
Normal file
42
source/hyporo/gpu/opengl/render_target.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "../render_target.hpp"
|
||||
|
||||
|
||||
namespace hpr::gpu::opengl
|
||||
{
|
||||
|
||||
class RenderTarget : public gpu::RenderTarget
|
||||
{
|
||||
friend class Device;
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int p_frameBufferIndex;
|
||||
unsigned int p_depthBufferIndex;
|
||||
unsigned int p_textureIndex;
|
||||
|
||||
public:
|
||||
|
||||
RenderTarget();
|
||||
|
||||
~RenderTarget() override;
|
||||
|
||||
unsigned int frameBuffer() const
|
||||
{
|
||||
return p_frameBufferIndex;
|
||||
}
|
||||
|
||||
unsigned int depthBuffer() const
|
||||
{
|
||||
return p_depthBufferIndex;
|
||||
}
|
||||
|
||||
unsigned int texture() const
|
||||
{
|
||||
return p_textureIndex;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -13,7 +13,6 @@ Shader::Shader() :
|
||||
p_shaderIndex {0}
|
||||
{}
|
||||
|
||||
Shader::~Shader()
|
||||
{}
|
||||
Shader::~Shader() = default;
|
||||
|
||||
}
|
@ -19,7 +19,7 @@ public:
|
||||
|
||||
Shader();
|
||||
|
||||
virtual ~Shader();
|
||||
~Shader() override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,6 @@ Texture::Texture() :
|
||||
p_textureIndex {0}
|
||||
{}
|
||||
|
||||
Texture::~Texture()
|
||||
{}
|
||||
Texture::~Texture() = default;
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ public:
|
||||
|
||||
Texture();
|
||||
|
||||
~Texture();
|
||||
~Texture() override;
|
||||
|
||||
};
|
||||
|
||||
|
35
source/hyporo/gpu/render_target.cpp
Normal file
35
source/hyporo/gpu/render_target.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "render_target.hpp"
|
||||
|
||||
|
||||
namespace hpr::gpu
|
||||
{
|
||||
|
||||
RenderTarget::RenderTarget() :
|
||||
Context {DeviceAPI::Unknown},
|
||||
p_posX {},
|
||||
p_posY {},
|
||||
p_width {},
|
||||
p_height {},
|
||||
p_type {Type::Unknown},
|
||||
p_hasColorData {true},
|
||||
p_hasDepthBuffer {false},
|
||||
p_depthTestEnabled {false},
|
||||
p_parent {nullptr}
|
||||
{}
|
||||
|
||||
RenderTarget::RenderTarget(DeviceAPI api) :
|
||||
Context {api},
|
||||
p_posX {},
|
||||
p_posY {},
|
||||
p_width {},
|
||||
p_height {},
|
||||
p_type {Type::Unknown},
|
||||
p_hasColorData {true},
|
||||
p_hasDepthBuffer {false},
|
||||
p_depthTestEnabled {false},
|
||||
p_parent {nullptr}
|
||||
{}
|
||||
|
||||
RenderTarget::~RenderTarget() = default;
|
||||
|
||||
}
|
98
source/hyporo/gpu/render_target.hpp
Normal file
98
source/hyporo/gpu/render_target.hpp
Normal file
@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
|
||||
namespace hpr::gpu
|
||||
{
|
||||
|
||||
class RenderTarget : public Context
|
||||
{
|
||||
friend class Device;
|
||||
|
||||
public:
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Unknown,
|
||||
Screen,
|
||||
Framebuffer
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
int p_posX;
|
||||
int p_posY;
|
||||
int p_width;
|
||||
int p_height;
|
||||
|
||||
Type p_type;
|
||||
|
||||
bool p_hasColorData;
|
||||
bool p_hasDepthBuffer;
|
||||
bool p_depthTestEnabled;
|
||||
|
||||
RenderTarget* p_parent;
|
||||
|
||||
public:
|
||||
|
||||
RenderTarget();
|
||||
|
||||
RenderTarget(DeviceAPI api);
|
||||
|
||||
virtual
|
||||
~RenderTarget();
|
||||
|
||||
int posX() const
|
||||
{
|
||||
return p_posX;
|
||||
}
|
||||
|
||||
int posY() const
|
||||
{
|
||||
return p_posY;
|
||||
}
|
||||
|
||||
int width() const
|
||||
{
|
||||
return p_width;
|
||||
}
|
||||
|
||||
int height() const
|
||||
{
|
||||
return p_height;
|
||||
}
|
||||
|
||||
Type type() const
|
||||
{
|
||||
return p_type;
|
||||
}
|
||||
|
||||
bool hasColorData() const
|
||||
{
|
||||
return p_hasColorData;
|
||||
}
|
||||
|
||||
bool hasDepthBuffer() const
|
||||
{
|
||||
return p_hasDepthBuffer;
|
||||
}
|
||||
|
||||
bool isDepthTestEnabled() const
|
||||
{
|
||||
return p_depthTestEnabled;
|
||||
}
|
||||
|
||||
void depthTest(bool enable)
|
||||
{
|
||||
p_depthTestEnabled = enable;
|
||||
}
|
||||
|
||||
RenderTarget* parent()
|
||||
{
|
||||
return p_parent;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -7,32 +7,31 @@ namespace hpr::gpu
|
||||
|
||||
Shader::Shader() :
|
||||
Context {DeviceAPI::Unknown},
|
||||
p_filename {"\0"},
|
||||
p_label {"\0"},
|
||||
p_filename {},
|
||||
p_label {},
|
||||
p_type {ShaderType::Vertex}
|
||||
{}
|
||||
|
||||
Shader::Shader(DeviceAPI api) :
|
||||
Context {api},
|
||||
p_filename {"\0"},
|
||||
p_label {"\0"},
|
||||
p_filename {},
|
||||
p_label {},
|
||||
p_type {ShaderType::Vertex}
|
||||
{}
|
||||
|
||||
Shader::~Shader()
|
||||
{}
|
||||
Shader::~Shader() = default;
|
||||
|
||||
const std::string Shader::filename() const
|
||||
std::string Shader::filename() const
|
||||
{
|
||||
return p_filename;
|
||||
}
|
||||
|
||||
const std::string Shader::label() const
|
||||
std::string Shader::label() const
|
||||
{
|
||||
return p_label;
|
||||
}
|
||||
|
||||
const Shader::ShaderType Shader::type() const
|
||||
Shader::ShaderType Shader::type() const
|
||||
{
|
||||
return p_type;
|
||||
}
|
||||
|
@ -34,17 +34,21 @@ public:
|
||||
|
||||
Shader();
|
||||
|
||||
explicit
|
||||
Shader(DeviceAPI api);
|
||||
|
||||
virtual ~Shader();
|
||||
~Shader() override;
|
||||
|
||||
// Member functions
|
||||
|
||||
const std::string filename() const;
|
||||
[[nodiscard]]
|
||||
std::string filename() const;
|
||||
|
||||
const std::string label() const;
|
||||
[[nodiscard]]
|
||||
std::string label() const;
|
||||
|
||||
const ShaderType type() const;
|
||||
[[nodiscard]]
|
||||
ShaderType type() const;
|
||||
};
|
||||
|
||||
} // end namespace hpr::gpu
|
@ -15,7 +15,6 @@ ShaderProgram::ShaderProgram(DeviceAPI api) :
|
||||
p_isLinked {false}
|
||||
{}
|
||||
|
||||
ShaderProgram::~ShaderProgram()
|
||||
{}
|
||||
ShaderProgram::~ShaderProgram() = default;
|
||||
|
||||
}
|
@ -24,9 +24,10 @@ public:
|
||||
|
||||
ShaderProgram();
|
||||
|
||||
explicit
|
||||
ShaderProgram(DeviceAPI api);
|
||||
|
||||
virtual ~ShaderProgram();
|
||||
~ShaderProgram() override;
|
||||
|
||||
// Member functions
|
||||
|
||||
|
204
source/hyporo/gpu/shaders/base.frag.glsl
Normal file
204
source/hyporo/gpu/shaders/base.frag.glsl
Normal file
@ -0,0 +1,204 @@
|
||||
#version 420
|
||||
|
||||
layout(binding = 0) uniform sampler2D diffuseTex;
|
||||
|
||||
out vec4 out_Color;
|
||||
|
||||
in vec4 ex_Pos;
|
||||
in vec2 ex_Tex;
|
||||
in vec3 ex_Normal;
|
||||
|
||||
layout (binding = 0) uniform ScreenVariables {
|
||||
mat4 CameraView;
|
||||
mat4 Projection;
|
||||
vec4 CameraEye;
|
||||
|
||||
vec4 FogColor;
|
||||
float FogNear;
|
||||
float FogFar;
|
||||
};
|
||||
|
||||
layout (binding = 1) uniform ObjectVariables {
|
||||
mat4 Transform;
|
||||
vec2 TexOffset;
|
||||
vec2 TexScale;
|
||||
vec4 Scale;
|
||||
|
||||
vec4 BaseColor;
|
||||
vec4 Emission;
|
||||
float SpecularMix;
|
||||
float DiffuseMix;
|
||||
float Metallic;
|
||||
float DiffuseRoughness;
|
||||
float SpecularPower;
|
||||
float IncidentSpecular;
|
||||
|
||||
int ColorReplace;
|
||||
int Lit;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
vec4 Position;
|
||||
vec4 Color;
|
||||
vec4 Direction;
|
||||
float Attenuation0;
|
||||
float Attenuation1;
|
||||
int FalloffEnabled;
|
||||
int Active;
|
||||
};
|
||||
|
||||
layout (binding = 3) uniform Lighting {
|
||||
Light Lights[32];
|
||||
vec4 AmbientLighting;
|
||||
};
|
||||
|
||||
float pow5(float v) {
|
||||
return (v * v) * (v * v) * v;
|
||||
}
|
||||
|
||||
float f_diffuse(vec3 i, vec3 o, vec3 h, vec3 normal, float power, float roughness) {
|
||||
float h_dot_i = dot(h, i);
|
||||
float h_dot_i_2 = h_dot_i * h_dot_i;
|
||||
float f_d90 = 0.5 + 2 * h_dot_i_2 * roughness;
|
||||
|
||||
float cos_theta_i = dot(i, normal);
|
||||
float cos_theta_o = dot(o, normal);
|
||||
|
||||
float f_d = (1 + (f_d90 - 1) * pow5(1 - cos_theta_i)) * (1 + (f_d90 - 1) * pow5(1 - cos_theta_o));
|
||||
return clamp(f_d * power * cos_theta_i, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float f_specular(vec3 i, vec3 o, vec3 h, vec3 normal, float F0, float power, float specularPower) {
|
||||
vec3 reflected = -reflect(i, normal);
|
||||
float intensity = dot(reflected, o);
|
||||
|
||||
if (intensity < 0) return 0;
|
||||
|
||||
// Fresnel approximation
|
||||
float F0_scaled = 0.08 * F0;
|
||||
float o_dot_h = dot(o, h);
|
||||
float s = pow5(1 - o_dot_h);
|
||||
float F = F0_scaled + s * (1 - F0_scaled);
|
||||
|
||||
return clamp(pow(intensity, specularPower) * F * power, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float f_specular_ambient(vec3 o, vec3 normal, float F0, float power) {
|
||||
// Fresnel approximation
|
||||
float F0_scaled = 0.08 * F0;
|
||||
float o_dot_n = dot(o, normal);
|
||||
float s = pow5(1 - o_dot_n);
|
||||
float F = F0_scaled + s * (1 - F0_scaled);
|
||||
|
||||
return clamp(F * power, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float linearToSrgb(float u) {
|
||||
const float MinSrgbPower = 0.0031308;
|
||||
|
||||
if (u < MinSrgbPower) {
|
||||
return 12.92 * u;
|
||||
}
|
||||
else {
|
||||
return 1.055 * pow(u, 1 / 2.4) - 0.055;
|
||||
}
|
||||
}
|
||||
|
||||
float srgbToLinear(float u) {
|
||||
const float MinSrgbPower = 0.04045;
|
||||
|
||||
if (u < MinSrgbPower) {
|
||||
return u / 12.92;
|
||||
}
|
||||
else {
|
||||
return pow((u + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 linearToSrgb(vec3 v) {
|
||||
return vec3(linearToSrgb(v.r), linearToSrgb(v.g), linearToSrgb(v.b));
|
||||
}
|
||||
|
||||
vec3 srgbToLinear(vec3 v) {
|
||||
return vec3(srgbToLinear(v.r), srgbToLinear(v.g), srgbToLinear(v.b));
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
const float FullSpecular = 1 / 0.08;
|
||||
|
||||
vec3 totalLighting = vec3(1.0, 1.0, 1.0);
|
||||
vec3 normal = normalize(ex_Normal.xyz);
|
||||
|
||||
vec4 baseColor;
|
||||
float roughness = 0.5;
|
||||
float power = 1.0;
|
||||
|
||||
if (ColorReplace == 0) {
|
||||
vec4 diffuse = texture(diffuseTex, ex_Tex).rgba;
|
||||
baseColor = vec4(srgbToLinear(diffuse.rgb), diffuse.a) * BaseColor;
|
||||
}
|
||||
else {
|
||||
baseColor = BaseColor;
|
||||
}
|
||||
|
||||
totalLighting = baseColor.rgb;
|
||||
|
||||
if (Lit == 1) {
|
||||
vec3 o = normalize(CameraEye.xyz - ex_Pos.xyz);
|
||||
float cos_theta_o = dot(o, normal);
|
||||
|
||||
vec3 ambientSpecular = f_specular_ambient(o, normal, IncidentSpecular, SpecularMix) * AmbientLighting.rgb;
|
||||
vec3 ambientDiffuse = f_diffuse(o, o, o, normal, DiffuseMix, DiffuseRoughness) * AmbientLighting.rgb * baseColor.rgb;
|
||||
vec3 ambientMetallic = f_specular_ambient(o, normal, FullSpecular, 1.0) * AmbientLighting.rgb * baseColor.rgb;
|
||||
|
||||
totalLighting = mix(ambientSpecular + ambientDiffuse, ambientMetallic, Metallic);
|
||||
totalLighting += Emission.rgb;
|
||||
|
||||
for (int li = 0; li < 32; ++li) {
|
||||
if (Lights[li].Active == 0) continue;
|
||||
|
||||
vec3 i = Lights[li].Position.xyz - ex_Pos.xyz;
|
||||
float inv_dist = 1.0 / length(i);
|
||||
i *= inv_dist;
|
||||
|
||||
float cos_theta_i = dot(i, normal);
|
||||
|
||||
if (cos_theta_i < 0) continue;
|
||||
if (cos_theta_o < 0) continue;
|
||||
|
||||
vec3 h = normalize(i + o);
|
||||
vec3 diffuse = f_diffuse(i, o, h, normal, DiffuseMix, DiffuseRoughness) * baseColor.rgb * Lights[li].Color.rgb;
|
||||
vec3 specular = f_specular(i, o, h, normal, IncidentSpecular, SpecularMix, SpecularPower) * Lights[li].Color.rgb;
|
||||
vec3 metallic = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
if (Metallic > 0) {
|
||||
metallic = f_specular(i, o, h, normal, FullSpecular, 1, SpecularPower) * Lights[li].Color.rgb * baseColor.rgb;
|
||||
}
|
||||
|
||||
// Spotlight calculation
|
||||
float spotCoherence = -dot(i, Lights[li].Direction.xyz);
|
||||
float spotAttenuation = 1.0;
|
||||
if (spotCoherence > Lights[li].Attenuation0) spotAttenuation = 1.0;
|
||||
else if (spotCoherence < Lights[li].Attenuation1) spotAttenuation = 0.0;
|
||||
else {
|
||||
float t = Lights[li].Attenuation0 - Lights[li].Attenuation1;
|
||||
if (t == 0) spotAttenuation = 1.0;
|
||||
else spotAttenuation = (spotCoherence - Lights[li].Attenuation1) / t;
|
||||
}
|
||||
|
||||
float falloff = 1.0;
|
||||
if (Lights[li].FalloffEnabled == 1) {
|
||||
falloff = (inv_dist * inv_dist);
|
||||
}
|
||||
|
||||
vec3 bsdf = mix(diffuse + specular, metallic, Metallic);
|
||||
|
||||
totalLighting += falloff * bsdf * spotAttenuation * spotAttenuation * spotAttenuation;
|
||||
}
|
||||
}
|
||||
|
||||
const float distanceToCamera = length(CameraEye.xyz - ex_Pos.xyz);
|
||||
const float fogAttenuation = (clamp(distanceToCamera, FogNear, FogFar) - FogNear) / (FogFar - FogNear);
|
||||
|
||||
out_Color = vec4(linearToSrgb(mix(totalLighting.rgb, FogColor.rgb, fogAttenuation)), baseColor.a);
|
||||
}
|
57
source/hyporo/gpu/shaders/base.vert.glsl
Normal file
57
source/hyporo/gpu/shaders/base.vert.glsl
Normal file
@ -0,0 +1,57 @@
|
||||
#version 420
|
||||
|
||||
layout(location=0) in vec4 in_Position;
|
||||
layout(location=1) in vec2 in_Tex;
|
||||
layout(location=2) in vec4 in_Normal;
|
||||
|
||||
out vec4 ex_Pos;
|
||||
out vec2 ex_Tex;
|
||||
out vec3 ex_Normal;
|
||||
|
||||
layout (binding = 0) uniform ScreenVariables {
|
||||
mat4 CameraView;
|
||||
mat4 Projection;
|
||||
vec4 CameraEye;
|
||||
|
||||
vec4 FogColor;
|
||||
float FogNear;
|
||||
float FogFar;
|
||||
};
|
||||
|
||||
layout (binding = 1) uniform ObjectVariables {
|
||||
mat4 Transform;
|
||||
vec2 TexOffset;
|
||||
vec2 TexScale;
|
||||
vec4 Scale;
|
||||
|
||||
vec4 BaseColor;
|
||||
vec4 Emission;
|
||||
float SpecularMix;
|
||||
float DiffuseMix;
|
||||
float Metallic;
|
||||
float DiffuseRoughness;
|
||||
float SpecularPower;
|
||||
float IncidentSpecular;
|
||||
|
||||
int ColorReplace;
|
||||
int Lit;
|
||||
};
|
||||
|
||||
void main(void) {
|
||||
vec4 inputPos = vec4(in_Position.xyz, 1.0);
|
||||
|
||||
inputPos.xyz *= Scale.xyz;
|
||||
|
||||
inputPos = inputPos * Transform;
|
||||
ex_Pos = inputPos;
|
||||
|
||||
inputPos = inputPos * CameraView;
|
||||
inputPos = inputPos * Projection;
|
||||
|
||||
vec4 finalNormal = vec4(in_Normal.xyz, 0.0);
|
||||
ex_Normal = vec3(finalNormal * Transform);
|
||||
|
||||
gl_Position = vec4(inputPos.xyzw);
|
||||
|
||||
ex_Tex = in_Tex;
|
||||
}
|
@ -20,8 +20,7 @@ Texture::Texture(DeviceAPI api) :
|
||||
p_height {0}
|
||||
{}
|
||||
|
||||
Texture::~Texture()
|
||||
{}
|
||||
Texture::~Texture() = default;
|
||||
|
||||
std::string Texture::filename() const
|
||||
{
|
||||
|
@ -22,16 +22,20 @@ public:
|
||||
|
||||
Texture();
|
||||
|
||||
explicit
|
||||
Texture(DeviceAPI api);
|
||||
|
||||
virtual ~Texture();
|
||||
~Texture() override;
|
||||
|
||||
// Member functions
|
||||
|
||||
[[nodiscard]]
|
||||
std::string filename() const;
|
||||
|
||||
[[nodiscard]]
|
||||
int width() const;
|
||||
|
||||
[[nodiscard]]
|
||||
int height() const;
|
||||
};
|
||||
|
||||
|
@ -6,10 +6,11 @@ include_directories(
|
||||
../hyplib/vector
|
||||
)
|
||||
|
||||
add_library(hyporo-hmesh STATIC
|
||||
add_library(hyporo-mesh STATIC
|
||||
|
||||
# Header files
|
||||
mesh.hpp
|
||||
vertex.hpp
|
||||
|
||||
# Source files
|
||||
mesh.cpp
|
||||
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Face.hpp"
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
|
||||
} // end namespace hyporo
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vertex.hpp"
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
|
||||
} // end namespace hyporo
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Edge.hpp"
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
|
||||
} // end namespace hyporo
|
@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cell.hpp"
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
class Mesh
|
||||
{
|
||||
|
||||
mutable list<shared_ptr<Vertex>> vertices_;
|
||||
mutable list<shared_ptr<Edge>> edges_;
|
||||
mutable list<shared_ptr<Face>> faces_;
|
||||
mutable list<shared_ptr<Cell>> cells_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Desctuctor
|
||||
virtual ~Mesh();
|
||||
|
||||
// Mesh size parameters
|
||||
|
||||
inline sizet nPoints() const;
|
||||
inline sizet nEdges() const;
|
||||
inline sizet nFaces() const;
|
||||
inline sizet nCells() const;
|
||||
};
|
||||
|
||||
} // end namespace hyporo
|
@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "vector.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
template <class T>
|
||||
using list = std::vector<T>;
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
|
||||
// Forward declaration
|
||||
|
||||
class Edge;
|
||||
|
||||
class Mesh;
|
||||
|
||||
// Class declaration
|
||||
|
||||
class Vertex : public VectorSpace<scalar, 3>
|
||||
{
|
||||
|
||||
//- List of weak pointers to edges that use this vertex
|
||||
mutable list<weak_ptr<Edge>> edges_;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
inline Vertex(Mesh& mesh, const scalar& x, const scalar& y, const scalar& z);
|
||||
|
||||
// Member functions
|
||||
|
||||
inline const scalar& x() const;
|
||||
|
||||
inline const scalar& y() const;
|
||||
|
||||
inline const scalar& z() const;
|
||||
};
|
||||
|
||||
} // end namespace hyporo
|
||||
|
||||
#include "Vertex.hxx"
|
@ -1,27 +0,0 @@
|
||||
|
||||
namespace hyporo
|
||||
{
|
||||
|
||||
Vertex::Point(const scalar& x, const scalar& y, const scalar& z)
|
||||
{
|
||||
row[0] = x;
|
||||
row[1] = y;
|
||||
row[2] = z;
|
||||
}
|
||||
|
||||
const scalar& Vertex::x() const
|
||||
{
|
||||
return row[0];
|
||||
}
|
||||
|
||||
const scalar& Vertex::y() const;
|
||||
{
|
||||
return row[1];
|
||||
}
|
||||
|
||||
const scalar& Vertex::z() const;
|
||||
{
|
||||
return row[2];
|
||||
}
|
||||
|
||||
} // end namespace hyporo
|
38
source/hyporo/hmesh/cell.hpp
Normal file
38
source/hyporo/hmesh/cell.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "../hyplib/scalar/scalar.hpp"
|
||||
#include "../hyplib/array/array.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
|
||||
namespace hpr::mesh
|
||||
{
|
||||
|
||||
class Face;
|
||||
|
||||
class Cell : public darray<Face*>
|
||||
{
|
||||
|
||||
using face_pointer = Face*;
|
||||
using base = darray<face_pointer>;
|
||||
|
||||
public:
|
||||
|
||||
Cell() :
|
||||
base {}
|
||||
{}
|
||||
|
||||
Cell(std::initializer_list<face_pointer> faces) :
|
||||
base{faces}
|
||||
{}
|
||||
|
||||
~Cell() override = default;
|
||||
|
||||
darray<face_pointer>& faces()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
65
source/hyporo/hmesh/edge.hpp
Normal file
65
source/hyporo/hmesh/edge.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "../hyplib/scalar/scalar.hpp"
|
||||
#include "../hyplib/array/array.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
|
||||
namespace hpr::mesh
|
||||
{
|
||||
|
||||
class Vertex;
|
||||
class Face;
|
||||
|
||||
class Edge : public sarray<Vertex*, 2>
|
||||
{
|
||||
friend class Mesh;
|
||||
|
||||
using vertex_pointer = Vertex*;
|
||||
using base = sarray<vertex_pointer, 2>;
|
||||
|
||||
protected:
|
||||
darray<Face*> p_refFaces;
|
||||
|
||||
public:
|
||||
Edge() :
|
||||
base{}
|
||||
{}
|
||||
|
||||
Edge(vertex_pointer v1, vertex_pointer v2) :
|
||||
base{v1, v2}
|
||||
{}
|
||||
|
||||
~Edge() override
|
||||
{
|
||||
for (auto& f: p_refFaces)
|
||||
f = nullptr;
|
||||
}
|
||||
|
||||
darray<Face*>& refFaces()
|
||||
{
|
||||
return p_refFaces;
|
||||
}
|
||||
|
||||
void addRefFace(Face* face)
|
||||
{
|
||||
p_refFaces.push(face);
|
||||
}
|
||||
|
||||
sarray<vertex_pointer, 2>& vertices()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
vertex_pointer vertex(size_type n)
|
||||
{
|
||||
return (*this)[n];
|
||||
}
|
||||
|
||||
bool isValid()
|
||||
{
|
||||
return *front() != *back();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
71
source/hyporo/hmesh/face.hpp
Normal file
71
source/hyporo/hmesh/face.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "../hyplib/scalar/scalar.hpp"
|
||||
#include "../hyplib/array/array.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
|
||||
namespace hpr::mesh
|
||||
{
|
||||
|
||||
class Vertex;
|
||||
class Edge;
|
||||
class Cell;
|
||||
|
||||
class Face : public darray<Edge*>
|
||||
{
|
||||
friend class Mesh;
|
||||
|
||||
using edge_pointer = Edge*;
|
||||
using vertex_pointer = Vertex*;
|
||||
using base = darray<edge_pointer>;
|
||||
|
||||
protected:
|
||||
darray<Cell*> p_refCells;
|
||||
|
||||
public:
|
||||
Face() :
|
||||
base{}
|
||||
{}
|
||||
|
||||
Face(std::initializer_list<edge_pointer> edges) :
|
||||
base{edges}
|
||||
{}
|
||||
|
||||
~Face() override
|
||||
{
|
||||
for (auto& c: p_refCells)
|
||||
c = nullptr;
|
||||
}
|
||||
|
||||
darray<Cell*>& refCells()
|
||||
{
|
||||
return p_refCells;
|
||||
}
|
||||
|
||||
void addRefCell(Cell* cell)
|
||||
{
|
||||
p_refCells.push(cell);
|
||||
}
|
||||
|
||||
darray<edge_pointer>& edges()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
edge_pointer edge(size_type n)
|
||||
{
|
||||
return (*this)[n];
|
||||
}
|
||||
|
||||
darray<vertex_pointer> vertices()
|
||||
{
|
||||
darray<vertex_pointer> vertices_ {size(), nullptr};
|
||||
for (auto n = 0; n < size(); ++n)
|
||||
vertices_[n] = edge(n)->vertex(0);
|
||||
return vertices_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -4,154 +4,37 @@
|
||||
#include "../hyplib/array/array.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include "vertex.hpp"
|
||||
#include "edge.hpp"
|
||||
#include "face.hpp"
|
||||
#include "cell.hpp"
|
||||
|
||||
|
||||
#include <vector>
|
||||
namespace hpr::mesh
|
||||
{
|
||||
class Edge;
|
||||
class Vertex : public vec<scalar, 3>
|
||||
{
|
||||
friend class Mesh;
|
||||
using base = vec<scalar, 3>;
|
||||
protected:
|
||||
darray<Edge*> p_refEdges;
|
||||
public:
|
||||
Vertex() :
|
||||
base {}
|
||||
{}
|
||||
Vertex(const scalar& x, const scalar& y, const scalar& z) :
|
||||
base {x, y, z}
|
||||
{}
|
||||
virtual
|
||||
~Vertex()
|
||||
{
|
||||
for (auto& e : p_refEdges)
|
||||
delete e;
|
||||
}
|
||||
darray<Edge*>& refEdges()
|
||||
{
|
||||
return p_refEdges;
|
||||
}
|
||||
void addRefEdge(Edge* edge)
|
||||
{
|
||||
p_refEdges.push(edge);
|
||||
}
|
||||
};
|
||||
class Face;
|
||||
class Edge : public sarray<Vertex*, 2>
|
||||
{
|
||||
friend class Mesh;
|
||||
using vertex_pointer = Vertex*;
|
||||
using base = sarray<vertex_pointer, 2>;
|
||||
protected:
|
||||
darray<Face*> p_refFaces;
|
||||
public:
|
||||
Edge() :
|
||||
base {}
|
||||
{}
|
||||
Edge(vertex_pointer v1, vertex_pointer v2) :
|
||||
base {v1, v2}
|
||||
{}
|
||||
virtual
|
||||
~Edge()
|
||||
{
|
||||
for (auto& f : p_refFaces)
|
||||
delete f;
|
||||
}
|
||||
darray<Face*>& refFaces()
|
||||
{
|
||||
return p_refFaces;
|
||||
}
|
||||
void addRefFace(Face* face)
|
||||
{
|
||||
p_refFaces.push(face);
|
||||
}
|
||||
sarray<vertex_pointer, 2>& vertices()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
vertex_pointer vertex(size_type n)
|
||||
{
|
||||
return (*this)[n];
|
||||
}
|
||||
};
|
||||
class Cell;
|
||||
class Face : public darray<Edge*>
|
||||
{
|
||||
friend class Mesh;
|
||||
using edge_pointer = Edge*;
|
||||
using vertex_pointer = Vertex*;
|
||||
using base = darray<edge_pointer>;
|
||||
protected:
|
||||
darray<Cell*> p_refCells;
|
||||
public:
|
||||
Face() :
|
||||
base {}
|
||||
{}
|
||||
Face(std::initializer_list<edge_pointer> edges) :
|
||||
base {edges}
|
||||
{}
|
||||
virtual
|
||||
~Face()
|
||||
{
|
||||
for (auto& c : p_refCells)
|
||||
delete c;
|
||||
}
|
||||
darray<Cell*>& refCells()
|
||||
{
|
||||
return p_refCells;
|
||||
}
|
||||
void addRefCell(Cell* cell)
|
||||
{
|
||||
p_refCells.push(cell);
|
||||
}
|
||||
darray<edge_pointer>& edges()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
edge_pointer edge(size_type n)
|
||||
{
|
||||
return (*this)[n];
|
||||
}
|
||||
darray<vertex_pointer> vertices()
|
||||
{
|
||||
darray<vertex_pointer> vertices_ {size(), nullptr};
|
||||
for (auto n = 0; n < size(); ++n)
|
||||
vertices_[n] = edge(n)->vertex(0);
|
||||
return vertices_;
|
||||
}
|
||||
};
|
||||
|
||||
class Cell : public darray<Face*>
|
||||
{
|
||||
using face_pointer = Face*;
|
||||
using base = darray<face_pointer>;
|
||||
public:
|
||||
Cell(std::initializer_list<face_pointer> faces) :
|
||||
base {faces}
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
class Mesh
|
||||
{
|
||||
#include "vertex.hpp"
|
||||
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using vertex_pointer = Vertex*;
|
||||
using edge_pointer = Edge*;
|
||||
using face_pointer = Face*;
|
||||
using cell_pointer = Cell*;
|
||||
|
||||
protected:
|
||||
darray<Vertex*> p_vertices;
|
||||
darray<Edge*> p_edges;
|
||||
darray<Face*> p_faces;
|
||||
darray<Cell*> p_cells;
|
||||
|
||||
public:
|
||||
|
||||
Mesh() = default;
|
||||
|
||||
Mesh(const Mesh&) = default;
|
||||
|
||||
~Mesh()
|
||||
{
|
||||
for (auto& v : p_vertices)
|
||||
@ -261,10 +144,13 @@ public:
|
||||
removeFace(indexOf(refFace), false);
|
||||
removeNullFaces();
|
||||
}
|
||||
for (auto& vertex : edge(n)->vertices())
|
||||
vertex->refEdges().remove([this, n](edge_pointer e){ return e == edge(n); });
|
||||
delete edge(n);
|
||||
if (erase)
|
||||
edges().remove(n);
|
||||
}
|
||||
|
||||
darray<Face*>& faces()
|
||||
{
|
||||
return p_faces;
|
||||
@ -297,6 +183,8 @@ public:
|
||||
removeCell(indexOf(refCell), false);
|
||||
removeNullFaces();
|
||||
}
|
||||
for (auto& edge : face(n)->edges())
|
||||
edge->refFaces().remove([this, n](face_pointer f){ return f == face(n); });
|
||||
delete face(n);
|
||||
if (erase)
|
||||
faces().remove(n);
|
||||
@ -313,6 +201,14 @@ public:
|
||||
return p_cells[n];
|
||||
}
|
||||
|
||||
template <std::convertible_to<face_pointer>... Faces>
|
||||
void addCell(const Faces& ...faces)
|
||||
{
|
||||
cells().push(new Cell {static_cast<face_pointer>(faces)...});
|
||||
for (auto& face : *cells().back())
|
||||
face->addRefCell(cells().back());
|
||||
}
|
||||
|
||||
void removeNullCells()
|
||||
{
|
||||
cells().remove([](cell_pointer cell){ return cell == nullptr; });
|
||||
@ -321,10 +217,13 @@ public:
|
||||
void removeCell(size_type n, bool erase = true, bool cascade = true)
|
||||
{
|
||||
static_cast<void>(cascade);
|
||||
for (auto& face : cell(n)->faces())
|
||||
face->refCells().remove([this, n](cell_pointer c){ return c == cell(n); });
|
||||
delete cell(n);
|
||||
if (erase)
|
||||
cells().remove(n);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -4,7 +4,18 @@
|
||||
TEST(hmeshTest, Mesh)
|
||||
{
|
||||
hpr::mesh::Mesh mesh;
|
||||
mesh.addVertex(1, 2, 3);
|
||||
mesh.addVertex(1, 3, 3);
|
||||
mesh.addVertex(0, 0, 0);
|
||||
mesh.addVertex(1, 1, 1);
|
||||
mesh.addVertex(10, 0, 0);
|
||||
mesh.addVertex(0, 0, 0);
|
||||
mesh.addEdge(mesh.vertex(0), mesh.vertex(1));
|
||||
mesh.addEdge(mesh.vertex(1), mesh.vertex(2));
|
||||
mesh.addEdge(mesh.vertex(2), mesh.vertex(0));
|
||||
mesh.addEdge(mesh.vertex(0), mesh.vertex(3));
|
||||
mesh.addFace(mesh.edge(0), mesh.edge(1), mesh.edge(2));
|
||||
EXPECT_EQ(mesh.vertices().size(), 4);
|
||||
EXPECT_EQ(mesh.edges().size(), 4);
|
||||
EXPECT_EQ(mesh.faces().size(), 1);
|
||||
EXPECT_EQ(mesh.vertex(1)->refEdges().size(), 2);
|
||||
EXPECT_FALSE(mesh.edges().back()->isValid());
|
||||
}
|
||||
|
49
source/hyporo/hmesh/vertex.hpp
Normal file
49
source/hyporo/hmesh/vertex.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "../hyplib/scalar/scalar.hpp"
|
||||
#include "../hyplib/array/array.hpp"
|
||||
#include "../hyplib/vector/vector.hpp"
|
||||
|
||||
|
||||
namespace hpr::mesh
|
||||
{
|
||||
|
||||
class Edge;
|
||||
|
||||
class Vertex : public vec<scalar, 3>
|
||||
{
|
||||
friend class Mesh;
|
||||
|
||||
using base = vec<scalar, 3>;
|
||||
|
||||
protected:
|
||||
darray<Edge*> p_refEdges;
|
||||
|
||||
public:
|
||||
Vertex() :
|
||||
base{}
|
||||
{}
|
||||
|
||||
Vertex(const scalar& x, const scalar& y, const scalar& z) :
|
||||
base{x, y, z}
|
||||
{}
|
||||
|
||||
~Vertex() override
|
||||
{
|
||||
for (auto& e: p_refEdges)
|
||||
e = nullptr;
|
||||
}
|
||||
|
||||
darray<Edge*>& refEdges()
|
||||
{
|
||||
return p_refEdges;
|
||||
}
|
||||
|
||||
void addRefEdge(Edge* edge)
|
||||
{
|
||||
p_refEdges.push(edge);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -23,7 +23,7 @@ public:
|
||||
using iterator = Iterator<Type>;
|
||||
using const_pointer = Type const*;
|
||||
using const_reference = Type const&;
|
||||
using const_iterator = Iterator<Type> const;
|
||||
using const_iterator = Iterator<const Type>;
|
||||
|
||||
protected:
|
||||
|
||||
@ -63,6 +63,28 @@ public:
|
||||
swap(*this, arr);
|
||||
}
|
||||
|
||||
inline
|
||||
DynamicArray(const_iterator start, const_iterator end) :
|
||||
p_size {size_type(end.operator->() - start.operator->())},
|
||||
p_capacity {p_size},
|
||||
p_start {new value_type[p_size]},
|
||||
p_end {p_start + p_size},
|
||||
p_storage_end {p_start + p_capacity}
|
||||
{
|
||||
std::copy(start, end, p_start);
|
||||
}
|
||||
|
||||
inline
|
||||
DynamicArray(iterator start, iterator end) :
|
||||
p_size {size_type(end.operator->() - start.operator->())},
|
||||
p_capacity {p_size},
|
||||
p_start {new value_type[p_size]},
|
||||
p_end {p_start + p_size},
|
||||
p_storage_end {p_start + p_capacity}
|
||||
{
|
||||
std::copy(start, end, p_start);
|
||||
}
|
||||
|
||||
inline
|
||||
DynamicArray(std::initializer_list<value_type> list) :
|
||||
p_size {list.size()},
|
||||
@ -76,14 +98,14 @@ public:
|
||||
|
||||
inline
|
||||
DynamicArray(size_type size, value_type value) :
|
||||
p_size {size},
|
||||
p_size {0},
|
||||
p_capacity {size},
|
||||
p_start {new value_type[p_capacity]},
|
||||
p_end {p_start + p_size},
|
||||
p_storage_end {p_start + p_capacity}
|
||||
{
|
||||
for (auto n = 0; n < p_size; ++n)
|
||||
*(p_start + n) = value;
|
||||
for (auto n = 0; n < size; ++n)
|
||||
push(value);
|
||||
}
|
||||
|
||||
inline
|
||||
@ -161,12 +183,16 @@ public:
|
||||
virtual
|
||||
reference operator[](size_type n)
|
||||
{
|
||||
if (n >= size())
|
||||
throw std::out_of_range("Index out of bounds");
|
||||
return *(p_start + n);
|
||||
}
|
||||
|
||||
virtual
|
||||
const_reference operator[](size_type n) const
|
||||
{
|
||||
if (n >= size())
|
||||
throw std::out_of_range("Index out of bounds");
|
||||
return *(p_start + n);
|
||||
}
|
||||
|
||||
@ -353,6 +379,11 @@ public:
|
||||
p_storage_end = p_end + p_capacity;
|
||||
}
|
||||
|
||||
DynamicArray slice(iterator start, iterator end)
|
||||
{
|
||||
return DynamicArray {start, end};
|
||||
}
|
||||
|
||||
// Friend functions
|
||||
|
||||
friend
|
||||
@ -373,6 +404,18 @@ public:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
friend
|
||||
DynamicArray operator+(const DynamicArray& lhs, const DynamicArray& rhs)
|
||||
{
|
||||
DynamicArray arr {rhs.size() + lhs.size(), {}};
|
||||
for (auto n = 0; n < rhs.size(); ++n)
|
||||
{
|
||||
arr[n] = rhs[n];
|
||||
arr[n + rhs.size()] = lhs[n];
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -124,7 +124,7 @@ public:
|
||||
}
|
||||
|
||||
inline
|
||||
StaticArray& operator=(const StaticArray& vs) noexcept
|
||||
StaticArray& operator=(const StaticArray& vs)
|
||||
{
|
||||
std::copy(vs.begin(), vs.end(), begin());
|
||||
return *this;
|
||||
@ -185,12 +185,16 @@ public:
|
||||
virtual
|
||||
reference operator[](size_type n)
|
||||
{
|
||||
if (n >= size())
|
||||
throw std::out_of_range("Index out of bounds");
|
||||
return *(p_start + n);
|
||||
}
|
||||
|
||||
virtual
|
||||
const_reference operator[](size_type n) const
|
||||
{
|
||||
if (n >= size())
|
||||
throw std::out_of_range("Index out of bounds");
|
||||
return *(p_start + n);
|
||||
}
|
||||
|
||||
@ -227,6 +231,13 @@ public:
|
||||
std::swap(lhs.p_end, rhs.p_end);
|
||||
}
|
||||
|
||||
friend
|
||||
void swap(StaticArray&& lhs, StaticArray&& rhs)
|
||||
{
|
||||
std::swap(lhs.p_start, rhs.p_start);
|
||||
std::swap(lhs.p_end, rhs.p_end);
|
||||
}
|
||||
|
||||
friend
|
||||
bool operator==(const StaticArray& lhs, const StaticArray& rhs)
|
||||
{
|
||||
|
35
source/hyporo/hyplib/logger/logger.hpp
Normal file
35
source/hyporo/hyplib/logger/logger.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
|
||||
namespace hpr
|
||||
{
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
enum Severity
|
||||
{
|
||||
None,
|
||||
Error,
|
||||
Warning,
|
||||
Info,
|
||||
Debug
|
||||
};
|
||||
static Severity severity;
|
||||
|
||||
template <typename T>
|
||||
friend
|
||||
Logger& operator<<(Logger& l, const T& data)
|
||||
{
|
||||
if (severity == Info)
|
||||
std::cout << data << std::endl;
|
||||
else if (severity == Error)
|
||||
std::cerr << data << std::endl;
|
||||
|
||||
return l;
|
||||
}
|
||||
};
|
||||
Logger::Severity Logger::severity = Logger::Warning;
|
||||
Logger logger;
|
||||
}
|
9
source/hyporo/hyplib/matrix/matrix_space.cpp
Normal file
9
source/hyporo/hyplib/matrix/matrix_space.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "matrix_space.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace hpr
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
@ -168,7 +168,7 @@ public:
|
||||
else {
|
||||
auto res = 0;
|
||||
for (auto m = 0; m < Cols; ++m)
|
||||
res += pow(-1, m) * (*this)(0, m) * minor(0, m).det();
|
||||
res += std::pow(-1, m) * (*this)(0, m) * minor(0, m).det();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@ -190,7 +190,7 @@ public:
|
||||
for (auto n = 0; n < Rows; ++n)
|
||||
for (auto k = 0; k < Cols; ++k)
|
||||
{
|
||||
ms(n, k) = pow(-1, n + k) * minor(n, k).det();
|
||||
ms(n, k) = std::pow(-1, n + k) * minor(n, k).det();
|
||||
}
|
||||
return ms.transpose();
|
||||
}
|
||||
|
@ -25,29 +25,58 @@ using scalar = float;
|
||||
|
||||
#endif
|
||||
|
||||
static const scalar small = std::numeric_limits<scalar>::epsilon();
|
||||
static const scalar great = static_cast<scalar>(1.0) / small;
|
||||
static const scalar valueSmall = std::numeric_limits<scalar>::min();
|
||||
static const scalar valueGreat = std::numeric_limits<scalar>::max() * 0.1;
|
||||
static const scalar NaN = std::numeric_limits<scalar>::signaling_NaN();
|
||||
static
|
||||
const scalar small = std::numeric_limits<scalar>::epsilon();
|
||||
static
|
||||
const scalar great = static_cast<scalar>(1.0) / small;
|
||||
static
|
||||
const scalar valueSmall = std::numeric_limits<scalar>::min();
|
||||
static
|
||||
const scalar valueGreat = std::numeric_limits<scalar>::max() * 0.1;
|
||||
static
|
||||
const scalar NaN = std::numeric_limits<scalar>::signaling_NaN();
|
||||
|
||||
|
||||
|
||||
//- Return 1 if s is positive or 0 otherwise -1
|
||||
inline int sign(const scalar s)
|
||||
inline
|
||||
int sign(const scalar s)
|
||||
{
|
||||
return (s >= 0) ? 1: -1;
|
||||
}
|
||||
|
||||
inline scalar mag(const scalar s)
|
||||
inline
|
||||
scalar mag(const scalar s)
|
||||
{
|
||||
return std::fabs(s);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline
|
||||
bool equal(Type lhs, Type rhs, Type precision = 1e-5)
|
||||
{
|
||||
return mag(lhs - rhs) < precision;
|
||||
}
|
||||
|
||||
inline
|
||||
scalar clip(scalar value, scalar valueMin, scalar valueMax)
|
||||
{
|
||||
return std::min(valueMax, std::max(value, valueMin));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type inversesqrt( Type n )
|
||||
{
|
||||
return static_cast<Type>(1) / sqrt(n);
|
||||
}
|
||||
|
||||
// trigonometric
|
||||
|
||||
static const scalar PI = static_cast<scalar>(M_PIl);
|
||||
static
|
||||
const scalar PI = static_cast<scalar>(M_PIl);
|
||||
|
||||
template <typename Type>
|
||||
constexpr
|
||||
inline
|
||||
Type radians(Type degrees)
|
||||
{
|
||||
static_assert(std::numeric_limits<Type>::is_iec559);
|
||||
@ -55,7 +84,7 @@ Type radians(Type degrees)
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
constexpr
|
||||
inline
|
||||
Type degrees(Type radians)
|
||||
{
|
||||
static_assert(std::numeric_limits<Type>::is_iec559);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "matrix.hpp"
|
||||
|
||||
|
||||
TEST(hyplib, Array)
|
||||
TEST(hyplib, StaticArray)
|
||||
{
|
||||
hpr::StaticArray<float, 3> arr {1, 3, 2};
|
||||
hpr::StaticArray<float, 4> sarr {arr, 5};
|
||||
@ -29,6 +29,13 @@ TEST(hyplib, DynamicArray)
|
||||
arr3.remove([](float num) { return num == 0; });
|
||||
EXPECT_EQ(arr3, hpr::darray<float>({1, 3, 2, 9, 5}));
|
||||
EXPECT_EQ(arr3.size(), 5);
|
||||
|
||||
hpr::DynamicArray<float*> arr4;
|
||||
arr4.push(new float(5));
|
||||
arr4.push(new float(7));
|
||||
arr4.push(new float(9));
|
||||
EXPECT_EQ(*arr4[0], 5.f);
|
||||
EXPECT_EQ(*arr4[2], 9.f);
|
||||
}
|
||||
|
||||
TEST(hyplib, Vector)
|
||||
@ -43,6 +50,9 @@ TEST(hyplib, Vector)
|
||||
EXPECT_EQ(v1 + v2, hpr::vec3(6, 10, 1));
|
||||
EXPECT_EQ(v1 - v2, hpr::vec3(-4, -4, 3));
|
||||
EXPECT_EQ((hpr::dot(v1, v2) ), 24);
|
||||
EXPECT_EQ((hpr::cross(hpr::vec3(1, 0, 0), hpr::vec3(0, 1, 0))), hpr::vec3(0, 0, 1));
|
||||
EXPECT_EQ((hpr::angle(hpr::vec3(1, 0, 0), hpr::vec3(0, 0, 1))), hpr::PI * 0.5);
|
||||
EXPECT_EQ((hpr::normalize(hpr::vec3(1, 1, 1))), hpr::vec3(0.5773502691896258, 0.5773502691896258, 0.5773502691896258));
|
||||
}
|
||||
|
||||
TEST(hyplib, Matrix)
|
||||
|
26
source/hyporo/hyplib/tests/mytest.cpp
Normal file
26
source/hyporo/hyplib/tests/mytest.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <iostream>
|
||||
#include "../vector/vector_space.hpp"
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
using vs = hpr::VectorSpace<Type, Size>;
|
||||
|
||||
using std::cout, std::endl;
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
void print(const vs<Type, Size>& vec)
|
||||
{
|
||||
cout << "Vector: ";
|
||||
for (auto n = vec.begin(); n != vec.end(); ++n)
|
||||
cout << *n << " ";
|
||||
cout << endl;
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
|
||||
vs<float, 3> v1 {3, 4, 7, 8};
|
||||
v1 += 3;
|
||||
print<float, 3>(v1);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "scalar.hpp"
|
||||
#include "../scalar/scalar.hpp"
|
||||
#include "vector_space.hpp"
|
||||
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../scalar/scalar.hpp"
|
||||
#include "../array/array.hpp"
|
||||
|
||||
|
||||
namespace hpr
|
||||
{
|
||||
|
||||
@ -40,12 +42,17 @@ public:
|
||||
{}
|
||||
|
||||
inline
|
||||
VectorSpace& operator=(const VectorSpace& vs) noexcept = default;
|
||||
VectorSpace& operator=(const VectorSpace& vs)
|
||||
{
|
||||
base::operator=(vs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
VectorSpace& operator=(VectorSpace&& vs) noexcept
|
||||
{
|
||||
std::swap(*this, vs);
|
||||
swap(*this, vs);//std::forward<base>(static_cast<base>(*this)), std::forward<base>(static_cast<base>(vs)));
|
||||
//std::swap(*this, vs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -67,6 +74,14 @@ public:
|
||||
base {list}
|
||||
{}
|
||||
|
||||
template <std::convertible_to<value_type>... Args>
|
||||
inline
|
||||
VectorSpace(const value_type& v, const Args& ...args) :
|
||||
base {v, static_cast<value_type>(args)...}
|
||||
{
|
||||
static_assert(1 + sizeof...(args) == Size, "Number of arguments must be equal to size of vector");
|
||||
}
|
||||
|
||||
template <std::convertible_to<value_type>... Args>
|
||||
inline
|
||||
VectorSpace(value_type&& v, Args&& ...args) :
|
||||
@ -261,11 +276,21 @@ public:
|
||||
|
||||
};
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
inline
|
||||
VectorSpace<bool, Size> equal(const VectorSpace<Type, Size>& lhs, const VectorSpace<Type, Size>& rhs, scalar precision = 1e-5)
|
||||
{
|
||||
VectorSpace<bool, Size> res;
|
||||
for (auto n = 0; n < Size; ++n)
|
||||
res[n] = equal(lhs[n], rhs[n], precision);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
inline
|
||||
Type sum(const VectorSpace<Type, Size>& vs)
|
||||
{
|
||||
Type sum {0};
|
||||
Type sum {};
|
||||
for (const Type& v : vs)
|
||||
sum += v;
|
||||
return sum;
|
||||
@ -297,12 +322,47 @@ constexpr
|
||||
VectorSpace<Type, 3> cross(const VectorSpace<Type, 3>& lhs, const VectorSpace<Type, 3>& rhs)
|
||||
{
|
||||
return VectorSpace<Type, 3>(
|
||||
lhs[2] * rhs[3] - lhs[3] * rhs[2],
|
||||
lhs[3] * rhs[1] - lhs[1] * rhs[3],
|
||||
lhs[1] * rhs[2] - lhs[2] * rhs[1]
|
||||
lhs[1] * rhs[2] - lhs[2] * rhs[1],
|
||||
lhs[2] * rhs[0] - lhs[0] * rhs[2],
|
||||
lhs[0] * rhs[1] - lhs[1] * rhs[0]
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
constexpr
|
||||
VectorSpace<Type, Size> pow(const VectorSpace<Type, Size>& vs, scalar degree)
|
||||
{
|
||||
VectorSpace<Type, Size> res;
|
||||
for (auto n = 0; n < Size; ++n)
|
||||
res[n] = std::pow(vs[n], degree);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
constexpr
|
||||
VectorSpace<Type, Size> abs(const VectorSpace<Type, Size>& vs)
|
||||
{
|
||||
VectorSpace<Type, Size> res;
|
||||
for (auto n = 0; n < Size; ++n)
|
||||
res[n] = std::abs(vs[n]);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
constexpr
|
||||
Type norm(const VectorSpace<Type, Size>& vs)
|
||||
{
|
||||
return sqrt(sum(pow(abs(vs), 2)));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
constexpr
|
||||
Type angle(const VectorSpace<Type, 3>& lhs, const VectorSpace<Type, 3>& rhs)
|
||||
{
|
||||
scalar cos = dot(lhs, rhs) / (norm(lhs) * norm(rhs));
|
||||
return acos(cos); //clip(cos, -1., 1.));
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
inline
|
||||
VectorSpace<Type, Size> normalize(const VectorSpace<Type, Size>& vs)
|
||||
@ -310,16 +370,6 @@ VectorSpace<Type, Size> normalize(const VectorSpace<Type, Size>& vs)
|
||||
return vs * inversesqrt(dot(vs, vs));
|
||||
}
|
||||
|
||||
template <typename Type, size_t Size>
|
||||
constexpr
|
||||
VectorSpace<bool, Size> equal(const VectorSpace<Type, Size>& lhs, const VectorSpace<Type, Size>& rhs)
|
||||
{
|
||||
VectorSpace<bool, Size> vs;
|
||||
for (auto n = 0; n < Size; ++n)
|
||||
vs[n] = lhs[n] == rhs[n];
|
||||
return vs;
|
||||
}
|
||||
|
||||
template <size_t Size>
|
||||
constexpr
|
||||
bool any(const VectorSpace<bool, Size>& vs)
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "window.hpp"
|
||||
#include "window_system.hpp"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
|
||||
namespace hpr::gpu::glfw
|
||||
{
|
||||
@ -30,9 +32,4 @@ gpu::Window* WindowSystem::newWindow()
|
||||
return static_cast<gpu::Window*>(p_windows.back());
|
||||
}
|
||||
|
||||
std::function<GLFWglproc(const char*)> WindowSystem::deviceProcAddress() const
|
||||
{
|
||||
return std::function<GLFWglproc(const char*)>(glfwGetProcAddress);
|
||||
}
|
||||
|
||||
}
|
@ -2,9 +2,6 @@
|
||||
|
||||
#include "../window_system.hpp"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace hpr::gpu::glfw
|
||||
{
|
||||
@ -20,7 +17,6 @@ public:
|
||||
|
||||
gpu::Window* newWindow() override;
|
||||
|
||||
std::function<GLFWglproc(const char*)> deviceProcAddress() const;
|
||||
};
|
||||
|
||||
}
|
@ -44,7 +44,9 @@ void WindowSystem::closeWindow(Window* window)
|
||||
|
||||
void WindowSystem::destroyWindow(Window* window)
|
||||
{
|
||||
p_windows.remove(window);
|
||||
for (auto n = 0; n < p_windows.size(); ++n)
|
||||
if (p_windows[n] == window)
|
||||
p_windows.remove(n);
|
||||
window->close();
|
||||
window = nullptr;
|
||||
}
|
||||
@ -56,6 +58,8 @@ Monitor* WindowSystem::monitor(int index)
|
||||
|
||||
void WindowSystem::destroyMonitor(Monitor* monitor)
|
||||
{
|
||||
p_monitors.remove(monitor);
|
||||
for (auto n = 0; n < p_monitors.size(); ++n)
|
||||
if (p_monitors[n] == monitor)
|
||||
p_monitors.remove(n);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user