render implement thread, wrap GL commands into tasks
This commit is contained in:
121
src/app.cpp
121
src/app.cpp
@@ -53,14 +53,12 @@ void App::open_document(std::string path)
|
|||||||
// on complete
|
// on complete
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
async_start();
|
|
||||||
title_update();
|
title_update();
|
||||||
for (int layer_index = 0; layer_index < canvas->m_canvas->m_layers.size(); layer_index++)
|
for (int layer_index = 0; layer_index < canvas->m_canvas->m_layers.size(); layer_index++)
|
||||||
{
|
{
|
||||||
auto l = layers->add_layer(canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false);
|
auto l = layers->add_layer(canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false);
|
||||||
l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible);
|
l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible);
|
||||||
}
|
}
|
||||||
async_end();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -80,7 +78,6 @@ bool App::request_close()
|
|||||||
return true;
|
return true;
|
||||||
if (!dialog_already_opened)
|
if (!dialog_already_opened)
|
||||||
{
|
{
|
||||||
async_start();
|
|
||||||
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
||||||
m->m_title->set_text("Unsaved document");
|
m->m_title->set_text("Unsaved document");
|
||||||
m->m_message->set_text("Do you want to close without saving?");
|
m->m_message->set_text("Do you want to close without saving?");
|
||||||
@@ -100,8 +97,6 @@ bool App::request_close()
|
|||||||
m->destroy();
|
m->destroy();
|
||||||
dialog_already_opened = false;
|
dialog_already_opened = false;
|
||||||
};
|
};
|
||||||
async_redraw();
|
|
||||||
async_end();
|
|
||||||
dialog_already_opened = true;
|
dialog_already_opened = true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -109,6 +104,7 @@ bool App::request_close()
|
|||||||
|
|
||||||
void App::clear()
|
void App::clear()
|
||||||
{
|
{
|
||||||
|
assert(is_render_thread());
|
||||||
glClearColor(.1f, .1f, .1f, 1.f);
|
glClearColor(.1f, .1f, .1f, 1.f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
@@ -384,67 +380,75 @@ void App::upload(std::string filename, std::string name, std::function<void(floa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static CONSOLE_SCREEN_BUFFER_INFO info;
|
||||||
|
void handle_gl_callback(GLenum source, GLenum type, GLuint id,
|
||||||
|
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||||
|
{
|
||||||
|
static std::map<GLenum, int> colors = {
|
||||||
|
{ GL_DEBUG_SEVERITY_NOTIFICATION, 8 },
|
||||||
|
{ GL_DEBUG_SEVERITY_LOW, 8 },
|
||||||
|
{ GL_DEBUG_SEVERITY_MEDIUM, FOREGROUND_GREEN | FOREGROUND_INTENSITY },
|
||||||
|
{ GL_DEBUG_SEVERITY_HIGH, FOREGROUND_RED | FOREGROUND_INTENSITY },
|
||||||
|
};
|
||||||
|
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM || severity == GL_DEBUG_SEVERITY_LOW)
|
||||||
|
{
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors[severity]);
|
||||||
|
LOG("OPENGL: %.*s", length, message);
|
||||||
|
FlushConsoleInputBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), info.wAttributes);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (severity == GL_DEBUG_SEVERITY_HIGH)
|
||||||
|
__debugbreak();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void App::init()
|
void App::init()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (glDebugMessageCallback)
|
if (glDebugMessageCallback)
|
||||||
{
|
{
|
||||||
static CONSOLE_SCREEN_BUFFER_INFO info;
|
|
||||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
|
|
||||||
// colors: http://stackoverflow.com/questions/4053837/colorizing-text-in-the-console-with-c
|
// colors: http://stackoverflow.com/questions/4053837/colorizing-text-in-the-console-with-c
|
||||||
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id,
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
|
||||||
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
|
||||||
|
render_task([]
|
||||||
{
|
{
|
||||||
static std::map<GLenum, int> colors = {
|
glDebugMessageCallback(handle_gl_callback, nullptr);
|
||||||
{ GL_DEBUG_SEVERITY_NOTIFICATION, 8 },
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
{ GL_DEBUG_SEVERITY_LOW, 8 },
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
{ GL_DEBUG_SEVERITY_MEDIUM, FOREGROUND_GREEN | FOREGROUND_INTENSITY },
|
});
|
||||||
{ GL_DEBUG_SEVERITY_HIGH, FOREGROUND_RED | FOREGROUND_INTENSITY },
|
|
||||||
};
|
|
||||||
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM || severity == GL_DEBUG_SEVERITY_LOW)
|
|
||||||
{
|
|
||||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors[severity]);
|
|
||||||
LOG("OPENGL: %.*s", length, message);
|
|
||||||
FlushConsoleInputBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
|
|
||||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), info.wAttributes);
|
|
||||||
#ifdef _WIN32 && _DEBUG
|
|
||||||
if (severity == GL_DEBUG_SEVERITY_HIGH)
|
|
||||||
__debugbreak();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}, nullptr);
|
|
||||||
glEnable(GL_DEBUG_OUTPUT);
|
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG("GL version: %s", glGetString(GL_VERSION));
|
|
||||||
LOG("GL vendor: %s", glGetString(GL_VENDOR));
|
|
||||||
LOG("GL renderer: %s", glGetString(GL_RENDERER));
|
|
||||||
|
|
||||||
//GLint n_exts;
|
|
||||||
//glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
|
|
||||||
//for (int i = 0; i < n_exts; i++)
|
|
||||||
//{
|
|
||||||
// std::string ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
|
||||||
// //if (ext.find("debug") != std::string::npos)
|
|
||||||
// {
|
|
||||||
// LOG("%s", glGetStringi(GL_EXTENSIONS, i));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
|
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
|
||||||
|
|
||||||
//zoom = ceilf(width / 2000.f);
|
render_task([]
|
||||||
//zoom = 2;
|
{
|
||||||
|
LOG("GL version: %s", glGetString(GL_VERSION));
|
||||||
|
LOG("GL vendor: %s", glGetString(GL_VENDOR));
|
||||||
|
LOG("GL renderer: %s", glGetString(GL_RENDERER));
|
||||||
|
|
||||||
|
//GLint n_exts;
|
||||||
|
//glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
|
||||||
|
//for (int i = 0; i < n_exts; i++)
|
||||||
|
//{
|
||||||
|
// std::string ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
// //if (ext.find("debug") != std::string::npos)
|
||||||
|
// {
|
||||||
|
// LOG("%s", glGetStringi(GL_EXTENSIONS, i));
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
#if defined(_WIN32) || defined(__OSX__)
|
#if defined(_WIN32) || defined(__OSX__)
|
||||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
#endif
|
#endif
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
|
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
|
||||||
|
});
|
||||||
|
|
||||||
int run_counter = Settings::value<Serializer::Integer>("run_counter") + 1;
|
int run_counter = Settings::value<Serializer::Integer>("run_counter") + 1;
|
||||||
Settings::set("run_counter", Serializer::Integer(run_counter));
|
Settings::set("run_counter", Serializer::Integer(run_counter));
|
||||||
@@ -462,15 +466,6 @@ void App::init()
|
|||||||
{
|
{
|
||||||
message_box("License", "Could not validate this license, running in demo mode.");
|
message_box("License", "Could not validate this license, running in demo mode.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//GLfloat width_range[2];
|
|
||||||
//glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, width_range);
|
|
||||||
//LOG("GL line range: %f - %f", width_range[0], width_range[1]);
|
|
||||||
LOG("Screen Size: %f %f", width, height);
|
|
||||||
|
|
||||||
GLint fb0;
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fb0);
|
|
||||||
LOG("Default Framebuffer %d", fb0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::async_start()
|
void App::async_start()
|
||||||
@@ -700,7 +695,6 @@ void App::terminate()
|
|||||||
NodeStrokePreview::terminate_renderer();
|
NodeStrokePreview::terminate_renderer();
|
||||||
rec_stop();
|
rec_stop();
|
||||||
|
|
||||||
async_start();
|
|
||||||
TextureManager::invalidate();
|
TextureManager::invalidate();
|
||||||
ShaderManager::invalidate();
|
ShaderManager::invalidate();
|
||||||
layout.unload();
|
layout.unload();
|
||||||
@@ -716,7 +710,6 @@ void App::terminate()
|
|||||||
floating_layers.reset();
|
floating_layers.reset();
|
||||||
floating_picker.reset();
|
floating_picker.reset();
|
||||||
quick_mode_state.clear();
|
quick_mode_state.clear();
|
||||||
async_end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::update_memory_usage(size_t bytes)
|
void App::update_memory_usage(size_t bytes)
|
||||||
|
|||||||
65
src/app.h
65
src/app.h
@@ -249,4 +249,69 @@ public:
|
|||||||
bool get_ui_rtl() const;
|
bool get_ui_rtl() const;
|
||||||
|
|
||||||
void cmd_convert(std::string pano_path, std::string out_path);
|
void cmd_convert(std::string pano_path, std::string out_path);
|
||||||
|
|
||||||
|
bool is_render_thread()
|
||||||
|
{
|
||||||
|
extern std::thread::id render_thread_id;
|
||||||
|
extern std::thread::id gl_thread;
|
||||||
|
return std::this_thread::get_id() == render_thread_id || std::this_thread::get_id() == gl_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't capture a reference to this ptr as the object may be destroyed
|
||||||
|
// by the time the task is executed
|
||||||
|
template<typename T, typename R = std::result_of<T()>::type>
|
||||||
|
std::future<R> render_task_async(T task)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern std::deque<std::packaged_task<R()>> render_tasklist;
|
||||||
|
extern std::mutex render_task_mutex;
|
||||||
|
extern std::condition_variable render_cv;
|
||||||
|
std::packaged_task<R()> pt(task);
|
||||||
|
std::future<R> f = pt.get_future();
|
||||||
|
if (is_render_thread())
|
||||||
|
{
|
||||||
|
pt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
||||||
|
render_tasklist.push_back(std::move(pt));
|
||||||
|
}
|
||||||
|
render_cv.notify_all();
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename R = std::result_of<T()>::type>
|
||||||
|
R render_task(T task)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern std::deque<std::packaged_task<R()>> render_tasklist;
|
||||||
|
extern std::mutex render_task_mutex;
|
||||||
|
extern std::condition_variable render_cv;
|
||||||
|
std::packaged_task<R()> pt(task);
|
||||||
|
std::future<R> f = pt.get_future();
|
||||||
|
if (is_render_thread())
|
||||||
|
{
|
||||||
|
pt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
||||||
|
render_tasklist.push_back(std::move(pt));
|
||||||
|
}
|
||||||
|
render_cv.notify_all();
|
||||||
|
}
|
||||||
|
return f.get();
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_sync()
|
||||||
|
{
|
||||||
|
render_task([] {});
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ std::shared_ptr<NodeProgressBar> App::show_progress(const std::string& title)
|
|||||||
|
|
||||||
NodeMessageBox* App::message_box(const std::string &title, const std::string& text, bool cancel_button)
|
NodeMessageBox* App::message_box(const std::string &title, const std::string& text, bool cancel_button)
|
||||||
{
|
{
|
||||||
async_start();
|
|
||||||
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
||||||
m->m_title->set_text(title.c_str());
|
m->m_title->set_text(title.c_str());
|
||||||
m->m_message->set_text(text.c_str());
|
m->m_message->set_text(text.c_str());
|
||||||
@@ -36,8 +35,6 @@ NodeMessageBox* App::message_box(const std::string &title, const std::string& te
|
|||||||
if (!cancel_button)
|
if (!cancel_button)
|
||||||
m->btn_cancel->destroy();
|
m->btn_cancel->destroy();
|
||||||
layout[main_id]->update();
|
layout[main_id]->update();
|
||||||
async_redraw();
|
|
||||||
async_end();
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +77,6 @@ void App::dialog_about()
|
|||||||
void App::dialog_newdoc()
|
void App::dialog_newdoc()
|
||||||
{
|
{
|
||||||
auto show_dialog = [this] {
|
auto show_dialog = [this] {
|
||||||
async_start();
|
|
||||||
auto dialog = std::make_shared<NodeDialogNewDoc>();
|
auto dialog = std::make_shared<NodeDialogNewDoc>();
|
||||||
dialog->m_manager = &layout;
|
dialog->m_manager = &layout;
|
||||||
dialog->init();
|
dialog->init();
|
||||||
@@ -153,7 +149,6 @@ void App::dialog_newdoc()
|
|||||||
dialog->destroy();
|
dialog->destroy();
|
||||||
App::I.hideKeyboard();
|
App::I.hideKeyboard();
|
||||||
};
|
};
|
||||||
async_end();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (canvas)
|
if (canvas)
|
||||||
@@ -190,7 +185,6 @@ void App::dialog_newdoc()
|
|||||||
void App::dialog_open()
|
void App::dialog_open()
|
||||||
{
|
{
|
||||||
auto show_dialog = [this] {
|
auto show_dialog = [this] {
|
||||||
async_start();
|
|
||||||
// load thumbnail test
|
// load thumbnail test
|
||||||
auto dialog = std::make_shared<NodeDialogOpen>();
|
auto dialog = std::make_shared<NodeDialogOpen>();
|
||||||
dialog->m_manager = &layout;
|
dialog->m_manager = &layout;
|
||||||
@@ -217,7 +211,6 @@ void App::dialog_open()
|
|||||||
// dialog->destroy();
|
// dialog->destroy();
|
||||||
// ActionManager::clear();
|
// ActionManager::clear();
|
||||||
};
|
};
|
||||||
async_end();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (canvas)
|
if (canvas)
|
||||||
@@ -253,7 +246,6 @@ void App::dialog_open()
|
|||||||
void App::dialog_browse()
|
void App::dialog_browse()
|
||||||
{
|
{
|
||||||
auto show_dialog = [this] {
|
auto show_dialog = [this] {
|
||||||
async_start();
|
|
||||||
// load thumbnail test
|
// load thumbnail test
|
||||||
auto dialog = std::make_shared<NodeDialogBrowse>();
|
auto dialog = std::make_shared<NodeDialogBrowse>();
|
||||||
dialog->m_manager = &layout;
|
dialog->m_manager = &layout;
|
||||||
@@ -277,7 +269,6 @@ void App::dialog_browse()
|
|||||||
dialog->destroy();
|
dialog->destroy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
async_end();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (canvas)
|
if (canvas)
|
||||||
|
|||||||
@@ -9,16 +9,18 @@ void App::initShaders()
|
|||||||
std::logic_error("check_uniform_uniqueness() failed");
|
std::logic_error("check_uniform_uniqueness() failed");
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
GLint n_exts;
|
render_task([] {
|
||||||
glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
|
GLint n_exts;
|
||||||
for (int i = 0; i < n_exts; i++)
|
glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
|
||||||
{
|
for (int i = 0; i < n_exts; i++)
|
||||||
std::string ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
|
||||||
if (ext.find("shader_framebuffer_fetch") != std::string::npos)
|
|
||||||
{
|
{
|
||||||
ShaderManager::ext_framebuffer_fetch = true;
|
std::string ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
if (ext.find("shader_framebuffer_fetch") != std::string::npos)
|
||||||
|
{
|
||||||
|
ShaderManager::ext_framebuffer_fetch = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled");
|
LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
|||||||
111
src/brush.cpp
111
src/brush.cpp
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4& proj)
|
void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4& proj)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
std::vector<instance_t> attributes;
|
std::vector<instance_t> attributes;
|
||||||
attributes.reserve(samples.size());
|
attributes.reserve(samples.size());
|
||||||
for (const auto& s : samples)
|
for (const auto& s : samples)
|
||||||
@@ -69,64 +70,74 @@ void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4&
|
|||||||
}
|
}
|
||||||
bool BrushMesh::create()
|
bool BrushMesh::create()
|
||||||
{
|
{
|
||||||
static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 };
|
bool ret = true;
|
||||||
static vertex_t vertices[4]{
|
App::I.render_task([&]
|
||||||
{ { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C
|
{
|
||||||
{ { -.5f, .5f, 0, 1 }, { 0, 1 } }, // B --\ | |
|
static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 };
|
||||||
{ { .5f, .5f, 0, 1 }, { 1, 1 } }, // C --/ | |
|
static vertex_t vertices[4]{
|
||||||
{ { .5f, -.5f, 0, 1 }, { 1, 0 } }, // D A----D
|
{ { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C
|
||||||
};
|
{ { -.5f, .5f, 0, 1 }, { 0, 1 } }, // B --\ | |
|
||||||
glGenBuffers(3, buffers);
|
{ { .5f, .5f, 0, 1 }, { 1, 1 } }, // C --/ | |
|
||||||
if (!(buffers[0] && buffers[1] && buffers[2]))
|
{ { .5f, -.5f, 0, 1 }, { 1, 0 } }, // D A----D
|
||||||
return false;
|
};
|
||||||
|
glGenBuffers(3, buffers);
|
||||||
|
if (!(buffers[0] && buffers[1] && buffers[2]))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static instance_t inst{ glm::mat4(1), .1f };
|
static instance_t inst{ glm::mat4(1), .1f };
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(instance_t), &inst, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(instance_t), &inst, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
auto shader = ShaderManager::get(kShader::BrushStroke);
|
auto shader = ShaderManager::get(kShader::BrushStroke);
|
||||||
|
|
||||||
loc_flow = shader->GetAttribLocation("a_flow");
|
loc_flow = shader->GetAttribLocation("a_flow");
|
||||||
loc_mvp = shader->GetAttribLocation("a_mvp");
|
loc_mvp = shader->GetAttribLocation("a_mvp");
|
||||||
|
|
||||||
#if USE_VBO
|
#if USE_VBO
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
if (!vao)
|
if (!vao)
|
||||||
return false;
|
{
|
||||||
glBindVertexArray(vao);
|
ret = false;
|
||||||
glEnableVertexAttribArray(0);
|
return;
|
||||||
glEnableVertexAttribArray(1);
|
}
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
glBindVertexArray(vao);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, pos));
|
glEnableVertexAttribArray(1);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
// Loop over each column of the matrix...
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, pos));
|
||||||
for (int i = 0; i < 4; i++)
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
{
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||||
// Set up the vertex attribute
|
// Loop over each column of the matrix...
|
||||||
glVertexAttribPointer(loc_mvp + i, 4, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
for (int i = 0; i < 4; i++)
|
||||||
(GLvoid*)(offsetof(instance_t, mvp) + sizeof(glm::vec4) * i));
|
{
|
||||||
// Enable it
|
// Set up the vertex attribute
|
||||||
glEnableVertexAttribArray(loc_mvp + i);
|
glVertexAttribPointer(loc_mvp + i, 4, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||||
// Make it instanced
|
(GLvoid*)(offsetof(instance_t, mvp) + sizeof(glm::vec4) * i));
|
||||||
glVertexAttribDivisor(loc_mvp + i, 1);
|
// Enable it
|
||||||
}
|
glEnableVertexAttribArray(loc_mvp + i);
|
||||||
glEnableVertexAttribArray(loc_flow);
|
// Make it instanced
|
||||||
glVertexAttribPointer(loc_flow, 1, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
glVertexAttribDivisor(loc_mvp + i, 1);
|
||||||
(GLvoid*)offsetof(instance_t, flow));
|
}
|
||||||
glVertexAttribDivisor(loc_flow, 1);
|
glEnableVertexAttribArray(loc_flow);
|
||||||
glBindVertexArray(0);
|
glVertexAttribPointer(loc_flow, 1, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||||
|
(GLvoid*)offsetof(instance_t, flow));
|
||||||
|
glVertexAttribDivisor(loc_flow, 1);
|
||||||
|
glBindVertexArray(0);
|
||||||
#endif
|
#endif
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, float dir_angle)
|
StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, float dir_angle)
|
||||||
{
|
{
|
||||||
|
|||||||
538
src/canvas.cpp
538
src/canvas.cpp
@@ -1474,10 +1474,13 @@ void Canvas::FloodData::apply()
|
|||||||
if (!dirty[plane])
|
if (!dirty[plane])
|
||||||
continue;
|
continue;
|
||||||
auto& rtt = layer->m_rtt[plane];
|
auto& rtt = layer->m_rtt[plane];
|
||||||
rtt.bindTexture();
|
App::I.render_task([&]
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(),
|
{
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get());
|
rtt.bindTexture();
|
||||||
rtt.unbindTexture();
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(),
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get());
|
||||||
|
rtt.unbindTexture();
|
||||||
|
});
|
||||||
layer->m_dirty_face[plane] = true;
|
layer->m_dirty_face[plane] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2766,111 +2769,115 @@ bool Canvas::project_open_thread(std::string file_path)
|
|||||||
|
|
||||||
Image Canvas::thumbnail_generate(int w, int h)
|
Image Canvas::thumbnail_generate(int w, int h)
|
||||||
{
|
{
|
||||||
// save viewport and clear color states
|
Image image;
|
||||||
GLint vp[4];
|
image.create(w, h);
|
||||||
GLfloat cc[4];
|
|
||||||
glGetIntegerv(GL_VIEWPORT, vp);
|
|
||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
|
||||||
GLboolean blend = glIsEnabled(GL_BLEND);
|
|
||||||
|
|
||||||
// prepare common states
|
App::I.render_task([this, w, h, &image]
|
||||||
glViewport(0, 0, w, h);
|
|
||||||
|
|
||||||
RTT fb;
|
|
||||||
fb.create(w, h);
|
|
||||||
fb.bindFramebuffer();
|
|
||||||
Plane m_face_plane;
|
|
||||||
m_face_plane.create<1>(2, 2);
|
|
||||||
Texture2D blendtex;
|
|
||||||
blendtex.create(w, h);
|
|
||||||
|
|
||||||
// recalculate because of different aspect ratio than the m_proj matrix
|
|
||||||
glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)w / (float)h, 0.1f, 1000.f);
|
|
||||||
|
|
||||||
fb.clear({ 1, 1, 1, 0 });
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
{
|
||||||
glDisable(GL_BLEND);
|
// save viewport and clear color states
|
||||||
auto plane_mvp = proj * m_mv * m_plane_transform[i] * glm::translate(glm::vec3(0, 0, -1));
|
GLint vp[4];
|
||||||
|
GLfloat cc[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, vp);
|
||||||
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
|
GLboolean blend = glIsEnabled(GL_BLEND);
|
||||||
|
|
||||||
ShaderManager::use(kShader::TextureBlend);
|
// prepare common states
|
||||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
glViewport(0, 0, w, h);
|
||||||
ShaderManager::u_int(kShaderUniform::TexA, 1);
|
|
||||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
RTT fb;
|
||||||
if (!ShaderManager::ext_framebuffer_fetch)
|
fb.create(w, h);
|
||||||
|
fb.bindFramebuffer();
|
||||||
|
Plane m_face_plane;
|
||||||
|
m_face_plane.create<1>(2, 2);
|
||||||
|
Texture2D blendtex;
|
||||||
|
blendtex.create(w, h);
|
||||||
|
|
||||||
|
// recalculate because of different aspect ratio than the m_proj matrix
|
||||||
|
glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)w / (float)h, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
fb.clear({ 1, 1, 1, 0 });
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
ShaderManager::u_int(kShaderUniform::TexBG, 2);
|
glDisable(GL_BLEND);
|
||||||
glActiveTexture(GL_TEXTURE2);
|
auto plane_mvp = proj * m_mv * m_plane_transform[i] * glm::translate(glm::vec3(0, 0, -1));
|
||||||
blendtex.bind();
|
|
||||||
m_sampler_bg.bind(2);
|
ShaderManager::use(kShader::TextureBlend);
|
||||||
}
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
m_sampler_bg.bind(0); // nearest
|
ShaderManager::u_int(kShaderUniform::TexA, 1);
|
||||||
m_sampler_mask.bind(1); // linear
|
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
||||||
for (int layer_index = 0; layer_index < m_layers.size(); layer_index++)
|
if (!ShaderManager::ext_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
if (!m_layers[layer_index]->m_visible ||
|
ShaderManager::u_int(kShaderUniform::TexBG, 2);
|
||||||
m_layers[layer_index]->m_opacity == 0.f ||
|
glActiveTexture(GL_TEXTURE2);
|
||||||
!m_layers[layer_index]->m_dirty_face[i])
|
blendtex.bind();
|
||||||
continue;
|
m_sampler_bg.bind(2);
|
||||||
|
}
|
||||||
|
m_sampler_bg.bind(0); // nearest
|
||||||
|
m_sampler_mask.bind(1); // linear
|
||||||
|
for (int layer_index = 0; layer_index < m_layers.size(); layer_index++)
|
||||||
|
{
|
||||||
|
if (!m_layers[layer_index]->m_visible ||
|
||||||
|
m_layers[layer_index]->m_opacity == 0.f ||
|
||||||
|
!m_layers[layer_index]->m_dirty_face[i])
|
||||||
|
continue;
|
||||||
|
if (!ShaderManager::ext_framebuffer_fetch)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE2);
|
||||||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
|
||||||
|
}
|
||||||
|
ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index]->m_blend_mode);
|
||||||
|
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_layers[layer_index]->m_rtt[i].bindTexture();
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
m_layers[layer_index]->m_rtt[i].bindTexture();
|
||||||
|
m_face_plane.draw_fill();
|
||||||
|
m_layers[layer_index]->m_rtt[i].unbindTexture();
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_layers[layer_index]->m_rtt[i].unbindTexture();
|
||||||
|
}
|
||||||
|
|
||||||
if (!ShaderManager::ext_framebuffer_fetch)
|
if (!ShaderManager::ext_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
glActiveTexture(GL_TEXTURE2);
|
glActiveTexture(GL_TEXTURE2);
|
||||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
|
blendtex.unbind();
|
||||||
}
|
}
|
||||||
ShaderManager::u_int(kShaderUniform::BlendMode, m_layers[layer_index]->m_blend_mode);
|
|
||||||
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index]->m_opacity);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
m_layers[layer_index]->m_rtt[i].bindTexture();
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
m_layers[layer_index]->m_rtt[i].bindTexture();
|
|
||||||
m_face_plane.draw_fill();
|
|
||||||
m_layers[layer_index]->m_rtt[i].unbindTexture();
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
m_layers[layer_index]->m_rtt[i].unbindTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ShaderManager::ext_framebuffer_fetch)
|
glActiveTexture(GL_TEXTURE0);
|
||||||
{
|
blendtex.bind();
|
||||||
glActiveTexture(GL_TEXTURE2);
|
// copy the content of the fb before drawing the grid
|
||||||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
|
||||||
|
|
||||||
|
// draw the grid
|
||||||
|
ShaderManager::use(kShader::Checkerboard);
|
||||||
|
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
||||||
|
m_face_plane.draw_fill();
|
||||||
|
|
||||||
|
// now blend with the background
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
ShaderManager::use(kShader::Texture);
|
||||||
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
|
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
||||||
|
m_sampler_mask.bind(0); // linear
|
||||||
|
m_plane.draw_fill();
|
||||||
|
|
||||||
blendtex.unbind();
|
blendtex.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb.unbindFramebuffer();
|
||||||
|
|
||||||
|
// read the rendered image
|
||||||
|
fb.readTextureData((uint8_t*)image.data());
|
||||||
|
|
||||||
|
fb.destroy();
|
||||||
|
blendtex.destroy();
|
||||||
|
|
||||||
|
// restore viewport and clear color states
|
||||||
|
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||||
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||||
|
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
blendtex.bind();
|
});
|
||||||
// copy the content of the fb before drawing the grid
|
|
||||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
|
|
||||||
|
|
||||||
// draw the grid
|
|
||||||
ShaderManager::use(kShader::Checkerboard);
|
|
||||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
|
||||||
m_face_plane.draw_fill();
|
|
||||||
|
|
||||||
// now blend with the background
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
ShaderManager::use(kShader::Texture);
|
|
||||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
|
||||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
|
|
||||||
m_sampler_mask.bind(0); // linear
|
|
||||||
m_plane.draw_fill();
|
|
||||||
|
|
||||||
blendtex.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
fb.unbindFramebuffer();
|
|
||||||
|
|
||||||
// read the rendered image
|
|
||||||
Image image;
|
|
||||||
image.create(w, h);
|
|
||||||
fb.readTextureData((uint8_t*)image.data());
|
|
||||||
|
|
||||||
fb.destroy();
|
|
||||||
blendtex.destroy();
|
|
||||||
|
|
||||||
// restore viewport and clear color states
|
|
||||||
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
|
||||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
@@ -2904,140 +2911,146 @@ Image Canvas::thumbnail_read(std::string file_path)
|
|||||||
|
|
||||||
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
|
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
|
||||||
{
|
{
|
||||||
// save viewport and clear color states
|
App::I.render_task([&]
|
||||||
GLint vp[4];
|
|
||||||
GLfloat cc[4];
|
|
||||||
glGetIntegerv(GL_VIEWPORT, vp);
|
|
||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
|
||||||
GLboolean blend = glIsEnabled(GL_BLEND);
|
|
||||||
|
|
||||||
// prepare common states
|
|
||||||
glViewport(0, 0, layer.w, layer.h);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
GLuint rboID;
|
|
||||||
glGenRenderbuffers(1, &rboID);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, layer.w, layer.h);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
||||||
|
|
||||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
{
|
||||||
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
|
// save viewport and clear color states
|
||||||
layer.m_rtt[i].bindFramebuffer();
|
GLint vp[4];
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
GLfloat cc[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, vp);
|
||||||
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
|
GLboolean blend = glIsEnabled(GL_BLEND);
|
||||||
|
|
||||||
observer(plane_camera, proj, i);
|
// prepare common states
|
||||||
|
glViewport(0, 0, layer.w, layer.h);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
GLuint rboID;
|
||||||
layer.m_rtt[i].unbindFramebuffer();
|
glGenRenderbuffers(1, &rboID);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, layer.w, layer.h);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
|
|
||||||
layer.m_dirty_face[i] = true;
|
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||||
layer.m_dirty_box[i] = { 0, 0, layer.w, layer.h };
|
for (int i = 0; i < 6; i++)
|
||||||
}
|
{
|
||||||
|
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
|
||||||
|
layer.m_rtt[i].bindFramebuffer();
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||||
|
|
||||||
glDeleteRenderbuffers(1, &rboID);
|
observer(plane_camera, proj, i);
|
||||||
|
|
||||||
// restore viewport and clear color states
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||||
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
layer.m_rtt[i].unbindFramebuffer();
|
||||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
draw_merge();
|
layer.m_dirty_face[i] = true;
|
||||||
|
layer.m_dirty_box[i] = { 0, 0, layer.w, layer.h };
|
||||||
|
}
|
||||||
|
|
||||||
|
glDeleteRenderbuffers(1, &rboID);
|
||||||
|
|
||||||
|
// restore viewport and clear color states
|
||||||
|
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||||
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||||
|
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
draw_merge();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
|
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
|
||||||
{
|
{
|
||||||
// save viewport and clear color states
|
App::I.render_task([&]
|
||||||
GLint vp[4];
|
|
||||||
GLfloat cc[4];
|
|
||||||
glGetIntegerv(GL_VIEWPORT, vp);
|
|
||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
|
||||||
GLboolean blend = glIsEnabled(GL_BLEND);
|
|
||||||
|
|
||||||
// prepare common states
|
|
||||||
glViewport(0, 0, layer.w, layer.h);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
GLuint rboID;
|
|
||||||
glGenRenderbuffers(1, &rboID);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, layer.w, layer.h);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
||||||
|
|
||||||
RTT rtt;
|
|
||||||
rtt.create(layer.w, layer.h);
|
|
||||||
rtt.bindFramebuffer();
|
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
|
||||||
rtt.unbindFramebuffer();
|
|
||||||
|
|
||||||
// allocate action to add to history
|
|
||||||
auto action = new ActionStroke;
|
|
||||||
action->was_saved = !m_unsaved;
|
|
||||||
|
|
||||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
{
|
||||||
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
|
// save viewport and clear color states
|
||||||
|
GLint vp[4];
|
||||||
|
GLfloat cc[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, vp);
|
||||||
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
|
GLboolean blend = glIsEnabled(GL_BLEND);
|
||||||
|
|
||||||
|
// prepare common states
|
||||||
|
glViewport(0, 0, layer.w, layer.h);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
GLuint rboID;
|
||||||
|
glGenRenderbuffers(1, &rboID);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, layer.w, layer.h);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
|
|
||||||
|
RTT rtt;
|
||||||
|
rtt.create(layer.w, layer.h);
|
||||||
rtt.bindFramebuffer();
|
rtt.bindFramebuffer();
|
||||||
rtt.clear({ 1, 1, 1, 0 });
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||||
observer(plane_camera, proj, i);
|
|
||||||
rtt.unbindFramebuffer();
|
rtt.unbindFramebuffer();
|
||||||
|
|
||||||
glm::vec4 bounds = rtt.calc_bounds();
|
// allocate action to add to history
|
||||||
|
auto action = new ActionStroke;
|
||||||
|
action->was_saved = !m_unsaved;
|
||||||
|
|
||||||
layer.m_rtt[i].bindFramebuffer();
|
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
// save image before commit
|
|
||||||
glm::vec2 box_sz = zw(bounds) - xy(bounds);
|
|
||||||
bool has_data = box_sz.x > 0 && box_sz.y > 0;
|
|
||||||
if (has_data)
|
|
||||||
{
|
{
|
||||||
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
|
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
|
||||||
glReadPixels(bounds.x, bounds.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get());
|
rtt.bindFramebuffer();
|
||||||
action->m_box[i] = bounds;
|
rtt.clear({ 1, 1, 1, 0 });
|
||||||
|
observer(plane_camera, proj, i);
|
||||||
|
rtt.unbindFramebuffer();
|
||||||
|
|
||||||
|
glm::vec4 bounds = rtt.calc_bounds();
|
||||||
|
|
||||||
|
layer.m_rtt[i].bindFramebuffer();
|
||||||
|
|
||||||
|
// save image before commit
|
||||||
|
glm::vec2 box_sz = zw(bounds) - xy(bounds);
|
||||||
|
bool has_data = box_sz.x > 0 && box_sz.y > 0;
|
||||||
|
if (has_data)
|
||||||
|
{
|
||||||
|
action->m_image[i] = std::make_unique<uint8_t[]>(box_sz.x * box_sz.y * 4);
|
||||||
|
glReadPixels(bounds.x, bounds.y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, action->m_image[i].get());
|
||||||
|
action->m_box[i] = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->m_old_box[i] = layer.m_dirty_box[i];
|
||||||
|
action->m_old_dirty[i] = layer.m_dirty_face[i];
|
||||||
|
|
||||||
|
// draw the tmp layer into the actual layer
|
||||||
|
if (has_data)
|
||||||
|
{
|
||||||
|
ShaderManager::use(kShader::Texture);
|
||||||
|
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||||
|
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-0.5f, 0.5f, -0.5f, 0.5f));
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
m_sampler_nearest.bind(0);
|
||||||
|
rtt.bindTexture();
|
||||||
|
m_plane.draw_fill();
|
||||||
|
rtt.unbindTexture();
|
||||||
|
|
||||||
|
layer.m_dirty_face[i] = true;
|
||||||
|
layer.m_dirty_box[i] = { glm::min(xy(layer.m_dirty_box[i]), xy(bounds)), glm::max(zw(layer.m_dirty_box[i]), zw(bounds)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
layer.m_rtt[i].unbindFramebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
action->m_old_box[i] = layer.m_dirty_box[i];
|
// save history
|
||||||
action->m_old_dirty[i] = layer.m_dirty_face[i];
|
action->m_layer_idx = m_current_layer_idx;
|
||||||
|
action->m_canvas = this;
|
||||||
|
//action->m_stroke = std::move(m_current_stroke);
|
||||||
|
ActionManager::add(action);
|
||||||
|
|
||||||
// draw the tmp layer into the actual layer
|
glDeleteRenderbuffers(1, &rboID);
|
||||||
if (has_data)
|
rtt.destroy();
|
||||||
{
|
|
||||||
ShaderManager::use(kShader::Texture);
|
|
||||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
|
||||||
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-0.5f, 0.5f, -0.5f, 0.5f));
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
m_sampler_nearest.bind(0);
|
|
||||||
rtt.bindTexture();
|
|
||||||
m_plane.draw_fill();
|
|
||||||
rtt.unbindTexture();
|
|
||||||
|
|
||||||
layer.m_dirty_face[i] = true;
|
|
||||||
layer.m_dirty_box[i] = { glm::min(xy(layer.m_dirty_box[i]), xy(bounds)), glm::max(zw(layer.m_dirty_box[i]), zw(bounds)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.m_rtt[i].unbindFramebuffer();
|
// restore viewport and clear color states
|
||||||
}
|
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||||
|
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||||
|
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
// save history
|
draw_merge();
|
||||||
action->m_layer_idx = m_current_layer_idx;
|
});
|
||||||
action->m_canvas = this;
|
|
||||||
//action->m_stroke = std::move(m_current_stroke);
|
|
||||||
ActionManager::add(action);
|
|
||||||
|
|
||||||
glDeleteRenderbuffers(1, &rboID);
|
|
||||||
rtt.destroy();
|
|
||||||
|
|
||||||
// restore viewport and clear color states
|
|
||||||
blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
|
||||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
draw_merge();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer)
|
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer)
|
||||||
@@ -3153,7 +3166,6 @@ void Layer::destroy()
|
|||||||
void Layer::optimize()
|
void Layer::optimize()
|
||||||
{
|
{
|
||||||
int saved_bytes = 0;
|
int saved_bytes = 0;
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
if (!m_dirty_face[i])
|
if (!m_dirty_face[i])
|
||||||
@@ -3209,24 +3221,25 @@ void Layer::restore(const Snapshot& snap)
|
|||||||
// it's just a quick fix DON'T SHIP!!
|
// it's just a quick fix DON'T SHIP!!
|
||||||
//m_rtt[i].recreate();
|
//m_rtt[i].recreate();
|
||||||
|
|
||||||
m_rtt[i].bindTexture();
|
App::I.render_task_async([this,i,&snap]
|
||||||
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
{
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
m_rtt[i].bindTexture();
|
||||||
m_dirty_box[i].x, m_dirty_box[i].y,
|
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
||||||
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||||
snap.image[i].get());
|
m_dirty_box[i].x, m_dirty_box[i].y,
|
||||||
m_rtt[i].unbindTexture();
|
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
LOG("restore face %d - %d bytes (%dx%d)", i,
|
snap.image[i].get());
|
||||||
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
|
m_rtt[i].unbindTexture();
|
||||||
|
LOG("restore face %d - %d bytes (%dx%d)", i,
|
||||||
|
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
App::I.render_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr*/, std::array<bool, 6> * dirty_face /*= nullptr*/)
|
Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr*/, std::array<bool, 6> * dirty_face /*= nullptr*/)
|
||||||
{
|
{
|
||||||
Snapshot snap;
|
Snapshot snap;
|
||||||
static int counter = 0;
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i];
|
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i];
|
||||||
@@ -3238,45 +3251,51 @@ Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr
|
|||||||
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
|
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
|
||||||
|
|
||||||
//glReadBuffer(GL_BACK);
|
//glReadBuffer(GL_BACK);
|
||||||
m_rtt[i].bindFramebuffer();
|
App::I.render_task_async([this,i,&snap]
|
||||||
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
|
{
|
||||||
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
|
m_rtt[i].bindFramebuffer();
|
||||||
m_rtt[i].unbindFramebuffer();
|
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
|
||||||
|
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
|
||||||
|
m_rtt[i].unbindFramebuffer();
|
||||||
|
});
|
||||||
//glReadBuffer(GL_NONE);
|
//glReadBuffer(GL_NONE);
|
||||||
}
|
}
|
||||||
counter++;
|
App::I.render_sync();
|
||||||
return snap;
|
return snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::clear(const glm::vec4& c)
|
void Layer::clear(const glm::vec4& c)
|
||||||
{
|
{
|
||||||
// push clear color state
|
App::I.render_task([&]
|
||||||
GLfloat cc[4];
|
|
||||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
|
||||||
glClearColor(c.r, c.g, c.b, c.a);
|
|
||||||
|
|
||||||
bool erase = (c.a == 0.f);
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
{
|
||||||
m_rtt[i].bindFramebuffer();
|
// push clear color state
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
GLfloat cc[4];
|
||||||
m_rtt[i].unbindFramebuffer();
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||||
|
glClearColor(c.r, c.g, c.b, c.a);
|
||||||
|
|
||||||
if (erase)
|
bool erase = (c.a == 0.f);
|
||||||
{
|
|
||||||
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
|
||||||
m_dirty_face[i] = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_dirty_box[i] = glm::vec4(0, 0, w, h); // reset bounding box
|
|
||||||
m_dirty_face[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore clear color state
|
for (int i = 0; i < 6; i++)
|
||||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
{
|
||||||
|
m_rtt[i].bindFramebuffer();
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
m_rtt[i].unbindFramebuffer();
|
||||||
|
|
||||||
|
if (erase)
|
||||||
|
{
|
||||||
|
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
||||||
|
m_dirty_face[i] = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dirty_box[i] = glm::vec4(0, 0, w, h); // reset bounding box
|
||||||
|
m_dirty_face[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore clear color state
|
||||||
|
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Layer::create(int width, int height, std::string name)
|
bool Layer::create(int width, int height, std::string name)
|
||||||
@@ -3284,15 +3303,18 @@ bool Layer::create(int width, int height, std::string name)
|
|||||||
m_name = name;
|
m_name = name;
|
||||||
w = width;
|
w = width;
|
||||||
h = height;
|
h = height;
|
||||||
for (int i = 0; i < 6; i++)
|
App::I.render_task([&]
|
||||||
{
|
{
|
||||||
m_rtt[i].create(width, height);
|
for (int i = 0; i < 6; i++)
|
||||||
m_rtt[i].bindFramebuffer();
|
{
|
||||||
m_rtt[i].clear();
|
m_rtt[i].create(width, height);
|
||||||
m_rtt[i].unbindFramebuffer();
|
m_rtt[i].bindFramebuffer();
|
||||||
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
m_rtt[i].clear();
|
||||||
m_dirty_face[i] = false;
|
m_rtt[i].unbindFramebuffer();
|
||||||
}
|
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
||||||
|
m_dirty_face[i] = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|||||||
|
|
||||||
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
if (m_draw_tip)
|
if (m_draw_tip)
|
||||||
{
|
{
|
||||||
const auto& brush = Canvas::I->m_current_brush;
|
const auto& brush = Canvas::I->m_current_brush;
|
||||||
|
|||||||
41
src/font.cpp
41
src/font.cpp
@@ -3,6 +3,8 @@
|
|||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
std::map<kFont, Font> FontManager::m_fonts;
|
std::map<kFont, Font> FontManager::m_fonts;
|
||||||
Sampler FontManager::m_sampler;
|
Sampler FontManager::m_sampler;
|
||||||
@@ -58,18 +60,21 @@ const Font& FontManager::get(kFont id)
|
|||||||
|
|
||||||
bool TextMesh::create()
|
bool TextMesh::create()
|
||||||
{
|
{
|
||||||
glGenBuffers(2, font_buffers);
|
App::I.render_task([this]
|
||||||
|
{
|
||||||
|
glGenBuffers(2, font_buffers);
|
||||||
#if USE_VBO
|
#if USE_VBO
|
||||||
glGenVertexArrays(1, &font_array);
|
glGenVertexArrays(1, &font_array);
|
||||||
glBindVertexArray(font_array);
|
glBindVertexArray(font_array);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
|
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0);
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float)*2));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float) * 2));
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
#endif // USE_VBO
|
#endif // USE_VBO
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,17 +125,21 @@ void TextMesh::update(kFont id, const char* text)
|
|||||||
vi -= glm::vec4(bbmin, 0, 0);
|
vi -= glm::vec4(bbmin, 0, 0);
|
||||||
bb = bbmax - bbmin;
|
bb = bbmax - bbmin;
|
||||||
font_array_count = (int)idx.size();
|
font_array_count = (int)idx.size();
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
App::I.render_task([&]
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(glm::vec4), v.data(), GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(glm::vec4), v.data(), GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextMesh::draw()
|
void TextMesh::draw()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
auto& f = FontManager::get(font_id);
|
auto& f = FontManager::get(font_id);
|
||||||
if (f.font_tex.ready())
|
if (f.font_tex.ready())
|
||||||
{
|
{
|
||||||
|
|||||||
185
src/main.cpp
185
src/main.cpp
@@ -33,12 +33,19 @@ std::thread::id gl_thread;
|
|||||||
std::map<kKey, int> vkey_map;
|
std::map<kKey, int> vkey_map;
|
||||||
|
|
||||||
std::thread hmd_renderer;
|
std::thread hmd_renderer;
|
||||||
std::thread renderer;
|
std::thread ui_renderer;
|
||||||
int vr_frames = 0;
|
int vr_frames = 0;
|
||||||
int running = -1;
|
int running = -1;
|
||||||
int vr_running = 0;
|
int vr_running = 0;
|
||||||
std::mutex render_mutex;
|
std::mutex ui_render_mutex;
|
||||||
|
std::condition_variable ui_render_cv;
|
||||||
|
|
||||||
|
std::deque<std::packaged_task<void()>> render_tasklist;
|
||||||
|
std::mutex render_task_mutex;
|
||||||
std::condition_variable render_cv;
|
std::condition_variable render_cv;
|
||||||
|
std::thread render_thread;
|
||||||
|
std::thread::id render_thread_id;
|
||||||
|
bool render_running = false;
|
||||||
|
|
||||||
int gl_count = 0;
|
int gl_count = 0;
|
||||||
std::deque<std::packaged_task<void()>> tasklist;
|
std::deque<std::packaged_task<void()>> tasklist;
|
||||||
@@ -112,6 +119,63 @@ void destroy_window()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_render_thread()
|
||||||
|
{
|
||||||
|
extern std::thread::id render_thread_id;
|
||||||
|
extern std::thread::id gl_thread;
|
||||||
|
return std::this_thread::get_id() == render_thread_id || std::this_thread::get_id() == gl_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename R = std::result_of<T()>::type>
|
||||||
|
std::future<R> render_task_async(T task)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern std::deque<std::packaged_task<R()>> render_tasklist;
|
||||||
|
extern std::mutex render_task_mutex;
|
||||||
|
extern std::condition_variable render_cv;
|
||||||
|
std::packaged_task<R()> pt(task);
|
||||||
|
std::future<R> f = pt.get_future();
|
||||||
|
if (is_render_thread())
|
||||||
|
{
|
||||||
|
pt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
||||||
|
render_tasklist.push_back(std::move(pt));
|
||||||
|
}
|
||||||
|
render_cv.notify_all();
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename R = std::result_of<T()>::type>
|
||||||
|
R render_task(T task)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern std::deque<std::packaged_task<R()>> render_tasklist;
|
||||||
|
extern std::mutex render_task_mutex;
|
||||||
|
extern std::condition_variable render_cv;
|
||||||
|
std::packaged_task<R()> pt(task);
|
||||||
|
std::future<R> f = pt.get_future();
|
||||||
|
if (is_render_thread())
|
||||||
|
{
|
||||||
|
pt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(render_task_mutex);
|
||||||
|
render_tasklist.push_back(std::move(pt));
|
||||||
|
}
|
||||||
|
render_cv.notify_all();
|
||||||
|
}
|
||||||
|
return f.get();
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
void async_lock()
|
void async_lock()
|
||||||
{
|
{
|
||||||
//std::lock_guard<std::mutex> _lock(async_mutex);
|
//std::lock_guard<std::mutex> _lock(async_mutex);
|
||||||
@@ -166,7 +230,7 @@ void async_unlock()
|
|||||||
|
|
||||||
void win32_render_thread_notify()
|
void win32_render_thread_notify()
|
||||||
{
|
{
|
||||||
render_cv.notify_all();
|
ui_render_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void win32_show_cursor(bool visible)
|
void win32_show_cursor(bool visible)
|
||||||
@@ -257,12 +321,6 @@ std::string win32_open_dir()
|
|||||||
return Buffer;
|
return Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct async_locker
|
|
||||||
{
|
|
||||||
async_locker() { async_lock(); }
|
|
||||||
~async_locker() { async_unlock(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
int read_WMI_info()
|
int read_WMI_info()
|
||||||
{
|
{
|
||||||
// see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html
|
// see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html
|
||||||
@@ -539,16 +597,13 @@ bool win32_vr_start()
|
|||||||
|
|
||||||
vive = new Vive;
|
vive = new Vive;
|
||||||
vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I.vr_draw(proj, view, pose); };
|
vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I.vr_draw(proj, view, pose); };
|
||||||
async_lock();
|
|
||||||
if (!vive->Initialize())
|
if (!vive->Initialize())
|
||||||
{
|
{
|
||||||
delete vive;
|
delete vive;
|
||||||
vive = nullptr;
|
vive = nullptr;
|
||||||
LOG("VR: failed to initialize vive");
|
LOG("VR: failed to initialize vive");
|
||||||
async_unlock();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
async_unlock();
|
|
||||||
|
|
||||||
hmd_renderer = std::thread([&] {
|
hmd_renderer = std::thread([&] {
|
||||||
if (!vive)
|
if (!vive)
|
||||||
@@ -726,6 +781,46 @@ BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle
|
|||||||
return fRc;
|
return fRc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void render_thread_main()
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
render_thread_id = std::this_thread::get_id();
|
||||||
|
render_running = true;
|
||||||
|
while (render_running == 1)
|
||||||
|
{
|
||||||
|
std::deque<std::packaged_task<void()>> working_list;
|
||||||
|
|
||||||
|
// move the task list locally to free the queue for other threads
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(render_task_mutex);
|
||||||
|
render_cv.wait(lock, [] { return render_tasklist.empty() && render_running ? false : true; });
|
||||||
|
working_list = std::move(render_tasklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
//{
|
||||||
|
// std::lock_guard<std::mutex> lock(task_mutex);
|
||||||
|
// working_list.insert(working_list.end(),
|
||||||
|
// std::make_move_iterator(tasklist.begin()),
|
||||||
|
// std::make_move_iterator(tasklist.end()));
|
||||||
|
// tasklist.clear();
|
||||||
|
//}
|
||||||
|
|
||||||
|
// execute the tasks
|
||||||
|
if (!working_list.empty())
|
||||||
|
{
|
||||||
|
async_lock();
|
||||||
|
while (!working_list.empty())
|
||||||
|
{
|
||||||
|
//LOG("render task %d", count);
|
||||||
|
count++;
|
||||||
|
working_list.front()();
|
||||||
|
working_list.pop_front();
|
||||||
|
}
|
||||||
|
async_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
WNDCLASS wc;
|
WNDCLASS wc;
|
||||||
@@ -917,7 +1012,10 @@ int main(int argc, char** argv)
|
|||||||
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
|
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
async_lock();
|
wglMakeCurrent(NULL, NULL);
|
||||||
|
|
||||||
|
running = 1;
|
||||||
|
render_thread = std::thread(render_thread_main);
|
||||||
|
|
||||||
LOG("init app");
|
LOG("init app");
|
||||||
App::I.init();
|
App::I.init();
|
||||||
@@ -932,15 +1030,11 @@ int main(int argc, char** argv)
|
|||||||
LOG("SKIP init WinTab");
|
LOG("SKIP init WinTab");
|
||||||
}
|
}
|
||||||
|
|
||||||
async_unlock();
|
|
||||||
|
|
||||||
LOG("change icon");
|
LOG("change icon");
|
||||||
SendMessage(hWnd, WM_SETICON, ICON_SMALL,
|
SendMessage(hWnd, WM_SETICON, ICON_SMALL,
|
||||||
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
|
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
|
||||||
|
|
||||||
running = 1;
|
ui_renderer = std::thread([&] {
|
||||||
|
|
||||||
renderer = std::thread([&] {
|
|
||||||
BT_SetTerminate();
|
BT_SetTerminate();
|
||||||
LOG("start render thread");
|
LOG("start render thread");
|
||||||
const float target_fps = 10;
|
const float target_fps = 10;
|
||||||
@@ -989,13 +1083,11 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (!working_list.empty())
|
if (!working_list.empty())
|
||||||
{
|
{
|
||||||
async_lock();
|
|
||||||
while (!working_list.empty())
|
while (!working_list.empty())
|
||||||
{
|
{
|
||||||
working_list.front()();
|
working_list.front()();
|
||||||
working_list.pop_front();
|
working_list.pop_front();
|
||||||
}
|
}
|
||||||
async_unlock();
|
|
||||||
//LOG("clear");
|
//LOG("clear");
|
||||||
//WacomTablet::I.m_stylus = false;
|
//WacomTablet::I.m_stylus = false;
|
||||||
//WacomTablet::I.m_eraser = false;
|
//WacomTablet::I.m_eraser = false;
|
||||||
@@ -1016,7 +1108,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
App::I.tick(dt);
|
App::I.tick(dt);
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(render_mutex);
|
std::unique_lock<std::mutex> lock(ui_render_mutex);
|
||||||
if (render_timer > 1.0f / target_fps)
|
if (render_timer > 1.0f / target_fps)
|
||||||
{
|
{
|
||||||
App::I.redraw = true;
|
App::I.redraw = true;
|
||||||
@@ -1041,19 +1133,20 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (App::I.redraw)
|
if (App::I.redraw)
|
||||||
{
|
{
|
||||||
async_lock();
|
render_task([frame_timer]
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
{
|
||||||
App::I.clear();
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
App::I.update(frame_timer);
|
App::I.clear();
|
||||||
SwapBuffers(hDC);
|
App::I.update(frame_timer);
|
||||||
async_unlock();
|
SwapBuffers(hDC);
|
||||||
|
});
|
||||||
frame_timer = 0;
|
frame_timer = 0;
|
||||||
frames++;
|
frames++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int framerate = (1.f / target_tick_rate) * 1000;
|
const int framerate = (1.f / target_tick_rate) * 1000;
|
||||||
const int diff = framerate - (t1 - t0);
|
const int diff = framerate - (t1 - t0);
|
||||||
render_cv.wait_for(lock, std::chrono::milliseconds(diff));
|
//render_cv.wait_for(lock, std::chrono::milliseconds(diff));
|
||||||
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||||
t0 = t1;
|
t0 = t1;
|
||||||
}
|
}
|
||||||
@@ -1109,10 +1202,11 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tasklist.empty())
|
if (!tasklist.empty())
|
||||||
render_cv.notify_all();
|
ui_render_cv.notify_all();
|
||||||
}
|
}
|
||||||
// Clean up
|
// Clean up
|
||||||
WacomTablet::I.terminate();
|
WacomTablet::I.terminate();
|
||||||
|
render_cv.notify_all();
|
||||||
|
|
||||||
UnregisterClass(className, hInst);
|
UnregisterClass(className, hInst);
|
||||||
LogRemote::I.stop();
|
LogRemote::I.stop();
|
||||||
@@ -1132,13 +1226,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
{
|
{
|
||||||
case WM_USER_CLOSE:
|
case WM_USER_CLOSE:
|
||||||
running = 0;
|
running = 0;
|
||||||
render_cv.notify_all();
|
ui_render_cv.notify_all();
|
||||||
if (renderer.joinable())
|
if (ui_renderer.joinable())
|
||||||
renderer.join();
|
ui_renderer.join();
|
||||||
if (hmd_renderer.joinable())
|
if (hmd_renderer.joinable())
|
||||||
hmd_renderer.join();
|
hmd_renderer.join();
|
||||||
App::I.terminate();
|
App::I.terminate();
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
|
render_running = false;
|
||||||
|
if (render_thread.joinable())
|
||||||
|
render_thread.join();
|
||||||
return 0;
|
return 0;
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
App::I.redraw = true;
|
App::I.redraw = true;
|
||||||
@@ -1150,13 +1247,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
if (App::I.request_close())
|
if (App::I.request_close())
|
||||||
{
|
{
|
||||||
running = 0;
|
running = 0;
|
||||||
render_cv.notify_all();
|
ui_render_cv.notify_all();
|
||||||
if (renderer.joinable())
|
if (ui_renderer.joinable())
|
||||||
renderer.join();
|
ui_renderer.join();
|
||||||
if (hmd_renderer.joinable())
|
if (hmd_renderer.joinable())
|
||||||
hmd_renderer.join();
|
hmd_renderer.join();
|
||||||
App::I.terminate();
|
App::I.terminate();
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
|
render_running = false;
|
||||||
|
if (render_thread.joinable())
|
||||||
|
render_thread.join();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1170,12 +1270,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
auto h = (float)HIWORD(lp);
|
auto h = (float)HIWORD(lp);
|
||||||
if (h != 0 && running == 1)
|
if (h != 0 && running == 1)
|
||||||
{
|
{
|
||||||
async_locker lock;
|
App::I.render_task([=]
|
||||||
App::I.resize(w, h);
|
{
|
||||||
App::I.clear();
|
App::I.resize(w, h);
|
||||||
App::I.redraw = true;
|
App::I.clear();
|
||||||
App::I.update(0.f);
|
App::I.redraw = true;
|
||||||
SwapBuffers(hDC);
|
App::I.update(0.f);
|
||||||
|
SwapBuffers(hDC);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1374,7 +1476,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
break;
|
break;
|
||||||
case WM_MOUSEWHEEL:
|
case WM_MOUSEWHEEL:
|
||||||
{
|
{
|
||||||
async_locker lock;
|
|
||||||
POINT pt;
|
POINT pt;
|
||||||
pt.x = GET_X_LPARAM(lp);
|
pt.x = GET_X_LPARAM(lp);
|
||||||
pt.y = GET_Y_LPARAM(lp);
|
pt.y = GET_Y_LPARAM(lp);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "node_colorwheel.h"
|
#include "node_colorwheel.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
Node* NodeColorWheel::clone_instantiate() const
|
Node* NodeColorWheel::clone_instantiate() const
|
||||||
{
|
{
|
||||||
@@ -42,21 +43,24 @@ void NodeColorWheel::loaded()
|
|||||||
vertices.push_back({{glm::cos(2.f/3.f*glm::pi<float>())*l,glm::sin(2.f/3.f*glm::pi<float>())*l,0,1},{0,0},{0,0,0,1}});
|
vertices.push_back({{glm::cos(2.f/3.f*glm::pi<float>())*l,glm::sin(2.f/3.f*glm::pi<float>())*l,0,1},{0,0},{0,0,0,1}});
|
||||||
vertices.push_back({{l,0,0,1},{1,1},{1,0,0,1}});
|
vertices.push_back({{l,0,0,1},{1,1},{1,0,0,1}});
|
||||||
|
|
||||||
glGenBuffers(1, &buffers);
|
App::I.render_task([&]
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
{
|
||||||
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW);
|
glGenBuffers(1, &buffers);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
glGenVertexArrays(1, &arrays);
|
glGenVertexArrays(1, &arrays);
|
||||||
glBindVertexArray(arrays);
|
glBindVertexArray(arrays);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
|
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeColorWheel::draw()
|
void NodeColorWheel::draw()
|
||||||
|
|||||||
@@ -151,11 +151,14 @@ void NodePanelGrid::init_controls()
|
|||||||
m_texture.create_mipmaps();
|
m_texture.create_mipmaps();
|
||||||
#else
|
#else
|
||||||
// get the texture data and resize it
|
// get the texture data and resize it
|
||||||
m_texture.bind();
|
|
||||||
Image img;
|
Image img;
|
||||||
img.create(m_texture.size().x, m_texture.size().y);
|
img.create(m_texture.size().x, m_texture.size().y);
|
||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data.get());
|
App::I.render_task([&]
|
||||||
m_texture.unbind();
|
{
|
||||||
|
m_texture.bind();
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data.get());
|
||||||
|
m_texture.unbind();
|
||||||
|
});
|
||||||
Image resized = img.resize(texres, texres);
|
Image resized = img.resize(texres, texres);
|
||||||
m_texture.create(resized);
|
m_texture.create(resized);
|
||||||
m_texture.create_mipmaps();
|
m_texture.create_mipmaps();
|
||||||
@@ -169,9 +172,6 @@ void NodePanelGrid::init_controls()
|
|||||||
m_plane.create<1>(1, 1);
|
m_plane.create<1>(1, 1);
|
||||||
|
|
||||||
TextureManager::load("data/sun.png");
|
TextureManager::load("data/sun.png");
|
||||||
|
|
||||||
//glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, m_line_range);
|
|
||||||
//glGetFloatv(GL_ALIASED_LINE_WIDTH_GRANULARITY, &m_line_granularity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NodePanelGrid::get_samples() const
|
int NodePanelGrid::get_samples() const
|
||||||
|
|||||||
@@ -514,13 +514,11 @@ void NodeStrokePreview::draw_stroke()
|
|||||||
// Good luck, future Omar
|
// Good luck, future Omar
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
#endif
|
#endif
|
||||||
App::I.async_start();
|
|
||||||
m_sampler_linear.create();
|
m_sampler_linear.create();
|
||||||
m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT);
|
m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT);
|
||||||
m_sampler_mipmap.create();
|
m_sampler_mipmap.create();
|
||||||
m_sampler_mipmap.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
|
m_sampler_mipmap.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
|
||||||
m_brush_shape.create();
|
m_brush_shape.create();
|
||||||
App::I.async_end();
|
|
||||||
while (s_running)
|
while (s_running)
|
||||||
{
|
{
|
||||||
auto node = s_queue.Get();
|
auto node = s_queue.Get();
|
||||||
@@ -530,43 +528,41 @@ void NodeStrokePreview::draw_stroke()
|
|||||||
bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
||||||
node->m_brush->preload();
|
node->m_brush->preload();
|
||||||
|
|
||||||
node->async_start();
|
App::I.render_task([node, to_unload]
|
||||||
|
|
||||||
gl_state gl;
|
|
||||||
gl.save();
|
|
||||||
|
|
||||||
auto new_size = node->m_preview_size;
|
|
||||||
if (!node->m_tex_preview.ready() || node->m_tex_preview.size() != new_size)
|
|
||||||
node->m_tex_preview.create((int)new_size.x, (int)new_size.y);
|
|
||||||
if (m_tex.size() != new_size)
|
|
||||||
{
|
{
|
||||||
m_rtt.create((int)new_size.x, (int)new_size.y);
|
gl_state gl;
|
||||||
m_rtt_mixer.create((int)new_size.x, (int)new_size.y);
|
gl.save();
|
||||||
m_tex.create((int)new_size.x, (int)new_size.y);
|
|
||||||
m_tex_dual.create((int)new_size.x, (int)new_size.y);
|
auto new_size = node->m_preview_size;
|
||||||
m_tex_background.create((int)new_size.x, (int)new_size.y);
|
if (!node->m_tex_preview.ready() || node->m_tex_preview.size() != new_size)
|
||||||
}
|
node->m_tex_preview.create((int)new_size.x, (int)new_size.y);
|
||||||
|
if (m_tex.size() != new_size)
|
||||||
|
{
|
||||||
|
m_rtt.create((int)new_size.x, (int)new_size.y);
|
||||||
|
m_rtt_mixer.create((int)new_size.x, (int)new_size.y);
|
||||||
|
m_tex.create((int)new_size.x, (int)new_size.y);
|
||||||
|
m_tex_dual.create((int)new_size.x, (int)new_size.y);
|
||||||
|
m_tex_background.create((int)new_size.x, (int)new_size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->m_brush->load();
|
||||||
|
node->draw_stroke_immediate();
|
||||||
|
if (to_unload)
|
||||||
|
node->m_brush->unload();
|
||||||
|
|
||||||
|
gl.restore();
|
||||||
|
});
|
||||||
|
|
||||||
node->m_brush->load();
|
|
||||||
node->draw_stroke_immediate();
|
|
||||||
if (to_unload)
|
|
||||||
node->m_brush->unload();
|
|
||||||
|
|
||||||
gl.restore();
|
|
||||||
node->app_redraw();
|
|
||||||
node->async_end();
|
|
||||||
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||||
std::this_thread::yield();
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
App::I.async_start();
|
|
||||||
m_rtt.destroy();
|
m_rtt.destroy();
|
||||||
m_rtt_mixer.destroy();
|
m_rtt_mixer.destroy();
|
||||||
m_tex.destroy();
|
m_tex.destroy();
|
||||||
m_tex_dual.destroy();
|
m_tex_dual.destroy();
|
||||||
m_tex_background.destroy();
|
m_tex_background.destroy();
|
||||||
m_brush_shape.destroy();
|
m_brush_shape.destroy();
|
||||||
App::I.async_end();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
s_queue.mutex.unlock();
|
s_queue.mutex.unlock();
|
||||||
|
|||||||
249
src/rtt.cpp
249
src/rtt.cpp
@@ -2,6 +2,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "rtt.h"
|
#include "rtt.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
RTT::RTT()
|
RTT::RTT()
|
||||||
{
|
{
|
||||||
@@ -38,19 +39,22 @@ void RTT::resize(int width, int height)
|
|||||||
{
|
{
|
||||||
RTT new_rtt;
|
RTT new_rtt;
|
||||||
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
App::I.render_task([&]
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
{
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||||
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||||
|
|
||||||
new_rtt.create(width, height, -1, int_fmt, rboID != 0);
|
new_rtt.create(width, height, -1, int_fmt, rboID != 0);
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, new_rtt.fboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, new_rtt.fboID);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
glBlitFramebuffer(0, 0, w, h, 0, 0, new_rtt.w, new_rtt.h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
glBlitFramebuffer(0, 0, w, h, 0, 0, new_rtt.w, new_rtt.h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||||
|
|
||||||
destroy();
|
destroy();
|
||||||
|
});
|
||||||
|
|
||||||
oldRFboID = 0;
|
oldRFboID = 0;
|
||||||
oldDFboID = 0;
|
oldDFboID = 0;
|
||||||
@@ -64,22 +68,25 @@ void RTT::resize(int width, int height)
|
|||||||
|
|
||||||
void RTT::destroy()
|
void RTT::destroy()
|
||||||
{
|
{
|
||||||
if (rboID)
|
App::I.render_task_async([rboID=rboID, texID=texID, fboID=fboID]
|
||||||
{
|
{
|
||||||
glDeleteRenderbuffers(1, &rboID);
|
if (rboID)
|
||||||
}
|
{
|
||||||
if (texID)
|
glDeleteRenderbuffers(1, &rboID);
|
||||||
{
|
}
|
||||||
unbindTexture();
|
if (texID)
|
||||||
glDeleteTextures(1, &texID);
|
{
|
||||||
//LOG("TEX rtt destroy %d", texID)
|
//unbindTexture();
|
||||||
}
|
glDeleteTextures(1, &texID);
|
||||||
if (fboID)
|
//LOG("TEX rtt destroy %d", texID)
|
||||||
{
|
}
|
||||||
unbindFramebuffer();
|
if (fboID)
|
||||||
glDeleteFramebuffers(1, &fboID);
|
{
|
||||||
//LOG("RTT DESTROY %d", fboID);
|
//unbindFramebuffer();
|
||||||
}
|
glDeleteFramebuffers(1, &fboID);
|
||||||
|
//LOG("RTT DESTROY %d", fboID);
|
||||||
|
}
|
||||||
|
});
|
||||||
texID = 0;
|
texID = 0;
|
||||||
fboID = 0;
|
fboID = 0;
|
||||||
rboID = 0;
|
rboID = 0;
|
||||||
@@ -89,101 +96,109 @@ void RTT::destroy()
|
|||||||
|
|
||||||
void RTT::copy(const RTT & source)
|
void RTT::copy(const RTT & source)
|
||||||
{
|
{
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
App::I.render_task([&]
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
{
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||||
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
||||||
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
|
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
|
||||||
{
|
{
|
||||||
// Destroy any previously created object
|
GLenum status = 0;
|
||||||
destroy();
|
App::I.render_task([&]
|
||||||
|
|
||||||
w = width;
|
|
||||||
h = height;
|
|
||||||
int_fmt = internal_format;
|
|
||||||
|
|
||||||
if (tex == -1)
|
|
||||||
{
|
{
|
||||||
glGenTextures(1, &texID);
|
// Destroy any previously created object
|
||||||
//LOG("TEX rtt create %d", texID);
|
destroy();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texID = tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ifmt = GL_UNSIGNED_BYTE;
|
w = width;
|
||||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
h = height;
|
||||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
int_fmt = internal_format;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texID);
|
|
||||||
if (tex == -1)
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, ifmt, 0);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
|
|
||||||
// Create a renderbuffer object to store depth info
|
if (tex == -1)
|
||||||
if (depth_buffer)
|
|
||||||
{
|
|
||||||
glGenRenderbuffers(1, &rboID);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint oldFboID;
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldFboID);
|
|
||||||
|
|
||||||
// Create a framebuffer object
|
|
||||||
glGenFramebuffers(1, &fboID);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
|
|
||||||
//LOG("RTT CREATE %d - tex %d", fboID, texID);
|
|
||||||
|
|
||||||
// Attach the texture to FBO color attachment point
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, 0);
|
|
||||||
if (depth_buffer)
|
|
||||||
{
|
|
||||||
// Attach the renderbuffer to depth attachment point
|
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto err2str = [](GLenum err) {
|
|
||||||
switch (err)
|
|
||||||
{
|
{
|
||||||
case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED";
|
glGenTextures(1, &texID);
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
//LOG("TEX rtt create %d", texID);
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
}
|
||||||
case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED";
|
else
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
{
|
||||||
default: return "UNKNOWN";
|
texID = tex;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Check FBO status
|
auto ifmt = GL_UNSIGNED_BYTE;
|
||||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||||
LOG("RTT::create failed because: %s", err2str(status));
|
|
||||||
|
|
||||||
// Switch back to window-system-provided framebuffer
|
glBindTexture(GL_TEXTURE_2D, texID);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
|
if (tex == -1)
|
||||||
oldRFboID = 0;
|
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, GL_RGBA, ifmt, 0);
|
||||||
oldDFboID = 0;
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
// Create a renderbuffer object to store depth info
|
||||||
|
if (depth_buffer)
|
||||||
|
{
|
||||||
|
glGenRenderbuffers(1, &rboID);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, rboID);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint oldFboID;
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldFboID);
|
||||||
|
|
||||||
|
// Create a framebuffer object
|
||||||
|
glGenFramebuffers(1, &fboID);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
|
||||||
|
//LOG("RTT CREATE %d - tex %d", fboID, texID);
|
||||||
|
|
||||||
|
// Attach the texture to FBO color attachment point
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texID, 0);
|
||||||
|
if (depth_buffer)
|
||||||
|
{
|
||||||
|
// Attach the renderbuffer to depth attachment point
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto err2str = [](GLenum err) {
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED";
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
||||||
|
case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED";
|
||||||
|
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
|
||||||
|
default: return "UNKNOWN";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check FBO status
|
||||||
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
LOG("RTT::create failed because: %s", err2str(status));
|
||||||
|
|
||||||
|
// Switch back to window-system-provided framebuffer
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
|
||||||
|
oldRFboID = 0;
|
||||||
|
oldDFboID = 0;
|
||||||
|
});
|
||||||
|
|
||||||
return status == GL_FRAMEBUFFER_COMPLETE;
|
return status == GL_FRAMEBUFFER_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTT::bindFramebuffer()
|
void RTT::bindFramebuffer()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (bound)
|
if (bound)
|
||||||
{
|
{
|
||||||
@@ -193,15 +208,16 @@ void RTT::bindFramebuffer()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
bound = true;
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
|
bound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTT::unbindFramebuffer()
|
void RTT::unbindFramebuffer()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
if (!bound)
|
if (!bound)
|
||||||
return;
|
return;
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||||
@@ -213,6 +229,7 @@ void RTT::unbindFramebuffer()
|
|||||||
|
|
||||||
void RTT::clear(glm::vec4 color)
|
void RTT::clear(glm::vec4 color)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
glClearColor(color.r, color.g, color.b, color.a);
|
glClearColor(color.r, color.g, color.b, color.a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
@@ -240,11 +257,14 @@ uint8_t* RTT::readTextureData(uint8_t* buffer)
|
|||||||
{
|
{
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
buffer = createBuffer();
|
buffer = createBuffer();
|
||||||
GLint old;
|
App::I.render_task([&]
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
{
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
GLint old;
|
||||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
|
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||||
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,11 +272,14 @@ float* RTT::readTextureDataFloat(float* buffer)
|
|||||||
{
|
{
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
buffer = createBufferFloat();
|
buffer = createBufferFloat();
|
||||||
GLint old;
|
App::I.render_task([&]
|
||||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
{
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
GLint old;
|
||||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||||
|
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||||
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,11 +295,13 @@ float * RTT::createBufferFloat()
|
|||||||
|
|
||||||
void RTT::bindTexture()
|
void RTT::bindTexture()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
glBindTexture(GL_TEXTURE_2D, texID);
|
glBindTexture(GL_TEXTURE_2D, texID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTT::unbindTexture()
|
void RTT::unbindTexture()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
240
src/shader.cpp
240
src/shader.cpp
@@ -2,6 +2,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
std::map<kShader, Shader> ShaderManager::m_shaders;
|
std::map<kShader, Shader> ShaderManager::m_shaders;
|
||||||
Shader* ShaderManager::m_current;
|
Shader* ShaderManager::m_current;
|
||||||
@@ -153,122 +154,135 @@ bool Shader::reload()
|
|||||||
|
|
||||||
bool Shader::create(const char* vertex, const char* fragment)
|
bool Shader::create(const char* vertex, const char* fragment)
|
||||||
{
|
{
|
||||||
GLint status;
|
bool ret = true;
|
||||||
static char infolog[4096];
|
App::I.render_task([&]
|
||||||
int infolen;
|
|
||||||
const GLchar* source;
|
|
||||||
|
|
||||||
auto vs = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
if (!vs)
|
|
||||||
{
|
{
|
||||||
return false;
|
GLint status;
|
||||||
}
|
static char infolog[4096];
|
||||||
source = vertex;
|
int infolen;
|
||||||
glShaderSource(vs, 1, &source, nullptr);
|
const GLchar* source;
|
||||||
glCompileShader(vs);
|
|
||||||
glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
|
|
||||||
glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
{
|
|
||||||
LOG("\nVERTEX SHADER: %s", m_path.c_str());
|
|
||||||
parse_error(infolog, vertex);
|
|
||||||
}
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
glDeleteShader(vs);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fs = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
if (!fs)
|
|
||||||
{
|
|
||||||
glDeleteShader(vs);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
source = fragment;
|
|
||||||
glShaderSource(fs, 1, &source, nullptr);
|
|
||||||
glCompileShader(fs);
|
|
||||||
glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
|
|
||||||
glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
{
|
|
||||||
LOG("\nFRAGMENT SHADER: %s", m_path.c_str());
|
|
||||||
parse_error(infolog, fragment);
|
|
||||||
}
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
glDeleteShader(vs);
|
|
||||||
glDeleteShader(fs);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ps = glCreateProgram();
|
|
||||||
if (!ps)
|
|
||||||
{
|
|
||||||
glDeleteShader(vs);
|
|
||||||
glDeleteShader(fs);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
glAttachShader(ps, vs);
|
|
||||||
glAttachShader(ps, fs);
|
|
||||||
glDeleteShader(vs);
|
|
||||||
glDeleteShader(fs);
|
|
||||||
|
|
||||||
glLinkProgram(ps);
|
|
||||||
if (glGetAttribLocation(ps, "pos") != -1)
|
|
||||||
glBindAttribLocation(ps, 0, "pos");
|
|
||||||
|
|
||||||
if (glGetAttribLocation(ps, "uvs") != -1)
|
|
||||||
glBindAttribLocation(ps, 1, "uvs");
|
|
||||||
|
|
||||||
if (glGetAttribLocation(ps, "uvs2") != -1)
|
|
||||||
glBindAttribLocation(ps, 2, "uvs2");
|
|
||||||
|
|
||||||
if (glGetAttribLocation(ps, "col") != -1)
|
auto vs = glCreateShader(GL_VERTEX_SHADER);
|
||||||
glBindAttribLocation(ps, 3, "col");
|
if (!vs)
|
||||||
|
|
||||||
if (glGetAttribLocation(ps, "nor") != -1)
|
|
||||||
glBindAttribLocation(ps, 3, "nor");
|
|
||||||
|
|
||||||
glLinkProgram(ps);
|
|
||||||
glGetProgramiv(ps, GL_LINK_STATUS, &status);
|
|
||||||
glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog);
|
|
||||||
if (infolen > 0)
|
|
||||||
LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog);
|
|
||||||
if (status == 0)
|
|
||||||
{
|
|
||||||
glDeleteProgram(ps);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse shader uniforms
|
|
||||||
{
|
|
||||||
GLint count;
|
|
||||||
GLint size; // size of the variable
|
|
||||||
GLenum type; // type of the variable (float, vec3 or mat4, etc)
|
|
||||||
const GLsizei bufSize = 16; // maximum name length
|
|
||||||
GLchar name[bufSize]; // variable name in GLSL
|
|
||||||
GLsizei length; // name length
|
|
||||||
glGetProgramiv(ps, GL_ACTIVE_UNIFORMS, &count);
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name);
|
ret = false;
|
||||||
m_umap[(kShaderUniform)const_hash(name)] = glGetUniformLocation(ps, name);
|
return;
|
||||||
//printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name));
|
|
||||||
}
|
}
|
||||||
}
|
source = vertex;
|
||||||
|
glShaderSource(vs, 1, &source, nullptr);
|
||||||
|
glCompileShader(vs);
|
||||||
|
glGetShaderiv(vs, GL_COMPILE_STATUS, &status);
|
||||||
|
glGetShaderInfoLog(vs, sizeof(infolog), &infolen, infolog);
|
||||||
|
if (infolen > 0)
|
||||||
|
{
|
||||||
|
LOG("\nVERTEX SHADER: %s", m_path.c_str());
|
||||||
|
parse_error(infolog, vertex);
|
||||||
|
}
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
glDeleteShader(vs);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fs = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
if (!fs)
|
||||||
|
{
|
||||||
|
glDeleteShader(vs);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
source = fragment;
|
||||||
|
glShaderSource(fs, 1, &source, nullptr);
|
||||||
|
glCompileShader(fs);
|
||||||
|
glGetShaderiv(fs, GL_COMPILE_STATUS, &status);
|
||||||
|
glGetShaderInfoLog(fs, sizeof(infolog), &infolen, infolog);
|
||||||
|
if (infolen > 0)
|
||||||
|
{
|
||||||
|
LOG("\nFRAGMENT SHADER: %s", m_path.c_str());
|
||||||
|
parse_error(infolog, fragment);
|
||||||
|
}
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ps = glCreateProgram();
|
||||||
|
if (!ps)
|
||||||
|
{
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glAttachShader(ps, vs);
|
||||||
|
glAttachShader(ps, fs);
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
|
||||||
|
glLinkProgram(ps);
|
||||||
|
if (glGetAttribLocation(ps, "pos") != -1)
|
||||||
|
glBindAttribLocation(ps, 0, "pos");
|
||||||
|
|
||||||
|
if (glGetAttribLocation(ps, "uvs") != -1)
|
||||||
|
glBindAttribLocation(ps, 1, "uvs");
|
||||||
|
|
||||||
|
if (glGetAttribLocation(ps, "uvs2") != -1)
|
||||||
|
glBindAttribLocation(ps, 2, "uvs2");
|
||||||
|
|
||||||
|
if (glGetAttribLocation(ps, "col") != -1)
|
||||||
|
glBindAttribLocation(ps, 3, "col");
|
||||||
|
|
||||||
|
if (glGetAttribLocation(ps, "nor") != -1)
|
||||||
|
glBindAttribLocation(ps, 3, "nor");
|
||||||
|
|
||||||
|
glLinkProgram(ps);
|
||||||
|
glGetProgramiv(ps, GL_LINK_STATUS, &status);
|
||||||
|
glGetProgramInfoLog(ps, sizeof(infolog), &infolen, infolog);
|
||||||
|
if (infolen > 0)
|
||||||
|
LOG("LINK SHADER: %s\n%s", m_path.c_str(), infolog);
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
glDeleteProgram(ps);
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse shader uniforms
|
||||||
|
{
|
||||||
|
GLint count;
|
||||||
|
GLint size; // size of the variable
|
||||||
|
GLenum type; // type of the variable (float, vec3 or mat4, etc)
|
||||||
|
const GLsizei bufSize = 16; // maximum name length
|
||||||
|
GLchar name[bufSize]; // variable name in GLSL
|
||||||
|
GLsizei length; // name length
|
||||||
|
glGetProgramiv(ps, GL_ACTIVE_UNIFORMS, &count);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name);
|
||||||
|
m_umap[(kShaderUniform)const_hash(name)] = glGetUniformLocation(ps, name);
|
||||||
|
//printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prog = ps;
|
||||||
|
});
|
||||||
|
|
||||||
prog = ps;
|
return ret;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::destroy()
|
void Shader::destroy()
|
||||||
{
|
{
|
||||||
if (prog)
|
if (prog)
|
||||||
{
|
{
|
||||||
glUseProgram(0);
|
App::I.render_task_async([prog=prog]
|
||||||
glDeleteProgram(prog);
|
{
|
||||||
|
glUseProgram(0);
|
||||||
|
glDeleteProgram(prog);
|
||||||
|
});
|
||||||
prog = 0;
|
prog = 0;
|
||||||
}
|
}
|
||||||
m_umap.clear();
|
m_umap.clear();
|
||||||
@@ -276,16 +290,19 @@ void Shader::destroy()
|
|||||||
|
|
||||||
void Shader::use()
|
void Shader::use()
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
glUseProgram(prog);
|
glUseProgram(prog);
|
||||||
}
|
}
|
||||||
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
||||||
{
|
{
|
||||||
if (m_umap.count(id) == 0)
|
assert(App::I.is_render_thread());
|
||||||
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else glUniform4fv(m_umap[id], 1, glm::value_ptr(v));
|
else glUniform4fv(m_umap[id], 1, glm::value_ptr(v));
|
||||||
}
|
}
|
||||||
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else glUniform3fv(m_umap[id], 1, glm::value_ptr(v));
|
else glUniform3fv(m_umap[id], 1, glm::value_ptr(v));
|
||||||
@@ -293,19 +310,22 @@ void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
|||||||
|
|
||||||
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
||||||
{
|
{
|
||||||
if (m_umap.count(id) == 0)
|
assert(App::I.is_render_thread());
|
||||||
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else glUniform2fv(m_umap[id], 1, glm::value_ptr(v));
|
else glUniform2fv(m_umap[id], 1, glm::value_ptr(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
||||||
{
|
{
|
||||||
if (m_umap.count(id) == 0)
|
assert(App::I.is_render_thread());
|
||||||
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m));
|
else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m));
|
||||||
}
|
}
|
||||||
void Shader::u_int(kShaderUniform id, int i)
|
void Shader::u_int(kShaderUniform id, int i)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
if (m_umap.count(id) == 0)
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else
|
else
|
||||||
@@ -313,12 +333,14 @@ void Shader::u_int(kShaderUniform id, int i)
|
|||||||
}
|
}
|
||||||
void Shader::u_float(kShaderUniform id, float f)
|
void Shader::u_float(kShaderUniform id, float f)
|
||||||
{
|
{
|
||||||
if (m_umap.count(id) == 0)
|
assert(App::I.is_render_thread());
|
||||||
|
if (m_umap.count(id) == 0)
|
||||||
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
|
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||||
else glUniform1f(m_umap[id], f);
|
else glUniform1f(m_umap[id], f);
|
||||||
}
|
}
|
||||||
GLint Shader::GetAttribLocation(const char* name)
|
GLint Shader::GetAttribLocation(const char* name)
|
||||||
{
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
return glGetAttribLocation(prog, name);
|
return glGetAttribLocation(prog, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
326
src/shape.cpp
326
src/shape.cpp
@@ -1,6 +1,7 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
bool Shape::create_buffers(GLushort * idx, GLvoid * vertices, int isize, int vsize)
|
bool Shape::create_buffers(GLushort * idx, GLvoid * vertices, int isize, int vsize)
|
||||||
{
|
{
|
||||||
@@ -20,79 +21,99 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
|
|||||||
{
|
{
|
||||||
use_idx = true;
|
use_idx = true;
|
||||||
|
|
||||||
destroy();
|
bool ret = false;
|
||||||
|
App::I.render_task([&]
|
||||||
glGenBuffers(2, buffers);
|
|
||||||
if (!(buffers[0] && buffers[1]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, vsize, vertices, GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
#if USE_VBO
|
|
||||||
glGenVertexArrays(2, arrays);
|
|
||||||
if (!(arrays[0] && arrays[1]))
|
|
||||||
return false;
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
{
|
||||||
glBindVertexArray(arrays[i]);
|
destroy();
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
glGenBuffers(2, buffers);
|
||||||
glEnableVertexAttribArray(2);
|
if (!(buffers[0] && buffers[1]))
|
||||||
glEnableVertexAttribArray(3);
|
{
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
glBufferData(GL_ARRAY_BUFFER, vsize, vertices, GL_STATIC_DRAW);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs2));
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, nor));
|
|
||||||
}
|
#if USE_VBO
|
||||||
glBindVertexArray(0);
|
glGenVertexArrays(2, arrays);
|
||||||
|
if (!(arrays[0] && arrays[1]))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
glBindVertexArray(arrays[i]);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs2));
|
||||||
|
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, nor));
|
||||||
|
}
|
||||||
|
glBindVertexArray(0);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
});
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
bool Shape::create_buffers(GLvoid* vertices, int vsize)
|
bool Shape::create_buffers(GLvoid* vertices, int vsize)
|
||||||
{
|
{
|
||||||
use_idx = false;
|
use_idx = false;
|
||||||
|
|
||||||
destroy();
|
bool ret = false;
|
||||||
|
App::I.render_task([&]
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
glGenBuffers(1, buffers);
|
||||||
|
if (!buffers[0])
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vsize)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vsize, vertices, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
glGenBuffers(1, buffers);
|
|
||||||
if (!buffers[0])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (vsize)
|
|
||||||
{
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, vsize, vertices, GL_STATIC_DRAW);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if USE_VBO
|
#if USE_VBO
|
||||||
glGenVertexArrays(2, arrays);
|
glGenVertexArrays(2, arrays);
|
||||||
if (!(arrays[0] && arrays[1]))
|
if (!(arrays[0] && arrays[1]))
|
||||||
return false;
|
{
|
||||||
for (int i = 0; i < 2; i++)
|
ret = false;
|
||||||
{
|
return;
|
||||||
glBindVertexArray(arrays[i]);
|
}
|
||||||
glEnableVertexAttribArray(0);
|
for (int i = 0; i < 2; i++)
|
||||||
glEnableVertexAttribArray(1);
|
{
|
||||||
glEnableVertexAttribArray(2);
|
glBindVertexArray(arrays[i]);
|
||||||
glEnableVertexAttribArray(3);
|
glEnableVertexAttribArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
glEnableVertexAttribArray(1);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
glEnableVertexAttribArray(2);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
glEnableVertexAttribArray(3);
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs2));
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, nor));
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
||||||
}
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
glBindVertexArray(0);
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs2));
|
||||||
|
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, nor));
|
||||||
|
}
|
||||||
|
glBindVertexArray(0);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
});
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
void Shape::draw_fill() const
|
void Shape::draw_fill() const
|
||||||
{
|
{
|
||||||
@@ -103,31 +124,34 @@ void Shape::draw_fill() const
|
|||||||
type = GL_POINTS;
|
type = GL_POINTS;
|
||||||
if (count[0] == 2)
|
if (count[0] == 2)
|
||||||
type = GL_LINES;
|
type = GL_LINES;
|
||||||
#if USE_VBO
|
App::I.render_task([=]
|
||||||
glBindVertexArray(arrays[0]);
|
|
||||||
if (use_idx)
|
|
||||||
glDrawElements(type, count[0], index_type, ioff[0]);
|
|
||||||
else
|
|
||||||
glDrawArrays(type, 0, count[0]);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
#else
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
|
||||||
if (use_idx)
|
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
#if USE_VBO
|
||||||
glDrawElements(type, count[0], GL_UNSIGNED_SHORT, ioff[0]);
|
glBindVertexArray(arrays[0]);
|
||||||
}
|
if (use_idx)
|
||||||
else
|
glDrawElements(type, count[0], index_type, ioff[0]);
|
||||||
glDrawArrays(type, 0, count[0]);
|
else
|
||||||
glDisableVertexAttribArray(0);
|
glDrawArrays(type, 0, count[0]);
|
||||||
glDisableVertexAttribArray(1);
|
glBindVertexArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
#else
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
|
if (use_idx)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
|
glDrawElements(type, count[0], GL_UNSIGNED_SHORT, ioff[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glDrawArrays(type, 0, count[0]);
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
#endif // USE_VBO
|
#endif // USE_VBO
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Shape::draw_stroke() const
|
void Shape::draw_stroke() const
|
||||||
{
|
{
|
||||||
@@ -136,32 +160,61 @@ void Shape::draw_stroke() const
|
|||||||
GLenum type = GL_LINES;
|
GLenum type = GL_LINES;
|
||||||
if (count[1] == 1)
|
if (count[1] == 1)
|
||||||
type = GL_POINTS;
|
type = GL_POINTS;
|
||||||
#if USE_VBO
|
App::I.render_task([=]
|
||||||
glBindVertexArray(arrays[1]);
|
|
||||||
if (use_idx)
|
|
||||||
glDrawElements(type, count[1], index_type, ioff[1]);
|
|
||||||
else
|
|
||||||
glDrawArrays(type, 0, count[1]);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
#else
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
|
||||||
if (use_idx)
|
|
||||||
{
|
{
|
||||||
|
#if USE_VBO
|
||||||
|
glBindVertexArray(arrays[1]);
|
||||||
|
if (use_idx)
|
||||||
|
glDrawElements(type, count[1], index_type, ioff[1]);
|
||||||
|
else
|
||||||
|
glDrawArrays(type, 0, count[1]);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
#else
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
glDrawElements(type, count[1], GL_UNSIGNED_SHORT, ioff[1]);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
}
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)0);
|
||||||
else
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||||
glDrawArrays(type, 0, count[1]);
|
if (use_idx)
|
||||||
glDisableVertexAttribArray(0);
|
{
|
||||||
glDisableVertexAttribArray(1);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glDrawElements(type, count[1], GL_UNSIGNED_SHORT, ioff[1]);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
}
|
||||||
|
else
|
||||||
|
glDrawArrays(type, 0, count[1]);
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
#endif // USE_VBO
|
#endif // USE_VBO
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shape::destroy()
|
||||||
|
{
|
||||||
|
App::I.render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
|
||||||
|
{
|
||||||
|
if (b1 || b2)
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &b1);
|
||||||
|
glDeleteBuffers(1, &b2);
|
||||||
|
}
|
||||||
|
#if USE_VBO
|
||||||
|
if (a1 || a2)
|
||||||
|
{
|
||||||
|
glDeleteVertexArrays(1, &a1);
|
||||||
|
glDeleteVertexArrays(1, &a2);
|
||||||
|
}
|
||||||
|
#endif // USE_VBO
|
||||||
|
});
|
||||||
|
buffers[0] = buffers[1] = 0;
|
||||||
|
arrays[0] = arrays[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shape::~Shape()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RectShape::create(float w, float h)
|
bool RectShape::create(float w, float h)
|
||||||
@@ -437,21 +490,24 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
|
|||||||
vertices[i].pos.z = q;
|
vertices[i].pos.z = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
App::I.render_task([this]
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
{
|
||||||
static GLushort idx[6 + 8]{
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
0, 1, 2,
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
0, 2, 3,
|
static GLushort idx[6 + 8]{
|
||||||
0, 1,
|
0, 1, 2,
|
||||||
1, 2,
|
0, 2, 3,
|
||||||
2, 3,
|
0, 1,
|
||||||
3, 0,
|
1, 2,
|
||||||
};
|
2, 3,
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
3, 0,
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
};
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Circle::create_impl(float radius, int div, GLushort* idx, vertex_t* vertices)
|
void Circle::create_impl(float radius, int div, GLushort* idx, vertex_t* vertices)
|
||||||
{
|
{
|
||||||
@@ -704,18 +760,24 @@ void Sphere::create_impl(int rings, int sectors, float radius,
|
|||||||
}
|
}
|
||||||
void LineSegment::update_vertices(const glm::vec4 data[2])
|
void LineSegment::update_vertices(const glm::vec4 data[2])
|
||||||
{
|
{
|
||||||
static vertex_t vertices[2];
|
App::I.render_task([&]
|
||||||
vertices[0] = { data[0], { 0, 0 } }; // A
|
{
|
||||||
vertices[1] = { data[1], { 0, 1 } }; // B
|
static vertex_t vertices[2];
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
vertices[0] = { data[0], { 0, 0 } }; // A
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
vertices[1] = { data[1], { 0, 1 } }; // B
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
|
void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
|
||||||
{
|
{
|
||||||
count[0] = vcount;
|
App::I.render_task([&]
|
||||||
count[1] = vcount;
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
count[0] = vcount;
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_t) * vcount, vertices, GL_STATIC_DRAW);
|
count[1] = vcount;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_t) * vcount, vertices, GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/shape.h
17
src/shape.h
@@ -25,22 +25,9 @@ public:
|
|||||||
bool create_buffers(GLvoid* vertices, int vsize);
|
bool create_buffers(GLvoid* vertices, int vsize);
|
||||||
void draw_fill() const;
|
void draw_fill() const;
|
||||||
void draw_stroke() const;
|
void draw_stroke() const;
|
||||||
void destroy()
|
void destroy();
|
||||||
{
|
|
||||||
if (buffers[0] || buffers[1])
|
|
||||||
glDeleteBuffers(2, buffers);
|
|
||||||
#if USE_VBO
|
|
||||||
if (arrays[0] || arrays[1])
|
|
||||||
glDeleteVertexArrays(2, arrays);
|
|
||||||
#endif // USE_VBO
|
|
||||||
buffers[0] = buffers[1] = 0;
|
|
||||||
arrays[0] = arrays[1] = 0;
|
|
||||||
}
|
|
||||||
virtual bool create_attrib() { return true; };
|
virtual bool create_attrib() { return true; };
|
||||||
~Shape()
|
~Shape();
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
protected:
|
protected:
|
||||||
glm::vec2 quad_mid_point(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d)
|
glm::vec2 quad_mid_point(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d)
|
||||||
{
|
{
|
||||||
|
|||||||
135
src/texture.cpp
135
src/texture.cpp
@@ -41,19 +41,22 @@ void TextureManager::invalidate()
|
|||||||
|
|
||||||
bool Texture2D::create(int width, int height, GLint internal_format, GLint format, const uint8_t* data)
|
bool Texture2D::create(int width, int height, GLint internal_format, GLint format, const uint8_t* data)
|
||||||
{
|
{
|
||||||
destroy();
|
App::I.render_task([=]
|
||||||
m_width = width;
|
{
|
||||||
m_height = height;
|
destroy();
|
||||||
m_format = format;
|
m_width = width;
|
||||||
m_iformat = internal_format;
|
m_height = height;
|
||||||
glGenTextures(1, &m_tex);
|
m_format = format;
|
||||||
//LOG("TEX create %d", m_tex);
|
m_iformat = internal_format;
|
||||||
bind();
|
glGenTextures(1, &m_tex);
|
||||||
auto ifmt = GL_UNSIGNED_BYTE;
|
//LOG("TEX create %d", m_tex);
|
||||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
bind();
|
||||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
auto ifmt = GL_UNSIGNED_BYTE;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, ifmt, data);
|
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||||
unbind();
|
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, ifmt, data);
|
||||||
|
unbind();
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Texture2D::create(const Image& img)
|
bool Texture2D::create(const Image& img)
|
||||||
@@ -65,10 +68,13 @@ bool Texture2D::create(const Image& img)
|
|||||||
|
|
||||||
void Texture2D::create_mipmaps()
|
void Texture2D::create_mipmaps()
|
||||||
{
|
{
|
||||||
bind();
|
App::I.render_task([this]
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
{
|
||||||
unbind();
|
bind();
|
||||||
has_mips = true;
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
unbind();
|
||||||
|
has_mips = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/)
|
void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/)
|
||||||
@@ -98,10 +104,37 @@ bool Texture2D::load_file(std::string filename)
|
|||||||
return create(img);
|
return create(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Texture2D::destroy()
|
||||||
|
{
|
||||||
|
if (m_tex)
|
||||||
|
{
|
||||||
|
App::I.render_task_async([id = m_tex]
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &id);
|
||||||
|
});
|
||||||
|
m_tex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::bind() const
|
||||||
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::unbind() const
|
||||||
|
{
|
||||||
|
assert(App::I.is_render_thread());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void Texture2D::update(const uint8_t* data)
|
void Texture2D::update(const uint8_t* data)
|
||||||
{
|
{
|
||||||
bind();
|
App::I.render_task([this, data]
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data);
|
{
|
||||||
|
bind();
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Texture2D::size() const
|
glm::vec2 Texture2D::size() const
|
||||||
@@ -113,57 +146,81 @@ Texture2D::~Texture2D()
|
|||||||
{
|
{
|
||||||
if (auto_destroy)
|
if (auto_destroy)
|
||||||
{
|
{
|
||||||
LOG("Texture2D auto destroy");
|
App::I.render_task_async([this]
|
||||||
App::I.async_start();
|
{
|
||||||
destroy();
|
LOG("Texture2D auto destroy");
|
||||||
App::I.async_end();
|
destroy();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sampler::create(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
|
bool Sampler::create(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
|
App::I.render_task([this, &ret, filter, wrap]
|
||||||
|
{
|
||||||
#if USE_SAMPLER
|
#if USE_SAMPLER
|
||||||
glGenSamplers(1, &id);
|
glGenSamplers(1, &id);
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
return false;
|
{
|
||||||
set(filter, wrap);
|
ret = false;
|
||||||
return true;
|
return;
|
||||||
|
}
|
||||||
|
set(filter, wrap);
|
||||||
|
ret = true;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
|
void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
|
||||||
{
|
{
|
||||||
|
App::I.render_task([=]
|
||||||
|
{
|
||||||
#if USE_SAMPLER
|
#if USE_SAMPLER
|
||||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap);
|
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap);
|
||||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap);
|
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap);
|
||||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_R, wrap);
|
glSamplerParameteri(id, GL_TEXTURE_WRAP_R, wrap);
|
||||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter);
|
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter);
|
||||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
|
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Sampler::set_filter(GLint filter_min, GLint filter_mag)
|
void Sampler::set_filter(GLint filter_min, GLint filter_mag)
|
||||||
{
|
{
|
||||||
|
App::I.render_task([=]
|
||||||
|
{
|
||||||
#if USE_SAMPLER
|
#if USE_SAMPLER
|
||||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
|
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
|
||||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
|
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Sampler::set_border(glm::vec4 rgba)
|
void Sampler::set_border(glm::vec4 rgba)
|
||||||
{
|
{
|
||||||
|
App::I.render_task([this, rgba]
|
||||||
|
{
|
||||||
#if USE_SAMPLER && !defined(__IOS__) && !defined(__ANDROID__)
|
#if USE_SAMPLER && !defined(__IOS__) && !defined(__ANDROID__)
|
||||||
glSamplerParameterfv(id, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(rgba));
|
glSamplerParameterfv(id, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(rgba));
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Sampler::bind(int unit) const
|
void Sampler::bind(int unit) const
|
||||||
{
|
{
|
||||||
current_unit = unit;
|
App::I.render_task([=]
|
||||||
|
{
|
||||||
|
current_unit = unit;
|
||||||
#if USE_SAMPLER
|
#if USE_SAMPLER
|
||||||
glBindSampler(unit, id);
|
glBindSampler(unit, id);
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void Sampler::unbind()
|
void Sampler::unbind()
|
||||||
{
|
{
|
||||||
|
App::I.render_task([=]
|
||||||
|
{
|
||||||
#if USE_SAMPLER
|
#if USE_SAMPLER
|
||||||
glBindSampler(current_unit, 0);
|
glBindSampler(current_unit, 0);
|
||||||
#endif // USE_SAMPLER
|
#endif // USE_SAMPLER
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ public:
|
|||||||
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
|
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
|
||||||
bool load(std::string filename);
|
bool load(std::string filename);
|
||||||
bool load_file(std::string filename);
|
bool load_file(std::string filename);
|
||||||
void destroy() { if (m_tex) /*LOG("TEX destroy %d", m_tex);*/ glDeleteTextures(1, &m_tex); m_tex = 0; }
|
void destroy();
|
||||||
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
void bind() const;
|
||||||
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
void unbind() const;
|
||||||
void update(const uint8_t* data);
|
void update(const uint8_t* data);
|
||||||
bool ready() const { return m_tex != 0; }
|
bool ready() const { return m_tex != 0; }
|
||||||
void create_mipmaps();
|
void create_mipmaps();
|
||||||
|
|||||||
Reference in New Issue
Block a user