trying to compile
This commit is contained in:
parent
b8bab2264f
commit
57d5bc61ed
19 changed files with 999 additions and 1890 deletions
|
|
@ -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}/")
|
||||
|
|
|
|||
|
|
@ -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<tp::Window::Events, tp::Graphics::Canvas> 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<obj::ListObject>("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();
|
||||
}
|
||||
108
Sketch3D/private/FrameBuffer.cpp
Normal file
108
Sketch3D/private/FrameBuffer.cpp
Normal file
|
|
@ -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; }
|
||||
|
||||
159
Sketch3D/private/Shader.cpp
Normal file
159
Sketch3D/private/Shader.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
|
||||
#include "Strings.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "LocalConnection.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "GraphicsApi.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
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<char> 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<char> 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);
|
||||
}
|
||||
|
|
@ -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<Point>* mPoints) {
|
||||
void Stroke::GLHandles::sendDataToGPU(tp::Buffer<Point>* 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::Point>& Stroke::buff() {
|
||||
tp::Buffer<Stroke::Point>& 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<Point> passed_poits;
|
||||
|
||||
for (auto idx : tp::Range(mPoints.length())) {
|
||||
for (auto idx : tp::Range(mPoints.size())) {
|
||||
passed_poits.pushBack(mPoints[idx]);
|
||||
}
|
||||
|
||||
tp::ListNode<Point>* min_node = NULL;
|
||||
tp::List<Point>::Node* min_node = NULL;
|
||||
do {
|
||||
min_node = NULL;
|
||||
tp::halnf min_factor = factor;
|
||||
|
||||
tp::ListNode<Point>* iter = passed_poits.first()->next;
|
||||
tp::List<Point>::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<Point> 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<tp::rgba>(&mCol);
|
||||
|
||||
tp::alni length = mPoints.length();
|
||||
file.write<tp::alni>(&length);
|
||||
for (auto piter : mPoints) {
|
||||
file.write<Point>(&piter.data());
|
||||
}
|
||||
}
|
||||
|
||||
void Stroke::load(tp::File& file) {
|
||||
tp::rgba color;
|
||||
file.read<tp::rgba>(&color);
|
||||
|
||||
tp::alni p_len;
|
||||
file.read<tp::alni>(&p_len);
|
||||
|
||||
mPoints.reserve(p_len);
|
||||
for (auto piter : mPoints) {
|
||||
file.read<Point>(&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<tp::Camera>(&mCamera);
|
||||
file.write<tp::rgba>(&mBackgroundColor);
|
||||
file.write<tp::halni>(&mActiveLayer);
|
||||
|
||||
tp::alni lay_len = mLayers.length();
|
||||
file.write<tp::alni>(&lay_len);
|
||||
for (auto layer : mLayers) {
|
||||
layer.data()->name.save(&file);
|
||||
|
||||
file.write<bool>(&layer.data()->enabled);
|
||||
|
||||
tp::alni len = layer.data()->strokes.length();
|
||||
file.write<tp::alni>(&len);
|
||||
for (auto stiter : layer.data()->strokes) {
|
||||
stiter->save(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Project::load(tp::File& file) {
|
||||
file.read<tp::Camera>(&mCamera);
|
||||
file.read<tp::rgba>(&mBackgroundColor);
|
||||
file.read<tp::halni>(&mActiveLayer);
|
||||
|
||||
tp::alni layers_len;
|
||||
file.read<tp::alni>(&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<bool>(&layer->enabled);
|
||||
|
||||
tp::alni len;
|
||||
file.read<tp::alni>(&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() {
|
||||
|
|
@ -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<obj::LinkObject>("TargetProject");
|
||||
if (!link) {
|
||||
return NULL;
|
||||
}
|
||||
auto obj = link->getLink();
|
||||
if (!obj) {
|
||||
link->setLink(getMember<obj::StrokesObject>("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<obj::ColorObject>("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<obj::ColorObject>("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<StrokesWidget>(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<obj::EnumObject>(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<obj::ListObject>("uis");
|
||||
NDO_CASTV(nd::GUI, uis_list->getItems()[0], gui);
|
||||
NDO_CASTV(nd::TUI, uis_list->getItems()[1], tui);
|
||||
|
||||
auto shortcuts = tui->getMemberAssert<obj::ListObject>("shortcuts");
|
||||
auto inputs = tui->getMemberAssert<obj::DictObject>("inputs");
|
||||
auto input_states = tui->getMemberAssert<obj::DictObject>("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<obj::EnumObject>("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<obj::EnumObject>("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<obj::EnumObject>("state");
|
||||
trigger->addComparator("comp", back, input_state_hold);
|
||||
}
|
||||
}
|
||||
207
Sketch3D/private/Texture.cpp
Normal file
207
Sketch3D/private/Texture.cpp
Normal file
|
|
@ -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<RGBA>& 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<String, GLuint> 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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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,
|
||||
};
|
||||
File diff suppressed because it is too large
Load diff
34
Sketch3D/public/FrameBuffer.hpp
Normal file
34
Sketch3D/public/FrameBuffer.hpp
Normal file
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
19
Sketch3D/public/GraphicsApi.hpp
Normal file
19
Sketch3D/public/GraphicsApi.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Environment.hpp"
|
||||
|
||||
#ifdef ENV_OS_ANDROID
|
||||
#include <EGL/egl.h>
|
||||
#include <GLES3/gl32.h>
|
||||
#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
|
||||
31
Sketch3D/public/Shader.hpp
Normal file
31
Sketch3D/public/Shader.hpp
Normal file
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
227
Sketch3D/public/Sketch3D.hpp
Normal file
227
Sketch3D/public/Sketch3D.hpp
Normal file
|
|
@ -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<Point> mPoints;
|
||||
tp::RGBA mCol;
|
||||
|
||||
private:
|
||||
struct GLHandles {
|
||||
GLuint VertexArrayID = 0;
|
||||
GLuint vertexbuffer = 0;
|
||||
GLuint vbo_len = 0;
|
||||
GLHandles();
|
||||
void sendDataToGPU(tp::Buffer<Point>* 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<Point>& 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<Stroke*> strokes;
|
||||
bool enabled = true;
|
||||
~Layer();
|
||||
};
|
||||
|
||||
tp::Buffer<Layer*> mLayers;
|
||||
tp::halni mActiveLayer = -1;
|
||||
|
||||
tp::Camera mCamera;
|
||||
tp::RGBA mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f };
|
||||
|
||||
tp::Map<tp::String, Brush*> 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<tp::Camera>(&mCamera);
|
||||
file.write<tp::rgba>(&mBackgroundColor);
|
||||
file.write<tp::halni>(&mActiveLayer);
|
||||
|
||||
tp::alni lay_len = mLayers.length();
|
||||
file.write<tp::alni>(&lay_len);
|
||||
for (auto layer : mLayers) {
|
||||
layer.data()->name.save(&file);
|
||||
|
||||
file.write<bool>(&layer.data()->enabled);
|
||||
|
||||
tp::alni len = layer.data()->strokes.length();
|
||||
file.write<tp::alni>(&len);
|
||||
for (auto stiter : layer.data()->strokes) {
|
||||
stiter->save(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Project::load(tp::File& file) {
|
||||
file.read<tp::Camera>(&mCamera);
|
||||
file.read<tp::rgba>(&mBackgroundColor);
|
||||
file.read<tp::halni>(&mActiveLayer);
|
||||
|
||||
tp::alni layers_len;
|
||||
file.read<tp::alni>(&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<bool>(&layer->enabled);
|
||||
|
||||
tp::alni len;
|
||||
file.read<tp::alni>(&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<tp::rgba>(&mCol);
|
||||
|
||||
tp::alni length = mPoints.length();
|
||||
file.write<tp::alni>(&length);
|
||||
for (auto piter : mPoints) {
|
||||
file.write<Point>(&piter.data());
|
||||
}
|
||||
}
|
||||
|
||||
void Stroke::load(tp::File& file) {
|
||||
tp::rgba color;
|
||||
file.read<tp::rgba>(&color);
|
||||
|
||||
tp::alni p_len;
|
||||
file.read<tp::alni>(&p_len);
|
||||
|
||||
mPoints.reserve(p_len);
|
||||
for (auto piter : mPoints) {
|
||||
file.read<Point>(&piter.data());
|
||||
}
|
||||
|
||||
updateGpuBuffers();
|
||||
}
|
||||
*/
|
||||
87
Sketch3D/public/Sketch3DWidget.hpp
Normal file
87
Sketch3D/public/Sketch3DWidget.hpp
Normal file
|
|
@ -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<obj::ColorObject>("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<obj::ColorObject>("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);
|
||||
}
|
||||
};
|
||||
|
|
@ -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);
|
||||
};
|
||||
};
|
||||
29
Sketch3D/public/Texture.hpp
Normal file
29
Sketch3D/public/Texture.hpp
Normal file
|
|
@ -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<RGBA>& 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;
|
||||
};
|
||||
};
|
||||
|
|
@ -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<Point> mPoints;
|
||||
tp::rgba mCol;
|
||||
|
||||
private:
|
||||
struct GLHandles {
|
||||
GLuint VertexArrayID = 0;
|
||||
GLuint vertexbuffer = 0;
|
||||
GLuint vbo_len = 0;
|
||||
GLHandles();
|
||||
void sendDataToGPU(tp::Array<Point>* 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<Point>& 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<Stroke*> strokes;
|
||||
bool enabled = true;
|
||||
~Layer();
|
||||
};
|
||||
|
||||
tp::Array<Layer*> mLayers;
|
||||
tp::halni mActiveLayer = -1;
|
||||
|
||||
tp::Camera mCamera;
|
||||
tp::rgba mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f };
|
||||
|
||||
tp::HashMap<Brush*, tp::string> 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();
|
||||
};
|
||||
};
|
||||
|
|
@ -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<tp::Camera>(&proj->cam);
|
||||
file.write<tp::rgba>(&proj->canvas_color);
|
||||
|
||||
drawlayer base_layer;
|
||||
proj->append_layers(&base_layer);
|
||||
|
||||
tp::alni len = base_layer.strokes.length();
|
||||
file.write<tp::alni>(&len);
|
||||
for (auto stiter : base_layer.strokes) {
|
||||
stroke* str = &stiter.data();
|
||||
|
||||
tp::alni length = str->points.length();
|
||||
file.write<tp::alni>(&length);
|
||||
file.write<tp::rgba>(&str->mesh.color);
|
||||
|
||||
for (auto piter : str->points) {
|
||||
file.write<stroke_point>(&piter.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load(tp::File& file, strokes_project* proj) {
|
||||
file.read<tp::Camera>(&proj->cam);
|
||||
|
||||
file.read<tp::rgba>(&proj->canvas_color);
|
||||
|
||||
drawlayer* base = proj->get_base_layer();
|
||||
|
||||
tp::alni len;
|
||||
file.read<tp::alni>(&len);
|
||||
|
||||
for (tp::alni str_idx = 0; str_idx < len; str_idx++) {
|
||||
stroke str = stroke();
|
||||
|
||||
tp::alni p_len; file.read<tp::alni>(&p_len);
|
||||
tp::rgba color; file.read<tp::rgba>(&color);
|
||||
|
||||
str.points.reserve(p_len);
|
||||
for (auto piter : str.points) {
|
||||
file.read<stroke_point>(&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<tp::Camera>(&proj->cam);
|
||||
file.write<tp::halnf>(&proj->sampler.eraser_size);
|
||||
file.write<tp::halnf>(&proj->sampler.screen_thikness);
|
||||
file.write<tp::rgba>(&proj->canvas_color);
|
||||
|
||||
tp::alni lay_len = proj->layers.length();
|
||||
file.write<tp::alni>(&lay_len);
|
||||
for (auto layer : proj->layers) {
|
||||
layer->name.save(&file);
|
||||
|
||||
file.write<bool>(&layer->hiden);
|
||||
|
||||
tp::alni len = layer->strokes.length();
|
||||
file.write<tp::alni>(&len);
|
||||
for (auto stiter : layer->strokes) {
|
||||
stroke* str = &stiter.data();
|
||||
|
||||
file.write<tp::rgba>(&str->mesh.color);
|
||||
|
||||
tp::alni length = str->points.length();
|
||||
file.write<tp::alni>(&length);
|
||||
for (auto piter : str->points) {
|
||||
file.write<stroke_point>(&piter.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load(tp::File& file, strokes_project* proj) {
|
||||
file.read<tp::Camera>(&proj->cam);
|
||||
|
||||
file.read<tp::halnf>(&proj->sampler.eraser_size);
|
||||
file.read<tp::halnf>(&proj->sampler.screen_thikness);
|
||||
file.read<tp::rgba>(&proj->canvas_color);
|
||||
|
||||
tp::alni layers_len;
|
||||
file.read<tp::alni>(&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<bool>(&layer->hiden);
|
||||
|
||||
tp::alni len;
|
||||
file.read<tp::alni>(&len);
|
||||
|
||||
for (tp::alni str_idx = 0; str_idx < len; str_idx++) {
|
||||
stroke str = stroke();
|
||||
|
||||
tp::rgba color; file.read<tp::rgba>(&color);
|
||||
|
||||
tp::alni p_len; file.read<tp::alni>(&p_len);
|
||||
str.points.reserve(p_len);
|
||||
for (auto piter : str.points) {
|
||||
file.read<stroke_point>(&piter.data());
|
||||
}
|
||||
|
||||
str.mesh.color = color;
|
||||
layer->add_stroke(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue