diff --git a/assets/shaders/2d-solid.fragment.glsl b/assets/shaders/2d-solid.fragment.glsl index 2995a9d..0a11589 100644 --- a/assets/shaders/2d-solid.fragment.glsl +++ b/assets/shaders/2d-solid.fragment.glsl @@ -1,8 +1,55 @@ #version 330 core -out vec4 frag_color; +out vec4 pixel_color; -in vec4 fragment_color; +in vec4 frag_color; +in vec2 frag_dest_position; +in vec2 frag_dest_center; +in vec2 frag_dest_half_size; +in float frag_softness; +in float frag_border_radius; +in float frag_border_thickness; + +float roundedRectSDF(vec2 sample_pos, vec2 rect_center, vec2 rect_half_size, float r) { + vec2 d2 = (abs(rect_center - sample_pos) - rect_half_size + vec2(r, r)); + return min(max(d2.x, d2.y), 0.0) + length(max(d2, 0.0)) - r; +} void main() { - frag_color = fragment_color; + vec2 softness_padding = vec2( + max(0, frag_softness*2-1), + max(0, frag_softness*2-1)); + + float border_factor = 1.0f; + if (frag_border_thickness != 0) { + vec2 interior_half_size = frag_dest_half_size - vec2(frag_border_thickness); + + float interior_radius_reduce_f = min( + interior_half_size.x / frag_dest_half_size.x, + interior_half_size.y / frag_dest_half_size.y); + + float interior_corner_radius = frag_border_radius * interior_radius_reduce_f * interior_radius_reduce_f; + + float inside_d = roundedRectSDF( + frag_dest_position, + frag_dest_center, + interior_half_size - softness_padding, + interior_corner_radius); + + + float inside_f = smoothstep(0, 2*frag_softness, inside_d); + border_factor = inside_f; + } + + float dist = roundedRectSDF( + frag_dest_position, + frag_dest_center, + frag_dest_half_size - softness_padding, + frag_border_radius); + + // For texturing later + float sample = 1; + + float sdf_factor = 1.0f - smoothstep(0, 2*frag_softness, dist); + + pixel_color = frag_color * sample * sdf_factor * border_factor; }; diff --git a/assets/shaders/2d-solid.vertex.glsl b/assets/shaders/2d-solid.vertex.glsl index 1e5308e..381f21e 100644 --- a/assets/shaders/2d-solid.vertex.glsl +++ b/assets/shaders/2d-solid.vertex.glsl @@ -2,10 +2,19 @@ layout (location = 0) in vec2 p0; layout (location = 1) in vec2 p1; layout (location = 2) in vec4 color; +layout (location = 3) in float border_radius; +layout (location = 4) in float border_thickness; +layout (location = 6) in float edge_softness; uniform mat4 projection; -out vec4 fragment_color; +out vec4 frag_color; +out vec2 frag_dest_position; +out vec2 frag_dest_center; +out vec2 frag_dest_half_size; +out float frag_softness; +out float frag_border_radius; +out float frag_border_thickness; const vec2 rectangle_vertices[4] = vec2[]( vec2(-1, -1), @@ -25,5 +34,11 @@ void main() { 1 ); - fragment_color = color; + frag_color = color; + frag_dest_position = dest_position; + frag_dest_center = dest_center; + frag_dest_half_size = dest_half_size; + frag_border_radius = border_radius; + frag_border_thickness = border_thickness; + frag_softness = edge_softness; } diff --git a/src/main.cpp b/src/main.cpp index 0141b80..cb28ae5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -94,13 +94,25 @@ struct Polycube { struct RenderObjects_Rectangle { uint32 vao; + uint64 count; + list> p0; uint32 p0BufferId; + list> p1; uint32 p1BufferId; + list> color; uint32 colorBufferId; - uint64 count; + + list borderRadius; + uint32 borderRadiusBufferId; + + list borderThickness; + uint32 borderThicknessBufferId; + + list edgeSoftness; + uint32 edgeSoftnessBufferId; }; struct Input { @@ -225,6 +237,7 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) { } glViewport(0, 0, 800, 600); + glfwSwapInterval(0); glfwSetFramebufferSizeCallback(window, framebufferSizeCallback); glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL); glEnable(GL_DEPTH_TEST); @@ -340,24 +353,24 @@ void processInput(Soma *soma) { } } -Polycube createPolycubeFromRepr(Soma *soma, Space *repr, Vector4 color) { - uint32 polycubeMainEntityHandle = createEntity(soma->scene); - Entity *polycubeMainEntity = getEntity(soma->scene, polycubeMainEntityHandle); +Polycube createPolycubeFromRepr(Scene *s, Space *repr, Vector4 color) { + uint32 polycubeMainEntityHandle = createEntity(s); + Entity *polycubeMainEntity = getEntity(s, polycubeMainEntityHandle); for (int x = 0; x < repr->dim_x; x++) { for (int y = 0; y < repr->dim_y; y++) { for (int z = 0; z < repr->dim_z; z++) { if (filledAt(repr, x, y, z)) { - uint32 segmentEntityHandle = createEntity(soma->scene); - Entity *polycubeSegment = getEntity(soma->scene, segmentEntityHandle); + uint32 segmentEntityHandle = createEntity(s); + Entity *polycubeSegment = getEntity(s, segmentEntityHandle); polycubeSegment->mesh = &cubeMesh; polycubeSegment->tex = &wallTex; - SceneGraphNode *graphNode = getSceneGraphNode(soma->scene, polycubeSegment->graphNodeHandle); + SceneGraphNode *graphNode = getSceneGraphNode(s, polycubeSegment->graphNodeHandle); graphNode->translation = glm::vec3( -((repr->dim_z - 1)/2.0f) + z, ((repr->dim_x - 1)/2.0f) - x, -((repr->dim_y - 1)/2.0f) + y ); - sceneNodeAddEntity(soma->scene, polycubeMainEntity->graphNodeHandle, segmentEntityHandle); + sceneNodeAddEntity(s, polycubeMainEntity->graphNodeHandle, segmentEntityHandle); } } } @@ -366,6 +379,9 @@ Polycube createPolycubeFromRepr(Soma *soma, Space *repr, Vector4 color) result.entityHandle = polycubeMainEntityHandle; result.color = color; result.repr = *repr; + SceneGraphNode *graphNode = getSceneGraphNodeForEntity(s, polycubeMainEntityHandle); + graphNode->rotation *= glm::angleAxis(PI / 4, glm::vec3(1, 0, 0)); + graphNode->rotation *= glm::angleAxis(PI / 4, glm::vec3(0, 1, 0)); return result; } @@ -376,16 +392,18 @@ RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) { result.p0 = PushFullList(arena, Vector2, count); result.p1 = PushFullList(arena, Vector2, count); result.color = PushFullList(arena, Vector4, count); + result.borderRadius = PushFullList(arena, real32, count); + result.borderThickness = PushFullList(arena, real32, count); + result.edgeSoftness = PushFullList(arena, real32, count); glGenVertexArrays(1, &result.vao); - uint32 p0Buffer; - uint32 p1Buffer; - uint32 colorBuffer; - glGenBuffers(1, &result.p0BufferId); glGenBuffers(1, &result.p1BufferId); glGenBuffers(1, &result.colorBufferId); + glGenBuffers(1, &result.borderRadiusBufferId); + glGenBuffers(1, &result.borderThicknessBufferId); + glGenBuffers(1, &result.edgeSoftnessBufferId); glBindVertexArray(result.vao); @@ -407,6 +425,24 @@ RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) { glVertexAttribDivisor(2, 1); glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, result.borderRadiusBufferId); + glBufferData(GL_ARRAY_BUFFER, result.borderRadius.length * sizeof(real32), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(real32), (void*)0); + glVertexAttribDivisor(3, 1); + glEnableVertexAttribArray(3); + + glBindBuffer(GL_ARRAY_BUFFER, result.borderThicknessBufferId); + glBufferData(GL_ARRAY_BUFFER, result.borderThickness.length * sizeof(real32), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(real32), (void*)0); + glVertexAttribDivisor(4, 1); + glEnableVertexAttribArray(4); + + glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftnessBufferId); + glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.length * sizeof(real32), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(real32), (void*)0); + glVertexAttribDivisor(5, 1); + glEnableVertexAttribArray(5); + return result; } @@ -421,6 +457,15 @@ void reinitRectangleObjectBuffers(Renderer *r) { glBindBuffer(GL_ARRAY_BUFFER, r->rects.colorBufferId); glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.color.head * sizeof(Vector4), r->rects.color.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderRadiusBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderRadius.head * sizeof(real32), r->rects.borderRadius.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderThicknessBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderThickness.head * sizeof(real32), r->rects.borderThickness.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.edgeSoftnessBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.edgeSoftness.head * sizeof(real32), r->rects.edgeSoftness.data); } Renderer createRenderer(Arena *arena, Scene *scene) { @@ -436,6 +481,9 @@ void renderBegin(Renderer *r) { r->rects.p0.head = 0; r->rects.p1.head = 0; r->rects.color.head = 0; + r->rects.borderRadius.head = 0; + r->rects.borderThickness.head = 0; + r->rects.edgeSoftness.head = 0; } void renderEnd(Soma *soma, Renderer *renderer) { @@ -478,10 +526,13 @@ void renderEnd(Soma *soma, Renderer *renderer) { glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, renderer->rects.p0.head); } -void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, Vector4 color) { +void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, Vector4 color, real32 borderRadius, real32 borderThickness) { appendList(&r->rects.p0, vec2(x, y)); appendList(&r->rects.p1, vec2(x + width, y + height)); appendList(&r->rects.color, color); + appendList(&r->rects.borderRadius, borderRadius); + appendList(&r->rects.borderThickness, borderThickness); + appendList(&r->rects.edgeSoftness, 0.0f); } inline bool pointInRect(Vector2 point, UI_Rect rect) { @@ -497,7 +548,25 @@ bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) { clicked = true; } } - rendererPlaceRectangle(ui->renderer, rect.x, rect.y, rect.width, rect.height, *value ? rect.color : vec4(1, 1, 1, 1)); + if (*value) { + rendererPlaceRectangle(ui->renderer, + rect.x, rect.y, + rect.width, rect.height, + rect.color, + 5, 0); + } else { + rendererPlaceRectangle(ui->renderer, + rect.x, rect.y, + rect.width, rect.height, + rect.color, + 5, 2); + rendererPlaceRectangle(ui->renderer, + rect.x, rect.y, + rect.width, rect.height, + COLOR_WHITE, + 5, 0); + } + return clicked; } @@ -593,7 +662,7 @@ int mainGfx() { Vector4 color = colorFromIndex(i); appendList(&soma.state.polycubeInput, PolycubeInput{ voxelSpace, color }); cullEmptySpace(&voxelSpace); - Polycube polycube = createPolycubeFromRepr(&soma, &voxelSpace, color); + Polycube polycube = createPolycubeFromRepr(soma.scene, &voxelSpace, color); polycube.color = color; appendList(&soma.state.polycubes, polycube); sceneNodeAddEntity(renderer.scene, renderer.scene->sceneRoot, polycube.entityHandle); @@ -607,20 +676,11 @@ int mainGfx() { glm::vec3 eyes = glm::normalize(soma.state.camera->pos - reference_polycube_gn->translation); soma.state.rotAxisX = glm::normalize(glm::cross(eyes, soma.state.rotAxisY)); - for (int i = 0; i < ArrayCount(STD_SOMA); i++) { - auto gn = getSceneGraphNodeForEntity(soma.scene, soma.state.polycubes.data[i].entityHandle); - gn->rotation *= glm::angleAxis(PI / 4, glm::vec3(1, 0, 0)); - gn->rotation *= glm::angleAxis(PI / 4, glm::vec3(0, 1, 0)); - } - real64 lastFrame = glfwGetTime(); real64 timeDelta = 1.0f/60.0f; while (!glfwWindowShouldClose(soma.window.handle)) { - real64 currTime = glfwGetTime(); - timeDelta = currTime - lastFrame; - lastFrame = currTime; - //print("%.7f\n", timeDelta); + real64 frameStart = glfwGetTime(); glfwPollEvents(); soma.currInput = getCurrentInput(soma.window.handle); @@ -632,14 +692,18 @@ int mainGfx() { soma.state.lastPolycubeVisible = soma.state.currentPolycube; } if (soma.state.polycubeDirty) { + Polycube *currentPolycube = &soma.state.polycubes.data[soma.state.currentPolycube]; PolycubeInput *pinput = &soma.state.polycubeInput.data[soma.state.currentPolycube]; - removeEntity(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].entityHandle); + removeEntity(soma.scene, currentPolycube->entityHandle); Space culledRepr = pinput->repr; cullEmptySpace(&culledRepr); - Polycube polycube = createPolycubeFromRepr(&soma, &culledRepr, pinput->color); - soma.state.polycubes.data[soma.state.currentPolycube] = polycube; - sceneNodeAddEntity(soma.scene, soma.scene->sceneRoot, polycube.entityHandle); + Polycube newPolycube = createPolycubeFromRepr(soma.scene, &culledRepr, pinput->color); + SceneGraphNode *graphNode = getSceneGraphNodeForEntity(soma.scene, newPolycube.entityHandle); + graphNode->rotation = getSceneGraphNodeForEntity(soma.scene, currentPolycube->entityHandle)->rotation; + soma.state.polycubes.data[soma.state.currentPolycube] = newPolycube; + sceneNodeAddEntity(soma.scene, soma.scene->sceneRoot, newPolycube.entityHandle); soma.state.polycubeDirty = false; + showEntity(soma.scene, newPolycube.entityHandle); } updateViewportFromFrame(soma.window.width, soma.window.height, &mainFrame); @@ -660,7 +724,13 @@ int mainGfx() { renderEnd(&soma, &renderer); + real64 frameEnd = glfwGetTime(); + real64 frameTime = frameEnd - frameStart; + lastFrame = frameStart; + // print("FPS: %.7f\n", 1 / frameTime); + glfwSwapBuffers(soma.window.handle); + soma.prevInput = soma.currInput; } diff --git a/src/world/scene.cpp b/src/world/scene.cpp index dd6012b..e4ef401 100644 --- a/src/world/scene.cpp +++ b/src/world/scene.cpp @@ -77,7 +77,7 @@ void removeEntity(Scene *s, uint32 entityHandle) { if (graphNode->parentHandle) { SceneGraphNode *parentNode = getSceneGraphNode(s, graphNode->parentHandle); for (int i = 0; i < parentNode->children.size(); i++) { - if (parentNode->children.at(i) == entityHandle) { + if (parentNode->children.at(i) == entity->graphNodeHandle) { parentNode->children.erase(parentNode->children.begin() + i); graphNode->parentHandle = 0; break;