first commit

This commit is contained in:
Argon 2022-12-15 10:28:00 +08:00
commit f1263d46c7
14 changed files with 4388 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
.vscode/
.idea/
build/
deps/
res/
*.obj
*.pdb
*.dll
*.exe
*.spv
*.ilk

317
basic_model.hpp Normal file
View File

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

4
build.bat Normal file
View File

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

31
image.cpp Normal file
View File

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

15
image.hpp Normal file
View File

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

510
main.cpp Normal file
View File

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

329
model_object.hpp Normal file
View File

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

500
rs_iter.hpp Normal file
View File

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

258
rusty.hpp Normal file
View File

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

40
shader/shader.frag Normal file
View File

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

40
shader/shader.vert Normal file
View File

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

253
tmath.hpp Normal file
View File

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

1707
vulkan.cpp Normal file

File diff suppressed because it is too large Load Diff

373
vulkan.hpp Normal file
View File

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