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
|
||||
if (success)
|
||||
{
|
||||
async_start();
|
||||
title_update();
|
||||
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);
|
||||
l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible);
|
||||
}
|
||||
async_end();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -80,7 +78,6 @@ bool App::request_close()
|
||||
return true;
|
||||
if (!dialog_already_opened)
|
||||
{
|
||||
async_start();
|
||||
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
||||
m->m_title->set_text("Unsaved document");
|
||||
m->m_message->set_text("Do you want to close without saving?");
|
||||
@@ -100,8 +97,6 @@ bool App::request_close()
|
||||
m->destroy();
|
||||
dialog_already_opened = false;
|
||||
};
|
||||
async_redraw();
|
||||
async_end();
|
||||
dialog_already_opened = true;
|
||||
}
|
||||
return false;
|
||||
@@ -109,6 +104,7 @@ bool App::request_close()
|
||||
|
||||
void App::clear()
|
||||
{
|
||||
assert(is_render_thread());
|
||||
glClearColor(.1f, .1f, .1f, 1.f);
|
||||
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()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
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
|
||||
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id,
|
||||
GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
|
||||
|
||||
render_task([]
|
||||
{
|
||||
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 _WIN32 && _DEBUG
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH)
|
||||
__debugbreak();
|
||||
#endif
|
||||
}
|
||||
}, nullptr);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glDebugMessageCallback(handle_gl_callback, nullptr);
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
});
|
||||
}
|
||||
#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);
|
||||
|
||||
//zoom = ceilf(width / 2000.f);
|
||||
//zoom = 2;
|
||||
render_task([]
|
||||
{
|
||||
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);
|
||||
#if defined(_WIN32) || defined(__OSX__)
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
#endif
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
#if defined(_WIN32) || defined(__OSX__)
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
#endif
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
|
||||
});
|
||||
|
||||
int run_counter = Settings::value<Serializer::Integer>("run_counter") + 1;
|
||||
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.");
|
||||
}
|
||||
|
||||
//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()
|
||||
@@ -700,7 +695,6 @@ void App::terminate()
|
||||
NodeStrokePreview::terminate_renderer();
|
||||
rec_stop();
|
||||
|
||||
async_start();
|
||||
TextureManager::invalidate();
|
||||
ShaderManager::invalidate();
|
||||
layout.unload();
|
||||
@@ -716,7 +710,6 @@ void App::terminate()
|
||||
floating_layers.reset();
|
||||
floating_picker.reset();
|
||||
quick_mode_state.clear();
|
||||
async_end();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
async_start();
|
||||
auto* m = layout[main_id]->add_child<NodeMessageBox>();
|
||||
m->m_title->set_text(title.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)
|
||||
m->btn_cancel->destroy();
|
||||
layout[main_id]->update();
|
||||
async_redraw();
|
||||
async_end();
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -80,7 +77,6 @@ void App::dialog_about()
|
||||
void App::dialog_newdoc()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
async_start();
|
||||
auto dialog = std::make_shared<NodeDialogNewDoc>();
|
||||
dialog->m_manager = &layout;
|
||||
dialog->init();
|
||||
@@ -153,7 +149,6 @@ void App::dialog_newdoc()
|
||||
dialog->destroy();
|
||||
App::I.hideKeyboard();
|
||||
};
|
||||
async_end();
|
||||
};
|
||||
|
||||
if (canvas)
|
||||
@@ -190,7 +185,6 @@ void App::dialog_newdoc()
|
||||
void App::dialog_open()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
async_start();
|
||||
// load thumbnail test
|
||||
auto dialog = std::make_shared<NodeDialogOpen>();
|
||||
dialog->m_manager = &layout;
|
||||
@@ -217,7 +211,6 @@ void App::dialog_open()
|
||||
// dialog->destroy();
|
||||
// ActionManager::clear();
|
||||
};
|
||||
async_end();
|
||||
};
|
||||
|
||||
if (canvas)
|
||||
@@ -253,7 +246,6 @@ void App::dialog_open()
|
||||
void App::dialog_browse()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
async_start();
|
||||
// load thumbnail test
|
||||
auto dialog = std::make_shared<NodeDialogBrowse>();
|
||||
dialog->m_manager = &layout;
|
||||
@@ -277,7 +269,6 @@ void App::dialog_browse()
|
||||
dialog->destroy();
|
||||
}
|
||||
};
|
||||
async_end();
|
||||
};
|
||||
|
||||
if (canvas)
|
||||
|
||||
@@ -9,16 +9,18 @@ void App::initShaders()
|
||||
std::logic_error("check_uniform_uniqueness() failed");
|
||||
#endif // _DEBUG
|
||||
|
||||
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("shader_framebuffer_fetch") != std::string::npos)
|
||||
render_task([] {
|
||||
GLint n_exts;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
|
||||
for (int i = 0; i < n_exts; i++)
|
||||
{
|
||||
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");
|
||||
|
||||
|
||||
111
src/brush.cpp
111
src/brush.cpp
@@ -6,6 +6,7 @@
|
||||
|
||||
void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4& proj)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
std::vector<instance_t> attributes;
|
||||
attributes.reserve(samples.size());
|
||||
for (const auto& s : samples)
|
||||
@@ -69,64 +70,74 @@ void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4&
|
||||
}
|
||||
bool BrushMesh::create()
|
||||
{
|
||||
static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 };
|
||||
static vertex_t vertices[4]{
|
||||
{ { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C
|
||||
{ { -.5f, .5f, 0, 1 }, { 0, 1 } }, // B --\ | |
|
||||
{ { .5f, .5f, 0, 1 }, { 1, 1 } }, // C --/ | |
|
||||
{ { .5f, -.5f, 0, 1 }, { 1, 0 } }, // D A----D
|
||||
};
|
||||
glGenBuffers(3, buffers);
|
||||
if (!(buffers[0] && buffers[1] && buffers[2]))
|
||||
return false;
|
||||
bool ret = true;
|
||||
App::I.render_task([&]
|
||||
{
|
||||
static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 };
|
||||
static vertex_t vertices[4]{
|
||||
{ { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C
|
||||
{ { -.5f, .5f, 0, 1 }, { 0, 1 } }, // B --\ | |
|
||||
{ { .5f, .5f, 0, 1 }, { 1, 1 } }, // C --/ | |
|
||||
{ { .5f, -.5f, 0, 1 }, { 1, 0 } }, // D A----D
|
||||
};
|
||||
glGenBuffers(3, buffers);
|
||||
if (!(buffers[0] && buffers[1] && buffers[2]))
|
||||
{
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
|
||||
static instance_t inst{ glm::mat4(1), .1f };
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(instance_t), &inst, GL_STATIC_DRAW);
|
||||
static instance_t inst{ glm::mat4(1), .1f };
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(instance_t), &inst, 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, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_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_mvp = shader->GetAttribLocation("a_mvp");
|
||||
loc_flow = shader->GetAttribLocation("a_flow");
|
||||
loc_mvp = shader->GetAttribLocation("a_mvp");
|
||||
|
||||
#if USE_VBO
|
||||
glGenVertexArrays(1, &vao);
|
||||
if (!vao)
|
||||
return false;
|
||||
glBindVertexArray(vao);
|
||||
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*)offsetof(vertex_t, pos));
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||
// Loop over each column of the matrix...
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Set up the vertex attribute
|
||||
glVertexAttribPointer(loc_mvp + i, 4, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||
(GLvoid*)(offsetof(instance_t, mvp) + sizeof(glm::vec4) * i));
|
||||
// Enable it
|
||||
glEnableVertexAttribArray(loc_mvp + i);
|
||||
// Make it instanced
|
||||
glVertexAttribDivisor(loc_mvp + i, 1);
|
||||
}
|
||||
glEnableVertexAttribArray(loc_flow);
|
||||
glVertexAttribPointer(loc_flow, 1, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||
(GLvoid*)offsetof(instance_t, flow));
|
||||
glVertexAttribDivisor(loc_flow, 1);
|
||||
glBindVertexArray(0);
|
||||
glGenVertexArrays(1, &vao);
|
||||
if (!vao)
|
||||
{
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
glBindVertexArray(vao);
|
||||
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*)offsetof(vertex_t, pos));
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||
// Loop over each column of the matrix...
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Set up the vertex attribute
|
||||
glVertexAttribPointer(loc_mvp + i, 4, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||
(GLvoid*)(offsetof(instance_t, mvp) + sizeof(glm::vec4) * i));
|
||||
// Enable it
|
||||
glEnableVertexAttribArray(loc_mvp + i);
|
||||
// Make it instanced
|
||||
glVertexAttribDivisor(loc_mvp + i, 1);
|
||||
}
|
||||
glEnableVertexAttribArray(loc_flow);
|
||||
glVertexAttribPointer(loc_flow, 1, GL_FLOAT, GL_FALSE, sizeof(instance_t),
|
||||
(GLvoid*)offsetof(instance_t, flow));
|
||||
glVertexAttribDivisor(loc_flow, 1);
|
||||
glBindVertexArray(0);
|
||||
#endif
|
||||
});
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
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])
|
||||
continue;
|
||||
auto& rtt = layer->m_rtt[plane];
|
||||
rtt.bindTexture();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(),
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get());
|
||||
rtt.unbindTexture();
|
||||
App::I.render_task([&]
|
||||
{
|
||||
rtt.bindTexture();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -2766,111 +2769,115 @@ bool Canvas::project_open_thread(std::string file_path)
|
||||
|
||||
Image Canvas::thumbnail_generate(int w, int h)
|
||||
{
|
||||
// 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);
|
||||
Image image;
|
||||
image.create(w, h);
|
||||
|
||||
// prepare common states
|
||||
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++)
|
||||
App::I.render_task([this, w, h, &image]
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
auto plane_mvp = proj * m_mv * m_plane_transform[i] * glm::translate(glm::vec3(0, 0, -1));
|
||||
// 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);
|
||||
|
||||
ShaderManager::use(kShader::TextureBlend);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_int(kShaderUniform::TexA, 1);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
||||
if (!ShaderManager::ext_framebuffer_fetch)
|
||||
// prepare common states
|
||||
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++)
|
||||
{
|
||||
ShaderManager::u_int(kShaderUniform::TexBG, 2);
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
blendtex.bind();
|
||||
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;
|
||||
glDisable(GL_BLEND);
|
||||
auto plane_mvp = proj * m_mv * m_plane_transform[i] * glm::translate(glm::vec3(0, 0, -1));
|
||||
|
||||
ShaderManager::use(kShader::TextureBlend);
|
||||
ShaderManager::u_int(kShaderUniform::Tex, 0);
|
||||
ShaderManager::u_int(kShaderUniform::TexA, 1);
|
||||
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
|
||||
if (!ShaderManager::ext_framebuffer_fetch)
|
||||
{
|
||||
ShaderManager::u_int(kShaderUniform::TexBG, 2);
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
blendtex.bind();
|
||||
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)
|
||||
{
|
||||
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_TEXTURE2);
|
||||
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
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
// 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);
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
App::I.render_task([&]
|
||||
{
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
layer.m_rtt[i].unbindFramebuffer();
|
||||
GLuint rboID;
|
||||
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;
|
||||
layer.m_dirty_box[i] = { 0, 0, layer.w, layer.h };
|
||||
}
|
||||
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]);
|
||||
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
|
||||
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);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
layer.m_rtt[i].unbindFramebuffer();
|
||||
|
||||
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)
|
||||
{
|
||||
// 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();
|
||||
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++)
|
||||
App::I.render_task([&]
|
||||
{
|
||||
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.clear({ 1, 1, 1, 0 });
|
||||
observer(plane_camera, proj, i);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboID);
|
||||
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();
|
||||
|
||||
// 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)
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
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;
|
||||
glm::mat4 plane_camera = glm::lookAt(glm::vec3(0), m_plane_origin[i], m_plane_tangent[i]);
|
||||
rtt.bindFramebuffer();
|
||||
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];
|
||||
action->m_old_dirty[i] = layer.m_dirty_face[i];
|
||||
// save history
|
||||
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
|
||||
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)) };
|
||||
}
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
rtt.destroy();
|
||||
|
||||
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
|
||||
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();
|
||||
draw_merge();
|
||||
});
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
int saved_bytes = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
for (int i = 0; i < 6; 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!!
|
||||
//m_rtt[i].recreate();
|
||||
|
||||
m_rtt[i].bindTexture();
|
||||
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
m_dirty_box[i].x, m_dirty_box[i].y,
|
||||
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
snap.image[i].get());
|
||||
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_task_async([this,i,&snap]
|
||||
{
|
||||
m_rtt[i].bindTexture();
|
||||
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
m_dirty_box[i].x, m_dirty_box[i].y,
|
||||
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
snap.image[i].get());
|
||||
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*/)
|
||||
{
|
||||
Snapshot snap;
|
||||
static int counter = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
for (int i = 0; i < 6; 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());
|
||||
|
||||
//glReadBuffer(GL_BACK);
|
||||
m_rtt[i].bindFramebuffer();
|
||||
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();
|
||||
App::I.render_task_async([this,i,&snap]
|
||||
{
|
||||
m_rtt[i].bindFramebuffer();
|
||||
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);
|
||||
}
|
||||
counter++;
|
||||
App::I.render_sync();
|
||||
return snap;
|
||||
}
|
||||
|
||||
void Layer::clear(const glm::vec4& c)
|
||||
{
|
||||
// push clear color state
|
||||
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++)
|
||||
App::I.render_task([&]
|
||||
{
|
||||
m_rtt[i].bindFramebuffer();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
m_rtt[i].unbindFramebuffer();
|
||||
// push clear color state
|
||||
GLfloat cc[4];
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
|
||||
glClearColor(c.r, c.g, c.b, c.a);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool erase = (c.a == 0.f);
|
||||
|
||||
// restore clear color state
|
||||
glClearColor(cc[0], cc[1], cc[2], cc[3]);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
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)
|
||||
@@ -3284,15 +3303,18 @@ bool Layer::create(int width, int height, std::string name)
|
||||
m_name = name;
|
||||
w = width;
|
||||
h = height;
|
||||
for (int i = 0; i < 6; i++)
|
||||
App::I.render_task([&]
|
||||
{
|
||||
m_rtt[i].create(width, height);
|
||||
m_rtt[i].bindFramebuffer();
|
||||
m_rtt[i].clear();
|
||||
m_rtt[i].unbindFramebuffer();
|
||||
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
||||
m_dirty_face[i] = false;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_rtt[i].create(width, height);
|
||||
m_rtt[i].bindFramebuffer();
|
||||
m_rtt[i].clear();
|
||||
m_rtt[i].unbindFramebuffer();
|
||||
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
|
||||
m_dirty_face[i] = false;
|
||||
}
|
||||
});
|
||||
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)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
if (m_draw_tip)
|
||||
{
|
||||
const auto& brush = Canvas::I->m_current_brush;
|
||||
|
||||
41
src/font.cpp
41
src/font.cpp
@@ -3,6 +3,8 @@
|
||||
#include "font.h"
|
||||
#include "shader.h"
|
||||
#include "asset.h"
|
||||
#include "util.h"
|
||||
#include "app.h"
|
||||
|
||||
std::map<kFont, Font> FontManager::m_fonts;
|
||||
Sampler FontManager::m_sampler;
|
||||
@@ -58,18 +60,21 @@ const Font& FontManager::get(kFont id)
|
||||
|
||||
bool TextMesh::create()
|
||||
{
|
||||
glGenBuffers(2, font_buffers);
|
||||
App::I.render_task([this]
|
||||
{
|
||||
glGenBuffers(2, font_buffers);
|
||||
#if USE_VBO
|
||||
glGenVertexArrays(1, &font_array);
|
||||
glBindVertexArray(font_array);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[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));
|
||||
glBindVertexArray(0);
|
||||
glGenVertexArrays(1, &font_array);
|
||||
glBindVertexArray(font_array);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[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));
|
||||
glBindVertexArray(0);
|
||||
#endif // USE_VBO
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -120,17 +125,21 @@ void TextMesh::update(kFont id, const char* text)
|
||||
vi -= glm::vec4(bbmin, 0, 0);
|
||||
bb = bbmax - bbmin;
|
||||
font_array_count = (int)idx.size();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[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);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[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()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
auto& f = FontManager::get(font_id);
|
||||
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::thread hmd_renderer;
|
||||
std::thread renderer;
|
||||
std::thread ui_renderer;
|
||||
int vr_frames = 0;
|
||||
int running = -1;
|
||||
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::thread render_thread;
|
||||
std::thread::id render_thread_id;
|
||||
bool render_running = false;
|
||||
|
||||
int gl_count = 0;
|
||||
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()
|
||||
{
|
||||
//std::lock_guard<std::mutex> _lock(async_mutex);
|
||||
@@ -166,7 +230,7 @@ void async_unlock()
|
||||
|
||||
void win32_render_thread_notify()
|
||||
{
|
||||
render_cv.notify_all();
|
||||
ui_render_cv.notify_all();
|
||||
}
|
||||
|
||||
void win32_show_cursor(bool visible)
|
||||
@@ -257,12 +321,6 @@ std::string win32_open_dir()
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
struct async_locker
|
||||
{
|
||||
async_locker() { async_lock(); }
|
||||
~async_locker() { async_unlock(); }
|
||||
};
|
||||
|
||||
int read_WMI_info()
|
||||
{
|
||||
// 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->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())
|
||||
{
|
||||
delete vive;
|
||||
vive = nullptr;
|
||||
LOG("VR: failed to initialize vive");
|
||||
async_unlock();
|
||||
return false;
|
||||
}
|
||||
async_unlock();
|
||||
|
||||
hmd_renderer = std::thread([&] {
|
||||
if (!vive)
|
||||
@@ -726,6 +781,46 @@ BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle
|
||||
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)
|
||||
{
|
||||
WNDCLASS wc;
|
||||
@@ -917,7 +1012,10 @@ int main(int argc, char** argv)
|
||||
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
|
||||
}
|
||||
|
||||
async_lock();
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
|
||||
running = 1;
|
||||
render_thread = std::thread(render_thread_main);
|
||||
|
||||
LOG("init app");
|
||||
App::I.init();
|
||||
@@ -932,15 +1030,11 @@ int main(int argc, char** argv)
|
||||
LOG("SKIP init WinTab");
|
||||
}
|
||||
|
||||
async_unlock();
|
||||
|
||||
LOG("change icon");
|
||||
SendMessage(hWnd, WM_SETICON, ICON_SMALL,
|
||||
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
|
||||
|
||||
running = 1;
|
||||
|
||||
renderer = std::thread([&] {
|
||||
ui_renderer = std::thread([&] {
|
||||
BT_SetTerminate();
|
||||
LOG("start render thread");
|
||||
const float target_fps = 10;
|
||||
@@ -989,13 +1083,11 @@ int main(int argc, char** argv)
|
||||
|
||||
if (!working_list.empty())
|
||||
{
|
||||
async_lock();
|
||||
while (!working_list.empty())
|
||||
{
|
||||
working_list.front()();
|
||||
working_list.pop_front();
|
||||
}
|
||||
async_unlock();
|
||||
//LOG("clear");
|
||||
//WacomTablet::I.m_stylus = false;
|
||||
//WacomTablet::I.m_eraser = false;
|
||||
@@ -1016,7 +1108,7 @@ int main(int argc, char** argv)
|
||||
|
||||
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)
|
||||
{
|
||||
App::I.redraw = true;
|
||||
@@ -1041,19 +1133,20 @@ int main(int argc, char** argv)
|
||||
|
||||
if (App::I.redraw)
|
||||
{
|
||||
async_lock();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
App::I.clear();
|
||||
App::I.update(frame_timer);
|
||||
SwapBuffers(hDC);
|
||||
async_unlock();
|
||||
render_task([frame_timer]
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
App::I.clear();
|
||||
App::I.update(frame_timer);
|
||||
SwapBuffers(hDC);
|
||||
});
|
||||
frame_timer = 0;
|
||||
frames++;
|
||||
}
|
||||
|
||||
const int framerate = (1.f / target_tick_rate) * 1000;
|
||||
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));
|
||||
t0 = t1;
|
||||
}
|
||||
@@ -1109,10 +1202,11 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (!tasklist.empty())
|
||||
render_cv.notify_all();
|
||||
ui_render_cv.notify_all();
|
||||
}
|
||||
// Clean up
|
||||
WacomTablet::I.terminate();
|
||||
render_cv.notify_all();
|
||||
|
||||
UnregisterClass(className, hInst);
|
||||
LogRemote::I.stop();
|
||||
@@ -1132,13 +1226,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
case WM_USER_CLOSE:
|
||||
running = 0;
|
||||
render_cv.notify_all();
|
||||
if (renderer.joinable())
|
||||
renderer.join();
|
||||
ui_render_cv.notify_all();
|
||||
if (ui_renderer.joinable())
|
||||
ui_renderer.join();
|
||||
if (hmd_renderer.joinable())
|
||||
hmd_renderer.join();
|
||||
App::I.terminate();
|
||||
PostQuitMessage(0);
|
||||
render_running = false;
|
||||
if (render_thread.joinable())
|
||||
render_thread.join();
|
||||
return 0;
|
||||
case WM_PAINT:
|
||||
App::I.redraw = true;
|
||||
@@ -1150,13 +1247,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
if (App::I.request_close())
|
||||
{
|
||||
running = 0;
|
||||
render_cv.notify_all();
|
||||
if (renderer.joinable())
|
||||
renderer.join();
|
||||
ui_render_cv.notify_all();
|
||||
if (ui_renderer.joinable())
|
||||
ui_renderer.join();
|
||||
if (hmd_renderer.joinable())
|
||||
hmd_renderer.join();
|
||||
App::I.terminate();
|
||||
PostQuitMessage(0);
|
||||
render_running = false;
|
||||
if (render_thread.joinable())
|
||||
render_thread.join();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -1170,12 +1270,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
auto h = (float)HIWORD(lp);
|
||||
if (h != 0 && running == 1)
|
||||
{
|
||||
async_locker lock;
|
||||
App::I.resize(w, h);
|
||||
App::I.clear();
|
||||
App::I.redraw = true;
|
||||
App::I.update(0.f);
|
||||
SwapBuffers(hDC);
|
||||
App::I.render_task([=]
|
||||
{
|
||||
App::I.resize(w, h);
|
||||
App::I.clear();
|
||||
App::I.redraw = true;
|
||||
App::I.update(0.f);
|
||||
SwapBuffers(hDC);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1374,7 +1476,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
break;
|
||||
case WM_MOUSEWHEEL:
|
||||
{
|
||||
async_locker lock;
|
||||
POINT pt;
|
||||
pt.x = GET_X_LPARAM(lp);
|
||||
pt.y = GET_Y_LPARAM(lp);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "node_colorwheel.h"
|
||||
#include "shader.h"
|
||||
#include "log.h"
|
||||
#include "app.h"
|
||||
|
||||
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({{l,0,0,1},{1,1},{1,0,0,1}});
|
||||
|
||||
glGenBuffers(1, &buffers);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGenBuffers(1, &buffers);
|
||||
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);
|
||||
glBindVertexArray(arrays);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
||||
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, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
|
||||
glBindVertexArray(0);
|
||||
glGenVertexArrays(1, &arrays);
|
||||
glBindVertexArray(arrays);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers);
|
||||
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, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
|
||||
glBindVertexArray(0);
|
||||
});
|
||||
}
|
||||
|
||||
void NodeColorWheel::draw()
|
||||
|
||||
@@ -151,11 +151,14 @@ void NodePanelGrid::init_controls()
|
||||
m_texture.create_mipmaps();
|
||||
#else
|
||||
// get the texture data and resize it
|
||||
m_texture.bind();
|
||||
Image img;
|
||||
img.create(m_texture.size().x, m_texture.size().y);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data.get());
|
||||
m_texture.unbind();
|
||||
App::I.render_task([&]
|
||||
{
|
||||
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);
|
||||
m_texture.create(resized);
|
||||
m_texture.create_mipmaps();
|
||||
@@ -169,9 +172,6 @@ void NodePanelGrid::init_controls()
|
||||
m_plane.create<1>(1, 1);
|
||||
|
||||
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
|
||||
|
||||
@@ -514,13 +514,11 @@ void NodeStrokePreview::draw_stroke()
|
||||
// Good luck, future Omar
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
#endif
|
||||
App::I.async_start();
|
||||
m_sampler_linear.create();
|
||||
m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT);
|
||||
m_sampler_mipmap.create();
|
||||
m_sampler_mipmap.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
|
||||
m_brush_shape.create();
|
||||
App::I.async_end();
|
||||
while (s_running)
|
||||
{
|
||||
auto node = s_queue.Get();
|
||||
@@ -530,43 +528,41 @@ void NodeStrokePreview::draw_stroke()
|
||||
bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
||||
node->m_brush->preload();
|
||||
|
||||
node->async_start();
|
||||
|
||||
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)
|
||||
App::I.render_task([node, to_unload]
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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::yield();
|
||||
}
|
||||
}
|
||||
App::I.async_start();
|
||||
m_rtt.destroy();
|
||||
m_rtt_mixer.destroy();
|
||||
m_tex.destroy();
|
||||
m_tex_dual.destroy();
|
||||
m_tex_background.destroy();
|
||||
m_brush_shape.destroy();
|
||||
App::I.async_end();
|
||||
});
|
||||
}
|
||||
s_queue.mutex.unlock();
|
||||
|
||||
249
src/rtt.cpp
249
src/rtt.cpp
@@ -2,6 +2,7 @@
|
||||
#include "log.h"
|
||||
#include "rtt.h"
|
||||
#include "util.h"
|
||||
#include "app.h"
|
||||
|
||||
RTT::RTT()
|
||||
{
|
||||
@@ -38,19 +39,22 @@ void RTT::resize(int width, int height)
|
||||
{
|
||||
RTT new_rtt;
|
||||
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
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_READ_FRAMEBUFFER, fboID);
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, new_rtt.w, new_rtt.h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, new_rtt.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);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
|
||||
destroy();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
|
||||
destroy();
|
||||
});
|
||||
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
@@ -64,22 +68,25 @@ void RTT::resize(int width, int height)
|
||||
|
||||
void RTT::destroy()
|
||||
{
|
||||
if (rboID)
|
||||
App::I.render_task_async([rboID=rboID, texID=texID, fboID=fboID]
|
||||
{
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
}
|
||||
if (texID)
|
||||
{
|
||||
unbindTexture();
|
||||
glDeleteTextures(1, &texID);
|
||||
//LOG("TEX rtt destroy %d", texID)
|
||||
}
|
||||
if (fboID)
|
||||
{
|
||||
unbindFramebuffer();
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
//LOG("RTT DESTROY %d", fboID);
|
||||
}
|
||||
if (rboID)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &rboID);
|
||||
}
|
||||
if (texID)
|
||||
{
|
||||
//unbindTexture();
|
||||
glDeleteTextures(1, &texID);
|
||||
//LOG("TEX rtt destroy %d", texID)
|
||||
}
|
||||
if (fboID)
|
||||
{
|
||||
//unbindFramebuffer();
|
||||
glDeleteFramebuffers(1, &fboID);
|
||||
//LOG("RTT DESTROY %d", fboID);
|
||||
}
|
||||
});
|
||||
texID = 0;
|
||||
fboID = 0;
|
||||
rboID = 0;
|
||||
@@ -89,101 +96,109 @@ void RTT::destroy()
|
||||
|
||||
void RTT::copy(const RTT & source)
|
||||
{
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
||||
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.fboID);
|
||||
glBlitFramebuffer(0, 0, source.w, source.h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
|
||||
});
|
||||
}
|
||||
|
||||
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
|
||||
{
|
||||
// Destroy any previously created object
|
||||
destroy();
|
||||
|
||||
w = width;
|
||||
h = height;
|
||||
int_fmt = internal_format;
|
||||
|
||||
if (tex == -1)
|
||||
GLenum status = 0;
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glGenTextures(1, &texID);
|
||||
//LOG("TEX rtt create %d", texID);
|
||||
}
|
||||
else
|
||||
{
|
||||
texID = tex;
|
||||
}
|
||||
// Destroy any previously created object
|
||||
destroy();
|
||||
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||
|
||||
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);
|
||||
w = width;
|
||||
h = height;
|
||||
int_fmt = internal_format;
|
||||
|
||||
// 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)
|
||||
if (tex == -1)
|
||||
{
|
||||
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";
|
||||
glGenTextures(1, &texID);
|
||||
//LOG("TEX rtt create %d", texID);
|
||||
}
|
||||
else
|
||||
{
|
||||
texID = tex;
|
||||
}
|
||||
};
|
||||
|
||||
// Check FBO status
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
LOG("RTT::create failed because: %s", err2str(status));
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||
|
||||
// Switch back to window-system-provided framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
|
||||
oldRFboID = 0;
|
||||
oldDFboID = 0;
|
||||
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 (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;
|
||||
}
|
||||
|
||||
void RTT::bindFramebuffer()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
#ifdef _DEBUG
|
||||
if (bound)
|
||||
{
|
||||
@@ -193,15 +208,16 @@ void RTT::bindFramebuffer()
|
||||
#endif
|
||||
}
|
||||
#endif // _DEBUG
|
||||
bound = true;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
bound = true;
|
||||
}
|
||||
|
||||
void RTT::unbindFramebuffer()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
if (!bound)
|
||||
return;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
|
||||
@@ -213,6 +229,7 @@ void RTT::unbindFramebuffer()
|
||||
|
||||
void RTT::clear(glm::vec4 color)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
@@ -240,11 +257,14 @@ uint8_t* RTT::readTextureData(uint8_t* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
buffer = createBuffer();
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -252,11 +272,14 @@ float* RTT::readTextureDataFloat(float* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
buffer = createBufferFloat();
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
GLint old;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -272,11 +295,13 @@ float * RTT::createBufferFloat()
|
||||
|
||||
void RTT::bindTexture()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
}
|
||||
|
||||
void RTT::unbindTexture()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
||||
240
src/shader.cpp
240
src/shader.cpp
@@ -2,6 +2,7 @@
|
||||
#include "log.h"
|
||||
#include "shader.h"
|
||||
#include "asset.h"
|
||||
#include "app.h"
|
||||
|
||||
std::map<kShader, Shader> ShaderManager::m_shaders;
|
||||
Shader* ShaderManager::m_current;
|
||||
@@ -153,122 +154,135 @@ bool Shader::reload()
|
||||
|
||||
bool Shader::create(const char* vertex, const char* fragment)
|
||||
{
|
||||
GLint status;
|
||||
static char infolog[4096];
|
||||
int infolen;
|
||||
const GLchar* source;
|
||||
|
||||
auto vs = glCreateShader(GL_VERTEX_SHADER);
|
||||
if (!vs)
|
||||
bool ret = true;
|
||||
App::I.render_task([&]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
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");
|
||||
GLint status;
|
||||
static char infolog[4096];
|
||||
int infolen;
|
||||
const GLchar* source;
|
||||
|
||||
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);
|
||||
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++)
|
||||
auto vs = glCreateShader(GL_VERTEX_SHADER);
|
||||
if (!vs)
|
||||
{
|
||||
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));
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
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 true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Shader::destroy()
|
||||
{
|
||||
if (prog)
|
||||
{
|
||||
glUseProgram(0);
|
||||
glDeleteProgram(prog);
|
||||
App::I.render_task_async([prog=prog]
|
||||
{
|
||||
glUseProgram(0);
|
||||
glDeleteProgram(prog);
|
||||
});
|
||||
prog = 0;
|
||||
}
|
||||
m_umap.clear();
|
||||
@@ -276,16 +290,19 @@ void Shader::destroy()
|
||||
|
||||
void Shader::use()
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
glUseProgram(prog);
|
||||
}
|
||||
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)
|
||||
else glUniform4fv(m_umap[id], 1, glm::value_ptr(v));
|
||||
}
|
||||
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
else glUniform2fv(m_umap[id], 1, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
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)
|
||||
else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m));
|
||||
}
|
||||
void Shader::u_int(kShaderUniform id, int i)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -313,12 +333,14 @@ void Shader::u_int(kShaderUniform id, int i)
|
||||
}
|
||||
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)
|
||||
else glUniform1f(m_umap[id], f);
|
||||
}
|
||||
GLint Shader::GetAttribLocation(const char* name)
|
||||
{
|
||||
assert(App::I.is_render_thread());
|
||||
return glGetAttribLocation(prog, name);
|
||||
}
|
||||
|
||||
|
||||
326
src/shape.cpp
326
src/shape.cpp
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#include "shape.h"
|
||||
#include "app.h"
|
||||
|
||||
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;
|
||||
|
||||
destroy();
|
||||
|
||||
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++)
|
||||
bool ret = false;
|
||||
App::I.render_task([&]
|
||||
{
|
||||
glBindVertexArray(arrays[i]);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(3);
|
||||
destroy();
|
||||
|
||||
glGenBuffers(2, buffers);
|
||||
if (!(buffers[0] && buffers[1]))
|
||||
{
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW);
|
||||
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);
|
||||
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]))
|
||||
{
|
||||
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
|
||||
return true;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
bool Shape::create_buffers(GLvoid* vertices, int vsize)
|
||||
{
|
||||
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
|
||||
glGenVertexArrays(2, arrays);
|
||||
if (!(arrays[0] && arrays[1]))
|
||||
return false;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
glBindVertexArray(arrays[i]);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(3);
|
||||
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);
|
||||
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_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
|
||||
return true;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
void Shape::draw_fill() const
|
||||
{
|
||||
@@ -103,31 +124,34 @@ void Shape::draw_fill() const
|
||||
type = GL_POINTS;
|
||||
if (count[0] == 2)
|
||||
type = GL_LINES;
|
||||
#if USE_VBO
|
||||
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)
|
||||
App::I.render_task([=]
|
||||
{
|
||||
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);
|
||||
#if USE_VBO
|
||||
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]);
|
||||
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
|
||||
});
|
||||
}
|
||||
void Shape::draw_stroke() const
|
||||
{
|
||||
@@ -136,32 +160,61 @@ void Shape::draw_stroke() const
|
||||
GLenum type = GL_LINES;
|
||||
if (count[1] == 1)
|
||||
type = GL_POINTS;
|
||||
#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_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)
|
||||
App::I.render_task([=]
|
||||
{
|
||||
#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]);
|
||||
glDrawElements(type, count[1], GL_UNSIGNED_SHORT, ioff[1]);
|
||||
}
|
||||
else
|
||||
glDrawArrays(type, 0, count[1]);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
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[1], GL_UNSIGNED_SHORT, ioff[1]);
|
||||
}
|
||||
else
|
||||
glDrawArrays(type, 0, count[1]);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
#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)
|
||||
@@ -437,21 +490,24 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
|
||||
vertices[i].pos.z = q;
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
static GLushort idx[6 + 8]{
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
};
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
|
||||
App::I.render_task([this]
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
static GLushort idx[6 + 8]{
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
};
|
||||
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_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
});
|
||||
}
|
||||
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])
|
||||
{
|
||||
static vertex_t vertices[2];
|
||||
vertices[0] = { data[0], { 0, 0 } }; // A
|
||||
vertices[1] = { data[1], { 0, 1 } }; // B
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
static vertex_t vertices[2];
|
||||
vertices[0] = { data[0], { 0, 0 } }; // A
|
||||
vertices[1] = { data[1], { 0, 1 } }; // B
|
||||
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)
|
||||
{
|
||||
count[0] = vcount;
|
||||
count[1] = vcount;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_t) * vcount, vertices, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
App::I.render_task([&]
|
||||
{
|
||||
count[0] = vcount;
|
||||
count[1] = vcount;
|
||||
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);
|
||||
void draw_fill() const;
|
||||
void draw_stroke() const;
|
||||
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;
|
||||
}
|
||||
void destroy();
|
||||
virtual bool create_attrib() { return true; };
|
||||
~Shape()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
~Shape();
|
||||
protected:
|
||||
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)
|
||||
{
|
||||
destroy();
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_iformat = internal_format;
|
||||
glGenTextures(1, &m_tex);
|
||||
//LOG("TEX create %d", m_tex);
|
||||
bind();
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, ifmt, data);
|
||||
unbind();
|
||||
App::I.render_task([=]
|
||||
{
|
||||
destroy();
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_iformat = internal_format;
|
||||
glGenTextures(1, &m_tex);
|
||||
//LOG("TEX create %d", m_tex);
|
||||
bind();
|
||||
auto ifmt = GL_UNSIGNED_BYTE;
|
||||
if (internal_format == GL_RGBA32F) ifmt = GL_FLOAT;
|
||||
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;
|
||||
}
|
||||
bool Texture2D::create(const Image& img)
|
||||
@@ -65,10 +68,13 @@ bool Texture2D::create(const Image& img)
|
||||
|
||||
void Texture2D::create_mipmaps()
|
||||
{
|
||||
bind();
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
unbind();
|
||||
has_mips = true;
|
||||
App::I.render_task([this]
|
||||
{
|
||||
bind();
|
||||
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*/)
|
||||
@@ -98,10 +104,37 @@ bool Texture2D::load_file(std::string filename)
|
||||
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)
|
||||
{
|
||||
bind();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data);
|
||||
App::I.render_task([this, data]
|
||||
{
|
||||
bind();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data);
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec2 Texture2D::size() const
|
||||
@@ -113,57 +146,81 @@ Texture2D::~Texture2D()
|
||||
{
|
||||
if (auto_destroy)
|
||||
{
|
||||
LOG("Texture2D auto destroy");
|
||||
App::I.async_start();
|
||||
destroy();
|
||||
App::I.async_end();
|
||||
App::I.render_task_async([this]
|
||||
{
|
||||
LOG("Texture2D auto destroy");
|
||||
destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
glGenSamplers(1, &id);
|
||||
glGenSamplers(1, &id);
|
||||
#endif // USE_SAMPLER
|
||||
if (id == 0)
|
||||
return false;
|
||||
set(filter, wrap);
|
||||
return true;
|
||||
if (id == 0)
|
||||
{
|
||||
ret = false;
|
||||
return;
|
||||
}
|
||||
set(filter, wrap);
|
||||
ret = true;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
|
||||
{
|
||||
App::I.render_task([=]
|
||||
{
|
||||
#if USE_SAMPLER
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_R, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_WRAP_R, wrap);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
|
||||
#endif // USE_SAMPLER
|
||||
});
|
||||
}
|
||||
void Sampler::set_filter(GLint filter_min, GLint filter_mag)
|
||||
{
|
||||
App::I.render_task([=]
|
||||
{
|
||||
#if USE_SAMPLER
|
||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
|
||||
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
|
||||
#endif // USE_SAMPLER
|
||||
});
|
||||
}
|
||||
void Sampler::set_border(glm::vec4 rgba)
|
||||
{
|
||||
App::I.render_task([this, rgba]
|
||||
{
|
||||
#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
|
||||
});
|
||||
}
|
||||
void Sampler::bind(int unit) const
|
||||
{
|
||||
current_unit = unit;
|
||||
App::I.render_task([=]
|
||||
{
|
||||
current_unit = unit;
|
||||
#if USE_SAMPLER
|
||||
glBindSampler(unit, id);
|
||||
glBindSampler(unit, id);
|
||||
#endif // USE_SAMPLER
|
||||
});
|
||||
}
|
||||
void Sampler::unbind()
|
||||
{
|
||||
App::I.render_task([=]
|
||||
{
|
||||
#if USE_SAMPLER
|
||||
glBindSampler(current_unit, 0);
|
||||
glBindSampler(current_unit, 0);
|
||||
#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);
|
||||
bool load(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 bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); }
|
||||
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); }
|
||||
void destroy();
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
void update(const uint8_t* data);
|
||||
bool ready() const { return m_tex != 0; }
|
||||
void create_mipmaps();
|
||||
|
||||
Reference in New Issue
Block a user