From 57d5bc61ed8da9ecd0d532d4003fb855e98a4c65 Mon Sep 17 00:00:00 2001 From: Ilusha Date: Sun, 17 Mar 2024 11:00:10 +0300 Subject: [PATCH] trying to compile --- Sketch3D/CMakeLists.txt | 10 +- Sketch3D/applications/Entry.cpp | 61 +- Sketch3D/{rsc => applications}/Font.ttf | Bin Sketch3D/private/FrameBuffer.cpp | 108 ++ Sketch3D/private/Shader.cpp | 159 +++ .../private/{strokes.cpp => Sketch3D.cpp} | 206 +--- Sketch3D/private/StrokesWidget.cpp | 260 ---- Sketch3D/private/Texture.cpp | 207 ++++ Sketch3D/private/strokesobject.cpp | 42 - Sketch3D/private/temp.cpp | 1049 ----------------- Sketch3D/public/FrameBuffer.hpp | 34 + Sketch3D/public/GraphicsApi.hpp | 19 + Sketch3D/public/Shader.hpp | 31 + Sketch3D/public/Sketch3D.hpp | 227 ++++ Sketch3D/public/Sketch3DWidget.hpp | 87 ++ Sketch3D/public/StrokesWidget.h | 29 - Sketch3D/public/Texture.hpp | 29 + Sketch3D/public/strokes.h | 153 --- Sketch3D/public/strokes_versions.h | 178 --- 19 files changed, 999 insertions(+), 1890 deletions(-) rename Sketch3D/{rsc => applications}/Font.ttf (100%) create mode 100644 Sketch3D/private/FrameBuffer.cpp create mode 100644 Sketch3D/private/Shader.cpp rename Sketch3D/private/{strokes.cpp => Sketch3D.cpp} (60%) delete mode 100644 Sketch3D/private/StrokesWidget.cpp create mode 100644 Sketch3D/private/Texture.cpp delete mode 100644 Sketch3D/private/strokesobject.cpp delete mode 100644 Sketch3D/private/temp.cpp create mode 100644 Sketch3D/public/FrameBuffer.hpp create mode 100644 Sketch3D/public/GraphicsApi.hpp create mode 100644 Sketch3D/public/Shader.hpp create mode 100644 Sketch3D/public/Sketch3D.hpp create mode 100644 Sketch3D/public/Sketch3DWidget.hpp delete mode 100644 Sketch3D/public/StrokesWidget.h create mode 100644 Sketch3D/public/Texture.hpp delete mode 100644 Sketch3D/public/strokes.h delete mode 100644 Sketch3D/public/strokes_versions.h diff --git a/Sketch3D/CMakeLists.txt b/Sketch3D/CMakeLists.txt index 567767b..22a5710 100644 --- a/Sketch3D/CMakeLists.txt +++ b/Sketch3D/CMakeLists.txt @@ -1,4 +1,4 @@ -project(Sketch3Dlib) +project(Sketch3D) ### ---------------------- Externals --------------------- ### set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) @@ -14,9 +14,9 @@ target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} target_link_libraries(${PROJECT_NAME} PUBLIC Graphics Connection Widgets Math Strings) target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS}) -file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") - ### -------------------------- Applications -------------------------- ### -add_executable(Sketch3D ./applications/Entry.cpp) -target_link_libraries(Sketch3D ${PROJECT_NAME}) +add_executable(Sketch3DApp ./applications/Entry.cpp) +target_link_libraries(Sketch3DApp ${PROJECT_NAME}) +file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") +file(COPY "applications/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/") diff --git a/Sketch3D/applications/Entry.cpp b/Sketch3D/applications/Entry.cpp index 33b0d6c..c97cb96 100644 --- a/Sketch3D/applications/Entry.cpp +++ b/Sketch3D/applications/Entry.cpp @@ -1,34 +1,49 @@ -#include "nodes.h" -#include "StrokesWidget.h" +#include "Sketch3D.hpp" -int main(int argc, char* argv[]) { - - auto nodes = (argc == 2) ? nd::NodesCore::createFast(argv[1]) : nd::NodesCore::createFast(); +#include "Graphics.hpp" +#include "Window.hpp" +#include "Widgets.hpp" - tp::init_utils(); +void runApp() { - obj::NDO->define(&obj::StrokesObject::TypeData); - obj::NDO->define(&nd::StrokesWidget::TypeData); - obj::NDO->type_groups.addType(&obj::StrokesObject::TypeData, { "Strokes", "StrokesProject" }); - obj::NDO->type_groups.addType(&nd::StrokesWidget::TypeData, { "Strokes", "StrokesWidget" }); + tp::GlobalGUIConfig config; + tp::gGlobalGUIConfig = &config; - nd::StrokesWidget::OpsInit(); - nd::StrokesWidget::addShortcuts(nodes); + tp::LabelWidget gui; - auto root_widget = NDO_CAST(nd::Widget, obj::NDO->create("RootWidget")); + auto window = tp::Window::createWindow(800, 600, "Window 1"); - auto childs = root_widget->getMember("childs"); - - childs->pushBack(obj::NDO->create("StrokesWidget")); - - nodes->bindRootWindow(root_widget); + if (window) { + while (!window->shouldClose()) { + window->processEvents(); - nodes->run(); + auto area = window->getCanvas().getAvaliableArea(); - nd::StrokesWidget::OpsUnInit(); - tp::finalize_utils(); + gui.proc(window->getEvents(), { area.x, area.y, area.z, area.w }, { area.x, area.y, area.z, area.w }); + gui.draw(window->getCanvas()); - nodes->destroyFast(); - tp::terminate(); + tp::sleep(100); + + window->draw(); + } + } + + tp::Window::destroyWindow(window); +} + +int main() { + + tp::ModuleManifest* deps[] = { &tp::gModuleGraphics, &tp::gModuleStrings, &tp::gModuleWidgets, nullptr }; + tp::ModuleManifest binModule("LibViewEntry", nullptr, nullptr, deps); + + if (!binModule.initialize()) { + return 1; + } + + tp::HeapAllocGlobal::disableCallstack(); + + runApp(); + + binModule.deinitialize(); } \ No newline at end of file diff --git a/Sketch3D/rsc/Font.ttf b/Sketch3D/applications/Font.ttf similarity index 100% rename from Sketch3D/rsc/Font.ttf rename to Sketch3D/applications/Font.ttf diff --git a/Sketch3D/private/FrameBuffer.cpp b/Sketch3D/private/FrameBuffer.cpp new file mode 100644 index 0000000..355ff87 --- /dev/null +++ b/Sketch3D/private/FrameBuffer.cpp @@ -0,0 +1,108 @@ + +#include "FrameBuffer.hpp" +#include "GraphicsApi.hpp" + +void glerr(GLenum type); +#define AssertGL(x) { x; GLenum __gle = glGetError(); if (__gle != GL_NO_ERROR) glerr(__gle); } + +using namespace tp; + +RenderBuffer::RenderBuffer(const Vec2F& size) : + mSize(size) { + + mDrawBuffers[0] = {GL_COLOR_ATTACHMENT0}; + + // --------- texture --------- + AssertGL(glGenTextures(1, &mTextureId)); + AssertGL(glBindTexture(GL_TEXTURE_2D, mTextureId)); + // Give an empty image to OpenGL ( the last "0" ) + AssertGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + // Poor filtering. Needed + AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + AssertGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + + // --------- depth --------- + AssertGL(glGenRenderbuffers(1, &mDepthBufferID)); + AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID)); + AssertGL(glRenderbufferStorage(GL_RENDERBUFFER, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y)); + + // ------------ framebuffer ------------ + AssertGL(glGenFramebuffers(1, &mFrameBufferID)); + AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID)); + AssertGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferID)); + // Set "renderedTexture" as our colour attachement #0 + AssertGL(glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextureId, 0)); + // Set the list of draw buffers. + AssertGL(glDrawBuffers(1, mDrawBuffers)); // "1" is the size of DrawBuffers + ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +RenderBuffer::RenderBuffer(const Vec2F& size, tp::uint1 samples) : + mSize(size) { + + mDrawBuffers[0] = { GL_COLOR_ATTACHMENT0 }; + + // ------- texture --------- + AssertGL(glGenTextures(1, &mTextureId)); + AssertGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextureId)); +#ifdef ENV_OS_ANDROID + AssertGL(glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE)); +#else + AssertGL(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA, (GLsizei)size.x, (GLsizei)size.y, GL_TRUE)); +#endif + // !? + //AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + //AssertGL(glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + + // ------- depth ------- + AssertGL(glGenRenderbuffers(1, &mDepthBufferID)); + AssertGL(glBindRenderbuffer(GL_RENDERBUFFER, mDepthBufferID)); + AssertGL(glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GLW_CONTEXT_DEPTH_COMPONENT, (GLsizei)size.x, (GLsizei)size.y)); + + // ------- fbuff ------- + AssertGL(glGenFramebuffers(1, &mFrameBufferID)); + AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID)); + AssertGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, mTextureId, 0)); + AssertGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferID)); + AssertGL(glDrawBuffers(1, mDrawBuffers)); + ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +uint4 RenderBuffer::buffId() const { + return mFrameBufferID; +} + +void RenderBuffer::beginDraw() { + AssertGL(glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferID)); + setViewport({ 0.f, 0.f, mSize.x, mSize.y }); +} + +void RenderBuffer::setViewport(const RectF& viewport) { + AssertGL(glViewport((GLsizei)viewport.x, (GLsizei)viewport.y, (GLsizei)viewport.z, (GLsizei)viewport.w)); +} + +void RenderBuffer::clear() { + AssertGL(glClearColor(mClearCol.r, mClearCol.g, mClearCol.b, mClearCol.a)); + AssertGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); +} + +void RenderBuffer::endDraw() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0, 0, 0, 0); + glUseProgram(0); +} + +RenderBuffer::~RenderBuffer() { + glDeleteFramebuffers(1, &mFrameBufferID); + glDeleteTextures(1, &mTextureId); + glDeleteRenderbuffers(1, &mDepthBufferID); +} + +uint4 RenderBuffer::texId() const { + return mTextureId; +} + +const Vec2F& RenderBuffer::getSize() const { return mSize; } + diff --git a/Sketch3D/private/Shader.cpp b/Sketch3D/private/Shader.cpp new file mode 100644 index 0000000..ef06812 --- /dev/null +++ b/Sketch3D/private/Shader.cpp @@ -0,0 +1,159 @@ + + +#include "Strings.hpp" +#include "Buffer.hpp" +#include "LocalConnection.hpp" +#include "Shader.hpp" +#include "GraphicsApi.hpp" + +#include + +using namespace tp; + +RenderShader::RenderShader() { + programm = 0; + VertexShaderID = 0; + FragmentShaderID = 0; + GeometryShaderID = 0; +} + +void RenderShader::vert_bind_source(const char* vert_src) { + VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + compile_shader(vert_src, VertexShaderID); +} + +void RenderShader::frag_bind_source(const char* frag_src) { + FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + compile_shader(frag_src, FragmentShaderID); +} + +void RenderShader::geom_bind_source(const char* geom_src) { + GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER); + compile_shader(geom_src, GeometryShaderID); +} + +void RenderShader::compile() { + GLint Result = GL_FALSE; + int InfoLogLength; + + programm = glCreateProgram(); + glAttachShader(programm, VertexShaderID); + if (GeometryShaderID) glAttachShader(programm, GeometryShaderID); + glAttachShader(programm, FragmentShaderID); + glLinkProgram(programm); + + // Check the program + glGetProgramiv(programm, GL_LINK_STATUS, &Result); + glGetProgramiv(programm, GL_INFO_LOG_LENGTH, &InfoLogLength); + + if (InfoLogLength > 0) { + Buffer ProgramErrorMessage(InfoLogLength + 1); + glGetProgramInfoLog(programm, InfoLogLength, NULL, &ProgramErrorMessage[0]); + printf("%s\n", &ProgramErrorMessage[0]); + } + + glDetachShader(programm, VertexShaderID); + glDetachShader(programm, FragmentShaderID); + if (GeometryShaderID) glDetachShader(programm, GeometryShaderID); + + glDeleteShader(VertexShaderID); + glDeleteShader(FragmentShaderID); + if (GeometryShaderID) glDeleteShader(GeometryShaderID); +} + +bool RenderShader::compile_shader(const char* ShaderCode, uint4 ShaderID) { + GLint Result = GL_FALSE; + int InfoLogLength; + + char const* SourcePointer = ShaderCode; + glShaderSource(ShaderID, 1, &SourcePointer, NULL); + glCompileShader(ShaderID); + + // Check Shader + glGetShaderiv(ShaderID, GL_COMPILE_STATUS, &Result); + glGetShaderiv(ShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); + + if (InfoLogLength > 0) { + Buffer VertexShaderErrorMessage(InfoLogLength + 1); + glGetShaderInfoLog(ShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); + printf("%s\n", &VertexShaderErrorMessage[0]); + } + + return Result; +} + + +void RenderShader::load(const char* pvert, const char* pgeom, const char* pfrag, bool paths) { + + // Create the shaders + VertexShaderID = glCreateShader(GL_VERTEX_SHADER); + FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + if (pgeom) GeometryShaderID = glCreateShader(GL_GEOMETRY_SHADER); + else GeometryShaderID = 0; + + GLint Result = GL_FALSE; + int InfoLogLength = 0; + + if (paths) { + + String content; + + auto loadFile = [&](const char* path) { + LocalConnection file; + if (!file.connect(LocalConnection::Location(path), LocalConnection::Type(true))) { + content = ""; + return false; + } + + content.resize(file.size()); + file.readBytes(content.write(), content.size()); + return true; + }; + + printf("Compiling shader : %s\n", pvert); + if (loadFile(pvert)) { + compile_shader(content.read(), VertexShaderID); + } + + if (GeometryShaderID) { + printf("Compiling shader : %s\n", pgeom); + if (loadFile(pgeom)) { + compile_shader(content.read(), GeometryShaderID); + } + } + + printf("Compiling shader : %s\n", pfrag); + if (loadFile(pfrag)) { + compile_shader(content.read(), FragmentShaderID); + } + } + else { + compile_shader(pvert, VertexShaderID); + if (GeometryShaderID) { + compile_shader(pgeom, GeometryShaderID); + } + compile_shader(pfrag, FragmentShaderID); + } + + compile(); +} + +RenderShader::RenderShader(const char* vert, const char* geom, const char* frag, bool paths) { + load(vert, geom, frag, paths); +} + +void RenderShader::bind() { + glUseProgram(programm); +} + +GLuint RenderShader::getu(const char* uid) { + return glGetUniformLocation(programm, uid); +} + +void RenderShader::unbind() { + glUseProgram(0); +} + +RenderShader::~RenderShader() { + glDeleteProgram(programm); +} \ No newline at end of file diff --git a/Sketch3D/private/strokes.cpp b/Sketch3D/private/Sketch3D.cpp similarity index 60% rename from Sketch3D/private/strokes.cpp rename to Sketch3D/private/Sketch3D.cpp index b38ae87..309867f 100644 --- a/Sketch3D/private/strokes.cpp +++ b/Sketch3D/private/Sketch3D.cpp @@ -1,5 +1,5 @@ -#include "Strokes.h" +#include "Sketch3D.hpp" using namespace strokes; @@ -10,11 +10,11 @@ Stroke::GLHandles::GLHandles() { glGenBuffers(1, &vertexbuffer); } -void Stroke::GLHandles::sendDataToGPU(tp::Array* mPoints) { +void Stroke::GLHandles::sendDataToGPU(tp::Buffer* mPoints) { glBindVertexArray(VertexArrayID); - vbo_len = mPoints->length(); + vbo_len = mPoints->size(); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(mPoints[0]) * vbo_len, mPoints->buff(), GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(mPoints[0]) * vbo_len, mPoints->getBuff(), GL_STATIC_DRAW); } Stroke::GLHandles::~GLHandles() { @@ -24,7 +24,7 @@ Stroke::GLHandles::~GLHandles() { Stroke::Stroke() {} -tp::Array& Stroke::buff() { +tp::Buffer& Stroke::buff() { return mPoints; } @@ -34,7 +34,7 @@ void Stroke::updateGpuBuffers() { void Stroke::denoisePos(tp::halni passes) { for (auto pass : tp::Range(passes)) { - for (auto pi : tp::Range(mPoints.length() - 2)) { + for (auto pi : tp::Range(mPoints.size() - 2)) { mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f; } } @@ -42,32 +42,32 @@ void Stroke::denoisePos(tp::halni passes) { void Stroke::denoiseThickness(tp::halni passes) { for (auto pass : tp::Range(passes)) { - for (auto pi : tp::Range(mPoints.length() - 2)) { + for (auto pi : tp::Range(mPoints.size() - 2)) { mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f; } } } void Stroke::compress(tp::halnf factor) { - if (mPoints.length() < 3) { + if (mPoints.size() < 3) { return; } tp::List passed_poits; - for (auto idx : tp::Range(mPoints.length())) { + for (auto idx : tp::Range(mPoints.size())) { passed_poits.pushBack(mPoints[idx]); } - tp::ListNode* min_node = NULL; + tp::List::Node* min_node = NULL; do { min_node = NULL; tp::halnf min_factor = factor; - tp::ListNode* iter = passed_poits.first()->next; + tp::List::Node* iter = passed_poits.first()->next; for (; iter->next; iter = iter->next) { - tp::vec3f dir1 = (iter->data.pos - iter->prev->data.pos).normalize(); - tp::vec3f dir2 = (iter->next->data.pos - iter->data.pos).normalize(); + tp::Vec3F dir1 = (iter->data.pos - iter->prev->data.pos).normalize(); + tp::Vec3F dir2 = (iter->next->data.pos - iter->data.pos).normalize(); tp::halnf factor = 1 - dir1.dot(dir2); if (factor < min_factor) { @@ -77,31 +77,33 @@ void Stroke::compress(tp::halnf factor) { } if (min_node) { - passed_poits.delNode(min_node); + passed_poits.deleteNode(min_node); } } while (min_node); mPoints.reserve(passed_poits.length()); + tp::ualni idx = 0; for (auto point : passed_poits) { - mPoints[point.idx()] = point.data(); + mPoints[idx] = point.data(); + idx++; } } void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) { // TODO - if (mPoints.length() < 4) { + if (mPoints.size() < 4) { return; } tp::List new_points; - for (auto idx : tp::Range(mPoints.length())) { + for (auto idx : tp::Range(mPoints.size())) { new_points.pushBack(mPoints[idx]); } - auto viewmat = cam->viewmat(); - auto projmat = cam->projmat(); + auto viewmat = cam->calculateViewMatrix(); + auto projmat = cam->calculateProjectionMatrix(); for (auto i : tp::Range(passes)) { @@ -120,14 +122,14 @@ void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) { auto len = (p1_2d - p2_2d).length(); if (len > precision * 1.5f) { - auto const a = (p1->data.pos - p0->data.pos).unitv(); - auto const b = (p2->data.pos - p3->data.pos).unitv(); + auto const a = (p1->data.pos - p0->data.pos).unitV(); + auto const b = (p2->data.pos - p3->data.pos).unitV(); auto const l = p1->data.pos - p2->data.pos; auto const l_len = l.length(); auto const ab = a.dot(b); auto const la = l.dot(a); auto const lb = l.dot(b); - tp::vec3f mid; + tp::Vec3F mid; if (1 - tp::abs(ab) < 0.001f) { goto SKIP; @@ -185,56 +187,25 @@ void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) { } } - if (new_points.length() != mPoints.length()) { + if (new_points.length() != mPoints.size()) { mPoints.reserve(new_points.length()); + tp::ualni idx = 0; for (auto point : new_points) { - mPoints[point.idx()] = point.data(); + mPoints[idx] = point.data(); + idx++; } } } -tp::halni Stroke::saveSize() { - tp::halni out = 0; - out += sizeof(tp::rgba); - out += sizeof(tp::alni); - out += mPoints.length() * sizeof(Point); - return out; -} - -void Stroke::save(tp::File& file) { - file.write(&mCol); - - tp::alni length = mPoints.length(); - file.write(&length); - for (auto piter : mPoints) { - file.write(&piter.data()); - } -} - -void Stroke::load(tp::File& file) { - tp::rgba color; - file.read(&color); - - tp::alni p_len; - file.read(&p_len); - - mPoints.reserve(p_len); - for (auto piter : mPoints) { - file.read(&piter.data()); - } - - updateGpuBuffers(); -} - PencilBrush::PencilBrush() { mType = "pencil"; } void PencilBrush::unsureReady(Stroke* stroke, tp::Camera* cam, bool debug) { - if (stroke->buff().length() == 1) { + if (stroke->buff().size() == 1) { auto new_point = stroke->buff()[0]; new_point.pos += 0.00001f; - stroke->buff().pushBack(new_point); + stroke->buff().append(new_point); } if (mEnableCompression && !debug) { @@ -246,12 +217,12 @@ void PencilBrush::unsureReady(Stroke* stroke, tp::Camera* cam, bool debug) { stroke->updateGpuBuffers(); } -void PencilBrush::sample(Project* proj, tp::vec2f crs, tp::halnf pressure) { +void PencilBrush::sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) { if (proj->mActiveLayer == -1) { return; } - bool max_level = mStroke && mStroke->mPoints.length() > mMaxPoints; + bool max_level = mStroke && mStroke->mPoints.size() > mMaxPoints; if (!pressure || max_level) { if (mStroke) { unsureReady(mStroke, &proj->mCamera); @@ -263,7 +234,7 @@ void PencilBrush::sample(Project* proj, tp::vec2f crs, tp::halnf pressure) { mStroke = new Stroke(); mStroke->mCol = mCol; - mStroke->mPoints.pushBack(proj->mLayers[proj->mActiveLayer]->strokes.last()->data->mPoints.last()); + mStroke->mPoints.append(proj->mLayers[proj->mActiveLayer]->strokes.last()->data->mPoints.last()); } if (!pressure) { @@ -274,7 +245,7 @@ void PencilBrush::sample(Project* proj, tp::vec2f crs, tp::halnf pressure) { auto thickness = pressure * (proj->mCamera.project({ 0.f, 0.f }) - proj->mCamera.project({ mSize, 0.f })).length(); bool point_passed = true; - if (mStroke && mStroke->buff().length()) { + if (mStroke && mStroke->buff().size()) { auto last_point_2d = proj->mCamera.project(mStroke->buff().last().pos); point_passed = (crs - last_point_2d).length() > mPrecision; } @@ -289,7 +260,7 @@ void PencilBrush::sample(Project* proj, tp::vec2f crs, tp::halnf pressure) { } auto point_coords = proj->mCamera.project(crs); - mStroke->buff().pushBack({ point_coords, (tp::halnf) thickness }); + mStroke->buff().append({ point_coords, (tp::halnf) thickness }); mStroke->updateGpuBuffers(); } @@ -317,11 +288,11 @@ Project::Layer::~Layer() { } Project::Project() { - mCamera.lookat({ 0.0f, 0.0f, 0.0f }, { 2.0f, 0.0f, 0.f }, { 0, 0, 1 }); + mCamera.lookAtPoint({ 0.0f, 0.0f, 0.0f }, { 2.0f, 0.0f, 0.f }, { 0, 0, 1 }); auto lay = new Layer(); lay->enabled = true; - mLayers.pushBack(lay); + mLayers.append(lay); mActiveLayer = 0; mBrushes.put("eraser", new EraserBrush()); @@ -341,77 +312,10 @@ Project::~Project() { } } -tp::alni Project::saveSize() { - tp::alni out = 0; - out += sizeof(tp::Camera); - out += sizeof(tp::rgba); - out += sizeof(tp::halni); - - out += sizeof(tp::alni); - for (auto layer : mLayers) { - out += layer.data()->name.save_size(); - out += sizeof(bool); - out += sizeof(tp::alni); - for (auto stiter : layer.data()->strokes) { - out += stiter->saveSize(); - } - } - return out; -} - -void Project::save(tp::File& file) { - file.write(&mCamera); - file.write(&mBackgroundColor); - file.write(&mActiveLayer); - - tp::alni lay_len = mLayers.length(); - file.write(&lay_len); - for (auto layer : mLayers) { - layer.data()->name.save(&file); - - file.write(&layer.data()->enabled); - - tp::alni len = layer.data()->strokes.length(); - file.write(&len); - for (auto stiter : layer.data()->strokes) { - stiter->save(file); - } - } -} - -void Project::load(tp::File& file) { - file.read(&mCamera); - file.read(&mBackgroundColor); - file.read(&mActiveLayer); - - tp::alni layers_len; - file.read(&layers_len); - mLayers.reserve(layers_len); - - for (tp::alni idx = 0; idx < layers_len; idx++) { - - tp::string key; key.load(&file); - auto layer = new Layer(); - layer->name = key; - mLayers[idx] = layer; - - file.read(&layer->enabled); - - tp::alni len; - file.read(&len); - - for (tp::alni str_idx = 0; str_idx < len; str_idx++) { - auto str = new Stroke(); - layer->strokes.pushBack(str); - layer->strokes.last()->data->load(file); - } - } -} - -Renderer::Renderer(tp::vec2f size) : - mBuffer(size, { 0.f, 0.f, 1.f, 1.f }, 4), - mBufferDowncast(size, { 0.f, 0.f, 1.f, 1.f }), - mShader(".\\rsc\\shaders\\stroke", ".\\rsc\\shaders\\stroke", ".\\rsc\\shaders\\stroke") +Renderer::Renderer(tp::Vec2F size) : + mBuffer(size, 4), + mBufferDowncast(size), + mShader(".\\rsc\\shaders\\stroke.vert", ".\\rsc\\shaders\\stroke.geom", ".\\rsc\\shaders\\stroke.frag") { mMatrixUniform = mShader.getu("MVP"); mColorUniform = mShader.getu("Color"); @@ -421,11 +325,11 @@ Renderer::Renderer(tp::vec2f size) : } void Renderer::renderBegin() { - mBuffer.begin_draw(); + mBuffer.beginDraw(); mBuffer.clear(); } -void Renderer::setViewport(tp::rectf viewport) { +void Renderer::setViewport(tp::RectF viewport) { mBuffer.setViewport(viewport); } @@ -441,18 +345,18 @@ void Renderer::drawStroke(Stroke* str, tp::Camera* camera) { glBindVertexArray(str->mGl.VertexArrayID); mShader.bind(); - auto cam_mat = camera->transform_mat().transpose(); + auto cam_mat = camera->calculateTransformationMatrix().transpose(); glUniformMatrix4fv(mMatrixUniform, 1, GL_FALSE, &cam_mat[0][0]); glUniform4fv(mColorUniform, 1, &str->mCol.r); - glUniform4fv(mBGColUniform, 1, &mBuffer.col_clear.r); + glUniform4fv(mBGColUniform, 1, &mBuffer.mClearCol.r); - auto ratio = camera->get_ratio(); + auto ratio = camera->getRatio(); glUniform1fv(mRatioUniform, 1, &ratio); - auto target = tp::halnf(((camera->get_target() - camera->get_pos()).length() - camera->get_near()) - / (camera->get_far() - camera->get_near())); + auto target = tp::halnf(((camera->getTarget() - camera->getPos()).length() - camera->getNear()) + / (camera->getFar() - camera->getNear())); glUniform1fv(mTargetUniform, 1, &target); @@ -470,9 +374,9 @@ void Renderer::drawStroke(Stroke* str, tp::Camera* camera) { } void Renderer::renderEnd() { - mBuffer.end_draw(); + mBuffer.endDraw(); - mBufferDowncast.begin_draw(); + mBufferDowncast.beginDraw(); auto size = mBufferDowncast.getSize(); @@ -481,20 +385,20 @@ void Renderer::renderEnd() { mBufferDowncast.clear(); glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST); - mBufferDowncast.end_draw(); + mBufferDowncast.endDraw(); } tp::uhalni Renderer::getTextudeId() { return mBufferDowncast.texId(); } -tp::ogl::fbuffer* Renderer::getBuff() { +tp::RenderBuffer* Renderer::getBuff() { return &mBufferDowncast; } -void Renderer::setClearCol(tp::rgba col) { - mBuffer.col_clear = col; - mBufferDowncast.col_clear = col; +void Renderer::setClearCol(tp::RGBA col) { + mBuffer.mClearCol = col; + mBufferDowncast.mClearCol = col; } Renderer::~Renderer() { diff --git a/Sketch3D/private/StrokesWidget.cpp b/Sketch3D/private/StrokesWidget.cpp deleted file mode 100644 index 3e72dd8..0000000 --- a/Sketch3D/private/StrokesWidget.cpp +++ /dev/null @@ -1,260 +0,0 @@ - -#include "StrokesWidget.h" -#include "operator.h" - -using namespace nd; - -void StrokesWidget::constructor(StrokesWidget* self) { - new (&self->mRenderer) strokes::Renderer({ 1980, 1020 }); - self->createMember("link", "TargetProject"); - self->createMember("StrokesProject", "default"); - self->createMember("rgba", "draw_color"); - self->addMember(obj::ColorObject::create({ 0.13f, 0.13f, 0.13f, 1.f }), "bg_color"); -} - -void StrokesWidget::destructor(StrokesWidget* self) { - self->mRenderer.~Renderer(); - self->mImage.free(self->mDrawer); - self->mImage.~ImageHandle(); -} - -void StrokesWidget::copy(Widget* self, const Widget* in) {} - -strokes::Project* StrokesWidget::getTargetProject() { - auto link = getMember("TargetProject"); - if (!link) { - return NULL; - } - auto obj = link->getLink(); - if (!obj) { - link->setLink(getMember("default")); - return getTargetProject(); - } - auto strokes = NDO_CAST(obj::StrokesObject, obj); - if (!strokes) { - return NULL; - } - - return &strokes->mProject; -} - -void StrokesWidget::procInputs(StrokesWidget* self, nd::GUIInputs* inputs) { - auto proj = self->getTargetProject(); - if (!proj) { - return; - } - - auto rec = self->getRect(); - proj->mCamera.set_ratio(rec.w / rec.z); - - auto col_obj_bg = self->getMember("bg_color"); - if (col_obj_bg) { - proj->mBackgroundColor = col_obj_bg->mCol; - } - - if (!rec.inside(inputs->mCrsPrev)) { - return; - } - - auto pressure = inputs->mPressure; - if (!inputs->Anticipating()) { - pressure = 0.f; - } - - auto idx = proj->mBrushes.presents(proj->mActiveBrush); - if (idx) { - auto brush = proj->mBrushes.getSlotVal(idx); - auto crs = (inputs->mCrs - rec.pos); - crs.x /= rec.z; - crs.y /= rec.w; - crs = (crs - 0.5) * 2; - - if (brush->mType == "pencil") { - auto col_obj = self->getMember("draw_color"); - if (col_obj) { - ((strokes::PencilBrush*)brush)->mCol = col_obj->mCol; - } - } - - brush->sample(proj, crs, pressure); - } -} - -void StrokesWidget::presentOutput(StrokesWidget* self, nd::GUIdrawer* drawer) { - auto proj = self->getTargetProject(); - if (!proj) { - return; - } - - if (!self->mImage.mId) { - self->mDrawer = drawer; - self->mImage.createFromBuff(self->mRenderer.getBuff(), drawer); - } - - auto rec = self->getRect(); - self->mRenderer.setViewport({ 0, 0, rec.z, rec.w }); - self->mRenderer.setClearCol(proj->mBackgroundColor); - self->mRenderer.renderBegin(); - - for (auto lay : proj->mLayers) { - if (lay.data()->enabled) { - for (auto str : lay.data()->strokes) { - self->mRenderer.drawStroke(str.data(), &proj->mCamera); - } - } - } - - auto idx = proj->mBrushes.presents(proj->mActiveBrush); - if (idx) { - auto brush = proj->mBrushes.getSlotVal(idx); - brush->draw(&self->mRenderer, &proj->mCamera); - } - - self->mRenderer.renderEnd(); - - drawer->drawImage(rec, &self->mImage, 0, 1, 12); -} - -struct obj::ObjectType StrokesWidget::TypeData = { - .base = &Widget::TypeData, - .constructor = (obj::object_constructor)StrokesWidget::constructor, - .destructor = (obj::object_destructor)StrokesWidget::destructor, - .copy = (obj::object_copy)StrokesWidget::copy, - .size = sizeof(StrokesWidget), - .name = "StrokesWidget", - .vtable = &StrokesWidget::vtable -}; - -struct StrokesWidget::Vtable StrokesWidget::vtable = { - (void (*)(Widget*, nd::GUIInputs*)) & StrokesWidget::procInputs, - (void (*)(Widget*, nd::GUIdrawer*)) & StrokesWidget::presentOutput, -}; - - -class StrokesWidgetOps : public nd::TypeOperators { - - struct CameraOrbit : public nd::Operator { - tp::vec2f prev_crs; - struct Invoke : public nd::OpCallBack { - Invoke() { - auto transf = obj::EnumObject::create({ "move", "rotate" , "scale" }); - arg_interface.put("Gui", obj::NDO->create("link")); - arg_interface.put("transf", transf); - - func = exec; - description = "invoke"; - } - static void exec(Operator* op, obj::DictObject* args) { - auto active = OpCallBack::getActiveWidget(args); - if (!active) { - return; - } - - auto proj = active->getTargetProject(); - if (!proj) { - return; - } - - auto rec = active->getRect(); - - auto gui = OpCallBack::getGUI(args); - auto prev_crs = ((CameraOrbit*)op)->prev_crs; - prev_crs = tp::vec2f(prev_crs.x / rec.size.x, prev_crs.y / rec.size.y); - prev_crs = (prev_crs - 0.5f) * 2.f; - auto crs = tp::vec2f(gui->mInputs.mCrs.x / rec.size.x, gui->mInputs.mCrs.y / rec.size.y); - crs = (crs - 0.5f) * 2.f; - auto delta = (crs - prev_crs); - - if (tp::abs(delta.x) < 0.1 && tp::abs(delta.y) < 0.1) { - - auto type = OpCallBack::getArg(args, "transf"); - switch (type->active) { - case 0: { - proj->mCamera.move(crs, prev_crs); - break; - } - case 1: { - proj->mCamera.rotate(-delta.x * 5, -delta.y * 5); - break; - } - case 2: { - proj->mCamera.zoom((crs.y + 1.f) / (prev_crs.y + 1.f)); - break; - } - } - - } - ((CameraOrbit*)op)->prev_crs = gui->mInputs.mCrs; - } - } invoke_callback; - - CameraOrbit() { - description = "Orbits camera"; - callbacks.put("invoke", &invoke_callback); - } - } camera_orbit_op; - -public: - StrokesWidgetOps() { - operators.put("camera_orbit", &camera_orbit_op); - } -}; - -void StrokesWidget::OpsInit() { - assert(!StrokesWidget::TypeData.nodes_custom_data); - StrokesWidget::TypeData.nodes_custom_data = new StrokesWidgetOps(); -} - -void StrokesWidget::OpsUnInit() { - assert(StrokesWidget::TypeData.nodes_custom_data); - auto del = (StrokesWidgetOps*)StrokesWidget::TypeData.nodes_custom_data; - StrokesWidget::TypeData.nodes_custom_data = NULL; - delete del; -} - -void StrokesWidget::addShortcuts(nd::NodesCore* nodes) { - auto uis_list = nodes->getMemberAssert("uis"); - NDO_CASTV(nd::GUI, uis_list->getItems()[0], gui); - NDO_CASTV(nd::TUI, uis_list->getItems()[1], tui); - - auto shortcuts = tui->getMemberAssert("shortcuts"); - auto inputs = tui->getMemberAssert("inputs"); - auto input_states = tui->getMemberAssert("input_states"); - auto input_state_hold = input_states->get("hold"); - - { // orbit - auto shortcut = nd::Shortcut::createShortcut("StrokesWidget", "camera_orbit"); - auto args = NDO_CAST(obj::DictObject, shortcut->callbacks_arguments->get("invoke")); - NDO_CAST(obj::LinkObject, args->get("Gui"))->setLink(gui); - NDO_CAST(obj::EnumObject, args->get("transf"))->active = 1; - - shortcuts->pushBack(shortcut); - - auto trigger = shortcut->addTrigger("invoke"); - auto back = tui->getInput(tp::Keycode::LEFT_ALT)->getMember("state"); - trigger->addComparator("comp", back, input_state_hold); - } - - { // zoom - auto shortcut = nd::Shortcut::createShortcut("StrokesWidget", "camera_orbit"); - auto args = NDO_CAST(obj::DictObject, shortcut->callbacks_arguments->get("invoke")); - NDO_CAST(obj::LinkObject, args->get("Gui"))->setLink(gui); - NDO_CAST(obj::EnumObject, args->get("transf"))->active = 2; - shortcuts->pushBack(shortcut); - - auto trigger = shortcut->addTrigger("invoke"); - auto back = tui->getInput(tp::Keycode::LEFT_CONTROL)->getMember("state"); - trigger->addComparator("comp", back, input_state_hold); - } - - { // pan - auto shortcut = nd::Shortcut::createShortcut("StrokesWidget", "camera_orbit"); - auto args = NDO_CAST(obj::DictObject, shortcut->callbacks_arguments->get("invoke")); - NDO_CAST(obj::LinkObject, args->get("Gui"))->setLink(gui); - shortcuts->pushBack(shortcut); - - auto trigger = shortcut->addTrigger("invoke"); - auto back = tui->getInput(tp::Keycode::SPACE)->getMember("state"); - trigger->addComparator("comp", back, input_state_hold); - } -} \ No newline at end of file diff --git a/Sketch3D/private/Texture.cpp b/Sketch3D/private/Texture.cpp new file mode 100644 index 0000000..66ec2bc --- /dev/null +++ b/Sketch3D/private/Texture.cpp @@ -0,0 +1,207 @@ + +#include "Texture.hpp" + +#include "Map.hpp" + +#include "Strings.hpp" + +#include "Shader.hpp" + +#include "GraphicsApi.hpp" + +const char* texture_vertex = +#ifdef ENV_OS_ANDROID +"#version 300 es\n" +"precision mediump float;\n" +#else +"#version 330 core\n" +#endif +"layout(location = 0) in vec3 vPos;\n" +"out vec2 UV;\n" +"void main() {\n" +" gl_Position = vec4(vPos, 1);\n" +" UV = (vPos.xy + vec2(1, 1)) / 2.0;\n" +"}\n"; + +const char* texture_fragment = +#ifdef ENV_OS_ANDROID +"#version 300 es\n" +"precision mediump float;\n" +#else +"#version 330 core\n" +#endif +"in vec2 UV;\n" +"out vec4 color;\n" +"uniform sampler2D renderedTexture;\n" +"uniform float time;\n" +"void main() {\n" +" vec4 texColor = texture(renderedTexture, UV);\n" +" if (texColor.a < 0.2)\n" +" discard;\n" +" color = texColor;\n" +"}\n"; + + +using namespace tp; + +GLuint RenderTexture::getid() { return id; } + +RenderTexture::RenderTexture() { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); +} + +RenderTexture::~RenderTexture() { glDeleteTextures(1, &id); } + + +void RenderTexture::update(const Buffer2D& buff) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)buff.size().x, (GLsizei)buff.size().y, 0, GL_RGBA, GL_FLOAT, buff.getBuff()); +} + +void RenderTexture::draw(const GLuint& out) { + draw_texture(out, id); +} + + +struct texture_drawer_data { + + Map textures; + + GLuint quad_VertexArrayID; + GLuint quad_vertexbuffer; + GLuint texID; + RenderShader shader; + + const GLfloat g_quad_vertex_buffer_data[18] = { + -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, + }; + + texture_drawer_data() : shader(texture_vertex, nullptr, texture_fragment, false) { + // The fullscreen quad's FBO + glGenVertexArrays(1, &quad_VertexArrayID); + glBindVertexArray(quad_VertexArrayID); + + glGenBuffers(1, &quad_vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), + g_quad_vertex_buffer_data, GL_STATIC_DRAW); + + texID = shader.getu("renderedTexture"); + } + + ~texture_drawer_data() { + glDeleteBuffers(1, &quad_vertexbuffer); + glDeleteVertexArrays(1, &quad_VertexArrayID); + + for (auto tex : textures) { + glDeleteTextures(1, &tex->val); + } + } +}; + +texture_drawer_data* texdd = NULL; + +void RenderTexture::init() { + if (!texdd) texdd = new texture_drawer_data(); +} + +void RenderTexture::deinit() { + if (texdd) delete texdd; + texdd = NULL; +} + +void RenderTexture::draw_texture(uint4 out, uint4 in) { + ASSERT(in); + + // Render to the screen + glBindFramebuffer(GL_FRAMEBUFFER, out); + + // Use our shader + texdd->shader.bind(); + + // Bind our texture in Texture Unit 0 + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, in); + // Set our "renderedTexture" sampler to use Texture Unit 0 + glUniform1i(texdd->texID, 0); + + // glUniformMatrix4fv(texdd->rect_mat, 1, GL_FALSE, &tmat[0][0]); + + // 1rst attribute buffer : vertices + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, texdd->quad_vertexbuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + + // Draw the triangles. 2*3 indices starting at 0 -> 2 triangles + glDrawArrays(GL_TRIANGLES, 0, 6); + + glDisableVertexAttribArray(0); + + texdd->shader.unbind(); +} + +GLuint load_texture(const String& name) { + GLuint tex_2d = 0; + + ASSERT(0 && "incomplete compilation - no SOIL support added"); + + if (0) { + //auto document = lunasvg::Document::loadFromFile("tiger.svg"); + //auto bitmap = document->renderToBitmap(); + } + else { + /* + tex_2d = SOIL_load_OGL_texture( + name.cstr(), SOIL_LOAD_RGBA, SOIL_CREATE_NEW_ID, + SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | + SOIL_FLAG_COMPRESS_TO_DXT); + + if (0 == tex_2d) { + printf("SOIL loading error: '%s'\n", SOIL_last_result()); + } + */ + } + + return tex_2d; +} + +GLuint RenderTexture::get_tex(const char* TexId) { + GLuint out = 0; + auto idx = texdd->textures.presents(TexId); + if (idx) { + out = texdd->textures.get(TexId); + } + else { + out = load_texture(TexId); + texdd->textures.put(TexId, out); + } + return out; +} + +void RenderTexture::drawCurcle(Vec2F pos, double radius, RGBA col) { +#ifndef ENV_OS_ANDROID + static alni precision = 40; + + glColor4f(col.r, col.g, col.b, col.a); + + double twicePi = 2.0 * 3.142; + + glBegin(GL_TRIANGLE_FAN); // BEGIN CIRCLE + glVertex2f(pos.x, pos.y); // center of circle + + for (alni i = 0; i <= precision; i++) { + glVertex2f((GLfloat)(pos.x + (radius * cos(i * twicePi / precision))), + (GLfloat)(pos.y + (radius * sin(i * twicePi / precision)))); + } + glEnd(); // END +#endif +} + + diff --git a/Sketch3D/private/strokesobject.cpp b/Sketch3D/private/strokesobject.cpp deleted file mode 100644 index 49ade1c..0000000 --- a/Sketch3D/private/strokesobject.cpp +++ /dev/null @@ -1,42 +0,0 @@ - -#include "strokesobject.h" - -using namespace tp; -using namespace obj; - -void StrokesObject::constructor(StrokesObject* self) { - new (&self->mProject) strokes::Project(); -} - -void StrokesObject::copy(StrokesObject* self, const StrokesObject* in) { - self->mProject = in->mProject; -} - -void StrokesObject::destructor(StrokesObject* self) { - self->mProject.~Project(); -} - -static alni save_size(StrokesObject* self) { - return self->mProject.saveSize(); -} - -static void save(StrokesObject* self, File& file_self) { - self->mProject.save(file_self); -} - -static void load(File& file_self, StrokesObject* self) { - new (&self->mProject) strokes::Project(); - self->mProject.load(file_self); -} - -struct ObjectType obj::StrokesObject::TypeData = { - .base = NULL, - .constructor = (object_constructor) StrokesObject::constructor, - .destructor = (object_destructor) StrokesObject::destructor, - .copy = (object_copy) StrokesObject::copy, - .size = sizeof(StrokesObject), - .name = "StrokesProject", - .save_size = (object_save_size) save_size, - .save = (object_save) save, - .load = (object_load) load, -}; diff --git a/Sketch3D/private/temp.cpp b/Sketch3D/private/temp.cpp deleted file mode 100644 index 0a0e4d2..0000000 --- a/Sketch3D/private/temp.cpp +++ /dev/null @@ -1,1049 +0,0 @@ - /* - -#include "app.h" - -#include "glutils.h" - -#include "shader.h" -#include "strings.h" - -#include "imgui_internal.h" - -#include "ImGuiUtils.h" - -using namespace tp; - -void StrokeApp::draw_explorer() { - using namespace ImGui; - //objects_gui.oexplorer(200); - //if (SubMenuBegin("Type Info", 1)) { - //objects_gui.oproperties(objects_gui.active->type); - //SubMenuEnd(1); - //} -} - -void StrokeApp::draw_brush_properties(rectf rect) { - using namespace ImGui; - if (ImGui::Button(project->sampler.eraser ? "Eraser" : "Pencil")) { - project->sampler.eraser = !project->sampler.eraser; - } ImGui::SameLine(); - - SetNextItemWidth(rect.z / 2.f); - //ImGui::SetNextItemWidth(rect.w); - if (project->sampler.eraser) { - ImGui::SliderFloat(" ", &project->sampler.eraser_size, 0.001f, 0.2f); - } else { - ImGui::SliderFloat(" ", &project->sampler.screen_thikness, 0.001f, 0.2f); - - SetNextItemWidth(rect.z / 1.5f); - int flags = ImGuiColorEditFlags_NoLabel | - ImGuiColorEditFlags_NoSmallPreview | - ImGuiColorEditFlags_NoSidePreview | - ImGuiColorEditFlags_NoInputs; - ImGui::ColorPicker4("Color", &project->sampler.stroke_col.r, flags); - - PushItemWidth(rect.z / 4.f); - if (SubMenuBegin("Sampler Settings", 1)) { - - if (SubMenuBegin("Denoising Passes", 2)) { - SliderInt("Position", &project->denoise_passes, 0, 10); - SliderInt("Thickness", &project->denoise_passes_thikness, 0, 10); - SubMenuEnd(2); - } - - if (SubMenuBegin("Size Reduction", 2)) { - SliderFloat("Input Precision", &project->sampler.screen_precision, 0, 0.005); - Checkbox("Auto Apply", &project->auto_reduction); - SubMenuEnd(2); - } - - if (SubMenuBegin("Pen Pressure", 2)) { - //ImGui::Bezier("easeOutSine", tablet_input_formater); - SubMenuEnd(2); - } - - SubMenuEnd(1); - } - PopItemWidth(); - } - - -} - -void StrokeApp::draw_toolbar(rectf rec) { - const halnf nbuttons = project ? 6 : 1; - halnf buttsize = clamp(rec.z / nbuttons, 5.f, 50.f) + 30; - vec2f buttrec = {buttsize - 20, buttsize - 50}; - - vec2f midpoint = (rec.pos + rec.size_vecw()) / 2.f; - rec.size = {buttsize * nbuttons + 20, buttsize - 30}; - rec.pos = midpoint - (rec.size / 2.f); - - //ImGui::SetNextWindowPos(ImVec2(rec.x, window.size.y - rec.y)); - ImGui::SetNextWindowSize(ImVec2(rec.z, rec.w)); - ImGui::Begin("ToolBar", 0, ImGui::frame_window); - - vec2f popup_size = vec2f(200, 300); - - auto popup = ImGui::ButtonHoverPopupBegin("Explore", buttrec, popup_size); - if (popup) { draw_explorer(); } - ImGui::HoverPopupEnd(popup); - - if (!project) { - ImGui::End(); - return; - } - - ImGui::SameLine(); - popup = ImGui::ButtonHoverPopupBegin("Layers", buttrec, popup_size); - if (popup) { - if (ImGui::Button("Add New", ImVec2(150, 30))) { - project->layers.pushBack(new drawlayer()); - } - - ImGui::Separator(); - - for (auto lay : project->layers) { - ImGui::PushID((int) lay.idx()); - - bool higlight = lay.data() == project->active_layer; - if (higlight) { - ImGui::PushStyleColor(ImGuiCol_Button, GImGui->Style.Colors[ImGuiCol_ButtonActive]); - } - - if (ImGui::Button(lay->name.cstr(), ImVec2(100, 30))) { - project->active_layer = lay.data(); - } - - if (higlight) { - ImGui::PopStyleColor(); - } - - - if (ImGui::BeginPopupContextItem(lay->name.cstr(), ImGuiPopupFlags_MouseButtonRight)) { - static char name[150] = {"asdas"}; - if (ImGui::InputTextEx(" ", "new name", name, 150, {150 , 30}, ImGuiInputTextFlags_EnterReturnsTrue)) { - lay->name = name; - lay->name.capture(); - } - if (ImGui::Button("Delete", ImVec2(150, 30))) { - project->active_layer = lay.node()->prev ? lay.node()->prev->data : NULL; - delete lay.node()->data; - project->layers.delNode(lay.node()); - ImGui::EndPopup(); - ImGui::PopID(); - break; - } - if (lay.node()->prev && ImGui::Button("Move Up", ImVec2(150, 30))) { - swap(lay.node()->prev->data, lay.data()); - } - if (lay.node()->next && ImGui::Button("Move Down", ImVec2(150, 30))) { - swap(lay.node()->next->data, lay.data()); - } - ImGui::EndPopup(); - } - - ImGui::SameLine(); - bool visable = !lay->hiden; - ImGui::Checkbox("", &visable); - lay->hiden = !visable; - - ImGui::PopID(); - } - } - HoverPopupEnd(popup); - - if (!project->active_layer) { - ImGui::End(); - return; - } - - ImGui::SameLine(); - popup = ImGui::ButtonHoverPopupBegin("Hist", buttrec, vec2f(200, 300)); - if (popup) { - if (ImGui::Button("Undo", ImVec2(100, 30))) { - project->active_layer->undo(); - } - if (ImGui::Button("Redo", ImVec2(100, 30))) { - project->active_layer->redo(); - } - if (ImGui::Button("Clear History", ImVec2(100, 30))) { - project->active_layer->clear_history(); - } - } - HoverPopupEnd(popup); - - ImGui::SameLine(); - popup = ImGui::ButtonHoverPopupBegin("Tool", buttrec, popup_size); - if (popup) { draw_brush_properties(rectf(0, 0, 200, 600)); } - ImGui::HoverPopupEnd(popup); - - - ImGui::SameLine(); - popup = ImGui::ButtonHoverPopupBegin("Proj", buttrec, popup_size); - if (popup) { - - ImGui::SetNextItemWidth(popup_size.x / 2.f); - int flags = ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs; - ImGui::ColorPicker4("Background Color", &project->canvas_color.r, flags); - - halni width = ImGui::GetWindowContentRegionWidth(); - if (ImGui::Button("Clear All Strokes", ImVec2(width, 30))) { - project->active_layer->clear_canvas(); - } - - if (ImGui::Button("Reduce Size", ImVec2(width, 30))) { - alni length = project->save_size() / (1024); - project->active_layer->reduce_size(project->pass_factor); - alni length_after = project->save_size() / (1024); - ImGui::Notify(sfmt("Size Redused from %i to %i kb", length, length_after).cstr()); - } - - ImGui::SetNextItemWidth(width / 2); - ImGui::SliderFloat("Pass Facor", &project->pass_factor, 0, 0.01); - } - HoverPopupEnd(popup); - - ImGui::SameLine(); - popup = ImGui::ButtonHoverPopupBegin("Cam", buttrec, vec2f(200, 300)); - if (popup) { - if (ImGui::Button("Reset", ImVec2(100, 30))) { - project->cam.lookat({0, 0, 0}, {100, 0, 0}, {0, 0, 1}); - } - halnf fov = project->cam.get_fov(); - ImGui::Text("Field Of View"); - ImGui::SetNextItemWidth(110); - ImGui::SliderFloat(" ", &fov, 0.1, PI - 0.1); - project->cam.set_fov(fov); - } - HoverPopupEnd(popup); - - ImGui::End(); -} - -void StrokeApp::gui_draw() { - /* - halnf toolbar_size = 290; - draw_toolbar(rectf(window.size.x / 2.f - toolbar_size / 2.f, window.size.y, toolbar_size, 60)); - - if (!project) { - DrawTextR(rectf(window.size / 2.2, 0), "Select Strokes Object", rgba(0.75, 0.75, 0.75, 1)); - - } else if (!gui_is_active || 1) { - - if (project->sampler.eraser) { - halnf size = project->sampler.eraser_size * window.size.x / 2.f; - DrawCircle(window.cursor(), size, rgba(0.9, 0.9, 0.9, 0.7), 2.f); - } else { - halnf size = project->sampler.screen_thikness / 2.f * window.size.x / 2.f; - DrawCircle(window.cursor(), size, rgba(0, 0, 0, 0.7), 4.f); - DrawCircle(window.cursor(), size, project->sampler.stroke_col, 2.f); - } - } -} -*/ - -/* - -#pragma once - -#include "gl.h" -#include "glutils.h" -#include "window.h" -#include "fbuffer.h" - -#include "filesystem.h" - -#include "strokes.h" -#include "ImGuiObjectEditor.h" - -#include "primitives/primitives.h" -#include "strokesobject.h" - -class StrokeApp { - - strokes_project* project = NULL; - - tp::halnf tablet_input_formater[5] = {0.5f, 0.f, 1.f, .5f}; - - public: - - StrokeApp(tp::vec2f size = tp::vec2f(1400, 800)); - ~StrokeApp(); - - private: - - void MainProcTick(); - void MainDrawTick(); - - void camera_controller(); - - private: - - void gui_draw(); - void draw_explorer(); - void draw_toolbar(tp::rectf rect); - void draw_brush_properties(tp::rectf rect); -}; - -using namespace tp; -using namespace obj; - -StrokeApp::StrokeApp(vec2f size) { - //window.col_clear = rgba(0.2, 0.2, 0.23, 1); - //main_window = false; - //window.minsize.assign(400, 400); - - //Object* new_scratch = NULL; - //alni dict_idx = objects_gui.root->items.presents("Scratch"); - //if (dict_idx == -1) { - //new_scratch = NDO->create("strokes"); - //objects_gui.root->items.put("Scratch", new_scratch); - //} else { - //new_scratch = objects_gui.root->items[dict_idx]; - //} - //objects_gui.cd(new_scratch, "Scratch"); -} - -void StrokeApp::MainProcTick() { - - if (!objects_gui.active || objects_gui.active->type->name != "strokes") { - project = NULL; - window.col_clear = rgba(0.22, 0.22, 0.25, 1); - return; - } - - project = &NDO_CAST(StrokesObject, objects_gui.active)->project; - - if (gui_is_active) { - return; - } - - if (!project->active_layer) { - return; - } - - camera_controller(); - - halnf pen_pressure = ImGui::BezierValue(window.pen_pressure(), tablet_input_formater); - project->sampler.sample(&project->active_layer->strokes, &project->active_layer->strokes_undo, window.cursor(1), pen_pressure, &project->cam); - - if (!project->sampler.active_state() && project->sampler.has_input()) { - stroke& str = project->sampler.get_stroke(); - - str.denoise_positions(project->denoise_passes); - str.denoise_thickness(project->denoise_passes_thikness); - - if (project->auto_reduction) { - str.reduce_nof_points(project->pass_factor); - } - - project->active_layer->add_stroke(project->sampler.get_stroke()); - project->sampler.clear(); - } - - whait_for_event = !project->sampler.active_state(); -} - -void StrokeApp::MainDrawTick() { - gui_draw(); - - if (project) { - mat4f cammat = (project->cam.projmat() * project->cam.viewmat()).transpose(); - project->sampler.draw(cammat); - - for (alni idx = project->layers.length() - 1; idx > -1; idx--) { - if (!project->layers[idx]->hiden) { - project->layers[idx]->draw(cammat); - } - } - - window.col_clear = project->canvas_color; - } -} - - -void StrokeApp::camera_controller() { - - vec2f prevcur = window.prevcursor(1); - vec2f cur = window.cursor(1); - - vec2f delta = prevcur - cur; - vec3f target = project->cam.get_target(); - - if (glfwGetKey(window.geth(), GLFW_KEY_LEFT_ALT) == GLFW_PRESS) { - project->cam.rotate(delta.x * 5, delta.y * 5); - } - - if (glfwGetKey(window.geth(), GLFW_KEY_Z) == GLFW_PRESS) { - project->cam.zoom((prevcur.y + 1.f) / (cur.y + 1.f)); - } - - if (glfwGetKey(window.geth(), GLFW_KEY_SPACE) == GLFW_PRESS) { - project->cam.move(cur, prevcur); - } - - if (glfwGetKey(window.geth(), GLFW_KEY_X) == GLFW_PRESS) { - project->pickTargetLength(cur); - } - - if (glfwGetKey(window.geth(), GLFW_KEY_B) == GLFW_PRESS) { - project->sampler.eraser = false; - } - - if (glfwGetKey(window.geth(), GLFW_KEY_E) == GLFW_PRESS) { - project->sampler.eraser = true; - } - - project->cam.set_ratio(window.aspect_ratio()); -} - -StrokeApp::~StrokeApp() {} -*/ - - -/* - -struct StrokesRootWidget : nd::Widget { - - static obj::ObjectType TypeData; - static struct Vtable : Widget::Vtable {} vtable; - - static void constructor(StrokesRootWidget* self) { - } - - static void destructor(StrokesRootWidget* self) {} - static void copy(StrokesRootWidget* self, const StrokesRootWidget* in) {} - - static void procInputs(StrokesRootWidget* self, nd::GUI* gui) { - - auto project = &self->strokes->project; - auto rec = self->getRect(); - - //camera_controller(); - auto cursor = gui->gui_window.mNativeWindow.mEvents.mCursor; - - cursor.y = rec.size.y - cursor.y; - cursor -= tp::vec2f(rec.size) / 2.f; - cursor /= tp::vec2f(rec.size) / 2.f; - - //bool = gui->gui_window.mNativeWindow.mEvents.mLMouseDown; - tp::alnf pressure = gui->gui_window.mNativeWindow.mEvents.mLMouseDown; - //tp::halnf pen_pressure = ImGui::BezierValue(window.pen_pressure(), tablet_input_formater); - project->sampler.sample(&project->active_layer->strokes, &project->active_layer->strokes_undo, cursor, pressure, &project->cam); - - if (!project->sampler.active_state() && project->sampler.has_input()) { - stroke& str = project->sampler.get_stroke(); - - str.denoise_positions(project->denoise_passes); - str.denoise_thickness(project->denoise_passes_thikness); - - if (project->auto_reduction) { - str.reduce_nof_points(project->pass_factor); - } - - project->active_layer->add_stroke(project->sampler.get_stroke()); - project->sampler.clear(); - } - } - - static void presentOutput(StrokesRootWidget* self, nd::GUI* gui) { - if (!self->retrieveProject()) { - return; - } - - tp::rect rec = self->getRect(); - rec.pos = 0; - - glViewport(0, 0, rec.z, rec.w); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - auto project = &self->strokes->project; - - tp::mat4f cammat = (project->cam.projmat() * project->cam.viewmat()).transpose(); - project->sampler.draw(cammat); - - for (auto lay : project->layers) { - if (!lay->hiden) { - lay->draw(cammat); - } - } - - //window.col_clear = project->canvas_color; - } - -}; - -*/ - - -/* - -// ----------------------------- strokes ------------------------ // - - -#pragma once - -#include "glcommon.h" -#include "shader.h" - -#include "array.h" -#include "list.h" -#include "map.h" -#include "topology.h" -#include "strings.h" - -struct StrokeMesh { - tp::Array vbo; - - tp::ogl::shader* shader; - tp::rgba color = tp::rgba(1); - - GLuint VertexArrayID; - GLuint vertexbuffer; - GLuint MatrixID; - GLuint ColorID; - - void init(); - - StrokeMesh(); - void operator=(const StrokeMesh& in); - - void bind_buffers(); - void draw_mesh(const tp::mat4f& cammat); - ~StrokeMesh(); -}; - -struct stroke_point { - tp::vec3f pos; - tp::vec3f normal; - tp::halnf thikness; - stroke_point(); -}; - -struct stroke { - - tp::Array points; - - StrokeMesh mesh; - - void gen_quad(tp::alni pidx, stroke_point* p1, stroke_point* p2, tp::vec3f dir1, tp::vec3f dir2); - tp::vec3f split_dir(tp::vec3f v1, tp::vec3f v2, const tp::vec3f& norm); - - void gen_mesh(); - - void drawcall(const tp::mat4f& cammat); - void add_point(const stroke_point& p); - - -}; - -class drawlayer { - public: - tp::string name = "new layer"; - tp::List strokes; - tp::List strokes_undo; - bool hiden = false; - - void undo(); - void redo(); - - void add_stroke(const stroke& str); - void draw(const tp::mat4f& cammat); - - void clear_history() { - strokes_undo.free(); - } - - void clear_canvas() { - tp::alni len = strokes.length(); - for (tp::alni idx = 0; idx < len; idx++) { - undo(); - } - } - - void reduce_size(tp::halnf pass_factor) { - for (auto str : strokes) { - str.data().reduce_nof_points(pass_factor); - str.data().gen_mesh(); - } - } - - void clear() { - strokes.free(); - strokes_undo.free(); - } -}; - -class inputsmpler { - public: - - bool is_active = false; - - stroke input; - tp::halnf pressure; - - tp::rgba stroke_col = tp::rgba(0.77, 0.77, 0.77, 1); - - tp::halnf screen_precision = 0.000f; - tp::halnf precision = 0.002; - tp::halnf screen_thikness = 0.01f; - tp::halnf thickness = 0.04; - - bool eraser = false; - tp::halnf eraser_size = 0.1f; - - void add_point(const tp::vec3f& pos, const tp::vec3f& norm, float thickness); - bool passed(const tp::vec3f& point); - void start(const tp::vec2f& cpos, tp::Camera* cam); - void sample_util(const tp::vec2f& cpos, tp::Camera* cam); - void erase_util(tp::List* pull, tp::List* undo, const tp::vec2f& cpos, tp::Camera* cam); - void finish(const tp::vec2f& cpos, tp::Camera* cam); - - void sample(tp::List* pool, tp::List* undo, tp::vec2f curs, float pressure, tp::Camera* cam); - void draw(const tp::mat4f& cammat); - - bool active_state(); - bool has_input(); - void clear(); - stroke& get_stroke(); -}; - -struct strokes_project { - - tp::Camera cam; - drawlayer* active_layer = NULL; - tp::List layers; - inputsmpler sampler; - tp::rgba canvas_color = tp::rgba(0.22f, 0.22f, 0.25f, 1.f); - - tp::halni denoise_passes = 1; - tp::halni denoise_passes_thikness = 3; - bool auto_reduction = true; - tp::halnf pass_factor = tp::halnf(0.001); - - strokes_project() { - cam.lookat({0, 0, 0}, {100, 0, 0}, {0, 0, 1}); - } - - drawlayer* get_base_layer() { - if (!layers.length()) { - layers.pushBack(new drawlayer()); - } - return layers[0]; - } - - void append_layers(drawlayer* base) { - for (auto lay : layers) { - base->strokes += lay->strokes; - } - } - - void pickTargetLength(const tp::vec2f& cur) { - using namespace tp; - stroke_point* target_point = NULL; - alnf min_length = FLT_MAX; - alnf min_tollerance = 0.05f; - - for (auto lay : layers) { - for (auto stroke : lay->strokes) { - for (auto pnt : stroke.data().points) { - - alnf tollerance = (cam.project(pnt.data().pos) - cur).length(); - alnf len = (pnt->pos - cam.get_pos()).dot(cam.get_fw()); - - alnf toll2 = abs(min_tollerance - tollerance); - bool selected = (toll2 < 0.01) ? (min_length > len) : (min_tollerance > tollerance); - - if (selected) { - target_point = &pnt.data(); - min_length = len; - min_tollerance = tollerance; - } - } - } - } - - if (target_point) { - cam.lookat(cam.get_pos() + (cam.get_fw() * min_length), cam.get_pos(), cam.get_up()); - } - } - - tp::alni save_size(); - void save(tp::File& file); - void load(tp::File& file); - - ~strokes_project() { - for (auto lay : layers) { - delete lay.data(); - } - } -}; - - - -#include "strokes.h" - -#include "glutils.h" - -#include "StrokesVersions.h" - -using namespace tp; - -void StrokeMesh::init() { - static ogl::shader shader("rsc/shaders/stroke", NULL, "rsc/shaders/stroke"); - this->shader = &shader; - - MatrixID = shader.getu("MVP"); - ColorID = shader.getu("StrokeColor"); - - glGenVertexArrays(1, &VertexArrayID); - glBindVertexArray(VertexArrayID); - - glGenBuffers(1, &vertexbuffer); -} - -StrokeMesh::StrokeMesh() { - init(); -} - -void StrokeMesh::operator=(const StrokeMesh& in) { - - glDeleteBuffers(1, &vertexbuffer); - glDeleteVertexArrays(1, &VertexArrayID); - - init(); - - vbo = in.vbo; - color = in.color; - - bind_buffers(); -} - -void StrokeMesh::bind_buffers() { - - glBindVertexArray(VertexArrayID); - - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vbo[0]) * vbo.length(), vbo.buff(), GL_STATIC_DRAW); -} - - -void StrokeMesh::draw_mesh(const mat4f& cammat) { - - glBindVertexArray(VertexArrayID); - - shader->bind(); - glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &cammat[0][0]); - glUniform4fv(ColorID, 1, &color.rgbs.r); - - // 1st attribute buffer : vertices - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); - - // Draw the triangles ! // mode. count. type. element. array buffer offset - glDrawArrays(GL_TRIANGLES, 0, vbo.length()); - - glDisableVertexAttribArray(0); - - shader->unbind(); -} - -StrokeMesh::~StrokeMesh() { - glDeleteBuffers(1, &vertexbuffer); - glDeleteVertexArrays(1, &VertexArrayID); -} - - -stroke_point::stroke_point() { - pos = vec3f(0, 0, 0); - normal = vec3f(0, 1, 0); - thikness = 0.06; -} - -void stroke::gen_quad(alni pidx, stroke_point* p1, stroke_point* p2, vec3f dir1, vec3f dir2) { - //vec3 perp = normalize(cross(p1->normal, p2->pos - p1->pos)) * p1->thikness; - //float cosa1 = dot(perp, dir1) / (dir1.length() * perp.length()); - //float cosa2 = dot(perp, dir2) / (dir2.length() * perp.length()); - //float thickness1 = -p1->thikness / cosa1; - //float thickness2 = -p2->thikness / cosa2; - -vec3f v1 = p1->pos + dir1 * p1->thikness; -vec3f v2 = p2->pos + dir2 * p2->thikness; -vec3f v3 = p2->pos - dir2 * p2->thikness; -vec3f v4 = p1->pos - dir1 * p1->thikness; - -alni vidx = pidx * 6; - -mesh.vbo[vidx] = v1; -mesh.vbo[vidx + 1] = v2; -mesh.vbo[vidx + 2] = v3; -mesh.vbo[vidx + 3] = v3; -mesh.vbo[vidx + 4] = v4; -mesh.vbo[vidx + 5] = v1; -} - -vec3f stroke::split_dir(vec3f v1, vec3f v2, const vec3f& norm) { - - v1.normalize(); - v2.normalize(); - - vec3f plane_normal; - - halnf val = v2.dot(v1); - - if (val > -0.999999) { - vec3f crossp = v1.cross(v2); - mat3f rot_matrix = mat3f::rotmat(crossp, acos(v1.dot(v2)) / 2.f); - vec3f middle = rot_matrix * v1; - plane_normal = middle.cross(crossp); - } - else { - plane_normal = v2; - } - - return plane_normal.cross(norm); -} - -void stroke::gen_mesh() { - - alni nvert = (points.length() - 1) * 6; - - mesh.vbo.reserve(nvert); - - for (alni pidx = 0; pidx < points.length() - 1; pidx++) { - - stroke_point pt0; - stroke_point pt1 = points[pidx]; - stroke_point pt2 = points[pidx + 1]; - stroke_point pt3; - - vec3f dir1; - vec3f dir2; - - if (pidx > 0) { - pt0 = points[pidx - 1]; - } - else { - pt0.pos = pt1.pos + (pt1.pos - pt2.pos); - pt0.thikness = 0.001; - } - - if (pidx < points.length() - 2) { - pt3 = points[pidx + 2]; - } - else { - pt3.pos = pt2.pos + (pt2.pos - pt1.pos); - pt3.thikness = 0.001; - } - - dir1 = split_dir(pt0.pos - pt1.pos, pt2.pos - pt1.pos, pt1.normal); - dir2 = split_dir(pt1.pos - pt2.pos, pt3.pos - pt2.pos, pt2.normal); - - if (dir1.dot(dir2) < 0) { - dir1 *= -1; - } - - gen_quad(pidx, &pt1, &pt2, dir1.unitv(), dir2.unitv()); - } - - mesh.bind_buffers(); -} - -void stroke::drawcall(const mat4f& cammat) { - mesh.draw_mesh(cammat); -} - -void stroke::add_point(const stroke_point& p) { - points.pushBack(p); -} - - -void drawlayer::undo() { - if (strokes.last()) { - strokes_undo.pushBack(strokes.last()->data); - strokes.delNode(strokes.last()); - } -} - -void drawlayer::redo() { - if (strokes_undo.last()) { - strokes.pushBack(strokes_undo.last()->data); - strokes_undo.delNode(strokes_undo.last()); - } -} - -void drawlayer::add_stroke(const stroke& str) { - strokes.pushBack(str); - strokes.last()->data.gen_mesh(); -} - -void drawlayer::draw(const mat4f& cammat) { - for (ListNode* str = strokes.last(); str; str = str->prev) { - str->data.drawcall(cammat); - } -} - -void inputsmpler::add_point(const vec3f& pos, const vec3f& norm, float thickness) { - stroke_point p; - p.pos = pos; - p.normal = norm; - p.thikness = thickness * pressure; - input.add_point(p); -} - -bool inputsmpler::passed(const vec3f& point) { - if (input.points.length()) { - return (point - input.points[input.points.length() - 1].pos).length() > precision; - } - return true; -} - -void inputsmpler::start(const vec2f& cpos, Camera* cam) { - input.points.free(); - vec3f point = cam->project(cpos); - add_point(point, cam->get_fw(), 0.001f); -} - -void inputsmpler::sample_util(const vec2f& cpos, Camera* cam) { - vec3f point = cam->project(cpos); - if (passed(point)) { - add_point(point, cam->get_fw(), thickness); - } -} - -void inputsmpler::erase_util(List* pull, List* undo, const vec2f& cpos, Camera* cam) { - - ListNode* str = pull->first(); - while (str) { - bool remove = false; - - for (auto pnt : str->data.points) { - if ((cam->project(pnt.data().pos) - cpos).length() < eraser_size) { - remove = true; - break; - } - } - - if (remove) { - ListNode* tmp = str->next; - undo->pushBack(str->data); - pull->delNode(str); - str = tmp; - } - else { - str = str->next; - } - } -} - -void inputsmpler::finish(const vec2f& cpos, Camera* cam) { - if (input.points.length() <= 1) { - input.points.free(); - } - else { - input.points[input.points.length() - 1].thikness = 0.001f; - cam->offset_target(0.0001); - } -} - -void inputsmpler::sample(List* pull, List* undo, vec2f curs, float pressure, Camera* cam) { - - this->input.mesh.color = stroke_col; - this->pressure = pressure; - - if (eraser) { - if (pressure > 0) { - input.points.free(); - erase_util(pull, undo, curs, cam); - } - return; - } - else { - vec3f zero_projection = cam->project(vec2f(0.f)); - thickness = (cam->project(vec2f(0.f, screen_thikness)) - zero_projection).length(); - precision = (cam->project(vec2f(0.f, screen_precision)) - zero_projection).length(); - } - - switch (is_active) { - case false: - { - if (pressure) { - start(curs, cam); - is_active = true; - } - return; - } - case true: - { - sample_util(curs, cam); - if (!pressure) { - finish(curs, cam); - is_active = false; - return; - } - return; - } - } -} - -void inputsmpler::draw(const mat4f& cammat) { - - static int prev_len = input.points.length(); - if (input.points.length() > 1) { - if (prev_len < input.points.length()) { - input.gen_mesh(); - } - input.drawcall(cammat); - } - prev_len = input.points.length(); -} - -bool inputsmpler::active_state() { - return is_active; -} -bool inputsmpler::has_input() { - return input.points.length() > 1; -} -void inputsmpler::clear() { - input.points.free(); - is_active = false; -} -stroke& inputsmpler::get_stroke() { - return input; -} - - -alni strokes_project::save_size() { - alni version_size = StrokesVersion1::save_size(this); - return version_size + sizeof(ProjectInfo); -} - -void strokes_project::save(File& file) { - ProjectInfo head; - head.init(1); - file.write(&head); - StrokesVersion1::save(file, this); -} - -void strokes_project::load(File& file) { - ProjectInfo head; - file.read(&head); - - if (string(head.name) != "strokes") { - return; - } - - alni version = alni(string(head.version)); - if (version > 1 || version < 0) { - return; - } - - version == 1 ? StrokesVersion1::load(file, this) : StrokesVersion0::load(file, this); - - active_layer = get_base_layer(); -} - -*/ \ No newline at end of file diff --git a/Sketch3D/public/FrameBuffer.hpp b/Sketch3D/public/FrameBuffer.hpp new file mode 100644 index 0000000..db8d130 --- /dev/null +++ b/Sketch3D/public/FrameBuffer.hpp @@ -0,0 +1,34 @@ + +#pragma once + +#include "Rect.hpp" +#include "Color.hpp" + +namespace tp { + class RenderBuffer { + public: + RenderBuffer(const Vec2F& size); + RenderBuffer(const Vec2F& size, tp::uint1 samples); + ~RenderBuffer(); + + void beginDraw(); + void setViewport(const RectF& viewport); + void clear(); + void endDraw(); + + uint4 texId() const; + uint4 buffId() const; + + const Vec2F& getSize() const; + + public: + RGBA mClearCol = 0.f; + + private: + uint4 mFrameBufferID = 0; // regroups 0, 1, or more textures, and 0 or 1 depth buffer. + uint4 mTextureId = 0; // texture we're going to render to ( colour attachement #0 ) + uint4 mDepthBufferID = 0; + uint4 mDrawBuffers[1]; + Vec2F mSize; + }; +}; \ No newline at end of file diff --git a/Sketch3D/public/GraphicsApi.hpp b/Sketch3D/public/GraphicsApi.hpp new file mode 100644 index 0000000..79e2d39 --- /dev/null +++ b/Sketch3D/public/GraphicsApi.hpp @@ -0,0 +1,19 @@ + +#pragma once + +#include "Environment.hpp" + +#ifdef ENV_OS_ANDROID +#include +#include +#else +#include "GL/glew.h" +#endif + +#ifdef ENV_OS_ANDROID +#define GLW_CONTEXT_DEPTH_BITS 16 +#define GLW_CONTEXT_DEPTH_COMPONENT GL_DEPTH_COMPONENT16 +#else +#define GLW_CONTEXT_DEPTH_BITS 32 +#define GLW_CONTEXT_DEPTH_COMPONENT GL_DEPTH_COMPONENT32 +#endif \ No newline at end of file diff --git a/Sketch3D/public/Shader.hpp b/Sketch3D/public/Shader.hpp new file mode 100644 index 0000000..8442e4d --- /dev/null +++ b/Sketch3D/public/Shader.hpp @@ -0,0 +1,31 @@ + +#pragma once + +namespace tp { + class RenderShader { + public: + RenderShader(); + RenderShader(const char* vertid, const char* geomid, const char* fragid, bool paths = true); + ~RenderShader(); + + void vert_bind_source(const char* vert_src); + void frag_bind_source(const char* frag_src); + void geom_bind_source(const char* geom_src); + + void compile(); + + void bind(); + uint4 getu(const char* uid); + void unbind(); + + private: + bool compile_shader(const char* ShaderCode, uint4 ShaderID); + void load(const char* vert, const char* geom, const char* frag, bool paths); + + private: + uint4 programm; + uint4 VertexShaderID; + uint4 FragmentShaderID; + uint4 GeometryShaderID; + }; +}; \ No newline at end of file diff --git a/Sketch3D/public/Sketch3D.hpp b/Sketch3D/public/Sketch3D.hpp new file mode 100644 index 0000000..4695c7d --- /dev/null +++ b/Sketch3D/public/Sketch3D.hpp @@ -0,0 +1,227 @@ + +#include "Buffer.hpp" +#include "List.hpp" +#include "Map.hpp" +#include "Topology.hpp" +#include "Color.hpp" +#include "Strings.hpp" + +#include "GraphicsApi.hpp" +#include "FrameBuffer.hpp" +#include "Shader.hpp" + +namespace strokes { + + class Renderer; + class Project; + + class Stroke { + + friend Renderer; + + public: + struct Point { + tp::Vec3F pos; + tp::halnf thickness = NULL; + }; + + tp::Buffer mPoints; + tp::RGBA mCol; + + private: + struct GLHandles { + GLuint VertexArrayID = 0; + GLuint vertexbuffer = 0; + GLuint vbo_len = 0; + GLHandles(); + void sendDataToGPU(tp::Buffer* mPoints); + ~GLHandles(); + } mGl; + + public: + + Stroke(); + + void denoisePos(tp::halni passes); + void denoiseThickness(tp::halni passes); + void compress(tp::halnf factor); + void subdiv(tp::halnf precition, tp::Camera* cam, tp::halni passes = 1); + + void updateGpuBuffers(); + + tp::Buffer& buff(); + }; + + class Brush { + public: + tp::String mType = "equal"; + Brush() {} + virtual void sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) {} + virtual void draw(Renderer* render, tp::Camera* camera) {} + virtual ~Brush() {} + }; + + class PencilBrush : public Brush { + + tp::halnf mPrecision = 0.001f; + + tp::halni mDenoisePassesPos = 1; + tp::halni mDenoisePassesThick = 3; + tp::halnf mCompressionFactor = 0.0001f; + tp::halni mSubdivPasses = 3; + bool mEnableCompression = true; + + tp::halni mMaxPoints = 100; + + Stroke* mStroke = NULL; + Stroke mShowStroke; + + void unsureReady(Stroke* stroke, tp::Camera* cam, bool debug = false); + + public: + + tp::RGBA mCol = tp::RGBA(1.0f); + tp::halnf mSize = 0.01f; + + PencilBrush(); + virtual void sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) override; + virtual void draw(Renderer* render, tp::Camera* camera) override; + virtual ~PencilBrush(); + }; + + struct EraserBrush : public Brush { + EraserBrush() { mType = "eraser"; } + virtual void sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) override {} + virtual void draw(Renderer* render, tp::Camera* camera) override {} + virtual ~EraserBrush() {} + }; + + class Project { + + public: + + struct Layer { + tp::String name = "new layer"; + tp::List strokes; + bool enabled = true; + ~Layer(); + }; + + tp::Buffer mLayers; + tp::halni mActiveLayer = -1; + + tp::Camera mCamera; + tp::RGBA mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f }; + + tp::Map mBrushes; + tp::String mActiveBrush; + + Project(); + ~Project(); + }; + + class Renderer { + tp::RenderBuffer mBufferDowncast; + tp::RenderBuffer mBuffer; + tp::RenderShader mShader; + + // shader uniforms + GLuint mMatrixUniform = 0; + GLuint mColorUniform = 0; + GLuint mRatioUniform = 0; + GLuint mTargetUniform = 0; + GLuint mBGColUniform = 0; + + public: + Renderer(tp::Vec2F size); + + void renderBegin(); + void setViewport(tp::RectF viewport); + void drawStroke(Stroke* str, tp::Camera* camera); + void renderEnd(); + + void setClearCol(tp::RGBA col); + tp::uhalni getTextudeId(); + tp::RenderBuffer* getBuff(); + + ~Renderer(); + }; +}; + +/* +void Project::save(tp::File& file) { + file.write(&mCamera); + file.write(&mBackgroundColor); + file.write(&mActiveLayer); + + tp::alni lay_len = mLayers.length(); + file.write(&lay_len); + for (auto layer : mLayers) { + layer.data()->name.save(&file); + + file.write(&layer.data()->enabled); + + tp::alni len = layer.data()->strokes.length(); + file.write(&len); + for (auto stiter : layer.data()->strokes) { + stiter->save(file); + } + } +} + +void Project::load(tp::File& file) { + file.read(&mCamera); + file.read(&mBackgroundColor); + file.read(&mActiveLayer); + + tp::alni layers_len; + file.read(&layers_len); + mLayers.reserve(layers_len); + + for (tp::alni idx = 0; idx < layers_len; idx++) { + + tp::string key; key.load(&file); + auto layer = new Layer(); + layer->name = key; + mLayers[idx] = layer; + + file.read(&layer->enabled); + + tp::alni len; + file.read(&len); + + for (tp::alni str_idx = 0; str_idx < len; str_idx++) { + auto str = new Stroke(); + layer->strokes.pushBack(str); + layer->strokes.last()->data->load(file); + } + } +} +*/ + +/* + void Stroke::save(tp::File& file) { + file.write(&mCol); + + tp::alni length = mPoints.length(); + file.write(&length); + for (auto piter : mPoints) { + file.write(&piter.data()); + } + } + + void Stroke::load(tp::File& file) { + tp::rgba color; + file.read(&color); + + tp::alni p_len; + file.read(&p_len); + + mPoints.reserve(p_len); + for (auto piter : mPoints) { + file.read(&piter.data()); + } + + updateGpuBuffers(); + } + */ \ No newline at end of file diff --git a/Sketch3D/public/Sketch3DWidget.hpp b/Sketch3D/public/Sketch3DWidget.hpp new file mode 100644 index 0000000..6a7d273 --- /dev/null +++ b/Sketch3D/public/Sketch3DWidget.hpp @@ -0,0 +1,87 @@ + +// #include "Fram.h" + +class Widget { + void destructor(StrokesWidget* self) { + self->mRenderer.~Renderer(); + self->mImage.free(self->mDrawer); + self->mImage.~ImageHandle(); + } + + void procInputs(StrokesWidget* self, nd::GUIInputs* inputs) { + auto proj = self->getTargetProject(); + if (!proj) { + return; + } + + auto rec = self->getRect(); + proj->mCamera.set_ratio(rec.w / rec.z); + + auto col_obj_bg = self->getMember("bg_color"); + if (col_obj_bg) { + proj->mBackgroundColor = col_obj_bg->mCol; + } + + if (!rec.inside(inputs->mCrsPrev)) { + return; + } + + auto pressure = inputs->mPressure; + if (!inputs->Anticipating()) { + pressure = 0.f; + } + + auto idx = proj->mBrushes.presents(proj->mActiveBrush); + if (idx) { + auto brush = proj->mBrushes.getSlotVal(idx); + auto crs = (inputs->mCrs - rec.pos); + crs.x /= rec.z; + crs.y /= rec.w; + crs = (crs - 0.5) * 2; + + if (brush->mType == "pencil") { + auto col_obj = self->getMember("draw_color"); + if (col_obj) { + ((strokes::PencilBrush*) brush)->mCol = col_obj->mCol; + } + } + + brush->sample(proj, crs, pressure); + } + } + + void presentOutput(StrokesWidget* self, nd::GUIdrawer* drawer) { + auto proj = self->getTargetProject(); + if (!proj) { + return; + } + + if (!self->mImage.mId) { + self->mDrawer = drawer; + self->mImage.createFromBuff(self->mRenderer.getBuff(), drawer); + } + + auto rec = self->getRect(); + self->mRenderer.setViewport({ 0, 0, rec.z, rec.w }); + self->mRenderer.setClearCol(proj->mBackgroundColor); + self->mRenderer.renderBegin(); + + for (auto lay : proj->mLayers) { + if (lay.data()->enabled) { + for (auto str : lay.data()->strokes) { + self->mRenderer.drawStroke(str.data(), &proj->mCamera); + } + } + } + + auto idx = proj->mBrushes.presents(proj->mActiveBrush); + if (idx) { + auto brush = proj->mBrushes.getSlotVal(idx); + brush->draw(&self->mRenderer, &proj->mCamera); + } + + self->mRenderer.renderEnd(); + + drawer->drawImage(rec, &self->mImage, 0, 1, 12); + } +}; \ No newline at end of file diff --git a/Sketch3D/public/StrokesWidget.h b/Sketch3D/public/StrokesWidget.h deleted file mode 100644 index 729c8f1..0000000 --- a/Sketch3D/public/StrokesWidget.h +++ /dev/null @@ -1,29 +0,0 @@ - -#include "gui/Widgets.h" - -#include "nodes.h" -#include "StrokesObject.h" - -namespace nd { - struct StrokesWidget : Widget { - static obj::ObjectType TypeData; - static struct Vtable : Widget::Vtable {} vtable; - - strokes::Renderer mRenderer; - nd::GUIdrawer::ImageHandle mImage; - nd::GUIdrawer* mDrawer = NULL; - - static void constructor(StrokesWidget* self); - static void destructor(StrokesWidget* self); - static void copy(Widget* self, const Widget* in); - static void procInputs(StrokesWidget* self, nd::GUIInputs* inputs); - static void presentOutput(StrokesWidget* self, nd::GUIdrawer* drawer); - - strokes::Project* getTargetProject(); - - static void OpsInit(); - static void OpsUnInit(); - - static void addShortcuts(nd::NodesCore* core); - }; -}; \ No newline at end of file diff --git a/Sketch3D/public/Texture.hpp b/Sketch3D/public/Texture.hpp new file mode 100644 index 0000000..71ee943 --- /dev/null +++ b/Sketch3D/public/Texture.hpp @@ -0,0 +1,29 @@ + +#pragma once + +#include "Buffer2D.hpp" +#include "Color.hpp" +#include "Vec.hpp" + +namespace tp { + class RenderTexture { + public: + RenderTexture(); + ~RenderTexture(); + + uint4 getid(); + + void update(const Buffer2D& buff); + void draw(const uint4& out = 0); + + public: + static void init(); + static void deinit(); + static void draw_texture(uint4 out, uint4 in); + static uint4 get_tex(const char* TexId); + static void drawCurcle(Vec2F pos, double radius, RGBA col); + + private: + uint4 id; + }; +}; \ No newline at end of file diff --git a/Sketch3D/public/strokes.h b/Sketch3D/public/strokes.h deleted file mode 100644 index f8bf250..0000000 --- a/Sketch3D/public/strokes.h +++ /dev/null @@ -1,153 +0,0 @@ - -#include "Buffer.hpp" -#include "List.hpp" -#include "Map.hpp" -#include "Topology.hpp" -#include "Color.hpp" -#include "Strings.hpp" - -namespace strokes { - - class Renderer; - class Project; - - class Stroke { - - friend Renderer; - - public: - struct Point { - tp::vec3f pos; - tp::halnf thickness = NULL; - }; - - tp::Array mPoints; - tp::rgba mCol; - - private: - struct GLHandles { - GLuint VertexArrayID = 0; - GLuint vertexbuffer = 0; - GLuint vbo_len = 0; - GLHandles(); - void sendDataToGPU(tp::Array* mPoints); - ~GLHandles(); - } mGl; - - public: - - Stroke(); - - void denoisePos(tp::halni passes); - void denoiseThickness(tp::halni passes); - void compress(tp::halnf factor); - void subdiv(tp::halnf precition, tp::Camera* cam, tp::halni passes = 1); - - void updateGpuBuffers(); - - tp::Array& buff(); - - tp::halni saveSize(); - void save(tp::File& file); - void load(tp::File& file); - }; - - class Brush { - public: - tp::string mType = "equal"; - Brush() {} - virtual void sample(Project* proj, tp::vec2f crs, tp::halnf pressure) {} - virtual void draw(Renderer* render, tp::Camera* camera) {} - virtual ~Brush() {} - }; - - class PencilBrush : public Brush { - - tp::halnf mPrecision = 0.001f; - - tp::halni mDenoisePassesPos = 1; - tp::halni mDenoisePassesThick = 3; - tp::halnf mCompressionFactor = 0.0001f; - tp::halni mSubdivPasses = 3; - bool mEnableCompression = true; - - tp::halni mMaxPoints = 100; - - Stroke* mStroke = NULL; - Stroke mShowStroke; - - void unsureReady(Stroke* stroke, tp::Camera* cam, bool debug = false); - - public: - - tp::rgba mCol = tp::rgba(1.0f); - tp::halnf mSize = 0.01f; - - PencilBrush(); - virtual void sample(Project* proj, tp::vec2f crs, tp::halnf pressure) override; - virtual void draw(Renderer* render, tp::Camera* camera) override; - virtual ~PencilBrush(); - }; - - struct EraserBrush : public Brush { - EraserBrush() { mType = "eraser"; } - virtual void sample(Project* proj, tp::vec2f crs, tp::halnf pressure) override {} - virtual void draw(Renderer* render, tp::Camera* camera) override {} - virtual ~EraserBrush() {} - }; - - class Project { - - public: - - struct Layer { - tp::string name = "new layer"; - tp::List strokes; - bool enabled = true; - ~Layer(); - }; - - tp::Array mLayers; - tp::halni mActiveLayer = -1; - - tp::Camera mCamera; - tp::rgba mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f }; - - tp::HashMap mBrushes; - tp::string mActiveBrush; - - Project(); - ~Project(); - - tp::alni saveSize(); - void save(tp::File& file); - void load(tp::File& file); - }; - - class Renderer { - tp::ogl::fbuffer mBufferDowncast; - tp::ogl::fbuffer mBuffer; - tp::ogl::shader mShader; - - // shader uniforms - GLuint mMatrixUniform = 0; - GLuint mColorUniform = 0; - GLuint mRatioUniform = 0; - GLuint mTargetUniform = 0; - GLuint mBGColUniform = 0; - - public: - Renderer(tp::vec2f size); - - void renderBegin(); - void setViewport(tp::rectf viewport); - void drawStroke(Stroke* str, tp::Camera* camera); - void renderEnd(); - - void setClearCol(tp::rgba col); - tp::uhalni getTextudeId(); - tp::ogl::fbuffer* getBuff(); - - ~Renderer(); - }; -}; \ No newline at end of file diff --git a/Sketch3D/public/strokes_versions.h b/Sketch3D/public/strokes_versions.h deleted file mode 100644 index 869221e..0000000 --- a/Sketch3D/public/strokes_versions.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once - -#include "strokes.h" - -struct ProjectInfo { - char name[10] = {0}; - char version[10] = {0}; - - void init(tp::alni v) { - tp::string version_s(v); - tp::memcp(name, "strokes", tp::slen("strokes")); - tp::memcp(version, version_s.cstr(), version_s.size()); - } -}; - -namespace StrokesVersion0 { - - tp::alni save_size(strokes_project* proj) { - tp::alni out = 0; - out += sizeof(tp::Camera); - out += sizeof(tp::rgba); - - out += sizeof(tp::alni); - for (auto layer : proj->layers) { - for (auto stiter : layer->strokes) { - stroke* str = &stiter.data(); - - out += sizeof(tp::rgba); - - out += sizeof(tp::alni); - out += str->points.length() * sizeof(stroke_point); - } - } - return out; - } - - void save(tp::File& file, strokes_project* proj) { - - file.write(&proj->cam); - file.write(&proj->canvas_color); - - drawlayer base_layer; - proj->append_layers(&base_layer); - - tp::alni len = base_layer.strokes.length(); - file.write(&len); - for (auto stiter : base_layer.strokes) { - stroke* str = &stiter.data(); - - tp::alni length = str->points.length(); - file.write(&length); - file.write(&str->mesh.color); - - for (auto piter : str->points) { - file.write(&piter.data()); - } - } - } - - void load(tp::File& file, strokes_project* proj) { - file.read(&proj->cam); - - file.read(&proj->canvas_color); - - drawlayer* base = proj->get_base_layer(); - - tp::alni len; - file.read(&len); - - for (tp::alni str_idx = 0; str_idx < len; str_idx++) { - stroke str = stroke(); - - tp::alni p_len; file.read(&p_len); - tp::rgba color; file.read(&color); - - str.points.reserve(p_len); - for (auto piter : str.points) { - file.read(&piter.data()); - } - - str.mesh.color = color; - base->add_stroke(str); - } - } -}; - -namespace StrokesVersion1 { - - tp::alni save_size(strokes_project* proj) { - tp::alni out = 0; - out += sizeof(tp::Camera); - out += sizeof(tp::halnf); - out += sizeof(tp::halnf); - out += sizeof(tp::rgba); - - out += sizeof(tp::alni); - for (auto layer : proj->layers) { - out += layer->name.save_size(); - out += sizeof(bool); - out += sizeof(tp::alni); - for (auto stiter : layer->strokes) { - stroke* str = &stiter.data(); - out += sizeof(tp::rgba); - out += sizeof(tp::alni); - out += str->points.length() * sizeof(stroke_point); - } - } - return out; - } - - void save(tp::File& file, strokes_project* proj) { - - file.write(&proj->cam); - file.write(&proj->sampler.eraser_size); - file.write(&proj->sampler.screen_thikness); - file.write(&proj->canvas_color); - - tp::alni lay_len = proj->layers.length(); - file.write(&lay_len); - for (auto layer : proj->layers) { - layer->name.save(&file); - - file.write(&layer->hiden); - - tp::alni len = layer->strokes.length(); - file.write(&len); - for (auto stiter : layer->strokes) { - stroke* str = &stiter.data(); - - file.write(&str->mesh.color); - - tp::alni length = str->points.length(); - file.write(&length); - for (auto piter : str->points) { - file.write(&piter.data()); - } - } - } - } - - void load(tp::File& file, strokes_project* proj) { - file.read(&proj->cam); - - file.read(&proj->sampler.eraser_size); - file.read(&proj->sampler.screen_thikness); - file.read(&proj->canvas_color); - - tp::alni layers_len; - file.read(&layers_len); - for (tp::alni str_idx = 0; str_idx < layers_len; str_idx++) { - - tp::string key; key.load(&file); - drawlayer* layer = new drawlayer(); - layer->name = key; - proj->layers.pushBack(layer); - - file.read(&layer->hiden); - - tp::alni len; - file.read(&len); - - for (tp::alni str_idx = 0; str_idx < len; str_idx++) { - stroke str = stroke(); - - tp::rgba color; file.read(&color); - - tp::alni p_len; file.read(&p_len); - str.points.reserve(p_len); - for (auto piter : str.points) { - file.read(&piter.data()); - } - - str.mesh.color = color; - layer->add_stroke(str); - } - } - } -};