This commit is contained in:
L-Nafaryus 2022-11-18 21:50:49 +05:00
parent 3be9178126
commit 0aea51b594
78 changed files with 3059 additions and 510 deletions

View File

@ -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
View File

@ -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"
}
}

View File

@ -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
View 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
View 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()

View File

@ -1,2 +1,3 @@
add_subdirectory(hyporo)
add_subdirectory(creator)
add_subdirectory(applications)

View File

@ -0,0 +1 @@
add_subdirectory(periodic)

View File

@ -0,0 +1,10 @@
add_executable(periodic
periodic.cpp
)
target_link_libraries(periodic
hyporo-hyplib
hyporo-csg
)

View 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;
}

View File

@ -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
)

View File

@ -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;
}

View File

@ -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()

View 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
View 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
{}

View 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);
}
};
}

View 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);
}
};
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "shape.hpp"
namespace hpr::csg
{
class Geometry
{
public:
Geometry() = default;
virtual
~Geometry() = default;
};
}

View 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
View 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);
}

View 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);
}
};
}

View 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);
}
};
}

View 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()};
}
};
}

View 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");
}

View 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()};
}
};
}

View 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);
}
};
}

View File

@ -36,5 +36,6 @@ add_library(hyporo-gpu STATIC
target_link_libraries(hyporo-gpu
glad
stb
hyporo-hyplib
)

View File

@ -19,8 +19,7 @@ Buffer::Buffer(DeviceAPI api) :
p_stride {0}
{}
Buffer::~Buffer()
{}
Buffer::~Buffer() = default;
// Member functions

View File

@ -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;
};

View File

@ -13,8 +13,7 @@ Context::Context(DeviceAPI api) :
p_api {api}
{}
Context::~Context()
{}
Context::~Context() = default;
bool Context::checkCompability(const Context* ctx) const
{

View File

@ -26,6 +26,7 @@ public:
Context();
explicit
Context(DeviceAPI api);
virtual

View File

@ -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);
buffer = nullptr;
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);
shader = nullptr;
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]);
program = nullptr;
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);
texture = nullptr;
if (*iter == texture)
{
delete texture;
texture = nullptr;
p_textures.remove(iter);
break;
}
}
}

View File

@ -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);
};
}

View File

@ -13,8 +13,7 @@ Buffer::Buffer() :
p_vertexArrayIndex {0}
{}
Buffer::~Buffer()
{}
Buffer::~Buffer() = default;
int Buffer::target() const
{

View File

@ -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);
}
}

View File

@ -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);
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "render_target.hpp"
namespace hpr::gpu::opengl
{
RenderTarget::RenderTarget() :
gpu::RenderTarget {DeviceAPI::OpenGL}
{}
RenderTarget::~RenderTarget() = default;
}

View 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;
}
};
}

View File

@ -13,7 +13,6 @@ Shader::Shader() :
p_shaderIndex {0}
{}
Shader::~Shader()
{}
Shader::~Shader() = default;
}

View File

@ -19,7 +19,7 @@ public:
Shader();
virtual ~Shader();
~Shader() override;
};

View File

@ -10,7 +10,6 @@ Texture::Texture() :
p_textureIndex {0}
{}
Texture::~Texture()
{}
Texture::~Texture() = default;
}

View File

@ -18,7 +18,7 @@ public:
Texture();
~Texture();
~Texture() override;
};

View 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;
}

View 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;
}
};
}

View File

@ -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;
}

View File

@ -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

View File

@ -15,7 +15,6 @@ ShaderProgram::ShaderProgram(DeviceAPI api) :
p_isLinked {false}
{}
ShaderProgram::~ShaderProgram()
{}
ShaderProgram::~ShaderProgram() = default;
}

View File

@ -24,9 +24,10 @@ public:
ShaderProgram();
explicit
ShaderProgram(DeviceAPI api);
virtual ~ShaderProgram();
~ShaderProgram() override;
// Member functions

View 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);
}

View 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;
}

View File

@ -20,8 +20,7 @@ Texture::Texture(DeviceAPI api) :
p_height {0}
{}
Texture::~Texture()
{}
Texture::~Texture() = default;
std::string Texture::filename() const
{

View File

@ -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;
};

View File

@ -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

View File

@ -1,9 +0,0 @@
#pragma once
#include "Face.hpp"
namespace hyporo
{
} // end namespace hyporo

View File

@ -1,9 +0,0 @@
#pragma once
#include "Vertex.hpp"
namespace hyporo
{
} // end namespace hyporo

View File

@ -1,9 +0,0 @@
#pragma once
#include "Edge.hpp"
namespace hyporo
{
} // end namespace hyporo

View File

@ -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

View File

@ -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"

View File

@ -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

View 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;
}
};
}

View 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();
}
};
}

View 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_;
}
};
}

View File

@ -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);
}
};
}

View File

@ -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());
}

View 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);
}
};
}

View File

@ -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;
}
};
}

View File

@ -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)
{

View 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;
}

View File

@ -0,0 +1,9 @@
#include "matrix_space.hpp"
#include <cmath>
namespace hpr
{
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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)

View 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;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "scalar.hpp"
#include "../scalar/scalar.hpp"
#include "vector_space.hpp"

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;
};
}

View File

@ -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);
}
}