Compare commits
4 Commits
cd3525b3b5
...
694e9e34bb
Author | SHA1 | Date | |
---|---|---|---|
694e9e34bb | |||
c1f7328628 | |||
dc3d8b15bf | |||
05201ef13e |
@ -82,6 +82,7 @@ target_sources(nf7
|
|||||||
common/gl_fence.hh
|
common/gl_fence.hh
|
||||||
common/gl_obj.hh
|
common/gl_obj.hh
|
||||||
common/gl_obj.cc
|
common/gl_obj.cc
|
||||||
|
common/gl_shader_preproc.hh
|
||||||
common/gui_config.hh
|
common/gui_config.hh
|
||||||
common/gui_context.hh
|
common/gui_context.hh
|
||||||
common/gui_dnd.hh
|
common/gui_dnd.hh
|
||||||
|
@ -313,7 +313,11 @@ class Future final {
|
|||||||
auto& pro, auto&& func) noexcept {
|
auto& pro, auto&& func) noexcept {
|
||||||
return Then(exec, ctx, [pro, func = std::move(func)](auto& fu) mutable {
|
return Then(exec, ctx, [pro, func = std::move(func)](auto& fu) mutable {
|
||||||
try {
|
try {
|
||||||
pro.Return(func(fu.value()));
|
if constexpr (std::is_void<decltype(func(fu.value()))>::value) {
|
||||||
|
func(fu.value());
|
||||||
|
} else {
|
||||||
|
pro.Return(func(fu.value()));
|
||||||
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
pro.Throw(std::current_exception());
|
pro.Throw(std::current_exception());
|
||||||
}
|
}
|
||||||
|
@ -110,8 +110,12 @@ nf7::Future<std::shared_ptr<Obj<Obj_ShaderMeta>>> Obj_ShaderMeta::Create(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GLchar* str = src.c_str();
|
static const char* kHeader =
|
||||||
glShaderSource(id, 1, &str, nullptr);
|
"#version 330\n"
|
||||||
|
"#extension GL_ARB_shading_language_include: require\n";
|
||||||
|
|
||||||
|
const GLchar* str[] = {kHeader, src.c_str()};
|
||||||
|
glShaderSource(id, 2, str, nullptr);
|
||||||
glCompileShader(id);
|
glCompileShader(id);
|
||||||
assert(0 == glGetError());
|
assert(0 == glGetError());
|
||||||
|
|
||||||
|
113
common/gl_shader_preproc.hh
Normal file
113
common/gl_shader_preproc.hh
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "nf7.hh"
|
||||||
|
|
||||||
|
#include "common/future.hh"
|
||||||
|
|
||||||
|
|
||||||
|
namespace nf7::gl {
|
||||||
|
|
||||||
|
class ShaderPreproc final : public nf7::Context,
|
||||||
|
public std::enable_shared_from_this<ShaderPreproc> {
|
||||||
|
public:
|
||||||
|
ShaderPreproc() = delete;
|
||||||
|
ShaderPreproc(const std::shared_ptr<nf7::Context>& ctx,
|
||||||
|
const std::shared_ptr<std::ostream>& ost,
|
||||||
|
const std::shared_ptr<std::istream>& ist,
|
||||||
|
std::filesystem::path&& path) noexcept :
|
||||||
|
nf7::Context(ctx->env(), ctx->initiator(), ctx),
|
||||||
|
pro_(ctx), ost_(ost), ist_(ist), path_(std::move(path)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderPreproc(const ShaderPreproc&) = delete;
|
||||||
|
ShaderPreproc(ShaderPreproc&&) = delete;
|
||||||
|
ShaderPreproc& operator=(const ShaderPreproc&) = delete;
|
||||||
|
ShaderPreproc& operator=(ShaderPreproc&&) = delete;
|
||||||
|
|
||||||
|
void ExecProcess() noexcept {
|
||||||
|
env().ExecAsync(shared_from_this(), [this]() { Process(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
nf7::Future<std::monostate> future() noexcept {
|
||||||
|
return pro_.future();
|
||||||
|
}
|
||||||
|
const std::vector<std::filesystem::path>& nfiles() const noexcept {
|
||||||
|
return *nfiles_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nf7::Future<std::monostate>::Promise pro_;
|
||||||
|
|
||||||
|
std::shared_ptr<std::ostream> ost_;
|
||||||
|
std::shared_ptr<std::istream> ist_;
|
||||||
|
|
||||||
|
std::filesystem::path path_;
|
||||||
|
size_t lnum_ = 1;
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<std::filesystem::path>> nfiles_;
|
||||||
|
|
||||||
|
|
||||||
|
void Process() noexcept
|
||||||
|
try {
|
||||||
|
*ost_ << "#line " << lnum_ << " \"" << path_.string() << "\"\n";
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(*ist_, line)) {
|
||||||
|
++lnum_;
|
||||||
|
|
||||||
|
if (line.starts_with('#')) {
|
||||||
|
std::string_view tok {line.begin() + 1, line.end()};
|
||||||
|
while (!tok.empty() && !std::isalpha(tok.front())) {
|
||||||
|
tok.remove_prefix(1);
|
||||||
|
}
|
||||||
|
if (tok.starts_with("include ")) {
|
||||||
|
tok.remove_prefix(sizeof("include")-1);
|
||||||
|
|
||||||
|
auto begin = std::find(tok.begin(), tok.end(), '"');
|
||||||
|
auto end = std::find(begin+1, tok.end(), '"');
|
||||||
|
if (begin == end || end == tok.end()) {
|
||||||
|
throw nf7::Exception {"invalid include syntax: "+line};
|
||||||
|
}
|
||||||
|
if (depth() >= 100) {
|
||||||
|
throw nf7::Exception {
|
||||||
|
"recursion detected in include directives ("+path_.string()+")"};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string name {begin+1, end};
|
||||||
|
const auto path = path_.parent_path() / name;
|
||||||
|
|
||||||
|
if (nfiles_ == nullptr) {
|
||||||
|
nfiles_ = std::make_shared<std::vector<std::filesystem::path>>();
|
||||||
|
}
|
||||||
|
nfiles_->push_back(path);
|
||||||
|
|
||||||
|
auto self = shared_from_this();
|
||||||
|
auto f = std::make_shared<std::ifstream>(path, std::ios::binary);
|
||||||
|
if (!*f) {
|
||||||
|
throw nf7::Exception {"missing include file: "+path.string()};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sub = std::make_shared<ShaderPreproc>(self, ost_, f, path.string());
|
||||||
|
sub->nfiles_ = nfiles_;
|
||||||
|
sub->Process();
|
||||||
|
sub->future().Chain(nf7::Env::kAsync, self, pro_,
|
||||||
|
[=, this](auto&) mutable { Process(); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ost_ << line << "\n";
|
||||||
|
}
|
||||||
|
pro_.Return({});
|
||||||
|
} catch (...) {
|
||||||
|
pro_.Throw<nf7::Exception>("failed to preprocess GLSL");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nf7::gl
|
@ -3,6 +3,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/file_base.hh"
|
#include "common/file_base.hh"
|
||||||
|
|
||||||
@ -18,29 +19,39 @@ class NFileWatcher final : public nf7::FileBase::Feature {
|
|||||||
NFileWatcher& operator=(NFileWatcher&&) = delete;
|
NFileWatcher& operator=(NFileWatcher&&) = delete;
|
||||||
|
|
||||||
void Watch(const std::filesystem::path& npath) noexcept {
|
void Watch(const std::filesystem::path& npath) noexcept {
|
||||||
npath_ = npath;
|
npaths_.push_back(npath);
|
||||||
|
lastmod_ = std::nullopt;
|
||||||
|
}
|
||||||
|
void Clear() noexcept {
|
||||||
|
npaths_.clear();
|
||||||
lastmod_ = std::nullopt;
|
lastmod_ = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<void()> onMod;
|
std::function<void()> onMod;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Update() noexcept override
|
void Update() noexcept override {
|
||||||
try {
|
auto latest = std::filesystem::file_time_type::duration::min();
|
||||||
if (npath_) {
|
for (const auto& npath : npaths_) {
|
||||||
const auto lastmod = std::filesystem::last_write_time(*npath_);
|
try {
|
||||||
if (lastmod_ && lastmod > *lastmod_) {
|
const auto lastmod = std::filesystem::last_write_time(npath).time_since_epoch();
|
||||||
onMod();
|
latest = std::max(latest, lastmod);
|
||||||
|
} catch (std::filesystem::filesystem_error&) {
|
||||||
}
|
}
|
||||||
lastmod_ = lastmod;
|
|
||||||
}
|
}
|
||||||
} catch (std::filesystem::filesystem_error&) {
|
if (!lastmod_) {
|
||||||
lastmod_.emplace();
|
lastmod_ = latest;
|
||||||
|
}
|
||||||
|
if (*lastmod_ < latest) {
|
||||||
|
onMod();
|
||||||
|
lastmod_ = latest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<std::filesystem::path> npath_;
|
std::vector<std::filesystem::path> npaths_;
|
||||||
std::optional<std::filesystem::file_time_type> lastmod_;
|
|
||||||
|
std::optional<std::filesystem::file_time_type::duration> lastmod_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nf7
|
} // namespace nf7
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "common/gl_enum.hh"
|
#include "common/gl_enum.hh"
|
||||||
#include "common/gl_fence.hh"
|
#include "common/gl_fence.hh"
|
||||||
#include "common/gl_obj.hh"
|
#include "common/gl_obj.hh"
|
||||||
|
#include "common/gl_shader_preproc.hh"
|
||||||
#include "common/gui_config.hh"
|
#include "common/gui_config.hh"
|
||||||
#include "common/life.hh"
|
#include "common/life.hh"
|
||||||
#include "common/logger_ref.hh"
|
#include "common/logger_ref.hh"
|
||||||
@ -136,8 +137,7 @@ class ObjBase : public nf7::FileBase,
|
|||||||
watch_->AddHandler(nf7::File::Event::kUpdate, [self = life_.ref()](auto&) {
|
watch_->AddHandler(nf7::File::Event::kUpdate, [self = life_.ref()](auto&) {
|
||||||
if (self) self->Drop();
|
if (self) self->Drop();
|
||||||
});
|
});
|
||||||
|
nwatch_->Clear();
|
||||||
// TODO: clear nwatch
|
|
||||||
|
|
||||||
fu_ = mem_->Create(CreateParam {
|
fu_ = mem_->Create(CreateParam {
|
||||||
.file = this,
|
.file = this,
|
||||||
@ -667,8 +667,23 @@ struct Shader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nf7::Future<std::shared_ptr<Product>> Create(const CreateParam& p) noexcept {
|
nf7::Future<std::shared_ptr<Product>> Create(const CreateParam& p) noexcept {
|
||||||
// TODO: preprocessing GLSL source
|
nf7::Future<std::shared_ptr<Product>>::Promise pro {p.ctx};
|
||||||
return Product::Create(p.ctx, type_, src_);
|
|
||||||
|
auto ost = std::make_shared<std::ostringstream>();
|
||||||
|
auto ist = std::make_shared<std::istringstream>(src_);
|
||||||
|
auto path = p.ctx->env().npath() / "INLINE_TEXT";
|
||||||
|
|
||||||
|
auto preproc = std::make_shared<gl::ShaderPreproc>(p.ctx, ost, ist, std::move(path));
|
||||||
|
preproc->ExecProcess();
|
||||||
|
preproc->future().Chain(p.ctx, pro, [=, type = type_](auto&) mutable {
|
||||||
|
Product::Create(p.ctx, type, ost->str()).Chain(pro);
|
||||||
|
});
|
||||||
|
return pro.future().
|
||||||
|
ThenIf(p.ctx, [=](auto&) mutable {
|
||||||
|
for (const auto& npath : preproc->nfiles()) {
|
||||||
|
p.nwatch->Watch(npath);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Handle(const HandleParam<Product>&) {
|
bool Handle(const HandleParam<Product>&) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user