separate initialization codes of GL objects

This commit is contained in:
falsycat 2022-10-19 01:06:45 +09:00
parent 0a55250f52
commit 96fd71df07
4 changed files with 287 additions and 229 deletions

View File

@ -308,8 +308,10 @@ class Future final {
}
// Finalizes the other promise on finalize of this future.
ThisFuture& Chain(auto& pro, auto&& func) noexcept {
return Then([pro, func = std::move(func)](auto& fu) mutable {
ThisFuture& Chain(nf7::Env::Executor exec,
const std::shared_ptr<nf7::Context>& ctx,
auto& pro, auto&& func) noexcept {
return Then(exec, ctx, [pro, func = std::move(func)](auto& fu) mutable {
try {
pro.Return(func(fu.value()));
} catch (...) {
@ -317,6 +319,12 @@ class Future final {
}
});
}
ThisFuture& Chain(const std::shared_ptr<nf7::Context>& ctx, auto& pro, auto&& func) noexcept {
return Chain(nf7::Env::kSub, ctx, pro, std::move(func));
}
ThisFuture& Chain(auto& pro, auto&& func) noexcept {
return Chain(nullptr, pro, std::move(func));
}
const auto& value() const {
if (imm_) {

View File

@ -12,18 +12,194 @@
namespace nf7::gl {
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>>
Obj_VertexArrayMeta::LockBuffers(
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt, size_t icnt) const noexcept
nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Obj_BufferMeta::Create(
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, type, pro]() mutable {
GLuint id;
glGenBuffers(1, &id);
pro.Return(std::make_shared<Obj<Obj_BufferMeta>>(ctx, id, type));
});
return pro.future();
}
nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Obj_TextureMeta::Create(
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, type, pro]() mutable {
GLuint id;
glGenTextures(1, &id);
pro.Return(std::make_shared<Obj<Obj_TextureMeta>>(ctx, id, type));
});
return pro.future();
}
nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Obj_ShaderMeta::Create(
const std::shared_ptr<nf7::Context>& ctx,
GLenum type,
const std::string& src) noexcept {
nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, type, src, pro]() mutable {
const auto id = glCreateShader(type);
if (id == 0) {
pro.Throw<nf7::Exception>("failed to allocate new shader");
return;
}
const GLchar* str = src.c_str();
glShaderSource(id, 1, &str, nullptr);
glCompileShader(id);
assert(0 == glGetError());
GLint status;
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
if (status == GL_TRUE) {
pro.Return(std::make_shared<Obj<Obj_ShaderMeta>>(ctx, id, type));
} else {
GLint len;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &len);
std::string ret(static_cast<size_t>(len), ' ');
glGetShaderInfoLog(id, len, nullptr, ret.data());
pro.Throw<nf7::Exception>(std::move(ret));
}
});
return pro.future();
}
nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Obj_ProgramMeta::Create(
const std::shared_ptr<nf7::Context>& ctx,
const std::vector<nf7::File::Id>& shaders) noexcept {
nf7::AggregatePromise apro {ctx};
std::vector<nf7::Future<nf7::Mutex::Resource<std::shared_ptr<gl::Shader>>>> shs;
for (auto shader : shaders) {
shs.emplace_back(ctx->env().GetFileOrThrow(shader).
interfaceOrThrow<nf7::gl::ShaderFactory>().Create());
apro.Add(shs.back());
}
nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>>::Promise pro {ctx};
apro.future().Chain(nf7::Env::kGL, ctx, pro, [ctx, shs = std::move(shs)](auto&) {
// check all shaders
for (auto& sh : shs) { sh.value(); }
// create program
const auto id = glCreateProgram();
if (id == 0) {
throw nf7::Exception {"failed to allocate new program"};
}
// attach shaders
for (auto& sh : shs) {
glAttachShader(id, (*sh.value())->id());
}
glLinkProgram(id);
// check status
GLint status;
glGetProgramiv(id, GL_LINK_STATUS, &status);
if (status == GL_TRUE) {
return std::make_shared<Obj<Obj_ProgramMeta>>(ctx, id);
} else {
GLint len;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &len);
std::string ret(static_cast<size_t>(len), ' ');
glGetProgramInfoLog(id, len, nullptr, ret.data());
throw nf7::Exception {std::move(ret)};
}
});
return pro.future();
}
nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>> Obj_VertexArrayMeta::Create(
const std::shared_ptr<nf7::Context>& ctx, std::vector<Attr>&& attrs) noexcept
try {
nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>>::Promise pro {ctx};
LockBuffers(ctx, attrs).Chain(
nf7::Env::kGL, ctx, pro,
[ctx, attrs = std::move(attrs), pro](auto& bufs) mutable {
// check all buffers
assert(attrs.size() == bufs.size());
for (auto& buf : bufs) {
if ((*buf.value()).meta().type != GL_ARRAY_BUFFER) {
throw nf7::Exception {"buffer is not Array"};
}
}
GLuint id;
glGenVertexArrays(1, &id);
glBindVertexArray(id);
for (size_t i = 0; i < attrs.size(); ++i) {
const auto& attr = attrs[i];
const auto& buf = *bufs[i].value();
glBindBuffer(GL_ARRAY_BUFFER, buf.id());
glEnableVertexAttribArray(attr.index);
glVertexAttribDivisor(attr.index, attr.divisor);
glVertexAttribPointer(
attr.index,
attr.size,
attr.type,
attr.normalize,
attr.stride,
reinterpret_cast<GLvoid*>(static_cast<GLintptr>(attr.offset)));
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
assert(0 == glGetError());
return std::make_shared<Obj<Obj_VertexArrayMeta>>(ctx, id, std::move(attrs));
});
return pro.future();
} catch (nf7::Exception&) {
return {std::current_exception()};
}
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>> Obj_VertexArrayMeta::LockBuffers(
const std::shared_ptr<nf7::Context>& ctx,
const std::vector<Attr>& attrs,
size_t vcnt, size_t icnt) noexcept
try {
std::vector<nf7::gl::BufferFactory::Product> fus;
nf7::AggregatePromise lock_pro {ctx};
nf7::AggregatePromise apro {ctx};
for (const auto& attr : attrs) {
auto& f = ctx->env().GetFileOrThrow(attr.id);
nf7::File& f = ctx->env().GetFileOrThrow(attr.buffer);
// calculate size required to the buffer
const auto required = std::max(attr.size_per_vertex*vcnt, attr.size_per_instance*icnt);
size_t required = 0;
if (attr.divisor == 0 && vcnt > 0) {
required = static_cast<size_t>(attr.size)*vcnt;
switch (attr.type) {
case GL_UNSIGNED_BYTE:
case GL_BYTE:
required *= 1;
break;
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_HALF_FLOAT:
required *= 2;
break;
case GL_UNSIGNED_INT:
case GL_INT:
case GL_FLOAT:
required *= 4;
break;
case GL_DOUBLE:
required *= 8;
break;
default:
throw nf7::Exception {"unknown attribute type"};
}
} else if (attr.divisor > 0 && icnt > 0) {
required = static_cast<size_t>(attr.stride)*(icnt-1) + attr.offset;
}
// validation after the lock
nf7::Future<nf7::Mutex::Resource<std::shared_ptr<nf7::gl::Buffer>>>::Promise pro {ctx};
@ -36,16 +212,16 @@ try {
});
// register a future of the validation
lock_pro.Add(pro.future());
apro.Add(pro.future());
fus.emplace_back(pro.future());
}
// wait for all registered futures
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>>::Promise pro {ctx};
lock_pro.future().Chain(pro, [fus = std::move(fus)](auto&) {
std::vector<std::shared_ptr<nf7::Mutex::Lock>> ret;
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>>::Promise pro {ctx};
apro.future().Chain(pro, [fus = std::move(fus)](auto&) {
std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>> ret;
for (auto& fu : fus) {
ret.emplace_back(fu.value().lock());
ret.emplace_back(fu.value());
}
return ret;
});

View File

@ -21,9 +21,15 @@ class Obj final {
public:
using Meta = T;
// NOT thread-safe
template <typename... Args>
static nf7::Future<std::shared_ptr<Obj<T>>> Create(Args&&... args) noexcept {
return Meta::Create(std::forward<Args>(args)...);
}
template <typename... Args>
Obj(const std::shared_ptr<nf7::Context>& ctx, GLuint id, Args&&... args) noexcept :
ctx_(ctx), meta_(std::forward<Args>(args)...), id_(id? id: meta_.Gen()) {
ctx_(ctx), meta_(std::forward<Args>(args)...), id_(id) {
}
~Obj() noexcept {
ctx_->env().ExecGL(ctx_, [id = id_]() { T::Delete(id); });
@ -48,6 +54,13 @@ class Obj final {
struct Obj_BufferMeta final {
public:
static nf7::Future<std::shared_ptr<Obj<Obj_BufferMeta>>> Create(
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept;
static void Delete(GLuint id) noexcept {
glDeleteBuffers(1, &id);
}
Obj_BufferMeta() = delete;
Obj_BufferMeta(GLenum t) noexcept : type(t) {
}
@ -55,15 +68,6 @@ struct Obj_BufferMeta final {
const GLenum type;
size_t size = 0;
static GLuint Gen() noexcept {
GLuint id;
glGenBuffers(1, &id);
return id;
}
static void Delete(GLuint id) noexcept {
glDeleteBuffers(1, &id);
}
};
using Buffer = Obj<Obj_BufferMeta>;
using BufferFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Buffer>>>;
@ -71,6 +75,13 @@ using BufferFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Buffer>>
struct Obj_TextureMeta final {
public:
static nf7::Future<std::shared_ptr<Obj<Obj_TextureMeta>>> Create(
const std::shared_ptr<nf7::Context>& ctx, GLenum type) noexcept;
static void Delete(GLuint id) noexcept {
glDeleteTextures(1, &id);
}
Obj_TextureMeta() = delete;
Obj_TextureMeta(GLenum t) noexcept : type(t) {
}
@ -79,15 +90,6 @@ struct Obj_TextureMeta final {
GLint format = 0;
uint32_t w = 0, h = 0, d = 0;
static GLuint Gen() noexcept {
GLuint id;
glGenTextures(1, &id);
return id;
}
static void Delete(GLuint id) noexcept {
glDeleteTextures(1, &id);
}
};
using Texture = Obj<Obj_TextureMeta>;
using TextureFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Texture>>>;
@ -95,18 +97,20 @@ using TextureFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Texture
struct Obj_ShaderMeta final {
public:
static nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Create(
const std::shared_ptr<nf7::Context>& ctx,
GLenum type,
const std::string& src) noexcept;
static void Delete(GLuint id) noexcept {
glDeleteShader(id);
}
Obj_ShaderMeta() = delete;
Obj_ShaderMeta(GLenum t) noexcept : type(t) {
}
const GLenum type;
GLuint Gen() noexcept {
return glCreateShader(type);
}
static void Delete(GLuint id) noexcept {
glDeleteShader(id);
}
};
using Shader = Obj<Obj_ShaderMeta>;
using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>>;
@ -114,14 +118,15 @@ using ShaderFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Shader>>
struct Obj_ProgramMeta final {
public:
Obj_ProgramMeta() = default;
static nf7::Future<std::shared_ptr<Obj<Obj_ProgramMeta>>> Create(
const std::shared_ptr<nf7::Context>& ctx,
const std::vector<nf7::File::Id>& shaders) noexcept;
GLuint Gen() noexcept {
return glCreateProgram();
}
static void Delete(GLuint id) noexcept {
glDeleteProgram(id);
}
Obj_ProgramMeta() = default;
};
using Program = Obj<Obj_ProgramMeta>;
using ProgramFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Program>>>;
@ -130,26 +135,38 @@ using ProgramFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<Program
struct Obj_VertexArrayMeta final {
public:
struct Attr {
nf7::File::Id id = 0;
size_t size_per_vertex = 0;
size_t size_per_instance = 0;
nf7::File::Id buffer;
GLuint index;
GLint size;
GLenum type;
bool normalize;
GLsizei stride;
uint64_t offset;
GLuint divisor;
};
Obj_VertexArrayMeta(std::vector<Attr>&& a) noexcept : attrs(std::move(a)) {
}
const std::vector<Attr> attrs;
static nf7::Future<std::shared_ptr<Obj<Obj_VertexArrayMeta>>> Create(
const std::shared_ptr<nf7::Context>& ctx, std::vector<Attr>&& attrs) noexcept;
nf7::Future<std::vector<std::shared_ptr<nf7::Mutex::Lock>>> LockBuffers(
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt, size_t icnt) const noexcept;
static GLuint Gen() noexcept {
GLuint id;
glGenVertexArrays(1, &id);
return id;
}
static void Delete(GLuint id) noexcept {
glDeleteVertexArrays(1, &id);
}
static nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>>
LockBuffers(
const std::shared_ptr<nf7::Context>& ctx,
const std::vector<Attr>& attrs,
size_t vcnt = 0, size_t icnt = 0) noexcept;
Obj_VertexArrayMeta(std::vector<Attr>&& a) noexcept : attrs(std::move(a)) {
}
nf7::Future<std::vector<nf7::Mutex::Resource<std::shared_ptr<gl::Buffer>>>> LockBuffers(
const std::shared_ptr<nf7::Context>& ctx, size_t vcnt = 0, size_t icnt = 0) const noexcept {
return LockBuffers(ctx, attrs, vcnt, icnt);
}
const std::vector<Attr> attrs;
};
using VertexArray = Obj<Obj_VertexArrayMeta>;
using VertexArrayFactory = AsyncFactory<nf7::Mutex::Resource<std::shared_ptr<VertexArray>>>;

View File

@ -102,7 +102,7 @@ class ObjBase : public nf7::FileBase,
mtx_.AcquireLock(ctx, ex).ThenIf([this, ctx, pro](auto& k) mutable {
if (!fu_) {
watcher_.emplace(env());
fu_ = mem_->Create(ctx, *watcher_);
fu_ = mem_->Create(ctx);
watcher_->AddHandler(nf7::File::Event::kUpdate, [this](auto&) { Drop(); });
}
fu_->Chain(pro, [k](auto& obj) { return Resource {k, obj}; });
@ -282,13 +282,8 @@ struct Buffer {
throw nf7::Exception {std::string {"YAML error: "}+e.what()};
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept {
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, pro, t = type_]() mutable {
pro.Return(std::make_shared<Product>(ctx, GLuint {0}, FromType(t)));
});
return pro.future();
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept {
return Product::Create(ctx, FromType(type_));
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>& handler,
@ -433,13 +428,8 @@ struct Texture {
throw nf7::Exception {std::string {"YAML error: "}+e.what()};
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept {
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, pro, t = type_]() mutable {
pro.Return(std::make_shared<Product>(ctx, GLuint {0}, FromType(t)));
});
return pro.future();
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept {
return Product::Create(ctx, FromType(type_));
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>& handler,
@ -633,32 +623,9 @@ struct Shader {
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept {
const std::shared_ptr<nf7::Context>& ctx) noexcept {
// TODO: preprocessing GLSL source
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
ctx->env().ExecGL(ctx, [ctx, pro, type = type_, src = src_]() mutable {
auto sh = std::make_shared<Product>(ctx, GLuint {0}, FromType(type));
const GLchar* str = src.c_str();
glShaderSource(sh->id(), 1, &str, nullptr);
glCompileShader(sh->id());
assert(0 == glGetError());
GLint status;
glGetShaderiv(sh->id(), GL_COMPILE_STATUS, &status);
if (status == GL_TRUE) {
pro.Return(sh);
} else {
GLint len;
glGetShaderiv(sh->id(), GL_INFO_LOG_LENGTH, &len);
std::string ret(static_cast<size_t>(len), ' ');
glGetShaderInfoLog(sh->id(), len, nullptr, ret.data());
pro.Throw<nf7::Exception>(std::move(ret));
}
});
return pro.future();
return Product::Create(ctx, FromType(type_), src_);
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
@ -747,61 +714,18 @@ struct Program {
throw nf7::Exception {std::string {"YAML error: "}+e.what()};
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept
try {
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
nf7::AggregatePromise sh_pro {ctx};
std::vector<
nf7::Future<
nf7::Mutex::Resource<
std::shared_ptr<nf7::gl::Shader>>>> sh;
for (auto& path : shaders_) {
sh.push_back(
base.ResolveOrThrow(path).
interfaceOrThrow<nf7::gl::ShaderFactory>().Create());
sh_pro.Add(sh.back());
// TODO: setup watcher
std::vector<nf7::File::Id> shaders;
for (const auto& path : shaders_) {
shaders.push_back(base.ResolveOrThrow(path).id());
}
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
sh_pro.future().Then(nf7::Env::kGL, ctx, [ctx, pro, shaders = std::move(sh)](auto&) mutable {
pro.Wrap([&]() {
std::vector<std::shared_ptr<nf7::gl::Shader>> sh;
for (auto& s : shaders) {
sh.push_back(*s.value());
}
return Link(ctx, sh);
});
});
return pro.future();
return Product::Create(ctx, shaders);
} catch (nf7::Exception&) {
return {std::current_exception()};
}
static std::shared_ptr<nf7::gl::Program> Link(
const std::shared_ptr<nf7::Context>& ctx,
std::span<std::shared_ptr<nf7::gl::Shader>> shaders) {
auto prog = std::make_shared<nf7::gl::Program>(ctx, GLuint {0});
assert(prog->id() > 0);
for (auto& sh : shaders) {
glAttachShader(prog->id(), sh->id());
}
glLinkProgram(prog->id());
GLint status;
glGetProgramiv(prog->id(), GL_LINK_STATUS, &status);
if (status == GL_TRUE) {
return prog;
} else {
GLint len;
glGetProgramiv(prog->id(), GL_INFO_LOG_LENGTH, &len);
std::string ret(static_cast<size_t>(len), ' ');
glGetProgramInfoLog(prog->id(), len, nullptr, ret.data());
throw nf7::Exception {std::move(ret)};
}
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,
const nf7::Mutex::Resource<std::shared_ptr<Product>>&,
@ -961,94 +885,27 @@ struct VertexArray {
throw nf7::Exception {std::string {"YAML error: "}+e.what()};
}
nf7::Future<std::shared_ptr<Product>> Create(
const std::shared_ptr<nf7::Context>& ctx, nf7::Env::Watcher&) noexcept
nf7::Future<std::shared_ptr<Product>> Create(const std::shared_ptr<nf7::Context>& ctx) noexcept
try {
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
auto attrs = attrs_; // copy it
auto& base = ctx->env().GetFileOrThrow(ctx->initiator());
nf7::AggregatePromise buf_pro {ctx};
std::vector<
std::pair<
nf7::File::Id,
nf7::Future<
nf7::Mutex::Resource<
std::shared_ptr<nf7::gl::Buffer>>>>> bufs;
for (auto& attr : attrs) {
auto& f = base.ResolveOrThrow(attr.buffer);
auto fu = f.interfaceOrThrow<nf7::gl::BufferFactory>().Create();
bufs.emplace_back(f.id(), fu);
buf_pro.Add(fu);
// TODO: setup watcher
}
nf7::Future<std::shared_ptr<Product>>::Promise pro {ctx};
buf_pro.future().Then(
nf7::Env::kGL, ctx,
[ctx, pro, attrs = std::move(attrs), bufs = std::move(bufs)](auto&) mutable {
pro.Wrap([&]() { return Create(ctx, attrs, bufs); });
});
return pro.future();
} catch (nf7::Exception&) {
return {std::current_exception()};
}
static std::shared_ptr<nf7::gl::VertexArray> Create(
const std::shared_ptr<nf7::Context>& ctx, auto& attrs, auto& bufs) {
assert(attrs.size() == bufs.size());
std::vector<GLuint> bufids;
bufids.reserve(attrs.size());
// build metadata of new VAO
std::vector<nf7::gl::VertexArray::Meta::Attr> meta_attrs;
meta_attrs.reserve(attrs.size());
for (size_t i = 0; i < attrs.size(); ++i) {
const auto& attr = attrs[i];
const auto& buf = **bufs[i].second.value();
bufids.push_back(buf.id());
// check buffer type
if (buf.meta().type != GL_ARRAY_BUFFER) {
throw nf7::Exception {
"buffer ("+std::to_string(i)+") is not GL_ARRAY_BUFFER"
};
}
// calculate meta data
const auto size = attr.size*(magic_enum::enum_integer(attr.type) & 0xF);
const auto stride = attr.stride?
static_cast<size_t>(attr.stride):
static_cast<size_t>(size);
meta_attrs.push_back({
.id = bufs[i].first,
.size_per_vertex = attr.divisor == 0? stride: 0,
.size_per_instance = attr.divisor >= 1? stride: 0,
std::vector<Product::Meta::Attr> attrs;
attrs.reserve(attrs_.size());
for (auto& attr : attrs_) {
attrs.push_back({
.buffer = base.ResolveOrThrow(attr.buffer).id(),
.index = attr.index,
.size = attr.size,
.type = ToAttrType(attr.type),
.normalize = attr.normalize,
.stride = attr.stride,
.offset = attr.offset,
.divisor = attr.divisor,
});
}
// setup VAO
auto vao = std::make_shared<nf7::gl::VertexArray>(ctx, GLuint {0}, std::move(meta_attrs));
glBindVertexArray(vao->id());
for (size_t i = 0; i < attrs.size(); ++i) {
const auto& attr = attrs[i];
// attach buffer
glBindBuffer(GL_ARRAY_BUFFER, bufids[i]);
glEnableVertexAttribArray(attr.index);
glVertexAttribDivisor(attr.index, attr.divisor);
glVertexAttribPointer(
attr.index,
attr.size,
ToAttrType(attr.type),
attr.normalize,
attr.stride,
reinterpret_cast<GLvoid*>(static_cast<GLintptr>(attr.offset)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
assert(0 == glGetError());
return vao;
return Product::Create(ctx, std::move(attrs));
} catch (nf7::Exception&) {
return {std::current_exception()};
}
bool Handle(const std::shared_ptr<nf7::Node::Lambda>&,