first commit
This commit is contained in:
commit
f1263d46c7
|
@ -0,0 +1,11 @@
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
build/
|
||||||
|
deps/
|
||||||
|
res/
|
||||||
|
*.obj
|
||||||
|
*.pdb
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.spv
|
||||||
|
*.ilk
|
|
@ -0,0 +1,317 @@
|
||||||
|
#ifndef _BASIC_MODEL_HPP_
|
||||||
|
#define _BASIC_MODEL_HPP_
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "tmath.hpp"
|
||||||
|
#include "rusty.hpp"
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
tmath::fvec3 position;
|
||||||
|
tmath::fvec3 normal;
|
||||||
|
tmath::fvec2 texcoord;
|
||||||
|
// 0 - attribute 1 - texture
|
||||||
|
tmath::ivec2 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexAttribute {
|
||||||
|
tmath::fmat4 matrix = tmath::fmat4::identity();
|
||||||
|
tmath::fmat4 nmatrix = tmath::fmat4::identity();
|
||||||
|
tmath::fvec4 color = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
tmath::fvec4 mixcolor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModelUnit {
|
||||||
|
uint32_t vert_offset;
|
||||||
|
uint32_t vert_count;
|
||||||
|
uint32_t index_offset;
|
||||||
|
uint32_t index_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VertCollection {
|
||||||
|
public:
|
||||||
|
ModelUnit gen_square(float tx = 0.0f, float ty = 0.0f, float tw = 1.0f, float th = 1.0f) {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 4;
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {tx, ty}});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {tx, ty + th}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {tx + tw, ty + th}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {tx + tw, ty}});
|
||||||
|
out_i.insert(out_i.end(), {0 + offset, 1 + offset, 2 + offset, 2 + offset, 3 + offset, 0 + offset});
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit gen_texture(uint32_t tilew, uint32_t tileh, float posx, float posy, float texw, float texh) {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
float tx = 1.0f / tilew;
|
||||||
|
float ty = 1.0f / tileh;
|
||||||
|
float mx = texw * tx;
|
||||||
|
float my = texh * ty;
|
||||||
|
// vert_count = (tilew + 1) * (tileyh + 1);
|
||||||
|
for(uint32_t y = 0; y <= tileh; ++y) {
|
||||||
|
for(uint32_t x = 0; x <= tilew; ++x)
|
||||||
|
out_v.push_back({{posx + x * mx, posy + y * my, 0.0f}, {0.0f, 0.0f, 1.0f}, {x * tx, y * ty}});
|
||||||
|
}
|
||||||
|
for(uint32_t y = 0; y < tileh; ++y) {
|
||||||
|
for(uint32_t x = 0; x < tilew; ++x) {
|
||||||
|
uint32_t idx = y * (tileh + 1) + x + offset;
|
||||||
|
out_i.insert(out_i.end(), {idx, idx + tileh + 1, idx + 1, idx + 1, idx + tileh + 1, idx + tileh + 2});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit gen_cube() {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 24;
|
||||||
|
out_v.push_back({{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {0 + offset, 1 + offset, 2 + offset, 2 + offset, 3 + offset, 0 + offset});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {4 + offset, 5 + offset, 6 + offset, 6 + offset, 7 + offset, 4 + offset});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {8 + offset, 9 + offset, 10 + offset, 10 + offset, 11 + offset, 8 + offset});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {12 + offset, 13 + offset, 14 + offset, 14 + offset, 15 + offset, 12 + offset});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {16 + offset, 17 + offset, 18 + offset, 18 + offset, 19 + offset, 16 + offset});
|
||||||
|
out_v.push_back({{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f}});
|
||||||
|
out_v.push_back({{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f}});
|
||||||
|
out_v.push_back({{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f}});
|
||||||
|
out_i.insert(out_i.end(), {20 + offset, 21 + offset, 22 + offset, 22 + offset, 23 + offset, 20 + offset});
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit gen_octahedron() {
|
||||||
|
const float nv = .5773503f; // 1.0 / sqrt(3)
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 24;
|
||||||
|
out_v.push_back({{1.0f, 0.0f, 0.0f}, {nv, nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, 1.0f}, {nv, nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, 1.0f, 0.0f}, {nv, nv, nv}});
|
||||||
|
out_i.insert(out_i.end(), {0 + offset, 1 + offset, 2 + offset});
|
||||||
|
out_v.push_back({{0.0f, -1.0f, 0.0f}, {nv, -nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, 1.0f}, {nv, -nv, nv}});
|
||||||
|
out_v.push_back({{1.0f, 0.0f, 0.0f}, {nv, -nv, nv}});
|
||||||
|
out_i.insert(out_i.end(), {3 + offset, 4 + offset, 5 + offset});
|
||||||
|
out_v.push_back({{-1.0f, 0.0f, 0.0f}, {-nv, -nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, 1.0f}, {-nv, -nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, -1.0f, 0.0f}, {-nv, -nv, nv}});
|
||||||
|
out_i.insert(out_i.end(), {6 + offset, 7 + offset, 8 + offset});
|
||||||
|
out_v.push_back({{0.0f, 1.0f, 0.0f}, {-nv, nv, nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, 1.0f}, {-nv, nv, nv}});
|
||||||
|
out_v.push_back({{-1.0f, 0.0f, 0.0f}, {-nv, nv, nv}});
|
||||||
|
out_i.insert(out_i.end(), {9 + offset, 10 + offset, 11 + offset});
|
||||||
|
out_v.push_back({{1.0f, 0.0f, 0.0f}, {nv, nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, 1.0f, 0.0f}, {nv, nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, -1.0f}, {nv, nv, -nv}});
|
||||||
|
out_i.insert(out_i.end(), {12 + offset, 13 + offset, 14 + offset});
|
||||||
|
out_v.push_back({{0.0f, -1.0f, 0.0f}, {nv, -nv, -nv}});
|
||||||
|
out_v.push_back({{1.0f, 0.0f, 0.0f}, {nv, -nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, -1.0f}, {nv, -nv, -nv}});
|
||||||
|
out_i.insert(out_i.end(), {15 + offset, 16 + offset, 17 + offset});
|
||||||
|
out_v.push_back({{-1.0f, 0.0f, 0.0f}, {-nv, -nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, -1.0f, 0.0f}, {-nv, -nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, -1.0f}, {-nv, -nv, -nv}});
|
||||||
|
out_i.insert(out_i.end(), {18 + offset, 19 + offset, 20 + offset});
|
||||||
|
out_v.push_back({{0.0f, 1.0f, 0.0f}, {-nv, nv, -nv}});
|
||||||
|
out_v.push_back({{-1.0f, 0.0f, 0.0f}, {-nv, nv, -nv}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, -1.0f}, {-nv, nv, -nv}});
|
||||||
|
out_i.insert(out_i.end(), {21 + offset, 22 + offset, 23 + offset});
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit gen_sphere(float radius, uint32_t slice, uint32_t stack) {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 2 + (stack - 1) * slice;
|
||||||
|
// vertices
|
||||||
|
out_v.push_back({{0.0f, 0.0f, radius}, {0.0f, 0.0f, 1.0f}, {0.5f, 0.0f}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, -radius}, {0.0f, 0.0f, -1.0f}, {0.5f, 1.0f}});
|
||||||
|
float za = pi / stack;
|
||||||
|
for(uint32_t i = 1; i < stack; ++i) {
|
||||||
|
float z = radius * std::cos(za);
|
||||||
|
float r = radius * std::sin(za);
|
||||||
|
float a = 0;
|
||||||
|
for(uint32_t s = 0; s < slice; ++s) {
|
||||||
|
float x = r * std::cos(a);
|
||||||
|
float y = r * std::sin(a);
|
||||||
|
tmath::fvec3 position = {x, y, z};
|
||||||
|
out_v.push_back({position, position * (1.0f / radius), {(x + 1.0f) * 0.5f, (1.0f - z / radius) * 0.5f}});
|
||||||
|
a += pi2 / slice;
|
||||||
|
}
|
||||||
|
za += pi / stack;
|
||||||
|
}
|
||||||
|
// draw indices
|
||||||
|
for(uint32_t i = 2; i < slice + 1; ++i)
|
||||||
|
out_i.insert(out_i.end(), {0, i + 1, i});
|
||||||
|
out_i.insert(out_i.end(), {0, 2, slice + 1});
|
||||||
|
for(uint32_t s = 0; s < stack - 2; ++s) {
|
||||||
|
uint32_t start = 2 + slice * s;
|
||||||
|
for(uint32_t i = start; i < start + slice - 1; ++i)
|
||||||
|
out_i.insert(out_i.end(), {i, i + 1, i + slice, i + slice, i + 1, i + slice + 1});
|
||||||
|
out_i.insert(out_i.end(), {start + slice - 1, start, start + slice * 2 - 1, start + slice * 2 - 1, start, start + slice});
|
||||||
|
}
|
||||||
|
uint32_t start = 2 + slice * (stack - 2);
|
||||||
|
for(uint32_t i = start; i < start + slice - 1; ++i)
|
||||||
|
out_i.insert(out_i.end(), {i, i + 1, 1});
|
||||||
|
out_i.insert(out_i.end(), {start + slice - 1, start, 1});
|
||||||
|
// fix offset
|
||||||
|
for(uint32_t i = ioffset; i < out_i.size(); ++i)
|
||||||
|
out_i[i] += offset;
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit gen_cylinder(float base, float top, float height, uint32_t slice, uint32_t stack) {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 2 + (stack + 3) * (slice + 1);
|
||||||
|
// vertices
|
||||||
|
out_v.push_back({{0.0f, 0.0f, height}, {0.0f, 0.0f, height}, {0.5f, 0.0f}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.5f, 1.0f}});
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
out_v.push_back({{std::cos(a * pi2) * top, std::sin(a * pi2) * top, height}, {0.0f, 0.0f, 1.0f}, {a, 0.0f}});
|
||||||
|
}
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
out_v.push_back({{std::cos(a * pi2) * base, std::sin(a * pi2) * base, 0.0f}, {0.0f, 0.0f, -1.0f}, {a, 1.0f}});
|
||||||
|
}
|
||||||
|
float z = height;
|
||||||
|
tmath::fvec3 norm = tmath::fvec3{top - base, 0, height}.cross(tmath::fvec3{0.0f, -1.0f, 0.0f}).normalize();
|
||||||
|
for(uint32_t zi = 0; zi < stack + 1; ++zi) {
|
||||||
|
float r = top + (base - top) * zi / stack;
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
float x = std::cos(a * pi2);
|
||||||
|
float y = std::sin(a * pi2);
|
||||||
|
out_v.push_back({{x * r, y * r, z}, {x * norm[0] - y * norm[1], y * norm[0] + x * norm[1], norm[2]}, {a, 1.0f - z / height}});
|
||||||
|
}
|
||||||
|
z -= height / stack;
|
||||||
|
}
|
||||||
|
// draw indices
|
||||||
|
for(uint32_t i = 2; i < 2 + slice; ++i)
|
||||||
|
out_i.insert(out_i.end(), {0, i + 1, i});
|
||||||
|
for(uint32_t i = 2 + slice + 1; i < 2 + slice * 2 + 1; ++i)
|
||||||
|
out_i.insert(out_i.end(), {1, i, i + 1});
|
||||||
|
for(uint32_t zi = 0; zi < stack; ++zi) {
|
||||||
|
uint32_t st = 2 + (zi + 2) * (slice + 1);
|
||||||
|
for(uint32_t i = st; i < st + slice; ++i)
|
||||||
|
out_i.insert(out_i.end(), {i, i + 1, i + slice + 1, i + slice + 1, i + 1, i + slice + 2});
|
||||||
|
}
|
||||||
|
// fix offset
|
||||||
|
for(uint32_t i = ioffset; i < out_i.size(); ++i)
|
||||||
|
out_i[i] += offset;
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
// radius = f(z)
|
||||||
|
template<typename F>
|
||||||
|
ModelUnit gen_solid_of_revolution(float zb, float zt, const F& f, uint32_t slice, uint32_t stack) {
|
||||||
|
uint32_t offset = out_v.size();
|
||||||
|
uint32_t ioffset = out_i.size();
|
||||||
|
// vert_count = 2 + (stack + 3) * (slice + 1);
|
||||||
|
// vertices
|
||||||
|
out_v.push_back({{0.0f, 0.0f, zt}, {0.0f, 0.0f, zt}, {0.5f, 0.0f}});
|
||||||
|
out_v.push_back({{0.0f, 0.0f, zb}, {0.0f, 0.0f, zb}, {0.5f, 1.0f}});
|
||||||
|
float top = f(zt);
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
out_v.push_back({{std::cos(a * pi2) * top, std::sin(a * pi2) * top, zt}, {0.0f, 0.0f, 1.0f}, {a, 0.0f}});
|
||||||
|
}
|
||||||
|
float base = f(zb);
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
out_v.push_back({{std::cos(a * pi2) * base, std::sin(a * pi2) * base, 0.0f}, {0.0f, 0.0f, -1.0f}, {a, 1.0f}});
|
||||||
|
}
|
||||||
|
rs::vector<float> rsample(stack + 1);
|
||||||
|
rs::vector<tmath::fvec3> norms(stack + 1);
|
||||||
|
float deltaz = (zb - zt) / stack;
|
||||||
|
for(uint32_t i = 0; i < stack + 1; ++i)
|
||||||
|
rsample[i] = f(zt + deltaz * i);
|
||||||
|
norms[0] = tmath::fvec3{rsample[0] - rsample[1], 0, -deltaz}.cross(tmath::fvec3{0.0f, -1.0f, 0.0f}).normalize();
|
||||||
|
for(uint32_t i = 1; i < stack; ++i)
|
||||||
|
norms[i] = tmath::fvec3{rsample[i - 1] - rsample[i + 1], 0, -deltaz * 2.0f}.cross(tmath::fvec3{0.0f, -1.0f, 0.0f}).normalize();
|
||||||
|
norms[stack] = tmath::fvec3{rsample[stack - 1] - rsample[stack], 0, -deltaz}.cross(tmath::fvec3{0.0f, -1.0f, 0.0f}).normalize();
|
||||||
|
// tmath::fvec3 norm = tmath::fvec3{top - base, 0, height}.cross(tmath::fvec3{0.0f, -1.0f, 0.0f}).normalize();
|
||||||
|
float z = zt;
|
||||||
|
for(uint32_t zi = 0; zi < stack + 1; ++zi) {
|
||||||
|
float r = rsample[zi];
|
||||||
|
tmath::fvec3& norm = norms[zi];
|
||||||
|
for(uint32_t i = 0; i < slice + 1; ++i) {
|
||||||
|
float a = (float)i / slice;
|
||||||
|
float x = std::cos(a * pi2);
|
||||||
|
float y = std::sin(a * pi2);
|
||||||
|
out_v.push_back({{x * r, y * r, z}, {x * norm[0] - y * norm[1], y * norm[0] + x * norm[1], norm[2]}, {a, 1.0f - deltaz * zi / (zb - zt)}});
|
||||||
|
}
|
||||||
|
z += deltaz;
|
||||||
|
}
|
||||||
|
// draw indices
|
||||||
|
for(uint32_t i = 2; i < 2 + slice; ++i)
|
||||||
|
out_i.insert(out_i.end(), {0, i + 1, i});
|
||||||
|
for(uint32_t i = 2 + slice + 1; i < 2 + slice * 2 + 1; ++i)
|
||||||
|
out_i.insert(out_i.end(), {1, i, i + 1});
|
||||||
|
for(uint32_t zi = 0; zi < stack; ++zi) {
|
||||||
|
uint32_t st = 2 + (zi + 2) * (slice + 1);
|
||||||
|
for(uint32_t i = st; i < st + slice; ++i)
|
||||||
|
out_i.insert(out_i.end(), {i, i + 1, i + slice + 1, i + slice + 1, i + 1, i + slice + 2});
|
||||||
|
}
|
||||||
|
// fix offset
|
||||||
|
for(uint32_t i = ioffset; i < out_i.size(); ++i)
|
||||||
|
out_i[i] += offset;
|
||||||
|
return ModelUnit{offset, (uint32_t)out_v.size() - offset, ioffset, (uint32_t)out_i.size() - ioffset};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t allocate_attribute_index() {
|
||||||
|
if(empty_indices.empty()) {
|
||||||
|
attrs.emplace_back();
|
||||||
|
return max_index++;
|
||||||
|
} else {
|
||||||
|
auto index = empty_indices.back();
|
||||||
|
empty_indices.pop_back();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelUnit clone_unit(ModelUnit pu) {
|
||||||
|
uint32_t new_voffset = out_v.size();
|
||||||
|
uint32_t new_ioffset = out_i.size();
|
||||||
|
out_v.insert(out_v.end(), &out_v[pu.vert_offset], &out_v[pu.vert_offset + pu.vert_count]);
|
||||||
|
out_i.insert(out_i.end(), &out_i[pu.index_offset], &out_i[pu.index_offset + pu.index_count]);
|
||||||
|
uint32_t diff = new_ioffset - pu.index_offset;
|
||||||
|
for(uint32_t i = new_ioffset; i < out_i.size(); ++i)
|
||||||
|
out_i[i] -= diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs::vector<Vertex>& all_vertices() { return out_v; }
|
||||||
|
rs::vector<uint32_t>& all_indices() { return out_i; }
|
||||||
|
rs::vector<VertexAttribute>& all_attributes() { return attrs; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
rs::vector<Vertex> out_v;
|
||||||
|
rs::vector<uint32_t> out_i;
|
||||||
|
rs::vector<uint32_t> empty_indices;
|
||||||
|
uint32_t max_index = 0;
|
||||||
|
rs::vector<VertexAttribute> attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,4 @@
|
||||||
|
cl /std:c++17 /EHsc /Zi -I%1/include -I%2/Include /c /Fd:build/main.pdb /Fo:build/main.obj main.cpp
|
||||||
|
cl /std:c++17 /EHsc /Zi -I%1/include -I%2/Include /c /Fd:build/vulkan.pdb /Fo:build/vulkan.obj vulkan.cpp
|
||||||
|
cl /std:c++17 /EHsc /Zi -I%1/include -I%2/Include /c /Fd:build/image.pdb /Fo:build/image.obj image.cpp
|
||||||
|
link /DEBUG:FULL /SUBSYSTEM:windows /ENTRY:mainCRTStartup /LIBPATH:%1/lib-vc2019 /LIBPATH:%2/Lib build/main.obj build/vulkan.obj build/image.obj glfw3dll.lib vulkan-1.lib shaderc_combined.lib /OUT:tacraft.exe
|
|
@ -0,0 +1,31 @@
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "deps/stb_image.h"
|
||||||
|
|
||||||
|
#include "image.hpp"
|
||||||
|
|
||||||
|
class ImageImpl : public Image {
|
||||||
|
public:
|
||||||
|
ImageImpl(unsigned char* data, int x, int y) : data(data), width(x), height(y) {}
|
||||||
|
ImageImpl(const ImageImpl&) = delete;
|
||||||
|
~ImageImpl() {
|
||||||
|
if(data)
|
||||||
|
stbi_image_free(data);
|
||||||
|
}
|
||||||
|
std::pair<int32_t, int32_t> img_size() override {
|
||||||
|
return std::make_pair(width, height);
|
||||||
|
}
|
||||||
|
const unsigned char* img_data() override {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* data = nullptr;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<Image> Image::load_from_file(const char* filename) {
|
||||||
|
int x, y, n;
|
||||||
|
auto data = stbi_load(filename, &x, &y, &n, STBI_rgb_alpha);
|
||||||
|
return std::make_shared<ImageImpl>(data, x, y);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _IMAGE_HPP_
|
||||||
|
#define _IMAGE_HPP_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Image> load_from_file(const char* filename);
|
||||||
|
|
||||||
|
virtual ~Image() = default;
|
||||||
|
virtual std::pair<int32_t, int32_t> img_size() = 0;
|
||||||
|
virtual const unsigned char* img_data() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,510 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_NONE
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "rusty.hpp"
|
||||||
|
#include "vulkan.hpp"
|
||||||
|
#include "tmath.hpp"
|
||||||
|
#include "image.hpp"
|
||||||
|
#include "model_object.hpp"
|
||||||
|
|
||||||
|
const uint32_t object_matrix_count = 2048;
|
||||||
|
|
||||||
|
struct GlobalVars {
|
||||||
|
tmath::fmat4 proj_view;
|
||||||
|
alignas(16) tmath::fvec3 light;
|
||||||
|
alignas(16) tmath::fvec3 eye;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
public:
|
||||||
|
~Application() {
|
||||||
|
if(device)
|
||||||
|
device->wait_idle();
|
||||||
|
swapchain.reset();
|
||||||
|
}
|
||||||
|
void init(GLFWwindow* window) {
|
||||||
|
mdl_objects.push_back(std::make_shared<mdo::MDLAxis>(verts));
|
||||||
|
field = std::make_shared<mdo::MDLField>(verts);
|
||||||
|
mdl_objects.push_back(field);
|
||||||
|
auto u1 = std::make_shared<mdo::MDLUnit1>(verts);
|
||||||
|
u1->set_pos(0, 0);
|
||||||
|
mdl_objects.push_back(u1);
|
||||||
|
auto u4 = std::make_shared<mdo::MDLUnit1>(verts);
|
||||||
|
u4->set_pos(4, 0);
|
||||||
|
u1->attack(*u4, 0.4f);
|
||||||
|
mdl_objects.push_back(u4);
|
||||||
|
this->window = window;
|
||||||
|
uint32_t ext_count;
|
||||||
|
const char** ext_names = glfwGetRequiredInstanceExtensions(&ext_count);
|
||||||
|
instance = vk::Instance::begin_build().set_application_name("Tacraft").set_enging_name("tacraft")
|
||||||
|
.set_layers({"VK_LAYER_LUNARG_standard_validation"})
|
||||||
|
.set_extensions(rs::vector<const char*>(ext_names, ext_names + ext_count))
|
||||||
|
.end();
|
||||||
|
physical_device = instance->enumerate_physical_device().nth(0).value();
|
||||||
|
auto maxsample = std::min(physical_device->properties()->limits.framebufferColorSampleCounts,
|
||||||
|
physical_device->properties()->limits.framebufferDepthSampleCounts);
|
||||||
|
|
||||||
|
VkSurfaceKHR raw_surface;
|
||||||
|
glfwCreateWindowSurface(instance->handle(), window, nullptr, &raw_surface);
|
||||||
|
surface = vk::Surface::from_raw_surface(raw_surface, *instance, *physical_device);
|
||||||
|
auto findex = physical_device->enumerate_queue_families().enumerate().filter([&](size_t idx, const VkQueueFamilyProperties* p) -> bool {
|
||||||
|
VkBool32 support_present = false;
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device->handle(), idx, raw_surface, &support_present);
|
||||||
|
return (p->queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && support_present
|
||||||
|
&& glfwGetPhysicalDevicePresentationSupport(instance->handle(), physical_device->handle(), idx);
|
||||||
|
}).unzip().first.nth(0).value();
|
||||||
|
|
||||||
|
device = vk::Device::begin_build(*physical_device).set_extensions({"VK_KHR_swapchain"})
|
||||||
|
.add_queue_family(findex, 1.0f).add_queue_family(findex, 1.0f)
|
||||||
|
.enable_features(*physical_device->supported_features())
|
||||||
|
.end();
|
||||||
|
auto gqueue = device->enumerate_queues().next().value();
|
||||||
|
auto pqueue = device->enumerate_queues().next().value_or(gqueue);
|
||||||
|
graphic_queue = *gqueue;
|
||||||
|
present_queue = *pqueue;
|
||||||
|
|
||||||
|
vert_shader = vk::ShaderModule::load_from_src(*device, "./shader/shader.vert", vk::ShaderModule::shader_type_vertex);
|
||||||
|
if(!vert_shader) {
|
||||||
|
std::cout << "vertex shader null!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frag_shader = vk::ShaderModule::load_from_src(*device, "./shader/shader.frag", vk::ShaderModule::shader_type_fragment);
|
||||||
|
if(!frag_shader) {
|
||||||
|
std::cout << "fragment shader null!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
render_pass = vk::RenderPass::begin_build(*device)
|
||||||
|
.set_samples(sample_count)
|
||||||
|
.end();
|
||||||
|
if(!render_pass) {
|
||||||
|
std::cout << "renderpass null!" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& vertices = verts.all_vertices();
|
||||||
|
auto& vert_indices = verts.all_indices();
|
||||||
|
vertex_buffer = vk::Buffer::begin_build(*device, *physical_device).alloc_size(vertices.size() * sizeof(Vertex))
|
||||||
|
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||||
|
.set_sharing_mode(VK_SHARING_MODE_EXCLUSIVE)
|
||||||
|
.set_cpu_accessible()
|
||||||
|
.end();
|
||||||
|
vertex_buffer->update_buffer(vertices.data(), vertices.size() * sizeof(Vertex));
|
||||||
|
index_buffer = vk::Buffer::begin_build(*device, *physical_device).alloc_size(vert_indices.size() * sizeof(uint32_t))
|
||||||
|
.set_usage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
|
||||||
|
.set_sharing_mode(VK_SHARING_MODE_EXCLUSIVE)
|
||||||
|
.set_cpu_accessible()
|
||||||
|
.end();
|
||||||
|
index_buffer->update_buffer(vert_indices.data(), vert_indices.size() * sizeof(uint32_t));
|
||||||
|
|
||||||
|
auto image = Image::load_from_file("res/snow.tga");
|
||||||
|
auto [imgx, imgy] = image->img_size();
|
||||||
|
img_buffer = vk::Buffer::begin_build(*device, *physical_device).alloc_size(imgx * imgy * 4 + 64)
|
||||||
|
.set_usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT)
|
||||||
|
.set_sharing_mode(VK_SHARING_MODE_EXCLUSIVE)
|
||||||
|
.set_cpu_accessible()
|
||||||
|
.end();
|
||||||
|
img_buffer->update_buffer(image->img_data(), imgx * imgy * 4);
|
||||||
|
memset(img_buffer->map(imgx * imgy * 4, 64), 0xff, 64);
|
||||||
|
img_buffer->unmap();
|
||||||
|
teximage = vk::Image::begin_build(*device, *physical_device)
|
||||||
|
.set_device_local()
|
||||||
|
.set_format(VK_FORMAT_R8G8B8A8_UNORM)
|
||||||
|
.set_extent({(uint32_t)imgx, (uint32_t)imgy, 1})
|
||||||
|
.end();
|
||||||
|
teximage_view = teximage->create_view(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
whiteimage = vk::Image::begin_build(*device, *physical_device)
|
||||||
|
.set_device_local()
|
||||||
|
.set_format(VK_FORMAT_R8G8B8A8_UNORM)
|
||||||
|
.set_extent({(uint32_t)4, (uint32_t)4, 1})
|
||||||
|
.end();
|
||||||
|
whiteimage_view = whiteimage->create_view(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
|
||||||
|
sampler = vk::Sampler::begin_build(*device).set_anisotrophy(16.0f).end();
|
||||||
|
descriptor_set_layout = vk::DescriptorSetLayout::begin_build(*device)
|
||||||
|
.add_binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER).set_count(1).set_stage(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
|
.add_binding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER).set_count(1).set_stage(VK_SHADER_STAGE_VERTEX_BIT)
|
||||||
|
.add_binding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER).set_count(2).set_stage(VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||||
|
.end();
|
||||||
|
descriptor_pool = vk::DescriptorPool::begin_build(*device).set_max_sets(2)
|
||||||
|
.add_pool_size(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 16)
|
||||||
|
.add_pool_size(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 16)
|
||||||
|
.add_pool_size(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 16)
|
||||||
|
.end();
|
||||||
|
descriptor_sets = descriptor_pool->alloc_descriptor_set(*descriptor_set_layout, 2);
|
||||||
|
uint32_t buffer_size = 0x100 + sizeof(VertexAttribute) * object_matrix_count;
|
||||||
|
for(uint32_t i = 0; i < 2; ++i) {
|
||||||
|
uniform_buffers.emplace_back(vk::Buffer::begin_build(*device, *physical_device).alloc_size(buffer_size)
|
||||||
|
.set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||||
|
.set_sharing_mode(VK_SHARING_MODE_EXCLUSIVE)
|
||||||
|
.set_cpu_accessible()
|
||||||
|
.end());
|
||||||
|
for(auto& ds : descriptor_sets) {
|
||||||
|
ds->update_write(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, 0)
|
||||||
|
.update_write_buffer_info(*uniform_buffers.back(), 0, sizeof(GlobalVars), 1)
|
||||||
|
.update_end();
|
||||||
|
ds->update_write(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, 0)
|
||||||
|
.update_write_buffer_info(*uniform_buffers.back(), 0x100, sizeof(VertexAttribute) * object_matrix_count, 1)
|
||||||
|
.update_write(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, 0)
|
||||||
|
.update_write_image_info(*whiteimage_view, *sampler)
|
||||||
|
.update_write_image_info(*teximage_view, *sampler)
|
||||||
|
.update_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_command_pool = vk::CommandPool::begin_build(*device)
|
||||||
|
.set_queue_family_index(graphic_queue.queue_family_index)
|
||||||
|
.set_pool_flag(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
|
||||||
|
.end();
|
||||||
|
onetime_command_pool = vk::CommandPool::begin_build(*device)
|
||||||
|
.set_queue_family_index(graphic_queue.queue_family_index)
|
||||||
|
.set_pool_flag(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT)
|
||||||
|
.end();
|
||||||
|
draw_command_pool->alloc_command_buffer(command_buffers, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2);
|
||||||
|
renderer = vk::Renderer::create_renderer(*device, 2);
|
||||||
|
|
||||||
|
onetime_command_pool->alloc_command_buffer(onetime_commands, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2);
|
||||||
|
onetime_commands[0]->begin_command(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT)
|
||||||
|
.add_image_memory_barrior(*teximage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
.image_set_access_mask(0, VK_ACCESS_TRANSFER_WRITE_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.begin_copy_buffer_to_image(*img_buffer, *teximage)
|
||||||
|
.add_region(0, {0, 0, 0}, {(uint32_t)imgx, (uint32_t)imgy, 1u})
|
||||||
|
.end_buffer_image_copy()
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||||
|
.add_image_memory_barrior(*teximage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
.image_set_access_mask(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.end_command();
|
||||||
|
onetime_commands[1]->begin_command(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT)
|
||||||
|
.add_image_memory_barrior(*whiteimage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
.image_set_access_mask(0, VK_ACCESS_TRANSFER_WRITE_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.begin_copy_buffer_to_image(*img_buffer, *whiteimage)
|
||||||
|
.add_region(imgx * imgy * 4, {0, 0, 0}, {4u, 4u, 1u})
|
||||||
|
.end_buffer_image_copy()
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
|
||||||
|
.add_image_memory_barrior(*whiteimage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
.image_set_access_mask(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.end_command();
|
||||||
|
recreate_sized_object();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_frame() {
|
||||||
|
if(skipdraw)
|
||||||
|
return;
|
||||||
|
if(recreate || renderer->out_of_date()) {
|
||||||
|
recreate_sized_object();
|
||||||
|
recreate = false;
|
||||||
|
}
|
||||||
|
uint32_t frame_index = renderer->prepare_for_next_frame();
|
||||||
|
uint32_t image_index = renderer->accquire_next_image(*swapchain);
|
||||||
|
if(renderer->out_of_date())
|
||||||
|
return;
|
||||||
|
// update attributes
|
||||||
|
// global_vars.light = tmath::fmat4::identity().translate(5.0f, 0.0f, 8.0f).rotatex(glfwGetTime() * 0.5f).rotatez(pi * 0.25f) * tmath::fvec3{0.0f, 0.0f, 0.0f};
|
||||||
|
for(auto& mdo : mdl_objects)
|
||||||
|
mdo->update(glfwGetTime());
|
||||||
|
auto ptr = uniform_buffers[frame_index]->map(0, 0x100 + sizeof(VertexAttribute) * object_matrix_count);
|
||||||
|
memcpy(ptr, &global_vars, sizeof(GlobalVars));
|
||||||
|
auto att_ptr = reinterpret_cast<VertexAttribute*>((uintptr_t)ptr + 0x100);
|
||||||
|
memcpy(att_ptr, verts.all_attributes().data(), verts.all_attributes().size() * sizeof(VertexAttribute));
|
||||||
|
uniform_buffers[frame_index]->unmap();
|
||||||
|
|
||||||
|
if(!onetime_commands.empty()) {
|
||||||
|
renderer->submit_onetime_command(graphic_queue, onetime_commands).wait_idle(graphic_queue);
|
||||||
|
onetime_commands.clear();
|
||||||
|
}
|
||||||
|
command_buffers[frame_index]->begin_command(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||||
|
.begin_render_pass(*render_pass, *framebuffers[image_index], VkClearValue{0.0, 0.0, 0.0, 0.8})
|
||||||
|
.bind_pipeline_and_descriptor_sets(*pipeline, *descriptor_sets[frame_index])
|
||||||
|
.draw_indexed(*vertex_buffer, *index_buffer, verts.all_indices().size())
|
||||||
|
.end_render_pass()
|
||||||
|
.end_command();
|
||||||
|
renderer->submit_draw_command(graphic_queue, *command_buffers[frame_index]);
|
||||||
|
renderer->present(present_queue, *swapchain, image_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recreate_sized_object() {
|
||||||
|
device->wait_idle();
|
||||||
|
swapchain = nullptr;
|
||||||
|
framebuffers.clear();
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
surface->refresh();
|
||||||
|
const VkSurfaceFormatKHR* format = surface->default_format();
|
||||||
|
auto caps = surface->capabilities();
|
||||||
|
swapchain = vk::Swapchain::begin_build(*device)
|
||||||
|
.set_surface(*surface)
|
||||||
|
.set_min_image_count(caps->maxImageCount)
|
||||||
|
.set_format(format->format)
|
||||||
|
.set_extent({(uint32_t)width, (uint32_t)height})
|
||||||
|
.set_image_usage(caps->supportedUsageFlags)
|
||||||
|
.set_queue_family_indices(device->queue_family_in_use())
|
||||||
|
.set_transform(caps->currentTransform)
|
||||||
|
.end();
|
||||||
|
auto swapchain_images = swapchain->get_swapchain_images();
|
||||||
|
|
||||||
|
depthimage = vk::Image::begin_build(*device, *physical_device)
|
||||||
|
.set_device_local()
|
||||||
|
.set_samples(sample_count)
|
||||||
|
.set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||||
|
.set_format(VK_FORMAT_D24_UNORM_S8_UINT)
|
||||||
|
.set_tilling(VK_IMAGE_TILING_OPTIMAL)
|
||||||
|
.set_extent({(uint32_t)width, (uint32_t)height, 1u})
|
||||||
|
.end();
|
||||||
|
depthimage_view = depthimage->create_view(VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
|
onetime_command_pool->alloc_command_buffer(onetime_commands, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
|
||||||
|
onetime_commands.back()->begin_command(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT)
|
||||||
|
.add_image_memory_barrior(*depthimage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||||
|
.image_set_access_mask(0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.end_command();
|
||||||
|
|
||||||
|
if(sample_count != VK_SAMPLE_COUNT_1_BIT) {
|
||||||
|
msaaimage = vk::Image::begin_build(*device, *physical_device)
|
||||||
|
.set_device_local()
|
||||||
|
.set_usage(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||||
|
.set_samples(sample_count)
|
||||||
|
.set_format(format->format)
|
||||||
|
.set_tilling(VK_IMAGE_TILING_OPTIMAL)
|
||||||
|
.set_extent({(uint32_t)width, (uint32_t)height, 1u})
|
||||||
|
.end();
|
||||||
|
msaaimage_view = msaaimage->create_view(format->format, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
onetime_command_pool->alloc_command_buffer(onetime_commands, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
|
||||||
|
onetime_commands.back()->begin_command(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||||
|
.begin_pipeline_barrior(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
|
||||||
|
.add_image_memory_barrior(*msaaimage)
|
||||||
|
.image_set_layout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||||
|
.image_set_aspect_mask(VK_IMAGE_ASPECT_COLOR_BIT)
|
||||||
|
.image_set_access_mask(0, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
|
||||||
|
.end_pipeline_barrior()
|
||||||
|
.end_command();
|
||||||
|
}
|
||||||
|
|
||||||
|
framebuffers.clear();
|
||||||
|
for(auto view : swapchain_images) {
|
||||||
|
if(sample_count == VK_SAMPLE_COUNT_1_BIT) {
|
||||||
|
framebuffers.emplace_back(vk::Framebuffer::begin_build(*device)
|
||||||
|
.set_render_pass(*render_pass)
|
||||||
|
.set_framebuffer_size(width, height)
|
||||||
|
.add_image_view(*view)
|
||||||
|
.add_image_view(*depthimage_view)
|
||||||
|
.end()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
framebuffers.emplace_back(vk::Framebuffer::begin_build(*device)
|
||||||
|
.set_render_pass(*render_pass)
|
||||||
|
.set_framebuffer_size(width, height)
|
||||||
|
.add_image_view(*msaaimage_view)
|
||||||
|
.add_image_view(*depthimage_view)
|
||||||
|
.add_image_view(*view)
|
||||||
|
.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pipeline = vk::Pipeline::begin_build(*device)
|
||||||
|
.set_render_pass(*render_pass)
|
||||||
|
.set_vertex_shader(*vert_shader)
|
||||||
|
.set_fragment_shader(*frag_shader)
|
||||||
|
.set_cull_mode(VK_CULL_MODE_BACK_BIT)
|
||||||
|
.normal_viewport((float)width, (float)height)
|
||||||
|
.normal_scissor((uint32_t)width, (uint32_t)height)
|
||||||
|
.add_descriptor_set_layout(*descriptor_set_layout)
|
||||||
|
.set_samples(sample_count)
|
||||||
|
.bind_vertex_size(sizeof(Vertex))
|
||||||
|
.add_binding_attribute(VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, position))
|
||||||
|
.add_binding_attribute(VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal))
|
||||||
|
.add_binding_attribute(VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texcoord))
|
||||||
|
.add_binding_attribute(VK_FORMAT_R32G32_SINT, offsetof(Vertex, index))
|
||||||
|
.end();
|
||||||
|
global_vars.proj_view = tmath::fmat4::perspective_fov(3.1415926f / 3.0f, (float)width / (float)height, 0.1f, 100.0f).scale(1.0f, -1.0f, 1.0f)
|
||||||
|
* tmath::fmat4::look_at({8.0f, 20.0f, 10.0f}, {8.0f, 10.0f, 0.0f}, {0.0f, 0.0f, 1.0f});
|
||||||
|
global_vars.light = {8.0f, 24.0f, 20.0f};
|
||||||
|
global_vars.eye = {8.0f, 20.0f, 10.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_buffer_to_image() {
|
||||||
|
|
||||||
|
}
|
||||||
|
void post_window_resized(bool skip = false) { skipdraw = skip; recreate = true; }
|
||||||
|
void mouse_move(float x, float y) {
|
||||||
|
auto& m = global_vars.proj_view;
|
||||||
|
float w = x * 2.0f / width - 1.0f;
|
||||||
|
float h = y * 2.0f / height - 1.0f;
|
||||||
|
float a1 = m[0] - w * m[3];
|
||||||
|
float b1 = m[4] - w * m[7];
|
||||||
|
float c1 = m[12] - w * m[15];
|
||||||
|
float a2 = m[1] - h * m[3];
|
||||||
|
float b2 = m[5] - h * m[7];
|
||||||
|
float c2 = m[13] - h * m[15];
|
||||||
|
float d = a1 * b2 - a2 * b1;
|
||||||
|
float zx = (b1 * c2 - b2 * c1) / d;
|
||||||
|
float zy = (c1 * a2 - c2 * a1) / d;
|
||||||
|
|
||||||
|
field->mouse_point(zx, zy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool recreate = false;
|
||||||
|
bool skipdraw = false;
|
||||||
|
GLFWwindow* window = nullptr;
|
||||||
|
std::shared_ptr<vk::Instance> instance;
|
||||||
|
const vk::PhysicalDevice* physical_device;
|
||||||
|
std::shared_ptr<vk::Device> device;
|
||||||
|
std::shared_ptr<vk::Swapchain> swapchain;
|
||||||
|
std::shared_ptr<vk::Surface> surface;
|
||||||
|
rs::vector<std::shared_ptr<vk::Framebuffer>> framebuffers;
|
||||||
|
std::shared_ptr<vk::ShaderModule> vert_shader;
|
||||||
|
std::shared_ptr<vk::ShaderModule> frag_shader;
|
||||||
|
std::shared_ptr<vk::RenderPass> render_pass;
|
||||||
|
std::shared_ptr<vk::Pipeline> pipeline;
|
||||||
|
std::shared_ptr<vk::CommandPool> draw_command_pool;
|
||||||
|
std::shared_ptr<vk::CommandPool> onetime_command_pool;
|
||||||
|
rs::vector<std::shared_ptr<vk::CommandBuffer>> command_buffers;
|
||||||
|
rs::vector<std::shared_ptr<vk::CommandBuffer>> onetime_commands;
|
||||||
|
std::shared_ptr<vk::Renderer> renderer;
|
||||||
|
vk::Queue graphic_queue;
|
||||||
|
vk::Queue present_queue;
|
||||||
|
std::shared_ptr<vk::Buffer> vertex_buffer;
|
||||||
|
std::shared_ptr<vk::Buffer> index_buffer;
|
||||||
|
rs::vector<std::shared_ptr<vk::Buffer>> uniform_buffers;
|
||||||
|
std::shared_ptr<vk::DescriptorSetLayout> descriptor_set_layout;
|
||||||
|
std::shared_ptr<vk::DescriptorPool> descriptor_pool;
|
||||||
|
rs::vector<std::shared_ptr<vk::DescriptorSet>> descriptor_sets;
|
||||||
|
std::shared_ptr<vk::Buffer> img_buffer;
|
||||||
|
std::shared_ptr<vk::Image> teximage;
|
||||||
|
std::shared_ptr<vk::Image> whiteimage;
|
||||||
|
std::shared_ptr<vk::Image> depthimage;
|
||||||
|
std::shared_ptr<vk::Image> msaaimage;
|
||||||
|
std::shared_ptr<vk::ImageView> teximage_view;
|
||||||
|
std::shared_ptr<vk::ImageView> whiteimage_view;
|
||||||
|
std::shared_ptr<vk::ImageView> depthimage_view;
|
||||||
|
std::shared_ptr<vk::ImageView> msaaimage_view;
|
||||||
|
std::shared_ptr<vk::Sampler> sampler;
|
||||||
|
GlobalVars global_vars;
|
||||||
|
VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_4_BIT;
|
||||||
|
VertCollection verts;
|
||||||
|
rs::vector<std::shared_ptr<ModelObject>> mdl_objects;
|
||||||
|
std::shared_ptr<mdo::MDLField> field;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
Application app;
|
||||||
|
|
||||||
|
void show_mat4(tmath::fmat4& m) {
|
||||||
|
printf("| %f %f %f %f |\n", m[0], m[4], m[8], m[12]);
|
||||||
|
printf("| %f %f %f %f |\n", m[1], m[5], m[9], m[13]);
|
||||||
|
printf("| %f %f %f %f |\n", m[2], m[6], m[10], m[14]);
|
||||||
|
printf("| %f %f %f %f |\n", m[3], m[7], m[11], m[15]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWwindow* window;
|
||||||
|
int dx, dy, dwx, dwy;
|
||||||
|
bool window_moving = false;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (!glfwInit())
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
if (!glfwVulkanSupported()) {
|
||||||
|
std::cout << "Vulkan not supported" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
||||||
|
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
||||||
|
window = glfwCreateWindow(1280, 800, "Tacraft!", NULL, NULL);
|
||||||
|
if (!window) {
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
||||||
|
int monitorX, monitorY;
|
||||||
|
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
|
||||||
|
int windowWidth, windowHeight;
|
||||||
|
glfwGetWindowSize(window, &windowWidth, &windowHeight);
|
||||||
|
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
|
||||||
|
float xscale, yscale;
|
||||||
|
glfwGetWindowContentScale(window, &xscale, &yscale);
|
||||||
|
|
||||||
|
app.init(window);
|
||||||
|
|
||||||
|
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||||
|
if(action == GLFW_PRESS) {
|
||||||
|
if(key == GLFW_KEY_ESCAPE)
|
||||||
|
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
glfwSetWindowSizeCallback(window, [](GLFWwindow* window, int x, int y) {
|
||||||
|
app.post_window_resized(x == 0 && y == 0);
|
||||||
|
});
|
||||||
|
glfwSetMouseButtonCallback(window, [](GLFWwindow*,int button,int action,int mods){
|
||||||
|
if(action == GLFW_PRESS) {
|
||||||
|
if(button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||||
|
double mx, my;
|
||||||
|
glfwGetWindowPos(window, &dwx, &dwy);
|
||||||
|
glfwGetCursorPos(window, &mx, &my);
|
||||||
|
dx = dwx + (int)mx;
|
||||||
|
dy = dwy + (int)my;
|
||||||
|
window_moving = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||||
|
window_moving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
glfwSetCursorPosCallback(window, [](GLFWwindow*,double x,double y) {
|
||||||
|
if(window_moving) {
|
||||||
|
int wx, wy, delx, dely;
|
||||||
|
glfwGetWindowPos(window, &wx, &wy);
|
||||||
|
delx = wx + (int)x - dx;
|
||||||
|
dely = wy + (int)y - dy;
|
||||||
|
glfwSetWindowPos(window, dwx + delx, dwy + dely);
|
||||||
|
}
|
||||||
|
app.mouse_move(x, y);
|
||||||
|
});
|
||||||
|
glfwSetTime(0.0);
|
||||||
|
double prev_time = 0.0;
|
||||||
|
double time_check= 0.0;
|
||||||
|
uint32_t frame = 0;
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
app.draw_frame();
|
||||||
|
frame++;
|
||||||
|
double curtime = glfwGetTime();
|
||||||
|
time_check += (curtime - prev_time);
|
||||||
|
prev_time = curtime;
|
||||||
|
if(time_check > 1.0) {
|
||||||
|
time_check -= 1.0;
|
||||||
|
char buffer[50];
|
||||||
|
sprintf(buffer, "Tacraft! %d", frame);
|
||||||
|
glfwSetWindowTitle(window, buffer);
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
|
@ -0,0 +1,329 @@
|
||||||
|
#ifndef _MODEL_OBJECT_HPP_
|
||||||
|
#define _MODEL_OBJECT_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "rusty.hpp"
|
||||||
|
#include "basic_model.hpp"
|
||||||
|
|
||||||
|
class SceneMgr {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelBasic {
|
||||||
|
public:
|
||||||
|
ModelBasic(ModelUnit u, VertCollection& v) : unit(u), vc(v) {}
|
||||||
|
|
||||||
|
const VertexAttribute& get_attribute() { return vc.all_attributes()[index[0]]; }
|
||||||
|
ModelBasic& set_attribute_index(uint32_t idx) {
|
||||||
|
index[0] = idx;
|
||||||
|
auto& vertices = vc.all_vertices();
|
||||||
|
for(uint32_t i = unit.vert_offset; i < unit.vert_offset + unit.vert_count; ++i)
|
||||||
|
vertices[i].index[0] = idx;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ModelBasic& set_texture_index(uint32_t idx) {
|
||||||
|
index[1] = idx;
|
||||||
|
auto& vertices = vc.all_vertices();
|
||||||
|
for(uint32_t i = unit.vert_offset; i < unit.vert_offset + unit.vert_count; ++i)
|
||||||
|
vertices[i].index[1] = idx;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
uint32_t att_index() { return index[0]; }
|
||||||
|
uint32_t tex_index() { return index[1]; }
|
||||||
|
ModelUnit model_info() { return unit; }
|
||||||
|
|
||||||
|
ModelBasic& set_matrix(tmath::fmat4 mat) {
|
||||||
|
vc.all_attributes()[index[0]].matrix = mat;
|
||||||
|
vc.all_attributes()[index[0]].nmatrix = mat.homo_inverse().transpose();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ModelBasic& set_matrix_no_normal(tmath::fmat4 mat) {
|
||||||
|
vc.all_attributes()[index[0]].matrix = mat;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
ModelBasic& set_color(tmath::fvec4 color) { vc.all_attributes()[index[0]].color = color; return *this; }
|
||||||
|
ModelBasic& set_mixcolor(tmath::fvec4 color) { vc.all_attributes()[index[0]].mixcolor = color; return *this; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelUnit unit;
|
||||||
|
uint32_t index[2];
|
||||||
|
VertCollection& vc;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelObject {
|
||||||
|
public:
|
||||||
|
virtual bool update(double tm) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mdo {
|
||||||
|
|
||||||
|
class MDLAxis : public ModelObject {
|
||||||
|
public:
|
||||||
|
MDLAxis(VertCollection& collection) {
|
||||||
|
auto m1 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
|
||||||
|
auto ptr1 = std::make_shared<ModelBasic>(m1, collection);
|
||||||
|
ptr1->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().rotatey(pi * 0.5f))
|
||||||
|
.set_color({1.0f, 0.0f, 0.0f, 1.0f});
|
||||||
|
units.push_back(ptr1);
|
||||||
|
|
||||||
|
auto m2 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
|
||||||
|
auto ptr2 = std::make_shared<ModelBasic>(m2, collection);
|
||||||
|
ptr2->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().rotatex(pi * -0.5f))
|
||||||
|
.set_color({0.0f, 0.85f, 0.3f, 1.0f});
|
||||||
|
units.push_back(ptr2);
|
||||||
|
|
||||||
|
auto m3 = collection.gen_cylinder(0.05f, 0.05f, 1.0f, 16, 1);
|
||||||
|
auto ptr3 = std::make_shared<ModelBasic>(m3, collection);
|
||||||
|
ptr3->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity())
|
||||||
|
.set_color({0.0f, 0.2f, 1.0f, 1.0f});
|
||||||
|
units.push_back(ptr3);
|
||||||
|
|
||||||
|
auto m4 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
|
||||||
|
auto ptr4 = std::make_shared<ModelBasic>(m4, collection);
|
||||||
|
ptr4->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().rotatey(pi * 0.5f).translate(1.0f, 0.0f, 0.0f))
|
||||||
|
.set_color({1.0f, 0.0f, 0.0f, 1.0f});
|
||||||
|
units.push_back(ptr4);
|
||||||
|
|
||||||
|
auto m5 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
|
||||||
|
auto ptr5 = std::make_shared<ModelBasic>(m5, collection);
|
||||||
|
ptr5->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().rotatex(pi * -0.5f).translate(0.0f, 1.0f, 0.0f))
|
||||||
|
.set_color({0.0f, 0.85f, 0.3f, 1.0f});
|
||||||
|
units.push_back(ptr5);
|
||||||
|
|
||||||
|
auto m6 = collection.gen_cylinder(0.1f, 0.0f, 0.2f, 16, 1);
|
||||||
|
auto ptr6 = std::make_shared<ModelBasic>(m6, collection);
|
||||||
|
ptr6->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().translate(0.0f, 0.0f, 1.0f))
|
||||||
|
.set_color({0.0f, 0.2f, 1.0f, 1.0f});
|
||||||
|
units.push_back(ptr6);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(double tm) override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<ModelBasic>> units;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MDLUnits : public ModelObject {
|
||||||
|
public:
|
||||||
|
static tmath::fvec3 pos_center(int32_t x, int32_t y) {
|
||||||
|
return tmath::fvec3{0.25f + x * 0.5f, 0.25f + (31 - y) * 0.5f, 0.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int32_t, int32_t> pos() { return std::make_pair(posx, posy); }
|
||||||
|
std::pair<int32_t, int32_t> target_pos() { return std::make_pair(tposx, tposy); }
|
||||||
|
void set_pos(int32_t x, int32_t y) {
|
||||||
|
posx = x;
|
||||||
|
posy = y;
|
||||||
|
auto pc = pos_center(x, y);
|
||||||
|
self_matrix = tmath::fmat4::identity().translate(pc[0], pc[1], pc[2]);
|
||||||
|
self_matrix_updated = true;
|
||||||
|
}
|
||||||
|
void set_target_pos(int32_t x, int32_t y) {
|
||||||
|
tposx = x;
|
||||||
|
tposy = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void move_to(int32_t x, int32_t y, float tm) = 0;
|
||||||
|
virtual void attack(MDLUnits&, float tm) = 0;
|
||||||
|
virtual void damage(MDLUnits&, float tm) = 0;
|
||||||
|
|
||||||
|
bool update(double tm) override {
|
||||||
|
last_update = tm;
|
||||||
|
self_matrix_updated = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t posx;
|
||||||
|
int32_t posy;
|
||||||
|
int32_t tposx;
|
||||||
|
int32_t tposy;
|
||||||
|
float last_update = 0.0f;
|
||||||
|
bool self_matrix_updated = false;
|
||||||
|
tmath::fmat4 self_matrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MDLField : public ModelObject {
|
||||||
|
public:
|
||||||
|
MDLField(VertCollection& collection) {
|
||||||
|
float tw = 1.0f / 32;
|
||||||
|
float th = 1.0f / 32;
|
||||||
|
for(uint32_t y = 0; y < 32; ++y) {
|
||||||
|
for(uint32_t x = 0; x < 32; ++x) {
|
||||||
|
auto m = collection.gen_square(tw * x, th * y, tw, th);
|
||||||
|
auto ptr = std::make_shared<ModelBasic>(m, collection);
|
||||||
|
ptr->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix_no_normal(tmath::fmat4::identity().scale(0.25f, 0.25f, 1.0f).translate(0.25f + x * 0.5f, 0.25f + y * 0.5f, 0.0f))
|
||||||
|
.set_texture_index(1);
|
||||||
|
units.push_back(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(double tm) override {
|
||||||
|
if(hindex != -1) {
|
||||||
|
units[hindex]->set_mixcolor({1.0f, 1.0f, 1.0f, std::sin((float)tm * 32.0f / pi) * 0.4f + 0.5f});
|
||||||
|
}
|
||||||
|
auto iter = status.begin();
|
||||||
|
while(iter != status.end()) {
|
||||||
|
auto cur = iter++;
|
||||||
|
float delta = (tm - cur->second) * 2.0f;
|
||||||
|
auto mc = units[cur->first]->get_attribute().mixcolor;
|
||||||
|
if(mc[3] > delta) {
|
||||||
|
mc[3] = mc[3] - delta;
|
||||||
|
units[cur->first]->set_mixcolor(mc);
|
||||||
|
cur->second = tm;
|
||||||
|
} else {
|
||||||
|
mc[3] = 0.0f;
|
||||||
|
units[cur->first]->set_mixcolor(mc);
|
||||||
|
status.erase(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_update = tm;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_point(float x, float y) {
|
||||||
|
int32_t idx = -1;
|
||||||
|
if(x > 0.0f && x < 16.0f && y > 0.0f && y < 16.0f) {
|
||||||
|
int32_t bx = (int32_t)(x * 2.0f);
|
||||||
|
int32_t by = (int32_t)(y * 2.0f);
|
||||||
|
idx = bx + by * 32;
|
||||||
|
}
|
||||||
|
if(hindex == idx)
|
||||||
|
return;
|
||||||
|
status.erase(idx);
|
||||||
|
if(hindex != -1) {
|
||||||
|
status[hindex] = last_update;
|
||||||
|
units[hindex]->set_mixcolor({1.0f, 1.0f, 1.0f, 0.9f});
|
||||||
|
}
|
||||||
|
hindex = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouse_press(bool up) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_object(std::weak_ptr<MDLUnits> obj, int32_t x, int32_t y) {
|
||||||
|
auto fid = uindex(x, y);
|
||||||
|
if(objects[fid].lock() != nullptr)
|
||||||
|
return;
|
||||||
|
objects[fid] = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MDLUnits> get_unit(int32_t x, int32_t y) {
|
||||||
|
return objects[uindex(x, y)].lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t uindex(int32_t x, int32_t y) { return x + (31 - y) * 32; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t hindex = -1;
|
||||||
|
float last_update = 0.0f;
|
||||||
|
rs::unordered_map<int32_t, float> status;
|
||||||
|
std::vector<std::shared_ptr<ModelBasic>> units;
|
||||||
|
std::weak_ptr<MDLUnits> objects[1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
class MDLUnit1 : public MDLUnits {
|
||||||
|
public:
|
||||||
|
MDLUnit1(VertCollection& collection) {
|
||||||
|
auto m1 = collection.gen_solid_of_revolution(0.0f, 1.0f, [](float z){ return (z - 0.55f) * (z - 0.55f)* 0.5f + 0.1f; }, 32, 32);
|
||||||
|
auto ptr1 = std::make_shared<ModelBasic>(m1, collection);
|
||||||
|
ptr1->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().scale(1.0f, 1.0f, 0.5f))
|
||||||
|
.set_color({0.0f, 0.8f, 0.3f, 1.0f});
|
||||||
|
units.push_back(ptr1);
|
||||||
|
|
||||||
|
auto m2 = collection.gen_octahedron();
|
||||||
|
auto ptr2 = std::make_shared<ModelBasic>(m2, collection);
|
||||||
|
ptr2->set_attribute_index(collection.allocate_attribute_index())
|
||||||
|
.set_matrix(tmath::fmat4::identity().scale(0.2f, 0.2f, 0.4f).translate(0.0f, 0.0f, 1.0f))
|
||||||
|
.set_color({0.7f, 0.1f, 0.3f, 0.8f});
|
||||||
|
units.push_back(ptr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(double tm) override {
|
||||||
|
bool updated = self_matrix_updated;
|
||||||
|
MDLUnits::update(tm);
|
||||||
|
for(auto iter = updator.begin(); iter != updator.end();) {
|
||||||
|
if((*iter)(tm))
|
||||||
|
updator.erase(iter++);
|
||||||
|
else
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
if(updated)
|
||||||
|
units[0]->set_matrix(self_matrix * tmath::fmat4::identity().scale(0.6f, 0.6f, 0.5f));
|
||||||
|
units[1]->set_matrix(self_matrix * tmath::fmat4::identity().scale(0.15f, 0.15f, 0.2f).rotatez(tm * 2.0f).translate(0.0f, 0.0f, 0.8f));
|
||||||
|
return !updator.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_to(int32_t x, int32_t y, float tm) {
|
||||||
|
auto cur = pos_center(posx, posy);
|
||||||
|
auto end = pos_center(x, y);
|
||||||
|
posx = x;
|
||||||
|
posy = y;
|
||||||
|
add_move(cur, end, tm, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void attack(MDLUnits& u, float tm) {
|
||||||
|
auto [x, y] = u.pos();
|
||||||
|
auto cur = pos_center(posx, posy);
|
||||||
|
auto src = pos_center(x, y);
|
||||||
|
auto end = cur + (src - cur) * 0.8f;
|
||||||
|
add_move(cur, end, tm * 0.5f, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, [this, &u, tm, end, cur](){
|
||||||
|
u.damage(*this, 0.2f);
|
||||||
|
add_move(end, cur, tm * 0.5f, {0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, nullptr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void damage(MDLUnits& u, float tm) {
|
||||||
|
auto [fx, fy] = u.pos();
|
||||||
|
auto cur = pos_center(posx, posy);
|
||||||
|
auto src = pos_center(fx, fy);
|
||||||
|
auto end = cur + (cur - src) * 0.25f;
|
||||||
|
add_move(cur, end, tm * 0.5f, {1.0f, 1.0f, 1.0f}, 0.0f, 0.9f, [this, tm, end, cur](){
|
||||||
|
add_move(end, cur, tm * 0.5f, {1.0f, 1.0f, 1.0f}, 0.9f, 0.0f, nullptr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_move(tmath::fvec3 from, tmath::fvec3 to, float tm, tmath::fvec3 mc, float a1, float a2, const std::function<void()>& end_cb) {
|
||||||
|
updator.push_back([this, from, to, st = last_update, tm, mc, a1, a2, end_cb](float t){
|
||||||
|
auto h = std::sqrt((to[0] - from[0]) * (to[0] - from[0]) + (to[1] - from[1]) * (to[1] - from[1]))* 1.0f;
|
||||||
|
if(t >= st + tm) {
|
||||||
|
if(end_cb)
|
||||||
|
end_cb();
|
||||||
|
for(auto& m : units)
|
||||||
|
m->set_mixcolor({mc[0], mc[1], mc[2], a2});
|
||||||
|
self_matrix = tmath::fmat4::identity().translate(to[0], to[1], to[2]);
|
||||||
|
self_matrix_updated = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
float factor = (t - st) / tm;
|
||||||
|
auto pos = from + (to - from) * factor;
|
||||||
|
for(auto& m : units)
|
||||||
|
m->set_mixcolor({mc[0], mc[1], mc[2], a1 + (a2 - a1) * factor});
|
||||||
|
self_matrix = tmath::fmat4::identity().translate(pos[0], pos[1], (factor - 0.5f) * (0.5f - factor) * h + h * 0.25f);
|
||||||
|
self_matrix_updated = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<ModelBasic>> units;
|
||||||
|
rs::list<std::function<bool(float)>> updator;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,500 @@
|
||||||
|
#ifndef _RC_ITER_HPP_
|
||||||
|
#define _RC_ITER_HPP_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace rs {
|
||||||
|
|
||||||
|
template<typename... ARGS>
|
||||||
|
struct InvokeType {
|
||||||
|
template<typename F>
|
||||||
|
auto Call(F f, ARGS... args) { return f(std::forward<ARGS>(args)...); }
|
||||||
|
template<typename F>
|
||||||
|
void CallNoReturn(F f, ARGS... args) { f(std::forward<ARGS>(args)...); }
|
||||||
|
template<typename F, typename S>
|
||||||
|
auto CallFold(F f, S s, ARGS... args) { return f(std::forward<S>(s), std::forward<ARGS>(args)...); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename U, typename V>
|
||||||
|
struct InvokeType<std::pair<U, V>> {
|
||||||
|
template<typename F>
|
||||||
|
auto Call(F f, std::pair<U, V> arg) { return f(arg.first, arg.second); }
|
||||||
|
template<typename F>
|
||||||
|
void CallNoReturn(F f, std::pair<U, V> arg) { f(arg.first, arg.second); }
|
||||||
|
template<typename F, typename S>
|
||||||
|
auto CallFold(F f, S s, std::pair<U, V> arg) { return f(std::forward<S>(s), arg.first, arg.second); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... ARGS>
|
||||||
|
struct InvokeType<std::tuple<ARGS...>> {
|
||||||
|
using sequence_type = std::index_sequence_for<ARGS...>;
|
||||||
|
template<typename F>
|
||||||
|
auto Call(F f, std::tuple<ARGS...> arg) { return UnpackCall(std::forward<F>(f), arg, sequence_type{}); }
|
||||||
|
template<typename F>
|
||||||
|
void CallNoReturn(F f, std::tuple<ARGS...> arg) { UnpackCallNoReturn(std::forward<F>(f), arg, sequence_type{}); }
|
||||||
|
template<typename F, typename S>
|
||||||
|
auto CallFold(F f, S s, std::tuple<ARGS...> arg) { return UnpackCallFold(std::forward<F>(f), std::forward<S>(s), arg, sequence_type{}); }
|
||||||
|
|
||||||
|
template<typename F, size_t... I>
|
||||||
|
auto UnpackCall(F f, std::tuple<ARGS...>& arg, std::index_sequence<I...>) { return f(std::get<I>(arg)...); }
|
||||||
|
template<typename F, size_t... I>
|
||||||
|
void UnpackCallNoReturn(F f, std::tuple<ARGS...>& arg, std::index_sequence<I...>) { f(std::get<I>(arg)...); }
|
||||||
|
template<typename F, typename S, size_t... I>
|
||||||
|
auto UnpackCallFold(F f, S s, std::tuple<ARGS...>& arg, std::index_sequence<I...>) { return f(s, std::get<I>(arg)...); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct StdFuncType {
|
||||||
|
using type = void;
|
||||||
|
using return_type = void;
|
||||||
|
};
|
||||||
|
template <typename RET, typename CLASS, typename... ARGS>
|
||||||
|
struct StdFuncType<RET (CLASS::*)(ARGS...) const> {
|
||||||
|
using type = std::function<RET(ARGS...)>;
|
||||||
|
using return_type = RET;
|
||||||
|
};
|
||||||
|
template <typename RET, typename CLASS, typename... ARGS>
|
||||||
|
struct StdFuncType<RET (CLASS::*)(ARGS...)> {
|
||||||
|
using type = std::function<RET(ARGS...)>;
|
||||||
|
using return_type = RET;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename HANDLER>
|
||||||
|
struct FunctionType {
|
||||||
|
using type = typename StdFuncType<decltype(&HANDLER::operator())>::type;
|
||||||
|
using return_type = typename StdFuncType<decltype(&HANDLER::operator())>::return_type;
|
||||||
|
};
|
||||||
|
template <typename RET, typename... ARGS>
|
||||||
|
struct FunctionType<RET (*)(ARGS...)> {
|
||||||
|
using type = std::function<RET(ARGS...)>;
|
||||||
|
using return_type = RET;
|
||||||
|
};
|
||||||
|
template <typename RET, typename... ARGS>
|
||||||
|
struct FunctionType<RET(ARGS...)> {
|
||||||
|
using type = std::function<RET(ARGS...)>;
|
||||||
|
using return_type = RET;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, template<typename... TARGS> typename TP>
|
||||||
|
struct TemplateChecker {
|
||||||
|
static constexpr bool value = false;
|
||||||
|
};
|
||||||
|
template <template<typename... TARGS> typename TP, typename... ARGS>
|
||||||
|
struct TemplateChecker<TP<ARGS...>, TP> {
|
||||||
|
static constexpr bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct iterator {
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
std::optional<T> next() {
|
||||||
|
return iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count() {
|
||||||
|
size_t result = 0;
|
||||||
|
for (auto n = next(); n.has_value(); n = next())
|
||||||
|
result++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> nth(size_t n) {
|
||||||
|
while (true) {
|
||||||
|
std::optional<T> value = next();
|
||||||
|
if (n-- == 0 || !value.has_value())
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<T> last() {
|
||||||
|
std::optional<T> value;
|
||||||
|
for (auto n = next(); n.has_value(); n = next())
|
||||||
|
value = n;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto step_by(int32_t s) {
|
||||||
|
return iterator<T>{[s, c = s, it = std::move(iter)]() mutable {
|
||||||
|
for (; c < s; c++)
|
||||||
|
it();
|
||||||
|
c = 1;
|
||||||
|
return it();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chain(iterator<T>&& i) {
|
||||||
|
return iterator<T>{[it1 = std::move(iter), it2 = std::move(i.iter), s = true]() mutable {
|
||||||
|
if (s) {
|
||||||
|
auto v = it1(true);
|
||||||
|
if (!v.has_value()) {
|
||||||
|
s = false;
|
||||||
|
return it2(true);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return it2(true);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
auto zip(iterator<U>&& i) {
|
||||||
|
return iterator<std::pair<T, U>>{[it1 = std::move(iter), it2 = std::move(i.iter)]() mutable {
|
||||||
|
if(auto v1 = it1(); v1.has_value()) {
|
||||||
|
if(auto v2 = it2(); v2.has_value())
|
||||||
|
return std::optional<std::pair<T, U>>(std::make_pair(v1.value(), v2.value()));
|
||||||
|
}
|
||||||
|
return std::optional<std::pair<T, U>>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void for_each(F f) {
|
||||||
|
for(auto v = next(); v.has_value(); v = next()) {
|
||||||
|
InvokeType<T>().CallNoReturn(std::ref(f), v.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto filter(F f) {
|
||||||
|
return iterator<T>{[f, it = std::move(iter)]() mutable {
|
||||||
|
auto value = it();
|
||||||
|
while(value.has_value() && !InvokeType<T>().Call(std::ref(f), value.value()))
|
||||||
|
value = it();
|
||||||
|
return value;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
auto map(M m) {
|
||||||
|
using RET = typename FunctionType<M>::return_type;
|
||||||
|
return iterator<RET>{[m, it = std::move(iter)]() {
|
||||||
|
auto t = it();
|
||||||
|
if (t.has_value())
|
||||||
|
return std::optional<RET>(InvokeType<T>().Call(std::ref(m), t.value()));
|
||||||
|
return std::optional<RET>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FM>
|
||||||
|
auto filter_map(FM fm) {
|
||||||
|
using OPT = typename FunctionType<FM>::return_type;
|
||||||
|
static_assert(TemplateChecker<OPT, std::optional>::value, "filter_map: filter must return an optional value.");
|
||||||
|
using RET = typename OPT::value_type;
|
||||||
|
return iterator<RET>{[fm, it = std::move(iter)]() {
|
||||||
|
auto value = it();
|
||||||
|
while (value.has_value()) {
|
||||||
|
if(auto mvalue = InvokeType<T>().Call(std::ref(fm), value.value()); mvalue.has_value())
|
||||||
|
return mvalue;
|
||||||
|
value = it();
|
||||||
|
}
|
||||||
|
return std::optional<RET>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto enumerate() {
|
||||||
|
return iterator<std::pair<size_t, T>>{[it = std::move(iter), i = 0]() mutable {
|
||||||
|
if(auto v = it(); v.has_value())
|
||||||
|
return std::optional<std::pair<size_t, T>>(std::make_pair(i++, v.value()));
|
||||||
|
return std::optional<std::pair<size_t, T>>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto skip(size_t n) {
|
||||||
|
return iterator<T>{[n, it = std::move(iter)]() mutable {
|
||||||
|
while (n > 0) {
|
||||||
|
n--;
|
||||||
|
it();
|
||||||
|
}
|
||||||
|
return it();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto take(size_t n) {
|
||||||
|
return iterator<T>{[n, it = std::move(iter)]() mutable {
|
||||||
|
if (n > 0) {
|
||||||
|
n--;
|
||||||
|
return it();
|
||||||
|
}
|
||||||
|
return std::optional<T>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
auto skip_while(F f) {
|
||||||
|
return iterator<T>{[f, it = std::move(iter), res = false]() mutable {
|
||||||
|
auto v = it();
|
||||||
|
if(res)
|
||||||
|
return v;
|
||||||
|
while(v.has_value() && InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
v = it();
|
||||||
|
res = true;
|
||||||
|
return v;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto take_while(F f) {
|
||||||
|
return iterator<T>{[f, it = std::move(iter), res = true]() mutable {
|
||||||
|
if (res) {
|
||||||
|
if(auto v = it(); v.has_value() && InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
return v;
|
||||||
|
else
|
||||||
|
res = false;
|
||||||
|
}
|
||||||
|
return std::optional<T>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename M>
|
||||||
|
auto scan(S s, M m) {
|
||||||
|
using RET = typename FunctionType<M>::return_type;
|
||||||
|
return iterator<RET>{[s, m, it = std::move(iter)]() mutable {
|
||||||
|
auto t = it();
|
||||||
|
if(t.has_value())
|
||||||
|
return std::optional<RET>(InvokeType<T>().CallFold(std::ref(m), std::ref(s), t.value()));
|
||||||
|
return std::optional<RET>();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename M>
|
||||||
|
auto flat_map(M m) {
|
||||||
|
return map(m).flatten();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flatten() {
|
||||||
|
static_assert(TemplateChecker<T, rs::iterator>::value, "flatten: value type can only be iterator type.");
|
||||||
|
using NT = typename T::value_type;
|
||||||
|
return iterator<NT>{[inited = false, cur = std::optional<iterator<NT>>(), it = std::move(iter)]() mutable {
|
||||||
|
if(!inited) {
|
||||||
|
cur = it();
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
if(!cur.has_value())
|
||||||
|
return std::optional<NT>();
|
||||||
|
auto v = cur.value().next();
|
||||||
|
while(!v.has_value() && cur.has_value()) {
|
||||||
|
cur = it();
|
||||||
|
if(cur.has_value())
|
||||||
|
v = cur.value().next();
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fuse() {
|
||||||
|
return iterator<T>{[end = false, it = std::move(iter)]() mutable {
|
||||||
|
if (end)
|
||||||
|
return std::optional<T>();
|
||||||
|
auto v = it();
|
||||||
|
if(!it.has_value())
|
||||||
|
end = true;
|
||||||
|
return v;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto inspect(F f) {
|
||||||
|
return iterator<T>{[f, it = std::move(iter)]() {
|
||||||
|
auto v = it();
|
||||||
|
if(v.has_value())
|
||||||
|
InvokeType<T>().CallNoReturn(std::ref(f), v.value());
|
||||||
|
return v;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
auto collect() {
|
||||||
|
C container;
|
||||||
|
for (auto v = next(); v.has_value(); v = next())
|
||||||
|
container.collect_item(v.value());
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
C& collect(C& container) {
|
||||||
|
for (auto v = next(); v.has_value(); v = next())
|
||||||
|
container.collect_item(v.value());
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C, typename F>
|
||||||
|
auto partition(F f) {
|
||||||
|
std::pair<C, C> result;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(InvokeType<T>().CallNoReturn(std::ref(f), v.value()))
|
||||||
|
result.first.collect_item(v.value());
|
||||||
|
else
|
||||||
|
result.second.collect_item(v.value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename F>
|
||||||
|
auto fold(S s, F f) {
|
||||||
|
using RET = typename FunctionType<F>::return_type;
|
||||||
|
static_assert(std::is_same<S, RET>::value, "fold: function should return same type as value.");
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
s = InvokeType<T>().CallFold(std::ref(f), s, v.value());
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
bool all(F f) {
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(!InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
bool any(F f) {
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto find(F f) {
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return std::optional<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto find_map(F f) {
|
||||||
|
using OPT = typename FunctionType<F>::return_type;
|
||||||
|
static_assert(TemplateChecker<OPT, std::optional>::value, "find_map: filter must return an optional value.");
|
||||||
|
using RET = typename OPT::value_type;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(auto mv = InvokeType<T>().Call(std::ref(f), v.value()); mv.has_value())
|
||||||
|
return mv;
|
||||||
|
}
|
||||||
|
return std::optional<RET>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto position(F f) {
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto v = next(); v.has_value(); v = next(), i++) {
|
||||||
|
if(InvokeType<T>().Call(std::ref(f), v.value()))
|
||||||
|
return std::optional<size_t>(i);
|
||||||
|
}
|
||||||
|
return std::optional<size_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto max() {
|
||||||
|
auto res = next();
|
||||||
|
if(!res.has_value())
|
||||||
|
return res;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(v.value() >= res.value())
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto min() {
|
||||||
|
auto res = next();
|
||||||
|
if(!res.has_value())
|
||||||
|
return res;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(v.value() < res.value())
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto max_by_key(F f) {
|
||||||
|
auto res = next();
|
||||||
|
if(!res.has_value())
|
||||||
|
return res;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(InvokeType<T>().Call(std::ref(f), v.value()) >= InvokeType<T>().Call(std::ref(f), res.value()))
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
auto min_by_key(F f) {
|
||||||
|
auto res = next();
|
||||||
|
if(!res.has_value())
|
||||||
|
return res;
|
||||||
|
for (auto v = next(); v.has_value(); v = next()) {
|
||||||
|
if(InvokeType<T>().Call(std::ref(f), v.value()) < InvokeType<T>().Call(std::ref(f), res.value()))
|
||||||
|
res = v;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unzip() {
|
||||||
|
static_assert(TemplateChecker<T, std::pair>::value, "unzip: iterator type must be pair");
|
||||||
|
using TP1 = typename T::first_type;
|
||||||
|
using TP2 = typename T::second_type;
|
||||||
|
std::pair<iterator<TP1>, iterator<TP2>> result;
|
||||||
|
result.first.iter = [it = iter](){
|
||||||
|
auto v = it();
|
||||||
|
return v.has_value() ? std::optional<TP1>(v.value().first): std::optional<TP1>();
|
||||||
|
};
|
||||||
|
result.second.iter = [it = iter](){
|
||||||
|
auto v = it();
|
||||||
|
return v.has_value() ? std::optional<TP2>(v.value().second): std::optional<TP2>();
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cycle() {
|
||||||
|
return iterator<T>{[it = iter, it2 = iter]() mutable {
|
||||||
|
auto v = it(false);
|
||||||
|
if(v.has_value())
|
||||||
|
return v;
|
||||||
|
it = it2;
|
||||||
|
return it(false);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sum() {
|
||||||
|
auto res = T(0);
|
||||||
|
for (auto v = next(); v.has_value(); v = next())
|
||||||
|
res += v.value();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto product() {
|
||||||
|
auto res = T(1);
|
||||||
|
for (auto v = next(); v.has_value(); v = next())
|
||||||
|
res *= v.value();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::function<std::optional<T>()> iter;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto range(T start, T end) {
|
||||||
|
return iterator<T>{[start, end]() mutable {
|
||||||
|
if(start >= end)
|
||||||
|
return std::optional<T>();
|
||||||
|
return std::optional<T>(start++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto repeat(T value) {
|
||||||
|
return iterator<T>{[value]() {
|
||||||
|
return std::optional<T>(value);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rs
|
||||||
|
#endif
|
|
@ -0,0 +1,258 @@
|
||||||
|
#ifndef _RC_HPP_
|
||||||
|
#define _RC_HPP_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <forward_list>
|
||||||
|
#include <deque>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rs_iter.hpp"
|
||||||
|
|
||||||
|
namespace rs {
|
||||||
|
|
||||||
|
template<typename P, typename TP>
|
||||||
|
class linear_container : public P {
|
||||||
|
public:
|
||||||
|
using P::P;
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<TP> into_iter() const {
|
||||||
|
if constexpr (!REV) {
|
||||||
|
return rs::iterator<TP>{[this, iter = this->begin()] () mutable {
|
||||||
|
if(iter == this->end())
|
||||||
|
return std::optional<TP>();
|
||||||
|
return std::optional<TP>(*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<TP>{[this, riter = this->rbegin()] () mutable {
|
||||||
|
if(riter == this->rend())
|
||||||
|
return std::optional<TP>();
|
||||||
|
return std::optional<TP>(*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<const TP*> into_iter_ptr() const {
|
||||||
|
if constexpr (!REV) {
|
||||||
|
return rs::iterator<const TP*>{[this, iter = this->cbegin()] () mutable {
|
||||||
|
if(iter == this->cend())
|
||||||
|
return std::optional<const TP*>();
|
||||||
|
return std::optional<const TP*>(&*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<const TP*>{[this, riter = this->crbegin()] () mutable {
|
||||||
|
if(riter == this->crend())
|
||||||
|
return std::optional<const TP*>();
|
||||||
|
return std::optional<const TP*>(&*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<TP*> into_iter_mptr() {
|
||||||
|
if constexpr (!REV) {
|
||||||
|
return rs::iterator<TP*>{[this, iter = this->begin()] () mutable {
|
||||||
|
if(iter == this->end())
|
||||||
|
return std::optional<TP*>();
|
||||||
|
return std::optional<TP*>(&*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<TP*>{[this, riter = this->rbegin()] () mutable {
|
||||||
|
if(riter == this->rend())
|
||||||
|
return std::optional<TP*>();
|
||||||
|
return std::optional<TP*>(&*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_item(const TP& v) {
|
||||||
|
this->push_back(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TP, typename ALLOC = std::allocator<TP>>
|
||||||
|
using vector = linear_container<std::vector<TP, ALLOC>, TP>;
|
||||||
|
template <typename TP, typename ALLOC = std::allocator<TP>>
|
||||||
|
using list = linear_container<std::list<TP, ALLOC>, TP>;
|
||||||
|
template <typename TP, typename ALLOC = std::allocator<TP>>
|
||||||
|
using forward_list = linear_container<std::forward_list<TP, ALLOC>, TP>;
|
||||||
|
template <typename TP, typename ALLOC = std::allocator<TP>>
|
||||||
|
using deque = linear_container<std::deque<TP, ALLOC>, TP>;
|
||||||
|
template <typename TP, size_t COUNT>
|
||||||
|
using array = linear_container<std::array<TP, COUNT>, TP>;
|
||||||
|
|
||||||
|
template<typename S, typename KEY, bool CanRev>
|
||||||
|
class set_container : public S {
|
||||||
|
public:
|
||||||
|
using S::S;
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<KEY> into_iter() const {
|
||||||
|
if constexpr (!REV || !CanRev) {
|
||||||
|
return rs::iterator<KEY>{[this, iter = this->begin()] () mutable {
|
||||||
|
if(iter == this->end())
|
||||||
|
return std::optional<KEY>();
|
||||||
|
return std::optional<KEY>(*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<KEY>{[this, riter = this->rbegin()] () mutable {
|
||||||
|
if(riter == this->rend())
|
||||||
|
return std::optional<KEY>();
|
||||||
|
return std::optional<KEY>(*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<const KEY*> into_iter_ptr() const {
|
||||||
|
if constexpr (!REV || !CanRev) {
|
||||||
|
return rs::iterator<const KEY*>{[this, iter = this->cbegin()] () mutable {
|
||||||
|
if(iter == this->cend())
|
||||||
|
return std::optional<const KEY*>();
|
||||||
|
return std::optional<const KEY*>(&*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<const KEY*>{[this, riter = this->crbegin()] () mutable {
|
||||||
|
if(riter == this->crend())
|
||||||
|
return std::optional<const KEY*>();
|
||||||
|
return std::optional<const KEY*>(&*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_item(const KEY& value) {
|
||||||
|
this->insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename KEY,
|
||||||
|
typename COMPARE = std::less<KEY>,
|
||||||
|
typename ALLOC = std::allocator<KEY>>
|
||||||
|
using set = set_container<std::set<KEY, COMPARE, ALLOC>, KEY, true>;
|
||||||
|
template<typename KEY,
|
||||||
|
typename COMPARE = std::less<KEY>,
|
||||||
|
typename ALLOC = std::allocator<KEY>>
|
||||||
|
using multiset = set_container<std::multiset<KEY, COMPARE, ALLOC>, KEY, true>;
|
||||||
|
template<typename KEY,
|
||||||
|
typename HASH = std::hash<KEY>,
|
||||||
|
typename PRED = std::equal_to<KEY>,
|
||||||
|
typename ALLOC = std::allocator<KEY>>
|
||||||
|
using unordered_set = set_container<std::unordered_set<KEY, HASH, PRED, ALLOC>, KEY, false>;
|
||||||
|
template<typename KEY, typename TP,
|
||||||
|
typename HASH = std::hash<KEY>,
|
||||||
|
typename PRED = std::equal_to<KEY>,
|
||||||
|
typename ALLOC = std::allocator<KEY>>
|
||||||
|
using unordered_multiset = set_container<std::unordered_multiset<KEY, HASH, PRED, ALLOC>, KEY, false>;
|
||||||
|
|
||||||
|
template<typename M, typename KEY, typename TP, bool CanRev>
|
||||||
|
class map_container : public M {
|
||||||
|
public:
|
||||||
|
using M::M;
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<std::pair<KEY, TP>> into_iter() const {
|
||||||
|
if constexpr (!REV || !CanRev) {
|
||||||
|
return rs::iterator<std::pair<KEY, TP>>{[this, iter = this->begin()] () mutable {
|
||||||
|
if(iter == this->end())
|
||||||
|
return std::optional<std::pair<KEY, TP>>();
|
||||||
|
return std::optional<std::pair<KEY, TP>>(*iter++);
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<std::pair<KEY, TP>>{[this, riter = this->rbegin()] () mutable {
|
||||||
|
if(riter == this->rend())
|
||||||
|
return std::optional<std::pair<KEY, TP>>();
|
||||||
|
return std::optional<std::pair<KEY, TP>>(*riter++);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<std::pair<const KEY*, const TP*>> into_iter_ptr() const {
|
||||||
|
if constexpr (!REV || !CanRev) {
|
||||||
|
return rs::iterator<std::pair<const KEY*, const TP*>>{[this, iter = this->cbegin()] (bool rev) mutable {
|
||||||
|
if(iter == this->cend())
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>();
|
||||||
|
auto ptr = &*iter++;
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>(std::make_pair(&ptr->first, &ptr->second));
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<std::pair<const KEY*, const TP*>>{[this, riter = this->crbegin()] (bool rev) mutable {
|
||||||
|
if(riter == this->crend())
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>();
|
||||||
|
auto ptr = &*riter++;
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>(std::make_pair(&ptr->first, &ptr->second));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool REV = false>
|
||||||
|
rs::iterator<std::pair<const KEY*, TP*>> into_iter_mptr() {
|
||||||
|
if constexpr (!REV || !CanRev) {
|
||||||
|
return rs::iterator<std::pair<const KEY*, const TP*>>{[this, iter = this->begin()] (bool rev) mutable {
|
||||||
|
if(iter == this->end())
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>();
|
||||||
|
auto ptr = &*iter++;
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>(std::make_pair(&ptr->first, &ptr->second));
|
||||||
|
}};
|
||||||
|
} else {
|
||||||
|
return rs::iterator<std::pair<const KEY*, const TP*>>{[this, riter = this->rbegin()] (bool rev) mutable {
|
||||||
|
if(riter == this->rend())
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>();
|
||||||
|
auto ptr = &*riter++;
|
||||||
|
return std::optional<std::pair<const KEY*, const TP*>>(std::make_pair(&ptr->first, &ptr->second));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rs::iterator<KEY> keys() const {
|
||||||
|
return into_iter().unzip().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs::iterator<const KEY*> keys_ptr() const {
|
||||||
|
return into_iter_ptr().unzip().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs::iterator<TP> values() const {
|
||||||
|
return into_iter().unzip().second;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs::iterator<const TP*> values_ptr() const {
|
||||||
|
return into_iter_ptr().unzip().second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_item(const std::pair<KEY, TP>& value) {
|
||||||
|
this->insert(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename KEY, typename TP,
|
||||||
|
typename COMPARE = std::less<KEY>,
|
||||||
|
typename ALLOC = std::allocator<std::pair<const KEY, TP>>>
|
||||||
|
using map = map_container<std::map<KEY, TP, COMPARE, ALLOC>, KEY, TP, true>;
|
||||||
|
template<typename KEY, typename TP,
|
||||||
|
typename COMPARE = std::less<KEY>,
|
||||||
|
typename ALLOC = std::allocator<std::pair<const KEY, TP>>>
|
||||||
|
using multimap = map_container<std::multimap<KEY, TP, COMPARE, ALLOC>, KEY, TP, true>;
|
||||||
|
template<typename KEY, typename TP,
|
||||||
|
typename HASH = std::hash<KEY>,
|
||||||
|
typename PRED = std::equal_to<KEY>,
|
||||||
|
typename ALLOC = std::allocator<std::pair<const KEY, TP>>>
|
||||||
|
using unordered_map = map_container<std::unordered_map<KEY, TP, HASH, PRED, ALLOC>, KEY, TP, false>;
|
||||||
|
template<typename KEY, typename TP,
|
||||||
|
typename HASH = std::hash<KEY>,
|
||||||
|
typename PRED = std::equal_to<KEY>,
|
||||||
|
typename ALLOC = std::allocator<std::pair<const KEY, TP>>>
|
||||||
|
using unordered_multimap = map_container<std::unordered_multimap<KEY, TP, HASH, PRED, ALLOC>, KEY, TP, false>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 frag_color;
|
||||||
|
layout(location = 1) in vec4 frag_mcolor;
|
||||||
|
layout(location = 2) in vec2 frag_texcoord;
|
||||||
|
layout(location = 3) in flat int frag_texindex;
|
||||||
|
layout(location = 4) in vec3 frag_pos;
|
||||||
|
layout(location = 5) in vec3 frag_normal;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform GlobalVars {
|
||||||
|
mat4 proj_view;
|
||||||
|
vec3 light;
|
||||||
|
vec3 eye;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
layout(binding = 2) uniform sampler2D teximage[2];
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// vec3 light_pos = vec3(5.0, 5.0, -5.0);
|
||||||
|
// vec3 view_pos = vec3(3.0, 3.0, 3.0);
|
||||||
|
|
||||||
|
float ambiant = 0.2;
|
||||||
|
|
||||||
|
vec3 light_dir = normalize(global.light - frag_pos);
|
||||||
|
float diff = max(dot(frag_normal, light_dir), 0.0);
|
||||||
|
|
||||||
|
float specular_strength = 0.7;
|
||||||
|
|
||||||
|
vec3 view_dir = normalize(global.eye - frag_pos);
|
||||||
|
vec3 reflect_dir = reflect(-light_dir, frag_normal);
|
||||||
|
float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 64);
|
||||||
|
float specular = specular_strength * spec;
|
||||||
|
|
||||||
|
float factor = ambiant + diff + specular;
|
||||||
|
vec4 pre_color = frag_color * texture(teximage[frag_texindex], frag_texcoord);
|
||||||
|
pre_color = vec4(mix((factor * pre_color).rgb, frag_mcolor.rgb, frag_mcolor.a), pre_color.a);
|
||||||
|
outColor = pre_color;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in vec3 normal;
|
||||||
|
layout(location = 2) in vec2 texcoord;
|
||||||
|
layout(location = 3) in ivec2 index;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
layout(location = 1) out vec4 frag_mcolor;
|
||||||
|
layout(location = 2) out vec2 frag_texcoord;
|
||||||
|
layout(location = 3) out int frag_texindex;
|
||||||
|
layout(location = 4) out vec3 frag_pos;
|
||||||
|
layout(location = 5) out vec3 frag_normal;
|
||||||
|
|
||||||
|
struct VertexAttribute {
|
||||||
|
mat4 matrix;
|
||||||
|
mat4 nmatrix;
|
||||||
|
vec4 color;
|
||||||
|
vec4 mixcolor;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 0) uniform GlobalVars {
|
||||||
|
mat4 proj_view;
|
||||||
|
vec3 light;
|
||||||
|
vec3 eye;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
layout (std430, binding = 1) buffer AttributeBlock {
|
||||||
|
VertexAttribute atts[2048];
|
||||||
|
} units;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = global.proj_view * units.atts[index[0]].matrix * vec4(position,1.0);
|
||||||
|
frag_color = units.atts[index[0]].color;
|
||||||
|
frag_mcolor = units.atts[index[0]].mixcolor;
|
||||||
|
frag_texcoord = texcoord;
|
||||||
|
frag_texindex = index[1];
|
||||||
|
frag_pos = vec3(units.atts[index[0]].matrix * vec4(position,1.0));
|
||||||
|
frag_normal = normalize(vec3(units.atts[index[0]].nmatrix * vec4(normal,1.0)));
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
#ifndef _TMATH_HPP_
|
||||||
|
#define _TMATH_HPP_
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
const float pi = 3.141593f;
|
||||||
|
const float pi2 = 6.283185f;
|
||||||
|
const float sr2 = 1.414214f;
|
||||||
|
const float isr2 = 0.7071068f;
|
||||||
|
|
||||||
|
namespace tmath {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct vec2 {
|
||||||
|
T val[2];
|
||||||
|
|
||||||
|
T& operator [] (int32_t idx) { return val[idx]; }
|
||||||
|
const T& operator [] (int32_t idx) const { return val[idx]; }
|
||||||
|
vec2<T> operator + (const vec2<T>& m) const { return vec2<T>{val[0] + m.val[0], val[1] + m.val[1]}; }
|
||||||
|
vec2<T> operator - (const vec2<T>& m) const { return vec2<T>{val[0] - m.val[0], val[1] - m.val[1]}; }
|
||||||
|
vec2<T> operator * (T scalar) const { return vec2<T>{val[0] * scalar, val[1] * scalar}; }
|
||||||
|
T dot(const vec2<T>& m) const { return val[0] * m.val[0] + val[1] * m.val[1]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct vec3 {
|
||||||
|
T val[3];
|
||||||
|
|
||||||
|
T& operator [] (int32_t idx) { return val[idx]; }
|
||||||
|
const T& operator [] (int32_t idx) const { return val[idx]; }
|
||||||
|
vec3<T> operator + (const vec3<T>& m) const { return vec3<T>{val[0] + m.val[0], val[1] + m.val[1], val[2] + m.val[2]}; }
|
||||||
|
vec3<T> operator - (const vec3<T>& m) const { return vec3<T>{val[0] - m.val[0], val[1] - m.val[1], val[2] - m.val[2]}; }
|
||||||
|
vec3<T> operator * (T scalar) const { return vec3<T>{val[0] * scalar, val[1] * scalar, val[2] * scalar}; }
|
||||||
|
T dot(const vec3<T>& m) const { return val[0] * m.val[0] + val[1] * m.val[1] + val[2] * m.val[2]; }
|
||||||
|
vec3<T> cross(const vec3<T>& m) const {
|
||||||
|
return vec3<T>{
|
||||||
|
val[1] * m.val[2] - val[2] * m.val[1],
|
||||||
|
val[2] * m.val[0] - val[0] * m.val[2],
|
||||||
|
val[0] * m.val[1] - val[1] * m.val[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
vec3<T> normalize() const {
|
||||||
|
T factor = std::sqrt(val[0] * val[0] + val[1] * val[1] + val[2] * val[2]);
|
||||||
|
return vec3<T>{val[0] / factor, val[1] / factor, val[2] / factor};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct vec4 {
|
||||||
|
T val[4];
|
||||||
|
|
||||||
|
T& operator [] (int32_t idx) { return val[idx]; }
|
||||||
|
const T& operator [] (int32_t idx) const { return val[idx]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// | 0 4 8 12 |
|
||||||
|
// | 1 5 9 13 |
|
||||||
|
// | 2 6 10 14 |
|
||||||
|
// | 3 7 11 15 |
|
||||||
|
template<typename T>
|
||||||
|
struct mat4 {
|
||||||
|
T val[16];
|
||||||
|
|
||||||
|
T& operator [] (int32_t idx) { return val[idx]; }
|
||||||
|
const T& operator [] (int32_t idx) const { return val[idx]; }
|
||||||
|
|
||||||
|
mat4<T> operator + (const mat4<T>& m) const {
|
||||||
|
return mat4<T> {
|
||||||
|
val[ 0] + m.val[ 0], val[ 1] + m.val[ 1], val[ 2] + m.val[ 2], val[ 3] + m.val[ 3],
|
||||||
|
val[ 4] + m.val[ 4], val[ 5] + m.val[ 5], val[ 6] + m.val[ 6], val[ 7] + m.val[ 7],
|
||||||
|
val[ 8] + m.val[ 8], val[ 9] + m.val[ 9], val[10] + m.val[10], val[11] + m.val[11],
|
||||||
|
val[12] + m.val[12], val[13] + m.val[13], val[14] + m.val[14], val[15] + m.val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3<T> operator * (const vec3<T>& m) const {
|
||||||
|
T fx = val[ 0] * m.val[0] + val[ 4] * m.val[1] + val[ 8] * m.val[2] + val[12];
|
||||||
|
T fy = val[ 1] * m.val[0] + val[ 5] * m.val[1] + val[ 9] * m.val[2] + val[13];
|
||||||
|
T fz = val[ 2] * m.val[0] + val[ 6] * m.val[1] + val[10] * m.val[2] + val[14];
|
||||||
|
T fw = val[ 3] * m.val[0] + val[ 7] * m.val[1] + val[11] * m.val[2] + val[15];
|
||||||
|
return vec3<T>{ fx / fw, fy / fw, fz / fw};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> operator * (const mat4<T>& m) const {
|
||||||
|
return mat4<T> {
|
||||||
|
val[ 0] * m.val[ 0] + val[ 4] * m.val[ 1] + val[ 8] * m.val[ 2] + val[12] * m.val[ 3],
|
||||||
|
val[ 1] * m.val[ 0] + val[ 5] * m.val[ 1] + val[ 9] * m.val[ 2] + val[13] * m.val[ 3],
|
||||||
|
val[ 2] * m.val[ 0] + val[ 6] * m.val[ 1] + val[10] * m.val[ 2] + val[14] * m.val[ 3],
|
||||||
|
val[ 3] * m.val[ 0] + val[ 7] * m.val[ 1] + val[11] * m.val[ 2] + val[15] * m.val[ 3],
|
||||||
|
val[ 0] * m.val[ 4] + val[ 4] * m.val[ 5] + val[ 8] * m.val[ 6] + val[12] * m.val[ 7],
|
||||||
|
val[ 1] * m.val[ 4] + val[ 5] * m.val[ 5] + val[ 9] * m.val[ 6] + val[13] * m.val[ 7],
|
||||||
|
val[ 2] * m.val[ 4] + val[ 6] * m.val[ 5] + val[10] * m.val[ 6] + val[14] * m.val[ 7],
|
||||||
|
val[ 3] * m.val[ 4] + val[ 7] * m.val[ 5] + val[11] * m.val[ 6] + val[15] * m.val[ 7],
|
||||||
|
val[ 0] * m.val[ 8] + val[ 4] * m.val[ 9] + val[ 8] * m.val[10] + val[12] * m.val[11],
|
||||||
|
val[ 1] * m.val[ 8] + val[ 5] * m.val[ 9] + val[ 9] * m.val[10] + val[13] * m.val[11],
|
||||||
|
val[ 2] * m.val[ 8] + val[ 6] * m.val[ 9] + val[10] * m.val[10] + val[14] * m.val[11],
|
||||||
|
val[ 3] * m.val[ 8] + val[ 7] * m.val[ 9] + val[11] * m.val[10] + val[15] * m.val[11],
|
||||||
|
val[ 0] * m.val[12] + val[ 4] * m.val[13] + val[ 8] * m.val[14] + val[12] * m.val[15],
|
||||||
|
val[ 1] * m.val[12] + val[ 5] * m.val[13] + val[ 9] * m.val[14] + val[13] * m.val[15],
|
||||||
|
val[ 2] * m.val[12] + val[ 6] * m.val[13] + val[10] * m.val[14] + val[14] * m.val[15],
|
||||||
|
val[ 3] * m.val[12] + val[ 7] * m.val[13] + val[11] * m.val[14] + val[15] * m.val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> translate(T tx, T ty, T tz) const {
|
||||||
|
return mat4<T>{
|
||||||
|
val[ 0] + val[ 3] * tx, val[ 1] + val[ 3] * ty, val[ 2] + val[ 3] * tz, val[ 3],
|
||||||
|
val[ 4] + val[ 7] * tx, val[ 5] + val[ 7] * ty, val[ 6] + val[ 7] * tz, val[ 7],
|
||||||
|
val[ 8] + val[11] * tx, val[ 9] + val[11] * ty, val[10] + val[11] * tz, val[11],
|
||||||
|
val[12] + val[15] * tx, val[13] + val[15] * ty, val[14] + val[15] * tz, val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> scale(T sx, T sy, T sz) const {
|
||||||
|
return mat4<T>{
|
||||||
|
val[ 0] * sx, val[ 1] * sy, val[ 2] * sz, val[ 3],
|
||||||
|
val[ 4] * sx, val[ 5] * sy, val[ 6] * sz, val[ 7],
|
||||||
|
val[ 8] * sx, val[ 9] * sy, val[10] * sz, val[11],
|
||||||
|
val[12] * sx, val[13] * sy, val[14] * sz, val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> rotatex(T rx) const {
|
||||||
|
T sv = std::sin(rx);
|
||||||
|
T cv = std::cos(rx);
|
||||||
|
return mat4<T>{
|
||||||
|
val[ 0], val[ 1] * cv - val[ 2] * sv, val[ 1] * sv + val[ 2] * cv, val[ 3],
|
||||||
|
val[ 4], val[ 5] * cv - val[ 6] * sv, val[ 5] * sv + val[ 6] * cv, val[ 7],
|
||||||
|
val[ 8], val[ 9] * cv - val[10] * sv, val[ 9] * sv + val[10] * cv, val[11],
|
||||||
|
val[12], val[13] * cv - val[14] * sv, val[13] * sv + val[14] * cv, val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> rotatey(T ry) const {
|
||||||
|
T sv = std::sin(ry);
|
||||||
|
T cv = std::cos(ry);
|
||||||
|
return mat4<T>{
|
||||||
|
val[ 0] * cv + val[ 2] * sv, val[ 1], -val[ 0] * sv + val[ 2] * cv, val[ 3],
|
||||||
|
val[ 4] * cv + val[ 6] * sv, val[ 5], -val[ 4] * sv + val[ 6] * cv, val[ 7],
|
||||||
|
val[ 8] * cv + val[10] * sv, val[ 9], -val[ 8] * sv + val[10] * cv, val[11],
|
||||||
|
val[12] * cv + val[14] * sv, val[13], -val[12] * sv + val[14] * cv, val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> rotatez(T rz) const {
|
||||||
|
T sv = std::sin(rz);
|
||||||
|
T cv = std::cos(rz);
|
||||||
|
return mat4<T>{
|
||||||
|
val[ 0] * cv - val[ 1] * sv, val[ 0] * sv + val[ 1] * cv, val[ 2], val[ 3],
|
||||||
|
val[ 4] * cv - val[ 5] * sv, val[ 4] * sv + val[ 5] * cv, val[ 6], val[ 7],
|
||||||
|
val[ 8] * cv - val[ 9] * sv, val[ 8] * sv + val[ 9] * cv, val[10], val[11],
|
||||||
|
val[12] * cv - val[13] * sv, val[12] * sv + val[13] * cv, val[14], val[15]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> homo_inverse() const {
|
||||||
|
T det = val[0] * val[5] * val[10] + val[4] * val[9] * val[2] + val[8] * val[1] * val[6]
|
||||||
|
-val[0] * val[6] * val[9] - val[1] * val[4] * val[10] - val[2] * val[5] * val[8];
|
||||||
|
T idet = (T)1.0 / det;
|
||||||
|
T adj0 = (val[5] * val[10] - val[6] * val[9]) * idet;
|
||||||
|
T adj1 = (val[4] * val[10] - val[6] * val[8]) * -idet;
|
||||||
|
T adj2 = (val[4] * val[9] - val[5] * val[8]) * idet;
|
||||||
|
T adj3 = (val[1] * val[10] - val[2] * val[9]) * -idet;
|
||||||
|
T adj4 = (val[0] * val[10] - val[2] * val[8]) * idet;
|
||||||
|
T adj5 = (val[0] * val[9] - val[1] * val[8]) * -idet;
|
||||||
|
T adj6 = (val[1] * val[6] - val[2] * val[5]) * idet;
|
||||||
|
T adj7 = (val[0] * val[6] - val[2] * val[4]) * -idet;
|
||||||
|
T adj8 = (val[0] * val[5] - val[1] * val[4]) * idet;
|
||||||
|
T d1 = -adj0 * val[12] - adj1 * val[13] - adj2 * val[14];
|
||||||
|
T d2 = -adj3 * val[12] - adj4 * val[13] - adj5 * val[14];
|
||||||
|
T d3 = -adj6 * val[12] - adj7 * val[13] - adj8 * val[14];
|
||||||
|
return mat4<T>{
|
||||||
|
adj0, adj3, adj6, (T)0,
|
||||||
|
adj1, adj4, adj7, (T)0,
|
||||||
|
adj2, adj5, adj8, (T)0,
|
||||||
|
d1, d2, d3, (T)1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
mat4<T> transpose() const {
|
||||||
|
return mat4<T>{
|
||||||
|
val[0], val[4], val[ 8], val[12],
|
||||||
|
val[1], val[5], val[ 9], val[13],
|
||||||
|
val[2], val[6], val[10], val[14],
|
||||||
|
val[3], val[7], val[11], val[15],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mat4<T> identity() {
|
||||||
|
return mat4<T>{(T)1, (T)0, (T)0, (T)0, (T)0, (T)1, (T)0, (T)0, (T)0, (T)0, (T)1, (T)0, (T)0, (T)0, (T)0, (T)1};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mat4<T> perspective(T width, T height, T near, T far, bool lh = true) {
|
||||||
|
T factor = lh ? (T)1 : (T)-1;
|
||||||
|
T val = far / (far - near);
|
||||||
|
return mat4<T>{
|
||||||
|
(T)2 * near / width, (T)0, (T)0, (T)0,
|
||||||
|
(T)0, (T)2 * near / height, (T)0, (T)0,
|
||||||
|
(T)0, (T)0, val * factor, (T)factor,
|
||||||
|
(T)0, (T)0, -near * val, (T)0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as glm::perspectiveNO, mapping z-axis to [-1, 1] (OpenGL clip volume definition)
|
||||||
|
static mat4<T> perspective_fov(T fov, T aspect, T near, T far, bool lh = true) {
|
||||||
|
T factor = lh ? (T)1 : (T)-1;
|
||||||
|
T yscale = (T)1 / std::tan(fov * (T)0.5);
|
||||||
|
T xscale = yscale / aspect;
|
||||||
|
T val = far / (far - near);
|
||||||
|
return mat4<T>{
|
||||||
|
xscale, (T)0, (T)0, (T)0,
|
||||||
|
(T)0, yscale, (T)0, (T)0,
|
||||||
|
(T)0, (T)0, (far + near) / (far - near) * factor, (T)factor,
|
||||||
|
(T)0, (T)0, -(T)2 * far * near / (far - near), (T)0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static mat4<T> orthogonal(T width, T height, T near, T far, bool lh = true) {
|
||||||
|
T factor = lh ? (T)1 : (T)-1;
|
||||||
|
T dist = far - near;
|
||||||
|
return mat4<T>{
|
||||||
|
(T)2 / width, (T)0, (T)0, (T)0,
|
||||||
|
(T)0, (T)2 / height, (T)0, (T)0,
|
||||||
|
(T)0, (T)0, factor / dist, -near / dist,
|
||||||
|
(T)0, (T)0, (T)0, (T)1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static mat4<T> look_at(vec3<T> eye, vec3<T> at, vec3<T> up, bool lh = true) {
|
||||||
|
T factor = lh ? (T)1 : (T)-1;
|
||||||
|
vec3<T> zaxis = (at - eye).normalize() * factor;
|
||||||
|
vec3<T> xaxis = up.cross(zaxis).normalize();
|
||||||
|
vec3<T> yaxis = zaxis.cross(xaxis);
|
||||||
|
return mat4<T>{
|
||||||
|
xaxis[0], yaxis[0], zaxis[0], (T)0,
|
||||||
|
xaxis[1], yaxis[1], zaxis[1], (T)0,
|
||||||
|
xaxis[2], yaxis[2], zaxis[2], (T)0,
|
||||||
|
-xaxis.dot(eye) * factor, -yaxis.dot(eye) * factor, -zaxis.dot(eye) * factor, (T)1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ivec2 = vec2<int32_t>;
|
||||||
|
using ivec3 = vec3<int32_t>;
|
||||||
|
using ivec4 = vec4<int32_t>;
|
||||||
|
using fvec2 = vec2<float>;
|
||||||
|
using fvec3 = vec3<float>;
|
||||||
|
using fvec4 = vec4<float>;
|
||||||
|
using fmat4 = mat4<float>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,373 @@
|
||||||
|
#ifndef _VULKAN_HPP_
|
||||||
|
#define _VULKAN_HPP_
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include "rusty.hpp"
|
||||||
|
|
||||||
|
namespace vk {
|
||||||
|
|
||||||
|
class InstanceBuilder;
|
||||||
|
class DeviceBuilder;
|
||||||
|
class BufferBuilder;
|
||||||
|
class ImageBuilder;
|
||||||
|
class SamplerBuilder;
|
||||||
|
class SwapchainBuilder;
|
||||||
|
class RenderPassBuilder;
|
||||||
|
class PipelineBuilder;
|
||||||
|
class FramebufferBuilder;
|
||||||
|
class CommandPoolBuilder;
|
||||||
|
class CommandBufferBuilder;
|
||||||
|
class DescriptorSetLayoutBuilder;
|
||||||
|
class DescriptorPoolBuilder;
|
||||||
|
|
||||||
|
struct Queue {
|
||||||
|
VkQueue handle;
|
||||||
|
uint32_t queue_family_index;
|
||||||
|
uint32_t queue_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PhysicalDevice {
|
||||||
|
public:
|
||||||
|
virtual ~PhysicalDevice() = default;
|
||||||
|
virtual VkPhysicalDevice handle() const = 0;
|
||||||
|
virtual const VkPhysicalDeviceProperties* properties() const = 0;
|
||||||
|
virtual const VkPhysicalDeviceMemoryProperties* mem_properties() const = 0;
|
||||||
|
virtual const VkPhysicalDeviceFeatures* supported_features() const = 0;
|
||||||
|
virtual rs::iterator<const VkExtensionProperties*> enumerate_extensions() const = 0;
|
||||||
|
virtual rs::iterator<const VkQueueFamilyProperties*> enumerate_queue_families() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Instance {
|
||||||
|
public:
|
||||||
|
static InstanceBuilder& begin_build();
|
||||||
|
virtual ~Instance() = default;
|
||||||
|
virtual VkInstance handle() const = 0;
|
||||||
|
virtual rs::iterator<const PhysicalDevice*> enumerate_physical_device() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Surface {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Surface> from_raw_surface(VkSurfaceKHR surface, const Instance& inst, const PhysicalDevice& physical_device);
|
||||||
|
virtual ~Surface() = default;
|
||||||
|
virtual VkSurfaceKHR handle() const = 0;
|
||||||
|
virtual void refresh() = 0;
|
||||||
|
virtual const VkSurfaceCapabilitiesKHR* capabilities() const = 0;
|
||||||
|
virtual rs::iterator<const VkSurfaceFormatKHR*> enumerate_formats() const = 0;
|
||||||
|
virtual const VkSurfaceFormatKHR* default_format() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
static DeviceBuilder& begin_build(const PhysicalDevice& physical_device);
|
||||||
|
virtual ~Device() = default;
|
||||||
|
virtual VkDevice handle() const = 0;
|
||||||
|
virtual void wait_idle() const = 0;
|
||||||
|
virtual rs::iterator<const Queue*> enumerate_queues() const = 0;
|
||||||
|
virtual rs::vector<uint32_t> queue_family_in_use() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Buffer {
|
||||||
|
public:
|
||||||
|
static BufferBuilder& begin_build(const Device& device, const PhysicalDevice& physical_device);
|
||||||
|
virtual ~Buffer() = default;
|
||||||
|
virtual VkBuffer handle() const = 0;
|
||||||
|
virtual bool can_map() const = 0;
|
||||||
|
virtual void* map(uint32_t offset, uint32_t size) = 0;
|
||||||
|
virtual void unmap() = 0;
|
||||||
|
virtual void update_buffer(const void* data, uint32_t size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImageView {
|
||||||
|
public:
|
||||||
|
virtual ~ImageView() = default;
|
||||||
|
virtual VkImageView handle() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
static ImageBuilder& begin_build(const Device& device, const PhysicalDevice& physical_device);
|
||||||
|
virtual ~Image() = default;
|
||||||
|
virtual VkImage handle() const = 0;
|
||||||
|
virtual std::shared_ptr<ImageView> create_view(VkFormat view_format, VkImageAspectFlags aspect) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sampler {
|
||||||
|
public:
|
||||||
|
static SamplerBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~Sampler() = default;
|
||||||
|
virtual VkSampler handle() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderModule {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<ShaderModule> load_from_spv(const Device& device, const std::string& filename);
|
||||||
|
static std::shared_ptr<ShaderModule> load_from_src(const Device& device, const std::string& filename, uint32_t kind);
|
||||||
|
virtual ~ShaderModule() = default;
|
||||||
|
virtual VkShaderModule handle() const = 0;
|
||||||
|
|
||||||
|
static const uint32_t shader_type_vertex = 0;
|
||||||
|
static const uint32_t shader_type_fragment = 1;
|
||||||
|
static const uint32_t shader_type_compute = 2;
|
||||||
|
static const uint32_t shader_type_geometry = 3;
|
||||||
|
static const uint32_t shader_type_tess_control = 4;
|
||||||
|
static const uint32_t shader_type_tess_evaluation = 5;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Swapchain {
|
||||||
|
public:
|
||||||
|
static SwapchainBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~Swapchain() = default;
|
||||||
|
virtual VkSwapchainKHR handle() const = 0;
|
||||||
|
virtual uint32_t image_count() const = 0;
|
||||||
|
virtual rs::vector<ImageView*> get_swapchain_images() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderPass {
|
||||||
|
public:
|
||||||
|
static RenderPassBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~RenderPass() = default;
|
||||||
|
virtual VkRenderPass handle() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorSet {
|
||||||
|
public:
|
||||||
|
virtual ~DescriptorSet() = default;
|
||||||
|
virtual VkDescriptorSet handle() const = 0;
|
||||||
|
virtual DescriptorSet& update_write(VkDescriptorType type, uint32_t binding, uint32_t start_index) = 0;
|
||||||
|
virtual DescriptorSet& update_write_buffer_info(const Buffer& buffer, uint32_t offset, uint32_t range, uint32_t rep_count) = 0;
|
||||||
|
virtual DescriptorSet& update_write_image_info(const ImageView& view, const Sampler& sampler) = 0;
|
||||||
|
virtual DescriptorSet& update_end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorSetLayout {
|
||||||
|
public:
|
||||||
|
static DescriptorSetLayoutBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~DescriptorSetLayout() = default;
|
||||||
|
virtual VkDescriptorSetLayout handle() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorPool {
|
||||||
|
public:
|
||||||
|
static DescriptorPoolBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~DescriptorPool() = default;
|
||||||
|
virtual VkDescriptorPool handle() const = 0;
|
||||||
|
virtual rs::vector<std::shared_ptr<DescriptorSet>> alloc_descriptor_set(const DescriptorSetLayout& layout, uint32_t count) = 0;
|
||||||
|
virtual void reset() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Pipeline {
|
||||||
|
public:
|
||||||
|
static PipelineBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~Pipeline() = default;
|
||||||
|
virtual VkPipeline handle() const = 0;
|
||||||
|
virtual VkPipelineLayout layout() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Framebuffer {
|
||||||
|
public:
|
||||||
|
static FramebufferBuilder& begin_build(const Device& device);
|
||||||
|
virtual ~Framebuffer() = default;
|
||||||
|
virtual VkFramebuffer handle() const = 0;
|
||||||
|
virtual VkExtent2D size() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandBuffer;
|
||||||
|
|
||||||
|
class CommandPipelineBarrierBuilder {
|
||||||
|
public:
|
||||||
|
virtual CommandPipelineBarrierBuilder& add_image_memory_barrior(const Image& img) = 0;
|
||||||
|
virtual CommandPipelineBarrierBuilder& image_set_layout(VkImageLayout old_layout, VkImageLayout new_layout) = 0;
|
||||||
|
virtual CommandPipelineBarrierBuilder& image_set_aspect_mask(VkImageAspectFlags aspect_mask) = 0;
|
||||||
|
virtual CommandPipelineBarrierBuilder& image_set_access_mask(VkAccessFlags src, VkAccessFlags dst) = 0;
|
||||||
|
virtual CommandBuffer& end_pipeline_barrior() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandBufferCopyBuilder {
|
||||||
|
public:
|
||||||
|
virtual CommandBufferCopyBuilder& add_region(uint32_t src_offset, uint32_t dst_offset, uint32_t size) = 0;
|
||||||
|
virtual CommandBuffer& end_buffer_copy() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandBufferImageCopyBuilder {
|
||||||
|
public:
|
||||||
|
virtual CommandBufferImageCopyBuilder& add_region(uint32_t offset, VkOffset3D img_offset, VkExtent3D img_extent) = 0;
|
||||||
|
virtual CommandBuffer& end_buffer_image_copy() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandBuffer {
|
||||||
|
public:
|
||||||
|
virtual ~CommandBuffer() = default;
|
||||||
|
virtual VkCommandBuffer handle() const = 0;
|
||||||
|
virtual CommandBuffer& begin_command(VkCommandBufferUsageFlags flag) = 0;
|
||||||
|
virtual void end_command() = 0;
|
||||||
|
virtual CommandBuffer& begin_render_pass(const RenderPass& pass, const Framebuffer& buffer, VkClearValue c) = 0;
|
||||||
|
virtual CommandBuffer& end_render_pass() = 0;
|
||||||
|
virtual CommandBuffer& bind_pipeline(const Pipeline& pipeline) = 0;
|
||||||
|
virtual CommandBuffer& bind_pipeline_and_descriptor_sets(const Pipeline& pipeline, const DescriptorSet& sets) = 0;
|
||||||
|
virtual CommandBuffer& draw(uint32_t count) = 0;
|
||||||
|
virtual CommandBuffer& draw_vertices(const Buffer& vertex_buffer, uint32_t count) = 0;
|
||||||
|
virtual CommandBuffer& draw_indexed(const Buffer& vertex_buffer, const Buffer& index_buffer, uint32_t count) = 0;
|
||||||
|
virtual CommandPipelineBarrierBuilder& begin_pipeline_barrior(VkPipelineStageFlags src, VkPipelineStageFlags dst) = 0;
|
||||||
|
virtual CommandBufferCopyBuilder& begin_copy_buffer(const Buffer& src, const Buffer& dst) = 0;
|
||||||
|
virtual CommandBufferImageCopyBuilder& begin_copy_buffer_to_image(const Buffer& src, const Image& dst) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandPool {
|
||||||
|
public:
|
||||||
|
static CommandPoolBuilder& begin_build(const Device& device);
|
||||||
|
virtual VkCommandPool handle() const = 0;
|
||||||
|
virtual rs::vector<std::shared_ptr<CommandBuffer>> alloc_command_buffer(VkCommandBufferLevel level, uint32_t count) = 0;
|
||||||
|
virtual CommandPool& alloc_command_buffer(rs::vector<std::shared_ptr<CommandBuffer>>& vec, VkCommandBufferLevel level, uint32_t count) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Renderer {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Renderer> create_renderer(const vk::Device& device, uint32_t img_count);
|
||||||
|
virtual ~Renderer() = default;
|
||||||
|
virtual uint32_t prepare_for_next_frame() = 0;
|
||||||
|
virtual uint32_t accquire_next_image(const Swapchain& swapchain) = 0;
|
||||||
|
virtual Renderer& submit_draw_command(const Queue& queue, const CommandBuffer& command_buffer) = 0;
|
||||||
|
virtual Renderer& present(const Queue& queue, const Swapchain& swapchain, uint32_t index) = 0;
|
||||||
|
virtual Renderer& wait_idle(const Queue& queue) = 0;
|
||||||
|
virtual Renderer& submit_onetime_command(const Queue& queue, rs::vector<std::shared_ptr<CommandBuffer>>& command_buffers) = 0;
|
||||||
|
virtual bool out_of_date() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
rs::vector<VkLayerProperties> list_layer_properties();
|
||||||
|
|
||||||
|
class InstanceBuilder {
|
||||||
|
public:
|
||||||
|
virtual InstanceBuilder& set_application_name(const char* name) = 0;
|
||||||
|
virtual InstanceBuilder& set_enging_name(const char* name) = 0;
|
||||||
|
virtual InstanceBuilder& set_application_version(uint32_t ver) = 0;
|
||||||
|
virtual InstanceBuilder& set_engine_version(uint32_t ver) = 0;
|
||||||
|
virtual InstanceBuilder& set_api_version(uint32_t ver) = 0;
|
||||||
|
virtual InstanceBuilder& set_layers(const rs::vector<const char*>& layers) = 0;
|
||||||
|
virtual InstanceBuilder& set_extensions(const rs::vector<const char*>& extensions) = 0;
|
||||||
|
virtual std::shared_ptr<Instance> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeviceBuilder {
|
||||||
|
public:
|
||||||
|
virtual DeviceBuilder& set_extensions(const rs::vector<const char*>& extensions) = 0;
|
||||||
|
virtual DeviceBuilder& add_queue_family(uint32_t queue_family_index, float priority) = 0;
|
||||||
|
virtual DeviceBuilder& enable_features(const VkPhysicalDeviceFeatures& features) = 0;
|
||||||
|
virtual std::shared_ptr<Device> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferBuilder {
|
||||||
|
public:
|
||||||
|
virtual BufferBuilder& alloc_size(size_t size) = 0;
|
||||||
|
virtual BufferBuilder& set_usage(VkBufferUsageFlags usage) = 0;
|
||||||
|
virtual BufferBuilder& set_sharing_mode(VkSharingMode mode) = 0;
|
||||||
|
virtual BufferBuilder& set_cpu_accessible() = 0;
|
||||||
|
virtual BufferBuilder& set_device_local() = 0;
|
||||||
|
virtual std::shared_ptr<Buffer> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImageBuilder {
|
||||||
|
public:
|
||||||
|
virtual ImageBuilder& set_type(VkImageType type) = 0;
|
||||||
|
virtual ImageBuilder& set_format(VkFormat format) = 0;
|
||||||
|
virtual ImageBuilder& set_extent(VkExtent3D ext) = 0;
|
||||||
|
virtual ImageBuilder& set_mip_level(uint32_t level) = 0;
|
||||||
|
virtual ImageBuilder& set_array_layers(uint32_t layer) = 0;
|
||||||
|
virtual ImageBuilder& set_samples(VkSampleCountFlagBits samples) = 0;
|
||||||
|
virtual ImageBuilder& set_tilling(VkImageTiling tiling) = 0;
|
||||||
|
virtual ImageBuilder& set_usage(VkImageUsageFlags usage) = 0;
|
||||||
|
virtual ImageBuilder& set_sharing_mode(VkSharingMode mode) = 0;
|
||||||
|
virtual ImageBuilder& set_init_layout(VkImageLayout layout) = 0;
|
||||||
|
virtual ImageBuilder& set_cpu_accessible() = 0;
|
||||||
|
virtual ImageBuilder& set_device_local() = 0;
|
||||||
|
virtual std::shared_ptr<Image> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SamplerBuilder {
|
||||||
|
public:
|
||||||
|
virtual SamplerBuilder& set_filter(VkFilter filter) = 0;
|
||||||
|
virtual SamplerBuilder& set_address_mode(VkSamplerAddressMode mode) = 0;
|
||||||
|
virtual SamplerBuilder& set_anisotrophy(float value) = 0;
|
||||||
|
virtual std::shared_ptr<Sampler> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwapchainBuilder {
|
||||||
|
public:
|
||||||
|
virtual SwapchainBuilder& set_surface(const Surface& surface) = 0;
|
||||||
|
virtual SwapchainBuilder& set_min_image_count(uint32_t count) = 0;
|
||||||
|
virtual SwapchainBuilder& set_format(VkFormat format) = 0;
|
||||||
|
virtual SwapchainBuilder& set_colorspace(VkColorSpaceKHR colorspace) = 0;
|
||||||
|
virtual SwapchainBuilder& set_extent(VkExtent2D ext) = 0;
|
||||||
|
virtual SwapchainBuilder& set_array_layer(uint32_t array_layer) = 0;
|
||||||
|
virtual SwapchainBuilder& set_image_usage(VkImageUsageFlags usage) = 0;
|
||||||
|
virtual SwapchainBuilder& set_queue_family_indices(const rs::vector<uint32_t>& queue_family_indices) = 0;
|
||||||
|
virtual SwapchainBuilder& set_transform(VkSurfaceTransformFlagBitsKHR transform) = 0;
|
||||||
|
virtual SwapchainBuilder& set_composite_alpha(VkCompositeAlphaFlagBitsKHR alpha) = 0;
|
||||||
|
virtual SwapchainBuilder& set_present_mode(VkPresentModeKHR mode) = 0;
|
||||||
|
virtual SwapchainBuilder& set_clipped(VkBool32 clipped) = 0;
|
||||||
|
virtual SwapchainBuilder& set_old_swapchain(Swapchain& old) = 0;
|
||||||
|
virtual std::shared_ptr<Swapchain> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderPassBuilder {
|
||||||
|
public:
|
||||||
|
virtual RenderPassBuilder& set_format(VkFormat format) = 0;
|
||||||
|
virtual RenderPassBuilder& set_samples(VkSampleCountFlagBits samples) = 0;
|
||||||
|
virtual std::shared_ptr<RenderPass> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorSetLayoutBuilder {
|
||||||
|
public:
|
||||||
|
virtual DescriptorSetLayoutBuilder& add_binding(VkDescriptorType type) = 0;
|
||||||
|
virtual DescriptorSetLayoutBuilder& set_count(uint32_t count) = 0;
|
||||||
|
virtual DescriptorSetLayoutBuilder& set_stage(VkShaderStageFlags stage) = 0;
|
||||||
|
virtual DescriptorSetLayoutBuilder& set_samplers() = 0;
|
||||||
|
virtual std::shared_ptr<DescriptorSetLayout> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorPoolBuilder {
|
||||||
|
public:
|
||||||
|
virtual DescriptorPoolBuilder& add_pool_size(VkDescriptorType type, uint32_t count) = 0;
|
||||||
|
virtual DescriptorPoolBuilder& set_max_sets(uint32_t count) = 0;
|
||||||
|
virtual DescriptorPoolBuilder& set_flags(VkDescriptorPoolCreateFlags flag) = 0;
|
||||||
|
virtual std::shared_ptr<DescriptorPool> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PipelineBuilder {
|
||||||
|
public:
|
||||||
|
virtual PipelineBuilder& set_render_pass(const RenderPass& render_pass) = 0;
|
||||||
|
virtual PipelineBuilder& set_vertex_shader(const ShaderModule& vert) = 0;
|
||||||
|
virtual PipelineBuilder& set_fragment_shader(const ShaderModule& frag) = 0;
|
||||||
|
virtual PipelineBuilder& normal_viewport(float w, float h) = 0;
|
||||||
|
virtual PipelineBuilder& normal_scissor(uint32_t w, uint32_t h) = 0;
|
||||||
|
virtual PipelineBuilder& draw_topology(VkPrimitiveTopology topology) = 0;
|
||||||
|
virtual PipelineBuilder& set_polygon_mode(VkPolygonMode mode) = 0;
|
||||||
|
virtual PipelineBuilder& set_cull_mode(VkCullModeFlags mode) = 0;
|
||||||
|
virtual PipelineBuilder& set_front_face(VkFrontFace front) = 0;
|
||||||
|
virtual PipelineBuilder& set_line_width(float width) = 0;
|
||||||
|
virtual PipelineBuilder& set_samples(VkSampleCountFlagBits samples) = 0;
|
||||||
|
virtual PipelineBuilder& bind_vertex_size(uint32_t sz) = 0;
|
||||||
|
virtual PipelineBuilder& add_binding_attribute(VkFormat format, uint32_t offset) = 0;
|
||||||
|
virtual PipelineBuilder& add_descriptor_set_layout(const DescriptorSetLayout& layout) = 0;
|
||||||
|
virtual std::shared_ptr<Pipeline> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FramebufferBuilder {
|
||||||
|
public:
|
||||||
|
virtual FramebufferBuilder& set_render_pass(const RenderPass& render_pass) = 0;
|
||||||
|
virtual FramebufferBuilder& set_framebuffer_size(uint32_t width, uint32_t height) = 0;
|
||||||
|
virtual FramebufferBuilder& add_image_view(const ImageView& view) = 0;
|
||||||
|
virtual FramebufferBuilder& set_layer(uint32_t layer) = 0;
|
||||||
|
virtual std::shared_ptr<Framebuffer> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandPoolBuilder {
|
||||||
|
public:
|
||||||
|
virtual CommandPoolBuilder& set_queue_family_index(uint32_t idx) = 0;
|
||||||
|
virtual CommandPoolBuilder& set_pool_flag(VkCommandPoolCreateFlags flags) = 0;
|
||||||
|
virtual std::shared_ptr<CommandPool> end() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _VULKAN_HPP_
|
Loading…
Reference in New Issue