Commit c2535f0f authored by TheNumbat's avatar TheNumbat
Browse files

upstream changes

parent 8b8ee1f1
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
...
......@@ -19,3 +19,4 @@ settings.json
media/test.*
media/env_maps/
media/test/
debug.log
......@@ -29,7 +29,7 @@ Finally, to build the project:
```
mkdir build
cd build
cmake ..
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
make -j4
```
......@@ -73,7 +73,7 @@ To build the project:
```
mkdir build
cd build
cmake ..
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
make -j4
```
......
......@@ -4,71 +4,72 @@
#include <imgui/imgui_impl_sdl.h>
#include "app.h"
#include "scene/renderer.h"
#include "geometry/util.h"
#include "platform/platform.h"
#include "scene/renderer.h"
App::App(Settings set, Platform* plt) :
window_dim(plt ? plt->window_draw() : Vec2{1.0f}),
camera(plt ? plt->window_draw() : Vec2{1.0f}),
plt(plt),
scene(Gui::n_Widget_IDs),
gui(scene, plt ? plt->window_size() : Vec2{1.0f}),
undo(scene, gui) {
App::App(Settings set, Platform *plt)
: window_dim(plt ? plt->window_draw() : Vec2{1.0f}),
camera(plt ? plt->window_draw() : Vec2{1.0f}), plt(plt), scene(Gui::n_Widget_IDs),
gui(scene, plt ? plt->window_size() : Vec2{1.0f}), undo(scene, gui) {
if(!set.headless) assert(plt);
if (!set.headless)
assert(plt);
std::string err;
bool loaded_scene = true;
if(!set.scene_file.empty()) {
if (!set.scene_file.empty()) {
info("Loading scene file...");
err = scene.load(true, undo, gui, set.scene_file);
gui.set_file(set.scene_file);
}
if(!err.empty()) {
if (!err.empty()) {
warn("Error loading scene: %s", err.c_str());
loaded_scene = false;
}
if(!set.env_map_file.empty()) {
if (!set.env_map_file.empty()) {
info("Loading environment map...");
err = scene.set_env_map(set.env_map_file);
if(!err.empty()) warn("Error loading environment map: %s", err.c_str());
if (!err.empty())
warn("Error loading environment map: %s", err.c_str());
}
if(!set.headless) {
if (!set.headless) {
GL::global_params();
Renderer::setup(window_dim);
apply_window_dim(plt->window_draw());
} else if(loaded_scene) {
} else if (loaded_scene) {
info("Rendering scene...");
err = gui.get_render().headless_render(gui.get_animate(), scene, set.output_file,
set.animate, set.w, set.h, set.s, set.ls, set.d, set.exp, set.w_from_ar);
set.animate, set.w, set.h, set.s, set.ls, set.d,
set.exp, set.w_from_ar);
if(!err.empty()) warn("Error rendering scene: %s", err.c_str());
if (!err.empty())
warn("Error rendering scene: %s", err.c_str());
else {
auto [build,render] = gui.get_render().completion_time();
auto [build, render] = gui.get_render().completion_time();
info("Built scene in %.2fs, rendered in %.2fs", build, render);
}
}
}
App::~App() {
Renderer::shutdown();
}
App::~App() { Renderer::shutdown(); }
void App::event(SDL_Event e) {
ImGuiIO& IO = ImGui::GetIO();
ImGuiIO &IO = ImGui::GetIO();
IO.DisplayFramebufferScale = plt->scale(Vec2{1.0f, 1.0f});
switch(e.type) {
switch (e.type) {
case SDL_KEYDOWN: {
if(IO.WantCaptureKeyboard) break;
if(gui.keydown(undo, e.key.keysym, scene, camera)) break;
if (IO.WantCaptureKeyboard)
break;
if (gui.keydown(undo, e.key.keysym, scene, camera))
break;
#ifdef __APPLE__
Uint16 mod = KMOD_GUI;
......@@ -76,13 +77,12 @@ void App::event(SDL_Event e) {
Uint16 mod = KMOD_CTRL;
#endif
if(e.key.keysym.sym == SDLK_z) {
if(e.key.keysym.mod & mod) {
if (e.key.keysym.sym == SDLK_z) {
if (e.key.keysym.mod & mod) {
undo.undo();
}
}
else if(e.key.keysym.sym == SDLK_y) {
if(e.key.keysym.mod & mod) {
} else if (e.key.keysym.sym == SDLK_y) {
if (e.key.keysym.mod & mod) {
undo.redo();
}
}
......@@ -103,11 +103,11 @@ void App::event(SDL_Event e) {
Vec2 dim = plt->window_draw();
Vec2 n = Vec2(2.0f * p.x / dim.x - 1.0f, 2.0f * p.y / dim.y - 1.0f);
if(gui_capture) {
if (gui_capture) {
gui.drag_to(scene, camera.pos(), n, screen_to_world(p));
} else if(cam_mode == Camera_Control::orbit) {
} else if (cam_mode == Camera_Control::orbit) {
camera.mouse_orbit(d);
} else if(cam_mode == Camera_Control::move) {
} else if (cam_mode == Camera_Control::move) {
camera.mouse_move(d);
} else {
gui.hover(p, camera.pos(), n, screen_to_world(p));
......@@ -117,35 +117,38 @@ void App::event(SDL_Event e) {
case SDL_MOUSEBUTTONDOWN: {
if(IO.WantCaptureMouse) break;
if (IO.WantCaptureMouse)
break;
Vec2 p = plt->scale(Vec2{e.button.x, e.button.y});
Vec2 dim = plt->window_draw();
Vec2 n = Vec2(2.0f * p.x / dim.x - 1.0f, 2.0f * p.y / dim.y - 1.0f);
if(e.button.button == SDL_BUTTON_LEFT) {
if (e.button.button == SDL_BUTTON_LEFT) {
Scene_ID id = Renderer::get().read_id(p);
if(cam_mode == Camera_Control::none && (plt->is_down(SDL_SCANCODE_LSHIFT) | plt->is_down(SDL_SCANCODE_RSHIFT))) {
if (cam_mode == Camera_Control::none &&
(plt->is_down(SDL_SCANCODE_LSHIFT) | plt->is_down(SDL_SCANCODE_RSHIFT))) {
cam_mode = Camera_Control::orbit;
} else if(gui.select(scene, undo, id, camera.pos(), n, screen_to_world(p))) {
} else if (gui.select(scene, undo, id, camera.pos(), n, screen_to_world(p))) {
cam_mode = Camera_Control::none;
plt->grab_mouse();
gui_capture = true;
} else if(id) {
} else if (id) {
selection_changed = true;
}
mouse_press = Vec2(e.button.x, e.button.y);
} else if(e.button.button == SDL_BUTTON_RIGHT) {
if(cam_mode == Camera_Control::none) {
} else if (e.button.button == SDL_BUTTON_RIGHT) {
if (cam_mode == Camera_Control::none) {
cam_mode = Camera_Control::move;
}
} else if(e.button.button == SDL_BUTTON_MIDDLE) {
} else if (e.button.button == SDL_BUTTON_MIDDLE) {
cam_mode = Camera_Control::orbit;
}
} break;
case SDL_MOUSEBUTTONUP: {
......@@ -154,8 +157,8 @@ void App::event(SDL_Event e) {
Vec2 dim = plt->window_draw();
Vec2 n = Vec2(2.0f * p.x / dim.x - 1.0f, 2.0f * p.y / dim.y - 1.0f);
if(e.button.button == SDL_BUTTON_LEFT) {
if(!IO.WantCaptureMouse && gui_capture) {
if (e.button.button == SDL_BUTTON_LEFT) {
if (!IO.WantCaptureMouse && gui_capture) {
gui_capture = false;
gui.drag_to(scene, camera.pos(), n, screen_to_world(p));
gui.end_drag(undo, scene);
......@@ -163,14 +166,14 @@ void App::event(SDL_Event e) {
break;
} else {
Vec2 diff = mouse_press - Vec2(e.button.x, e.button.y);
if(!selection_changed && diff.norm() <= 3) {
if (!selection_changed && diff.norm() <= 3) {
gui.clear_select();
}
selection_changed = false;
}
}
if((e.button.button == SDL_BUTTON_LEFT && cam_mode == Camera_Control::orbit) ||
if ((e.button.button == SDL_BUTTON_LEFT && cam_mode == Camera_Control::orbit) ||
(e.button.button == SDL_BUTTON_MIDDLE && cam_mode == Camera_Control::orbit) ||
(e.button.button == SDL_BUTTON_RIGHT && cam_mode == Camera_Control::move)) {
cam_mode = Camera_Control::none;
......@@ -179,7 +182,8 @@ void App::event(SDL_Event e) {
} break;
case SDL_MOUSEWHEEL: {
if(IO.WantCaptureMouse) break;
if (IO.WantCaptureMouse)
break;
camera.mouse_radius((float)e.wheel.y);
} break;
}
......@@ -191,7 +195,7 @@ void App::render() {
view = camera.get_view();
iviewproj = (proj * view).inverse();
Renderer& r = Renderer::get();
Renderer &r = Renderer::get();
r.begin();
r.proj(proj);
......@@ -204,8 +208,7 @@ void App::render() {
Vec3 App::screen_to_world(Vec2 mouse) {
Vec2 t(2.0f * mouse.x / window_dim.x - 1.0f,
1.0f - 2.0f * mouse.y / window_dim.y);
Vec2 t(2.0f * mouse.x / window_dim.x - 1.0f, 1.0f - 2.0f * mouse.y / window_dim.y);
Vec3 p = iviewproj * Vec3(t.x, t.y, 0.1f);
return (p - camera.pos()).unit();
}
......@@ -216,4 +219,3 @@ void App::apply_window_dim(Vec2 new_dim) {
gui.update_dim(plt->window_size());
Renderer::get().update_dim(window_dim);
}
#pragma once
#include <SDL2/SDL.h>
#include <map>
#include <string>
#include <SDL2/SDL.h>
#include "util/camera.h"
#include "lib/mathlib.h"
#include "gui/manager.h"
#include "lib/mathlib.h"
#include "util/camera.h"
#include "scene/scene.h"
#include "scene/undo.h"
......@@ -17,9 +17,11 @@ class Platform;
class App {
public:
struct Settings {
std::string scene_file;
std::string env_map_file;
bool headless = false;
// If headless is true, use all of these
std::string output_file = "out.png";
int w = 640;
......@@ -32,7 +34,7 @@ public:
bool w_from_ar = false;
};
App(Settings set, Platform* plt = nullptr);
App(Settings set, Platform *plt = nullptr);
~App();
void render();
......@@ -43,11 +45,7 @@ private:
Vec3 screen_to_world(Vec2 mouse);
// Camera data
enum class Camera_Control {
none,
orbit,
move
};
enum class Camera_Control { none, orbit, move };
Vec2 window_dim, mouse_press;
bool selection_changed = false;
Camera_Control cam_mode = Camera_Control::none;
......@@ -55,7 +53,7 @@ private:
Mat4 view, proj, iviewproj;
// Systems
Platform* plt = nullptr;
Platform *plt = nullptr;
Scene scene;
Gui::Manager gui;
Undo undo;
......
......@@ -2,20 +2,21 @@
#include "halfedge.h"
#include <map>
#include <unordered_map>
#include <set>
#include <sstream>
#include <unordered_map>
#include "../gui/widgets.h"
Halfedge_Mesh::Halfedge_Mesh() {
next_id = Gui::n_Widget_IDs;
}
Halfedge_Mesh::Halfedge_Mesh(const GL::Mesh& mesh) {
Halfedge_Mesh::Halfedge_Mesh() { next_id = Gui::n_Widget_IDs; }
Halfedge_Mesh::Halfedge_Mesh(const GL::Mesh &mesh) {
next_id = Gui::n_Widget_IDs;
from_mesh(mesh);
}
Halfedge_Mesh::Halfedge_Mesh(const std::vector<std::vector<Index>>& polygons, const std::vector<Vec3>& verts) {
Halfedge_Mesh::Halfedge_Mesh(const std::vector<std::vector<Index>> &polygons,
const std::vector<Vec3> &verts) {
next_id = Gui::n_Widget_IDs;
from_poly(polygons, verts);
}
......@@ -29,11 +30,9 @@ void Halfedge_Mesh::clear() {
render_dirty_flag = true;
}
void Halfedge_Mesh::copy_to(Halfedge_Mesh& mesh) {
copy_to(mesh, 0);
}
void Halfedge_Mesh::copy_to(Halfedge_Mesh &mesh) { copy_to(mesh, 0); }
Halfedge_Mesh::ElementRef Halfedge_Mesh::copy_to(Halfedge_Mesh& mesh, unsigned int eid) {
Halfedge_Mesh::ElementRef Halfedge_Mesh::copy_to(Halfedge_Mesh &mesh, unsigned int eid) {
// Clear any existing elements.
mesh.clear();
......@@ -50,47 +49,52 @@ Halfedge_Mesh::ElementRef Halfedge_Mesh::copy_to(Halfedge_Mesh& mesh, unsigned i
// Copy geometry from the original mesh and create a map from
// pointers in the original mesh to those in the new mesh.
for(HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
auto hn = mesh.halfedges.insert(mesh.halfedges.end(), *h);
if(h->id() == eid) ret = hn;
if (h->id() == eid)
ret = hn;
halfedgeOldToNew[h] = hn;
}
for(VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
for (VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
auto vn = mesh.vertices.insert(mesh.vertices.end(), *v);
if(v->id() == eid) ret = vn;
if (v->id() == eid)
ret = vn;
vertexOldToNew[v] = vn;
}
for(EdgeCRef e = edges_begin(); e != edges_end(); e++) {
for (EdgeCRef e = edges_begin(); e != edges_end(); e++) {
auto en = mesh.edges.insert(mesh.edges.end(), *e);
if(e->id() == eid) ret = en;
if (e->id() == eid)
ret = en;
edgeOldToNew[e] = en;
}
for(FaceCRef f = faces_begin(); f != faces_end(); f++) {
for (FaceCRef f = faces_begin(); f != faces_end(); f++) {
auto fn = mesh.faces.insert(mesh.faces.end(), *f);
if(f->id() == eid) ret = fn;
if (f->id() == eid)
ret = fn;
faceOldToNew[f] = fn;
}
for(FaceCRef b = boundaries_begin(); b != boundaries_end(); b++) {
for (FaceCRef b = boundaries_begin(); b != boundaries_end(); b++) {
auto bn = mesh.boundaries.insert(mesh.boundaries.end(), *b);
if(b->id() == eid) ret = bn;
if (b->id() == eid)
ret = bn;
faceOldToNew[b] = bn;
}
// "Search and replace" old pointers with new ones.
for(HalfedgeRef he = mesh.halfedges_begin(); he != mesh.halfedges_end(); he++) {
for (HalfedgeRef he = mesh.halfedges_begin(); he != mesh.halfedges_end(); he++) {
he->next() = halfedgeOldToNew[he->next()];
he->twin() = halfedgeOldToNew[he->twin()];
he->vertex() = vertexOldToNew[he->vertex()];
he->edge() = edgeOldToNew[he->edge()];
he->face() = faceOldToNew[he->face()];
}
for(VertexRef v = mesh.vertices_begin(); v != mesh.vertices_end(); v++)
for (VertexRef v = mesh.vertices_begin(); v != mesh.vertices_end(); v++)
v->halfedge() = halfedgeOldToNew[v->halfedge()];
for(EdgeRef e = mesh.edges_begin(); e != mesh.edges_end(); e++)
for (EdgeRef e = mesh.edges_begin(); e != mesh.edges_end(); e++)
e->halfedge() = halfedgeOldToNew[e->halfedge()];
for(FaceRef f = mesh.faces_begin(); f != mesh.faces_end(); f++)
for (FaceRef f = mesh.faces_begin(); f != mesh.faces_end(); f++)
f->halfedge() = halfedgeOldToNew[f->halfedge()];
for(FaceRef b = mesh.boundaries_begin(); b != mesh.boundaries_end(); b++)
for (FaceRef b = mesh.boundaries_begin(); b != mesh.boundaries_end(); b++)
b->halfedge() = halfedgeOldToNew[b->halfedge()];
mesh.render_dirty_flag = true;
......@@ -190,9 +194,7 @@ Vec3 Halfedge_Mesh::Face::normal() const {
return n.unit();
}
Vec3 Halfedge_Mesh::Vertex::center() const {
return pos;
}
Vec3 Halfedge_Mesh::Vertex::center() const { return pos; }
float Halfedge_Mesh::Edge::length() const {
return (_halfedge->vertex()->pos - _halfedge->twin()->vertex()->pos).norm();
......@@ -216,38 +218,21 @@ Vec3 Halfedge_Mesh::Face::center() const {
unsigned int Halfedge_Mesh::id_of(ElementRef elem) {
unsigned int id;
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
id = vert->id();
},
[&](Halfedge_Mesh::EdgeRef edge) {
id = edge->id();
},
[&](Halfedge_Mesh::FaceRef face) {
id = face->id();
},
[&](auto) {}
}, elem);
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) { id = vert->id(); },
[&](Halfedge_Mesh::EdgeRef edge) { id = edge->id(); },
[&](Halfedge_Mesh::FaceRef face) { id = face->id(); }, [&](auto) {}},
elem);
return id;
}
Vec3 Halfedge_Mesh::normal_of(Halfedge_Mesh::ElementRef elem) {
Vec3 n;
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
n = vert->normal();
},
[&](Halfedge_Mesh::EdgeRef edge) {
n = edge->normal();
},
[&](Halfedge_Mesh::FaceRef face) {
n = face->normal();
},
[&](Halfedge_Mesh::HalfedgeRef he) {
n = he->edge()->normal();
}
}, elem);
if(flip_orientation) {
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) { n = vert->normal(); },
[&](Halfedge_Mesh::EdgeRef edge) { n = edge->normal(); },
[&](Halfedge_Mesh::FaceRef face) { n = face->normal(); },
[&](Halfedge_Mesh::HalfedgeRef he) { n = he->edge()->normal(); }},
elem);
if (flip_orientation) {
n = -n;
}
return n;
......@@ -255,58 +240,52 @@ Vec3 Halfedge_Mesh::normal_of(Halfedge_Mesh::ElementRef elem) {
Vec3 Halfedge_Mesh::center_of(Halfedge_Mesh::ElementRef elem) {
Vec3 pos;
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
pos = vert->center();
},
[&](Halfedge_Mesh::EdgeRef edge) {
pos = edge->center();
},
[&](Halfedge_Mesh::FaceRef face) {
pos = face->center();
},
[&](Halfedge_Mesh::HalfedgeRef he) {
pos = he->edge()->center();
}
}, elem);
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) { pos = vert->center(); },
[&](Halfedge_Mesh::EdgeRef edge) { pos = edge->center(); },
[&](Halfedge_Mesh::FaceRef face) { pos = face->center(); },
[&](Halfedge_Mesh::HalfedgeRef he) { pos = he->edge()->center(); }},
elem);
return pos;
}
void Halfedge_Mesh::to_mesh(GL::Mesh& mesh, bool split_faces) const {
void Halfedge_Mesh::to_mesh(GL::Mesh &mesh, bool split_faces) const {
std::vector<GL::Mesh::Vert> verts;
std::vector<GL::Mesh::Index> idxs;
if(split_faces) {
if (split_faces) {
std::vector<GL::Mesh::Vert> face_verts;
for(FaceCRef f = faces_begin(); f != faces_end(); f++) {
for (FaceCRef f = faces_begin(); f != faces_end(); f++) {
if(f->is_boundary()) continue;
if (f->is_boundary())
continue;
HalfedgeCRef h = f->halfedge();
face_verts.clear();
do {
VertexCRef v = h->vertex();
Vec3 n = v->normal();
if(flip_orientation) n = -n;
if (flip_orientation)
n = -n;
face_verts.push_back({v->pos, n, f->id()});
h = h->next();
} while (h != f->halfedge());
Vec3 v0 = face_verts[0].pos;
for(size_t i = 1; i <= face_verts.size() - 2; i++) {
for (size_t i = 1; i <= face_verts.size() - 2; i++) {
Vec3 v1 = face_verts[i].pos;
Vec3 v2 = face_verts[i+1].pos;
Vec3 v2 = face_verts[i + 1].pos;
Vec3 n = cross(v1 - v0, v2 - v0).unit();
if(flip_orientation) n = -n;
if (flip_orientation)
n = -n;
GL::Mesh::Index idx = (GL::Mesh::Index)verts.size();
verts.push_back({v0, n, f->_id});
verts.push_back({v1, n, f->_id});
verts.push_back({v2, n, f->_id});
idxs.push_back(idx);
idxs.push_back(idx+1);
idxs.push_back(idx+2);
idxs.push_back(idx + 1);
idxs.push_back(idx + 2);
}
}
......@@ -315,16 +294,18 @@ void Halfedge_Mesh::to_mesh(GL::Mesh& mesh, bool split_faces) const {
// Need to build this map to get vertex's linear index in O(lg n)
std::map<VertexCRef, Index> vref_to_idx;
Index i = 0;
for(VertexCRef v = vertices_begin(); v != vertices_end(); v++, i++) {
for (VertexCRef v = vertices_begin(); v != vertices_end(); v++, i++) {
vref_to_idx[v] = i;
Vec3 n = v->normal();
if(flip_orientation) n = -n;
if (flip_orientation)
n = -n;
verts.push_back({v->pos, n, v->_id});
}
for(FaceCRef f = faces_begin(); f != faces_end(); f++) {
for (FaceCRef f = faces_begin(); f != faces_end(); f++) {
if(f->is_boundary()) continue;
if (f->is_boundary())
continue;
std::vector<Index> face_verts;
HalfedgeCRef h = f->halfedge();
......@@ -334,10 +315,10 @@ void Halfedge_Mesh::to_mesh(GL::Mesh& mesh, bool split_faces) const {
} while (h != f->halfedge());
assert(face_verts.size() >= 3);
for(size_t j = 1; j <= face_verts.size() - 2; j++) {
for (size_t j = 1; j <= face_verts.size() - 2; j++) {
idxs.push_back((GL::Mesh::Index)face_verts[0]);
idxs.push_back((GL::Mesh::Index)face_verts[j]);
idxs.push_back((GL::Mesh::Index)face_verts[j+1]);
idxs.push_back((GL::Mesh::Index)face_verts[j + 1]);
}
}
}
......@@ -345,18 +326,17 @@ void Halfedge_Mesh::to_mesh(GL::Mesh& mesh, bool split_faces) const {
mesh = GL::Mesh(std::move(verts), std::move(idxs));
}
void Halfedge_Mesh::mark_dirty() {
render_dirty_flag = true;
}
void Halfedge_Mesh::mark_dirty() { render_dirty_flag = true; }
std::string Halfedge_Mesh::validate() const {
if(!check_finite()) return "A vertex position was set to a non-finite value.";
if (!check_finite())
return "A vertex position was set to a non-finite value.";
std::set<HalfedgeCRef> permutation;
// Check valid halfedge permutation
for(HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
// Check whether each halfedge's next points to a unique halfedge
if (permutation.find(h->next()) == permutation.end()) {
......@@ -365,7 +345,7 @@ std::string Halfedge_Mesh::validate() const {
return "A halfedge is the next of more than one halfedge!";
}
}
for(HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
// Check whether each halfedge was pointed to by a halfedge
if (permutation.find(h) == permutation.end()) {
......@@ -374,7 +354,7 @@ std::string Halfedge_Mesh::validate() const {
}
// Check twin relationships
for(HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
for (HalfedgeCRef h = halfedges_begin(); h != halfedges_end(); h++) {
if (h->twin() == h) {
return "A halfedge's twin points to itself!";
......@@ -385,7 +365,7 @@ std::string Halfedge_Mesh::validate() const {
}
// Check whether each halfedge incident on a vertex points to that vertex
for(VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
for (VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
HalfedgeCRef h = v->halfedge();
do {
if (h->vertex() != v) {
......@@ -396,7 +376,7 @@ std::string Halfedge_Mesh::validate() const {
}
// Check whether each halfedge incident on an edge points to that edge
for(EdgeCRef e = edges_begin(); e != edges_end(); e++) {
for (EdgeCRef e = edges_begin(); e != edges_end(); e++) {
HalfedgeCRef h = e->halfedge();
do {
if (h->edge() != e) {
......@@ -407,7 +387,7 @@ std::string Halfedge_Mesh::validate() const {
}
// Check whether each halfedge incident on a face points to that face
for(FaceCRef f = faces_begin(); f != faces_end(); f++) {
for (FaceCRef f = faces_begin(); f != faces_end(); f++) {
HalfedgeCRef h = f->halfedge();
do {
if (h->face() != f) {
......@@ -418,7 +398,7 @@ std::string Halfedge_Mesh::validate() const {
}
// Check whether each halfedge incident on a boundary loop points to that boundary loop
for(FaceCRef b = boundaries_begin(); b != boundaries_end(); b++) {
for (FaceCRef b = boundaries_begin(); b != boundaries_end(); b++) {
HalfedgeCRef h = b->halfedge();
do {
if (h->face() != b) {
......@@ -431,7 +411,7 @@ std::string Halfedge_Mesh::validate() const {
return {};
}
std::string Halfedge_Mesh::from_mesh(const GL::Mesh& mesh) {
std::string Halfedge_Mesh::from_mesh(const GL::Mesh &mesh) {
auto idx = mesh.indices();
auto v = mesh.verts();
......@@ -439,29 +419,32 @@ std::string Halfedge_Mesh::from_mesh(const GL::Mesh& mesh) {
std::vector<std::vector<Index>> polys;
std::vector<Vec3> verts(v.size());
for(size_t i = 0; i < idx.size(); i += 3) {
if(idx[i] != idx[i+1] && idx[i] != idx[i+2] && idx[i+1] != idx[i+2])
polys.push_back({idx[i], idx[i+1], idx[i+2]});
for (size_t i = 0; i < idx.size(); i += 3) {
if (idx[i] != idx[i + 1] && idx[i] != idx[i + 2] && idx[i + 1] != idx[i + 2])
polys.push_back({idx[i], idx[i + 1], idx[i + 2]});
}
for(size_t i = 0; i < v.size(); i++) {
for (size_t i = 0; i < v.size(); i++) {
verts[i] = v[i].pos;
}
std::string err = from_poly(polys, verts);
if(!err.empty()) return err;
if (!err.empty())
return err;
err = validate();
if(!err.empty()) return err;
if (!err.empty())
return err;
return {};
}
bool Halfedge_Mesh::check_finite() const {
for(VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
for (VertexCRef v = vertices_begin(); v != vertices_end(); v++) {
Vec3 p = v->pos;
bool finite = std::isfinite(p.x) && std::isfinite(p.y) && std::isfinite(p.z);
if(!finite) return false;
if (!finite)
return false;
}
return true;
}
......@@ -472,25 +455,28 @@ bool Halfedge_Mesh::subdivide(SubD strategy) {
std::vector<Vec3> verts;
std::unordered_map<unsigned int, Index> layout;
switch(strategy) {
switch (strategy) {
case SubD::linear: {
linear_subdivide_positions();
} break;
case SubD::catmullclark: {
if(boundaries.size()) return false;
if (boundaries.size())
return false;
catmullclark_subdivide_positions();
} break;
case SubD::loop: {
for(FaceRef f = faces_begin(); f != faces_end(); f++) {
if(f->degree() != 3) return false;
for (FaceRef f = faces_begin(); f != faces_end(); f++) {
if (f->degree() != 3)
return false;
}
loop_subdivide();
return true;
} break;
default: assert(false);
default:
assert(false);
}
Index idx = 0;
......@@ -529,7 +515,8 @@ bool Halfedge_Mesh::subdivide(SubD strategy) {
return true;
}
std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& polygons, const std::vector<Vec3>& verts) {
std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>> &polygons,
const std::vector<Vec3> &verts) {
// This method initializes the halfedge data structure from a raw list of
// polygons, where each input polygon is specified as a list of vertex indices.
......@@ -578,7 +565,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
std::map<VertexRef, Size> vertexDegree;
// First, we do some basic sanity checks on the input.
for(PolygonListCRef p = polygons.begin(); p != polygons.end(); p++) {
for (PolygonListCRef p = polygons.begin(); p != polygons.end(); p++) {
if (p->size() < 3) {
// Refuse to build the mesh if any of the polygons have fewer than three
// vertices.(Note that if we omit this check the code will still
......@@ -596,14 +583,13 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
std::set<Index> polygonIndices;
// loop over polygon vertices
for(IndexListCRef i = p->begin(); i != p->end(); i++) {
for (IndexListCRef i = p->begin(); i != p->end(); i++) {
polygonIndices.insert(*i);
// allocate one vertex for each new index we encounter
if (indexToVertex.find(*i) == indexToVertex.end()) {
VertexRef v = new_vertex();
v->halfedge() =
halfedges.end(); // this vertex doesn't yet point to any halfedge
v->halfedge() = halfedges.end(); // this vertex doesn't yet point to any halfedge
indexToVertex[*i] = v;
vertexDegree[v] = 1; // we've now seen this vertex only once
} else {
......@@ -616,10 +602,9 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
Size degree = p->size(); // number of vertices in this polygon
if (polygonIndices.size() < degree) {
std::stringstream stream;
stream << "One of the input polygons does not have distinct vertices!"
<< std::endl;
stream << "One of the input polygons does not have distinct vertices!" << std::endl;
stream << "(vertex indices:";
for(IndexListCRef i = p->begin(); i != p->end(); i++) {
for (IndexListCRef i = p->begin(); i != p->end(); i++) {
stream << " " << *i;
}
stream << ")" << std::endl;
......@@ -630,7 +615,8 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// The number of faces is just the number of polygons in the input.
Size nFaces = polygons.size();
for(Size i = 0; i < nFaces; i++) new_face();
for (Size i = 0; i < nFaces; i++)
new_face();
// We will store a map from ordered pairs of vertex indices to
// the corresponding halfedge object in our new (halfedge) mesh;
......@@ -641,7 +627,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// polygons
PolygonListCRef p;
FaceRef f;
for(p = polygons.begin(), f = faces.begin(); p != polygons.end(); p++, f++) {
for (p = polygons.begin(), f = faces.begin(); p != polygons.end(); p++, f++) {
std::vector<HalfedgeRef> faceHalfedges; // cyclically ordered list of the half
// edges of this face
......@@ -649,7 +635,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// loop over the halfedges of this face (equivalently, the ordered pairs of
// consecutive vertices)
for(Index i = 0; i < degree; i++) {
for (Index i = 0; i < degree; i++) {
Index a = (*p)[i]; // current index
Index b = (*p)[(i + 1) % degree]; // next index, in cyclic order
......@@ -659,8 +645,8 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// check if this halfedge already exists; if so, we have a problem!
if (pairToHalfedge.find(ab) != pairToHalfedge.end()) {
std::stringstream stream;
stream << "Found multiple oriented edges with indices ("
<< a << ", " << b << ")." << std::endl;
stream << "Found multiple oriented edges with indices (" << a << ", " << b << ")."
<< std::endl;
stream << "This means that either (i) more than two faces contain this "
"edge (hence the surface is nonmanifold), or"
<< std::endl;
......@@ -718,9 +704,8 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// Now that all the halfedges of this face have been allocated,
// we can link them together via their "next" pointers.
for(Index i = 0; i < degree; i++) {
Index j =
(i + 1) % degree; // index of the next halfedge, in cyclic order
for (Index i = 0; i < degree; i++) {
Index j = (i + 1) % degree; // index of the next halfedge, in cyclic order
faceHalfedges[i]->next() = faceHalfedges[j];
}
......@@ -728,7 +713,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// For each vertex on the boundary, advance its halfedge pointer to one that
// is also on the boundary.
for(VertexRef v = vertices_begin(); v != vertices_end(); v++) {
for (VertexRef v = vertices_begin(); v != vertices_end(); v++) {
// loop over halfedges around vertex
HalfedgeRef h = v->halfedge();
do {
......@@ -743,8 +728,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
} // done advancing halfedge pointers for boundary vertices
// Next we construct new faces for each boundary component.
for(HalfedgeRef h = halfedges_begin(); h != halfedges_end();
h++) // loop over all halfedges
for (HalfedgeRef h = halfedges_begin(); h != halfedges_end(); h++) // loop over all halfedges
{
// Any halfedge that does not yet have a twin is on the boundary of the
// domain. If we follow the boundary around long enough we will of course
......@@ -804,7 +788,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// orientation of the boundary loop is opposite the orientation of the
// halfedges "inside" the domain boundary.
Size degree = boundaryHalfedges.size();
for(Index id = 0; id < degree; id++) {
for (Index id = 0; id < degree; id++) {
Index q = (id - 1 + degree) % degree;
boundaryHalfedges[id]->next() = boundaryHalfedges[q];
}
......@@ -823,12 +807,12 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// halfedge
// associated with each vertex such that it refers to the *first* non-boundary
// halfedge, rather than the last one.
for(VertexRef v = vertices_begin(); v != vertices_end(); v++) {
for (VertexRef v = vertices_begin(); v != vertices_end(); v++) {
v->halfedge() = v->halfedge()->twin()->next();
}
// Finally, we check that all vertices are manifold.
for(VertexRef v = vertices.begin(); v != vertices.end(); v++) {
for (VertexRef v = vertices.begin(); v != vertices.end(); v++) {
// First check that this vertex is not a "floating" vertex;
// if it is then we do not have a valid 2-manifold surface.
if (v->halfedge() == halfedges.end()) {
......@@ -859,10 +843,10 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// positions into member variables of the individual vertices.
if (verts.size() < vertices.size()) {
std::stringstream stream;
stream << "The number of vertex positions is different from the number of distinct vertices!"
<< std::endl;
stream << "(number of positions in input: " << verts.size() << ")"
stream
<< "The number of vertex positions is different from the number of distinct vertices!"
<< std::endl;
stream << "(number of positions in input: " << verts.size() << ")" << std::endl;
stream << "(number of vertices in mesh: " << vertices.size() << ")" << std::endl;
return stream.str();
}
......@@ -871,7 +855,7 @@ std::string Halfedge_Mesh::from_poly(const std::vector<std::vector<Index>>& poly
// from vertex indices to vertex iterators to visit our (input) vertices in
// lexicographic order
int i = 0;
for(std::map<Index, VertexRef>::const_iterator e = indexToVertex.begin();
for (std::map<Index, VertexRef>::const_iterator e = indexToVertex.begin();
e != indexToVertex.end(); e++) {
// grab a pointer to the vertex associated with the current key (i.e., the
// current index)
......
......@@ -130,19 +130,15 @@
#pragma once
#include <list>
#include <vector>
#include <variant>
#include <optional>
#include <string>
#include <variant>
#include <vector>
#include "../platform/gl.h"
// Types of sub-division
enum class SubD {
linear,
catmullclark,
loop
};
enum class SubD { linear, catmullclark, loop };
class Halfedge_Mesh {
public:
......@@ -246,19 +242,22 @@ public:
Computes vertex positions for a face that was just created by beveling a vertex,
but not yet confirmed.
*/
void bevel_vertex_positions(const std::vector<Vec3>& start_positions, FaceRef face, float tangent_offset);
void bevel_vertex_positions(const std::vector<Vec3> &start_positions, FaceRef face,
float tangent_offset);
/*
Computes vertex positions for a face that was just created by beveling an edge,
but not yet confirmed.
*/
void bevel_edge_positions(const std::vector<Vec3>& start_positions, FaceRef face, float tangent_offset);
void bevel_edge_positions(const std::vector<Vec3> &start_positions, FaceRef face,
float tangent_offset);
/*
Computes vertex positions for a face that was just created by beveling a face,
but not yet confirmed.
*/
void bevel_face_positions(const std::vector<Vec3>& start_positions, FaceRef face, float tangent_offset, float normal_offset);
void bevel_face_positions(const std::vector<Vec3> &start_positions, FaceRef face,
float tangent_offset, float normal_offset);
//////////////////////////////////////////////////////////////////////////////////////////
// Student Global Operations | student/meshedit.cpp
......@@ -312,8 +311,8 @@ public:
class Vertex {
public:
// Returns a halfedge incident from the vertex
HalfedgeRef& halfedge() {return _halfedge;}
HalfedgeCRef halfedge() const {return _halfedge;}
HalfedgeRef &halfedge() { return _halfedge; }
HalfedgeCRef halfedge() const { return _halfedge; }
// Returns whether the vertex is on a boundary loop
bool on_boundary() const;
......@@ -326,7 +325,7 @@ public:
// Computes the centroid of the loop of the vertex
Vec3 neighborhood_center() const;
// Returns an id unique to this vertex
unsigned int id() const {return _id;}
unsigned int id() const { return _id; }
// The vertex position
Vec3 pos;
......@@ -343,8 +342,8 @@ public:
class Edge {
public:
// Returns one of the two halfedges associated with this edge
HalfedgeRef& halfedge() {return _halfedge;}
HalfedgeCRef halfedge() const {return _halfedge;}
HalfedgeRef &halfedge() { return _halfedge; }
HalfedgeCRef halfedge() const { return _halfedge; }
// Returns whether this edge is contained in a boundary loop
bool on_boundary() const;
......@@ -355,7 +354,7 @@ public:
// Returns the length of the edge
float length() const;
// Returns an id unique to this edge
unsigned int id() const {return _id;}
unsigned int id() const { return _id; }
private:
Edge(unsigned int id) : _id(id) {}
......@@ -369,11 +368,11 @@ public:
class Face {
public:
// Returns some halfedge contained within this face
HalfedgeRef& halfedge() {return _halfedge;}
HalfedgeCRef halfedge() const {return _halfedge;}
HalfedgeRef &halfedge() { return _halfedge; }
HalfedgeCRef halfedge() const { return _halfedge; }
// Returns whether this is a boundary face
bool is_boundary() const {return boundary;}
bool is_boundary() const { return boundary; }
// Returns the centroid of this face
Vec3 center() const;
// Returns an area weighted face normal
......@@ -381,7 +380,7 @@ public:
// Returns the number of vertices/edges in this face
unsigned int degree() const;
// Returns an id unique to this face
unsigned int id() const {return _id;}
unsigned int id() const { return _id; }
private:
Face(unsigned int id, bool is_boundary = false) : _id(id), boundary(is_boundary) {}
......@@ -395,34 +394,34 @@ public:
class Halfedge {
public:
// Retrives the twin halfedge
HalfedgeRef& twin() {return _twin;}
HalfedgeCRef twin() const {return _twin;}
HalfedgeRef &twin() { return _twin; }
HalfedgeCRef twin() const { return _twin; }
// Retrieves the next halfedge
HalfedgeRef& next() {return _next;}
HalfedgeCRef next() const {return _next;}
HalfedgeRef &next() { return _next; }
HalfedgeCRef next() const { return _next; }
// Retrieves the associated vertex
VertexRef& vertex() {return _vertex;}
VertexCRef vertex() const {return _vertex;}
VertexRef &vertex() { return _vertex; }
VertexCRef vertex() const { return _vertex; }
// Retrieves the associated edge
EdgeRef& edge() {return _edge;}
EdgeCRef edge() const {return _edge;}
EdgeRef &edge() { return _edge; }
EdgeCRef edge() const { return _edge; }
// Retrieves the associated face
FaceRef& face() {return _face;}
FaceCRef face() const {return _face;}
FaceRef &face() { return _face; }
FaceCRef face() const { return _face; }
// Returns an id unique to this halfedge
unsigned int id() const {return _id;}
unsigned int id() const { return _id; }
// Returns whether this edge is inside a boundary face
bool is_boundary() const {return _face->is_boundary();}
bool is_boundary() const { return _face->is_boundary(); }
// Convenience function for setting all members of the halfedge
void set_neighbors(HalfedgeRef next, HalfedgeRef twin, VertexRef vertex,
EdgeRef edge, FaceRef face) {
void set_neighbors(HalfedgeRef next, HalfedgeRef twin, VertexRef vertex, EdgeRef edge,
FaceRef face) {
_next = next;
_twin = twin;
_vertex = vertex;
......@@ -441,13 +440,13 @@ public:
};
/*
These methods delete a specified mesh element. One should think very, very carefully about
exactly when and how to delete mesh elements, since other elements will often still point
to the element that is being deleted, and accessing a deleted element will cause your
program to crash (or worse!). A good exercise to think about is: suppose you're iterating
over a linked list, and want to delete some of the elements as you go. How do you do this
without causing any problems? For instance, if you delete the current
element, will you be able to iterate to the next element? Etc.
These methods delete a specified mesh element. One should think very, very carefully
about exactly when and how to delete mesh elements, since other elements will often still
point to the element that is being deleted, and accessing a deleted element will cause your
program to crash (or worse!). A good exercise to think about is: suppose you're
iterating over a linked list, and want to delete some of the elements as you go. How do you
do this without causing any problems? For instance, if you delete the current element, will
you be able to iterate to the next element? Etc.
*/
void erase(HalfedgeRef h) { halfedges.erase(h); }
void erase(VertexRef v) { vertices.erase(v); }
......@@ -456,8 +455,8 @@ public:
void erase_boundary(FaceRef f) { boundaries.erase(f); }
/*
These methods allocate new mesh elements, returning a pointer (i.e., iterator) to the new element.
(These methods cannot have const versions, because they modify the mesh!)
These methods allocate new mesh elements, returning a pointer (i.e., iterator) to the
new element. (These methods cannot have const versions, because they modify the mesh!)
*/
HalfedgeRef new_halfedge() { return halfedges.insert(halfedges.end(), Halfedge(next_id++)); }
VertexRef new_vertex() { return vertices.insert(vertices.end(), Vertex(next_id++)); }
......@@ -506,10 +505,10 @@ public:
/*
This return simple statistics about the current mesh.
*/
Size n_vertices() const {return vertices.size();};
Size n_edges() const {return edges.size();};
Size n_faces() const {return faces.size();};
Size n_halfedges() const {return halfedges.size();};
Size n_vertices() const { return vertices.size(); };
Size n_edges() const { return edges.size(); };
Size n_faces() const { return faces.size(); };
Size n_halfedges() const { return halfedges.size(); };
/// Check if half-edge mesh is valid
std::string validate() const;
......@@ -520,34 +519,36 @@ public:
// Various ways of constructing meshes
Halfedge_Mesh();
Halfedge_Mesh(const GL::Mesh& mesh);
Halfedge_Mesh(const std::vector<std::vector<Index>>& polygons, const std::vector<Vec3>& verts);
Halfedge_Mesh(const Halfedge_Mesh& src) = delete;
Halfedge_Mesh(Halfedge_Mesh&& src) = default;
Halfedge_Mesh(const GL::Mesh &mesh);
Halfedge_Mesh(const std::vector<std::vector<Index>> &polygons, const std::vector<Vec3> &verts);
Halfedge_Mesh(const Halfedge_Mesh &src) = delete;
Halfedge_Mesh(Halfedge_Mesh &&src) = default;
~Halfedge_Mesh() = default;
// Various ways of copying meshes
void operator=(const Halfedge_Mesh& src) = delete;
Halfedge_Mesh& operator=(Halfedge_Mesh&& src) = default;
void copy_to(Halfedge_Mesh& mesh);
ElementRef copy_to(Halfedge_Mesh& mesh, unsigned int eid);
void operator=(const Halfedge_Mesh &src) = delete;
Halfedge_Mesh &operator=(Halfedge_Mesh &&src) = default;
void copy_to(Halfedge_Mesh &mesh);
ElementRef copy_to(Halfedge_Mesh &mesh, unsigned int eid);
/// Clear mesh of all elements.
void clear();
/// Creates new sub-divided mesh with provided scheme
bool subdivide(SubD strategy);
/// Export to renderable vertex-index mesh. Indexes the mesh.
void to_mesh(GL::Mesh& mesh, bool split_faces) const;
void to_mesh(GL::Mesh &mesh, bool split_faces) const;
/// Create mesh from polygon list
std::string from_poly(const std::vector<std::vector<Index>>& polygons, const std::vector<Vec3>& verts);
/// Create mesh from renderable triangle mesh (beware of connectivity, does not de-duplicate vertices)
std::string from_mesh(const GL::Mesh& mesh);
std::string from_poly(const std::vector<std::vector<Index>> &polygons,
const std::vector<Vec3> &verts);
/// Create mesh from renderable triangle mesh (beware of connectivity, does not de-duplicate
/// vertices)
std::string from_mesh(const GL::Mesh &mesh);
/// For rendering
bool render_dirty_flag = false;
void mark_dirty();
bool flipped() const {return flip_orientation;}
void flip() {flip_orientation = !flip_orientation;};
bool flipped() const { return flip_orientation; }
void flip() { flip_orientation = !flip_orientation; };
Vec3 normal_of(ElementRef elem);
static Vec3 center_of(ElementRef elem);
......@@ -568,28 +569,28 @@ private:
Here we just say that one iterator comes before another if the address of the
object it points to is smaller. (You should not have to worry about this!)
*/
inline bool operator<(const Halfedge_Mesh::HalfedgeRef& i, const Halfedge_Mesh::HalfedgeRef& j) {
inline bool operator<(const Halfedge_Mesh::HalfedgeRef &i, const Halfedge_Mesh::HalfedgeRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::VertexRef& i, const Halfedge_Mesh::VertexRef& j) {
inline bool operator<(const Halfedge_Mesh::VertexRef &i, const Halfedge_Mesh::VertexRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::EdgeRef& i, const Halfedge_Mesh::EdgeRef& j) {
inline bool operator<(const Halfedge_Mesh::EdgeRef &i, const Halfedge_Mesh::EdgeRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::FaceRef& i, const Halfedge_Mesh::FaceRef& j) {
inline bool operator<(const Halfedge_Mesh::FaceRef &i, const Halfedge_Mesh::FaceRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::HalfedgeCRef& i, const Halfedge_Mesh::HalfedgeCRef& j) {
inline bool operator<(const Halfedge_Mesh::HalfedgeCRef &i, const Halfedge_Mesh::HalfedgeCRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::VertexCRef& i, const Halfedge_Mesh::VertexCRef& j) {
inline bool operator<(const Halfedge_Mesh::VertexCRef &i, const Halfedge_Mesh::VertexCRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::EdgeCRef& i, const Halfedge_Mesh::EdgeCRef& j) {
inline bool operator<(const Halfedge_Mesh::EdgeCRef &i, const Halfedge_Mesh::EdgeCRef &j) {
return &*i < &*j;
}
inline bool operator<(const Halfedge_Mesh::FaceCRef& i, const Halfedge_Mesh::FaceCRef& j) {
inline bool operator<(const Halfedge_Mesh::FaceCRef &i, const Halfedge_Mesh::FaceCRef &j) {
return &*i < &*j;
}
......@@ -598,52 +599,52 @@ inline bool operator<(const Halfedge_Mesh::FaceCRef& i, const Halfedge_Mesh::Fac
Here we simply hash the unique ID of the element.
*/
namespace std {
template<> struct hash<Halfedge_Mesh::VertexRef> {
template <> struct hash<Halfedge_Mesh::VertexRef> {
uint64_t operator()(Halfedge_Mesh::VertexRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::EdgeRef> {
};
template <> struct hash<Halfedge_Mesh::EdgeRef> {
uint64_t operator()(Halfedge_Mesh::EdgeRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::FaceRef> {
};
template <> struct hash<Halfedge_Mesh::FaceRef> {
uint64_t operator()(Halfedge_Mesh::FaceRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::HalfedgeRef> {
};
template <> struct hash<Halfedge_Mesh::HalfedgeRef> {
uint64_t operator()(Halfedge_Mesh::HalfedgeRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::VertexCRef> {
};
template <> struct hash<Halfedge_Mesh::VertexCRef> {
uint64_t operator()(Halfedge_Mesh::VertexCRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::EdgeCRef> {
};
template <> struct hash<Halfedge_Mesh::EdgeCRef> {
uint64_t operator()(Halfedge_Mesh::EdgeCRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::FaceCRef> {
};
template <> struct hash<Halfedge_Mesh::FaceCRef> {
uint64_t operator()(Halfedge_Mesh::FaceCRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
template<> struct hash<Halfedge_Mesh::HalfedgeCRef> {
};
template <> struct hash<Halfedge_Mesh::HalfedgeCRef> {
uint64_t operator()(Halfedge_Mesh::HalfedgeCRef key) const {
static const std::hash<unsigned int> h;
return h(key->id());
}
};
}
};
} // namespace std
#pragma once
#include "../lib/mathlib.h"
#include <map>
#include <set>
#include "../lib/mathlib.h"
template<typename T>
class Spline {
template <typename T> class Spline {
public:
// Returns the interpolated value.
T at(float time) const;
......@@ -42,7 +40,8 @@ public:
// Returns set of keys
std::set<float> keys() const {
std::set<float> ret;
for(auto& e : control_points) ret.insert(e.first);
for (auto &e : control_points)
ret.insert(e.first);
return ret;
}
......@@ -52,18 +51,19 @@ private:
// Given a time between 0 and 1, evaluates a cubic polynomial with
// the given endpoint and tangent values at the beginning (0) and
// end (1) of the interval
static T cubic_unit_spline(float time,
const T& position0, const T& position1,
const T& tangent0, const T& tangent1);
static T cubic_unit_spline(float time, const T &position0, const T &position1,
const T &tangent0, const T &tangent1);
};
template<>
class Spline<Quat> {
template <> class Spline<Quat> {
public:
Quat at(float time) const {
if(values.empty()) return Quat::euler(Vec3(0.0f));
if(values.size() == 1) return values.begin()->second;
if(values.begin()->first > time)
if (values.empty())
return Quat::euler(Vec3(0.0f));
if (values.size() == 1)
return values.begin()->second;
if (values.begin()->first > time)
return values.begin()->second;
auto k2 = values.upper_bound(time);
if (k2 == values.end())
......@@ -94,8 +94,8 @@ public:
}
float norm_t = (time - t1) / dt;
Quat qa = tangent(p0,p1,p2);
Quat pb = tangent(p1,p2,p3);
Quat qa = tangent(p0, p1, p2);
Quat pb = tangent(p1, p2, p3);
float slerpT = 2.0f * norm_t * (1.0f - norm_t);
Quat slerp1 = p1.slerp(p2, norm_t);
......@@ -103,18 +103,13 @@ public:
return slerp1.slerp(slerp2, slerpT);
}
Quat operator()(float time) const {
return at(time);
}
void set(float time, Quat value) {
values[time] = value;
}
void erase(float time) {
values.erase(time);
}
Quat operator()(float time) const { return at(time); }
void set(float time, Quat value) { values[time] = value; }
void erase(float time) { values.erase(time); }
std::set<float> keys() const {
std::set<float> ret;
for(auto& e : values) ret.insert(e.first);
for (auto &e : values)
ret.insert(e.first);
return ret;
}
bool has(float t) const { return values.count(t); }
......@@ -127,7 +122,7 @@ public:
private:
std::map<float, Quat> values;
static Quat tangent(const Quat& q0, const Quat& q1, const Quat& q2) {
static Quat tangent(const Quat &q0, const Quat &q1, const Quat &q2) {
Quat q1inv = q1.inverse();
Quat c1 = q1inv * q2;
Quat c2 = q1inv * q0;
......@@ -141,8 +136,7 @@ private:
}
};
template<typename T, typename... Ts>
class Splines {
template <typename T, typename... Ts> class Splines {
public:
void set(float t, T arg, Ts... args) {
head.set(t, arg);
......@@ -152,12 +146,8 @@ public:
head.erase(t);
tail.erase(t);
}
bool any() const {
return head.any() || tail.any();
}
bool has(float t) const {
return head.has(t) || tail.has(t);
}
bool any() const { return head.any() || tail.any(); }
bool has(float t) const { return head.has(t) || tail.has(t); }
void clear() {
head.clear();
tail.clear();
......@@ -181,33 +171,16 @@ private:
Splines<Ts...> tail;
};
template<typename T>
class Splines<T> {
template <typename T> class Splines<T> {
public:
void set(float t, T arg) {
head.set(t, arg);
}
void erase(float t) {
head.erase(t);
}
bool any() const {
return head.any();
}
bool has(float t) const {
return head.has(t);
}
void crop(float t) {
head.crop(t);
}
void clear() {
head.clear();
}
std::set<float> keys() const {
return head.keys();
}
std::tuple<T> at(float t) const {
return std::make_tuple(head.at(t));
}
void set(float t, T arg) { head.set(t, arg); }
void erase(float t) { head.erase(t); }
bool any() const { return head.any(); }
bool has(float t) const { return head.has(t); }
void crop(float t) { head.crop(t); }
void clear() { head.clear(); }
std::set<float> keys() const { return head.keys(); }
std::tuple<T> at(float t) const { return std::make_tuple(head.at(t)); }
private:
Spline<T> head;
......
......@@ -5,71 +5,76 @@
namespace Util {
GL::Mesh cyl_mesh(float radius, float height, int sides, bool cap) {
GL::Mesh cyl_mesh(float radius, float height, int sides, bool cap) {
return cone_mesh(radius, radius, height, sides, cap);
}
}
GL::Mesh arrow_mesh(float rbase, float rtip, float height) {
GL::Mesh arrow_mesh(float rbase, float rtip, float height) {
Gen::Data base = Gen::cone(rbase, rbase, 0.75f * height, 10, true);
Gen::Data tip = Gen::cone(rtip, 0.001f, 0.25f * height, 10, true);
for(auto& v : tip.verts) v.pos.y += 0.7f;
for (auto &v : tip.verts)
v.pos.y += 0.7f;
return Gen::merge(std::move(base), std::move(tip));
}
}
GL::Mesh scale_mesh() {
GL::Mesh scale_mesh() {
Gen::Data base = Gen::cone(0.03f, 0.03f, 0.7f, 10, true);
Gen::Data tip = Gen::cube(0.1f);
for(auto& v : tip.verts) v.pos.y += 0.7f;
for (auto &v : tip.verts)
v.pos.y += 0.7f;
return Gen::merge(std::move(base), std::move(tip));
}
}
GL::Mesh cone_mesh(float bradius, float tradius, float height, int sides, bool cap) {
GL::Mesh cone_mesh(float bradius, float tradius, float height, int sides, bool cap) {
Gen::Data cone = Gen::cone(bradius, tradius, height, sides, cap);
return GL::Mesh(std::move(cone.verts), std::move(cone.elems));
}
}
GL::Mesh torus_mesh(float iradius, float oradius, int segments, int sides) {
GL::Mesh torus_mesh(float iradius, float oradius, int segments, int sides) {
Gen::Data torus = Gen::torus(iradius, oradius, segments, sides);
return GL::Mesh(std::move(torus.verts), std::move(torus.elems));
}
}
GL::Mesh cube_mesh(float r) {
GL::Mesh cube_mesh(float r) {
Gen::Data cube = Gen::cube(r);
return GL::Mesh(std::move(cube.verts), std::move(cube.elems));
}
}
GL::Mesh square_mesh(float r) {
GL::Mesh square_mesh(float r) {
Gen::Data square = Gen::quad(r, r);
return GL::Mesh(std::move(square.verts), std::move(square.elems));
}
}
GL::Mesh quad_mesh(float x, float y) {
GL::Mesh quad_mesh(float x, float y) {
Gen::Data square = Gen::quad(x, y);
return GL::Mesh(std::move(square.verts), std::move(square.elems));
}
}
GL::Mesh sphere_mesh(float r, int i) {
GL::Mesh sphere_mesh(float r, int i) {
Gen::Data ico_sphere = Gen::ico_sphere(r, i);
return GL::Mesh(std::move(ico_sphere.verts), std::move(ico_sphere.elems));
}
}
GL::Mesh hemi_mesh(float r) {
GL::Mesh hemi_mesh(float r) {
Gen::Data hemi = Gen::uv_hemisphere(r);
return GL::Mesh(std::move(hemi.verts), std::move(hemi.elems));
}
}
GL::Mesh capsule_mesh(float h, float r) {
GL::Mesh capsule_mesh(float h, float r) {
Gen::Data bottom = Gen::uv_hemisphere(r);
Gen::Data top = Gen::uv_hemisphere(r);
for(auto& v : top.verts) v.pos.y = -v.pos.y + h;
for (auto &v : top.verts)
v.pos.y = -v.pos.y + h;
Gen::Data cyl = Gen::cone(r, r, h, 64, false);
GL::Mesh::Index cyl_off = (GL::Mesh::Index)bottom.verts.size();
GL::Mesh::Index top_off = cyl_off + (GL::Mesh::Index)cyl.verts.size();
for(auto& i : cyl.elems) i += cyl_off;
for(auto& i : top.elems) i += top_off;
for (auto &i : cyl.elems)
i += cyl_off;
for (auto &i : top.elems)
i += top_off;
bottom.verts.insert(bottom.verts.end(), cyl.verts.begin(), cyl.verts.end());
bottom.elems.insert(bottom.elems.end(), cyl.elems.begin(), cyl.elems.end());
......@@ -78,9 +83,9 @@ namespace Util {
bottom.elems.insert(bottom.elems.end(), top.elems.begin(), top.elems.end());
return GL::Mesh(std::move(bottom.verts), std::move(bottom.elems));
}
}
GL::Lines spotlight_mesh(Vec3 color, float inner, float outer) {
GL::Lines spotlight_mesh(Vec3 color, float inner, float outer) {
const int steps = 72;
const float step = (2.0f * PI_F) / (steps + 1);
......@@ -93,63 +98,63 @@ namespace Util {
Gen::LData iring = Gen::circle(color, ri, steps);
Gen::LData oring = Gen::circle(color, ro, steps);
Gen::LData rings = Gen::merge(std::move(iring), std::move(oring));
for(auto& v : rings.verts) v.pos.y += 5.0f;
for (auto &v : rings.verts)
v.pos.y += 5.0f;
float t = 0.0f;
for(int i = 0; i < steps; i += steps / 4) {
for (int i = 0; i < steps; i += steps / 4) {
Vec3 point = ro * Vec3(std::sin(t), 0.0f, std::cos(t));
rings.verts.push_back({{}, color});
rings.verts.push_back({Vec3(point.x, 5.0f, point.z), color});
t += step * (steps / 4);
}
return GL::Lines(std::move(rings.verts), 1.0f);
}
}
namespace Gen {
namespace Gen {
GL::Mesh merge(Data&& l, Data&& r) {
for(auto& i : r.elems) i += (GL::Mesh::Index)l.verts.size();
GL::Mesh merge(Data &&l, Data &&r) {
for (auto &i : r.elems)
i += (GL::Mesh::Index)l.verts.size();
l.verts.insert(l.verts.end(), r.verts.begin(), r.verts.end());
l.elems.insert(l.elems.end(), r.elems.begin(), r.elems.end());
return GL::Mesh(std::move(l.verts), std::move(l.elems));
}
}
LData merge(LData&& l, LData&& r) {
LData merge(LData &&l, LData &&r) {
l.verts.insert(l.verts.end(), r.verts.begin(), r.verts.end());
return std::move(l);
}
}
LData circle(Vec3 color, float r, int sides) {
LData circle(Vec3 color, float r, int sides) {
std::vector<Vec3> points;
float t = 0.0f;
float step = (2.0f * PI_F) / (sides + 1);
for(int i = 0; i < sides; i++) {
for (int i = 0; i < sides; i++) {
points.push_back(r * Vec3(std::sin(t), 0.0f, std::cos(t)));
t += step;
}
std::vector<GL::Lines::Vert> verts;
for(size_t i = 0; i < points.size(); i++) {
for (size_t i = 0; i < points.size(); i++) {
verts.push_back({points[i], color});
verts.push_back({points[(i + 1) % points.size()], color});
}
return LData{std::move(verts)};
}
}
Data quad(float x, float y) {
return {{
{Vec3{-x, 0.0f, -y}, Vec3{0.0f, 1.0f, 0.0f}, 0},
Data quad(float x, float y) {
return {{{Vec3{-x, 0.0f, -y}, Vec3{0.0f, 1.0f, 0.0f}, 0},
{Vec3{-x, 0.0f, y}, Vec3{0.0f, 1.0f, 0.0f}, 0},
{Vec3{x, 0.0f, -y}, Vec3{0.0f, 1.0f, 0.0f}, 0},
{Vec3{x, 0.0f, y}, Vec3{0.0f, 1.0f, 0.0f}, 0}},
{0, 1, 2, 2, 1, 3}};
}
}
Data cube(float r) {
return {{
{Vec3{-r, -r, -r}, Vec3{-r, -r, -r}.unit(), 0},
Data cube(float r) {
return {{{Vec3{-r, -r, -r}, Vec3{-r, -r, -r}.unit(), 0},
{Vec3{r, -r, -r}, Vec3{r, -r, -r}.unit(), 0},
{Vec3{r, r, -r}, Vec3{r, r, -r}.unit(), 0},
{Vec3{-r, r, -r}, Vec3{-r, r, -r}.unit(), 0},
......@@ -157,16 +162,12 @@ namespace Util {
{Vec3{r, -r, r}, Vec3{r, -r, r}.unit(), 0},
{Vec3{r, r, r}, Vec3{r, r, r}.unit(), 0},
{Vec3{-r, r, r}, Vec3{-r, r, r}.unit(), 0}},
{0, 1, 3, 3, 1, 2,
1, 5, 2, 2, 5, 6,
5, 4, 6, 6, 4, 7,
4, 0, 7, 7, 0, 3,
3, 2, 7, 7, 2, 6,
4, 5, 0, 0, 5, 1}};
}
{0, 1, 3, 3, 1, 2, 1, 5, 2, 2, 5, 6, 5, 4, 6, 6, 4, 7,
4, 0, 7, 7, 0, 3, 3, 2, 7, 7, 2, 6, 4, 5, 0, 0, 5, 1}};
}
// https://wiki.unity3d.com/index.php/ProceduralPrimitives
Data cone(float bradius, float tradius, float height, int sides, bool caps) {
// https://wiki.unity3d.com/index.php/ProceduralPrimitives
Data cone(float bradius, float tradius, float height, int sides, bool caps) {
const size_t n_sides = sides, n_cap = n_sides + 1;
const float _2pi = PI_F * 2.0f;
......@@ -175,23 +176,23 @@ namespace Util {
size_t vert = 0;
vertices[vert++] = Vec3(0.0f, 0.0f, 0.0f);
while(vert <= n_sides) {
while (vert <= n_sides) {
float rad = (float)vert / n_sides * _2pi;
vertices[vert] = Vec3(std::cos(rad) * bradius, 0.0f, std::sin(rad) * bradius);
vert++;
}
vertices[vert++] = Vec3(0.0f, height, 0.0f);
while(vert <= n_sides * 2 + 1) {
while (vert <= n_sides * 2 + 1) {
float rad = (float)(vert - n_sides - 1) / n_sides * _2pi;
vertices[vert] = Vec3(std::cos(rad) * tradius, height, std::sin(rad) * tradius);
vert++;
}
int v = 0;
while(vert <= vertices.size() - 4) {
while (vert <= vertices.size() - 4) {
float rad = (float)v / n_sides * _2pi;
vertices[vert] = Vec3(std::cos(rad) * tradius, height, std::sin(rad) * tradius);
vertices[vert + 1] = Vec3(std::cos(rad) * bradius, 0.0f, std::sin(rad) * bradius);
vert+=2;
vert += 2;
v++;
}
vertices[vert] = vertices[n_sides * 2 + 2];
......@@ -199,25 +200,25 @@ namespace Util {
std::vector<Vec3> normals(vertices.size());
vert = 0;
while(vert <= n_sides) {
while (vert <= n_sides) {
normals[vert++] = Vec3(0.0f, -1.0f, 0.0f);
}
while(vert <= n_sides * 2 + 1) {
while (vert <= n_sides * 2 + 1) {
normals[vert++] = Vec3(0.0f, 1.0f, 0.0f);
}
v = 0;
while(vert <= vertices.size() - 4) {
while (vert <= vertices.size() - 4) {
float rad = (float)v / n_sides * _2pi;
float cos = std::cos(rad);
float sin = std::sin(rad);
normals[vert] = Vec3(cos, 0.0f, sin);
normals[vert+1] = normals[vert];
vert+=2;
normals[vert + 1] = normals[vert];
vert += 2;
v++;
}
normals[vert] = normals[n_sides * 2 + 2 ];
normals[vert + 1] = normals[n_sides * 2 + 3 ];
normals[vert] = normals[n_sides * 2 + 2];
normals[vert + 1] = normals[n_sides * 2 + 3];
size_t n_tris = n_sides + n_sides + n_sides * 2;
std::vector<GL::Mesh::Index> triangles(n_tris * 3 + 3);
......@@ -225,7 +226,7 @@ namespace Util {
GL::Mesh::Index tri = 0;
size_t i = 0;
while (tri < n_sides - 1) {
if(caps) {
if (caps) {
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 2;
......@@ -233,7 +234,7 @@ namespace Util {
tri++;
i += 3;
}
if(caps) {
if (caps) {
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = 1;
......@@ -241,8 +242,8 @@ namespace Util {
tri++;
i += 3;
while(tri < n_sides * 2) {
if(caps) {
while (tri < n_sides * 2) {
if (caps) {
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = (GLuint)n_cap;
......@@ -250,7 +251,7 @@ namespace Util {
tri++;
i += 3;
}
if(caps) {
if (caps) {
triangles[i] = (GLuint)n_cap + 1;
triangles[i + 1] = tri + 1;
triangles[i + 2] = (GLuint)n_cap;
......@@ -259,7 +260,7 @@ namespace Util {
i += 3;
tri++;
while(tri <= n_tris) {
while (tri <= n_tris) {
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 0;
......@@ -273,45 +274,47 @@ namespace Util {
}
std::vector<GL::Mesh::Vert> verts;
for(size_t j = 0; j < vertices.size(); j++) {
for (size_t j = 0; j < vertices.size(); j++) {
verts.push_back({vertices[j], normals[j], 0});
}
return {verts, triangles};
}
}
Data torus(float iradius, float oradius, int segments, int sides) {
Data torus(float iradius, float oradius, int segments, int sides) {
const int n_rad_sides = segments, n_sides = sides;
const float _2pi = PI_F * 2.0f;
iradius = oradius - iradius;
std::vector<Vec3> vertices((n_rad_sides+1) * (n_sides+1));
for(int seg = 0; seg <= n_rad_sides; seg++) {
std::vector<Vec3> vertices((n_rad_sides + 1) * (n_sides + 1));
for (int seg = 0; seg <= n_rad_sides; seg++) {
int cur_seg = seg == n_rad_sides ? 0 : seg;
float t1 = (float)cur_seg / n_rad_sides * _2pi;
Vec3 r1(std::cos(t1) * oradius, 0.0f, std::sin(t1) * oradius);
for(int side = 0; side <= n_sides; side++) {
for (int side = 0; side <= n_sides; side++) {
int cur_side = side == n_sides ? 0 : side;
float t2 = (float)cur_side / n_sides * _2pi;
Vec3 r2 = Mat4::rotate(Degrees(-t1), Vec3{0.0f, 1.0f, 0.0f}) * Vec3(std::sin(t2) * iradius, std::cos(t2) * iradius, 0.0f);
Vec3 r2 = Mat4::rotate(Degrees(-t1), Vec3{0.0f, 1.0f, 0.0f}) *
Vec3(std::sin(t2) * iradius, std::cos(t2) * iradius, 0.0f);
vertices[side + seg * (n_sides+1)] = r1 + r2;
vertices[side + seg * (n_sides + 1)] = r1 + r2;
}
}
std::vector<Vec3> normals(vertices.size());
for(int seg = 0; seg <= n_rad_sides; seg++) {
for (int seg = 0; seg <= n_rad_sides; seg++) {
int cur_seg = seg == n_rad_sides ? 0 : seg;
float t1 = (float)cur_seg / n_rad_sides * _2pi;
Vec3 r1(std::cos(t1) * oradius, 0.0f, std::sin(t1) * oradius);
for(int side = 0; side <= n_sides; side++) {
normals[side + seg * (n_sides+1)] = (vertices[side + seg * (n_sides+1)] - r1).unit();
for (int side = 0; side <= n_sides; side++) {
normals[side + seg * (n_sides + 1)] =
(vertices[side + seg * (n_sides + 1)] - r1).unit();
}
}
......@@ -321,58 +324,56 @@ namespace Util {
std::vector<GL::Mesh::Index> triangles(n_idx);
size_t i = 0;
for(int seg = 0; seg <= n_rad_sides; seg++) {
for(int side = 0; side <= n_sides - 1; side++) {
for (int seg = 0; seg <= n_rad_sides; seg++) {
for (int side = 0; side <= n_sides - 1; side++) {
int current = side + seg * (n_sides+1);
int next = side + (seg < (n_rad_sides) ?(seg+1) * (n_sides+1) : 0);
int current = side + seg * (n_sides + 1);
int next = side + (seg < (n_rad_sides) ? (seg + 1) * (n_sides + 1) : 0);
if(i < triangles.size() - 6) {
if (i < triangles.size() - 6) {
triangles[i++] = current;
triangles[i++] = next;
triangles[i++] = next+1;
triangles[i++] = next + 1;
triangles[i++] = current;
triangles[i++] = next+1;
triangles[i++] = current+1;
triangles[i++] = next + 1;
triangles[i++] = current + 1;
}
}
}
std::vector<GL::Mesh::Vert> verts;
for(size_t j = 0; j < vertices.size(); j++) {
for (size_t j = 0; j < vertices.size(); j++) {
verts.push_back({vertices[j], normals[j], 0});
}
return {verts, triangles};
}
}
Data uv_hemisphere(float radius) {
Data uv_hemisphere(float radius) {
int nbLong = 64;
int nbLat = 16;
std::vector<Vec3> vertices((nbLong+1) * nbLat + 2);
std::vector<Vec3> vertices((nbLong + 1) * nbLat + 2);
float _pi = PI_F;
float _2pi = _pi * 2.0f;
vertices[0] = Vec3{0.0f, radius, 0.0f};
for( int lat = 0; lat < nbLat; lat++ )
{
float a1 = _pi * (float)(lat+1) / (nbLat+1);
for (int lat = 0; lat < nbLat; lat++) {
float a1 = _pi * (float)(lat + 1) / (nbLat + 1);
float sin1 = std::sin(a1);
float cos1 = std::cos(a1);
for( int lon = 0; lon <= nbLong; lon++ )
{
for (int lon = 0; lon <= nbLong; lon++) {
float a2 = _2pi * (float)(lon == nbLong ? 0 : lon) / nbLong;
float sin2 = std::sin(a2);
float cos2 = std::cos(a2);
vertices[ lon + lat * (nbLong + 1) + 1] = Vec3( sin1 * cos2, cos1, sin1 * sin2 ) * radius;
vertices[lon + lat * (nbLong + 1) + 1] = Vec3(sin1 * cos2, cos1, sin1 * sin2) * radius;
}
}
vertices[vertices.size()-1] = Vec3{0.0f, -radius, 0.0f};
vertices[vertices.size() - 1] = Vec3{0.0f, -radius, 0.0f};
std::vector<Vec3> normals(vertices.size());
for(size_t n = 0; n < vertices.size(); n++)
for (size_t n = 0; n < vertices.size(); n++)
normals[n] = vertices[n].unit();
int nbFaces = (int)vertices.size();
......@@ -381,8 +382,8 @@ namespace Util {
std::vector<GL::Mesh::Index> triangles(nbIndexes);
int i = 0;
for(int lat = (nbLat - 1) / 2; lat < nbLat - 1; lat++) {
for(int lon = 0; lon < nbLong; lon++) {
for (int lat = (nbLat - 1) / 2; lat < nbLat - 1; lat++) {
for (int lon = 0; lon < nbLong; lon++) {
int current = lon + lat * (nbLong + 1) + 1;
int next = current + nbLong + 1;
......@@ -396,26 +397,27 @@ namespace Util {
}
}
for(int lon = 0; lon < nbLong; lon++) {
for (int lon = 0; lon < nbLong; lon++) {
triangles[i++] = (int)vertices.size() - 1;
triangles[i++] = (int)vertices.size() - (lon+2) - 1;
triangles[i++] = (int)vertices.size() - (lon+1) - 1;
triangles[i++] = (int)vertices.size() - (lon + 2) - 1;
triangles[i++] = (int)vertices.size() - (lon + 1) - 1;
}
std::vector<GL::Mesh::Vert> verts;
for(size_t j = 0; j < vertices.size(); j++) {
for (size_t j = 0; j < vertices.size(); j++) {
verts.push_back({vertices[j], normals[j], 0});
}
triangles.resize(i);
return {verts, triangles};
}
}
Data ico_sphere(float radius, int level) {
Data ico_sphere(float radius, int level) {
struct TriIdx {
int v1, v2, v3;
};
auto middle_point = [&](int p1, int p2, std::vector<Vec3>& vertices, std::map<int64_t, size_t>& cache, float radius) -> size_t {
auto middle_point = [&](int p1, int p2, std::vector<Vec3> &vertices,
std::map<int64_t, size_t> &cache, float radius) -> size_t {
bool firstIsSmaller = p1 < p2;
int64_t smallerIndex = firstIsSmaller ? p1 : p2;
int64_t greaterIndex = firstIsSmaller ? p2 : p1;
......@@ -428,11 +430,8 @@ namespace Util {
Vec3 point1 = vertices[p1];
Vec3 point2 = vertices[p2];
Vec3 middle (
(point1.x + point2.x) / 2.0f,
(point1.y + point2.y) / 2.0f,
(point1.z + point2.z) / 2.0f
);
Vec3 middle((point1.x + point2.x) / 2.0f, (point1.y + point2.y) / 2.0f,
(point1.z + point2.z) / 2.0f);
size_t i = vertices.size();
vertices.push_back(middle.unit() * radius);
cache[key] = i;
......@@ -443,15 +442,15 @@ namespace Util {
std::map<int64_t, size_t> middlePointIndexCache;
float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
vertices.push_back(Vec3(-1.0f, t, 0.0f).unit() * radius);
vertices.push_back(Vec3( 1.0f, t, 0.0f).unit() * radius);
vertices.push_back(Vec3(1.0f, t, 0.0f).unit() * radius);
vertices.push_back(Vec3(-1.0f, -t, 0.0f).unit() * radius);
vertices.push_back(Vec3( 1.0f, -t, 0.0f).unit() * radius);
vertices.push_back(Vec3(1.0f, -t, 0.0f).unit() * radius);
vertices.push_back(Vec3(0.0f, -1.0f, t).unit() * radius);
vertices.push_back(Vec3(0.0f, 1.0f, t).unit() * radius);
vertices.push_back(Vec3(0.0f, -1.0f, -t).unit() * radius);
vertices.push_back(Vec3(0.0f, 1.0f, -t).unit() * radius);
vertices.push_back(Vec3( t, 0.0f, -1.0f).unit() * radius);
vertices.push_back(Vec3( t, 0.0f, 1.0f).unit() * radius);
vertices.push_back(Vec3(t, 0.0f, -1.0f).unit() * radius);
vertices.push_back(Vec3(t, 0.0f, 1.0f).unit() * radius);
vertices.push_back(Vec3(-t, 0.0f, -1.0f).unit() * radius);
vertices.push_back(Vec3(-t, 0.0f, 1.0f).unit() * radius);
......@@ -477,9 +476,9 @@ namespace Util {
faces.push_back(TriIdx{8, 6, 7});
faces.push_back(TriIdx{9, 8, 1});
for(int i = 0; i < level; i++) {
for (int i = 0; i < level; i++) {
std::vector<TriIdx> faces2;
for(auto tri : faces) {
for (auto tri : faces) {
int a = (int)middle_point(tri.v1, tri.v2, vertices, middlePointIndexCache, radius);
int b = (int)middle_point(tri.v2, tri.v3, vertices, middlePointIndexCache, radius);
int c = (int)middle_point(tri.v3, tri.v1, vertices, middlePointIndexCache, radius);
......@@ -492,21 +491,22 @@ namespace Util {
}
std::vector<GL::Mesh::Index> triangles;
for(size_t i = 0; i < faces.size(); i++ ) {
for (size_t i = 0; i < faces.size(); i++) {
triangles.push_back(faces[i].v1);
triangles.push_back(faces[i].v2);
triangles.push_back(faces[i].v3);
}
std::vector<Vec3> normals(vertices.size());
for(size_t i = 0; i < normals.size(); i++)
for (size_t i = 0; i < normals.size(); i++)
normals[i] = vertices[i].unit();
std::vector<GL::Mesh::Vert> verts;
for(size_t i = 0; i < vertices.size(); i++) {
for (size_t i = 0; i < vertices.size(); i++) {
verts.push_back({vertices[i], normals[i], 0});
}
return {verts, triangles};
}
}
}
} // namespace Gen
} // namespace Util
......@@ -7,42 +7,42 @@
namespace Util {
GL::Mesh cube_mesh(float radius);
GL::Mesh square_mesh(float radius);
GL::Mesh quad_mesh(float x, float y);
GL::Mesh cyl_mesh(float radius, float height, int sides = 12, bool cap = true);
GL::Mesh torus_mesh(float iradius, float oradius, int segments = 48, int sides = 24);
GL::Mesh sphere_mesh(float r, int subdivsions);
GL::Mesh hemi_mesh(float r);
GL::Mesh cone_mesh(float bradius, float tradius, float height, int sides = 12, bool cap = true);
GL::Mesh capsule_mesh(float h, float r);
GL::Mesh arrow_mesh(float base, float tip, float height);
GL::Mesh scale_mesh();
GL::Lines spotlight_mesh(Vec3 color, float inner, float outer);
namespace Gen {
struct Data {
std::vector<GL::Mesh::Vert> verts;
std::vector<GL::Mesh::Index> elems;
};
struct LData {
std::vector<GL::Lines::Vert> verts;
};
GL::Mesh cube_mesh(float radius);
GL::Mesh square_mesh(float radius);
GL::Mesh quad_mesh(float x, float y);
GL::Mesh cyl_mesh(float radius, float height, int sides = 12, bool cap = true);
GL::Mesh torus_mesh(float iradius, float oradius, int segments = 48, int sides = 24);
GL::Mesh sphere_mesh(float r, int subdivsions);
GL::Mesh hemi_mesh(float r);
GL::Mesh cone_mesh(float bradius, float tradius, float height, int sides = 12, bool cap = true);
GL::Mesh capsule_mesh(float h, float r);
GL::Mesh merge(Data&& l, Data&& r);
LData merge(LData&& l, LData&& r);
GL::Mesh arrow_mesh(float base, float tip, float height);
GL::Mesh scale_mesh();
LData circle(Vec3 color, float r, int sides);
GL::Lines spotlight_mesh(Vec3 color, float inner, float outer);
Data cube(float r);
Data quad(float x, float y);
namespace Gen {
// https://wiki.unity3d.com/index.php/ProceduralPrimitives
Data ico_sphere(float radius, int level);
Data uv_hemisphere(float radius);
Data cone(float bradius, float tradius, float height, int sides, bool caps);
Data torus(float iradius, float oradius, int segments, int sides);
}
}
struct Data {
std::vector<GL::Mesh::Vert> verts;
std::vector<GL::Mesh::Index> elems;
};
struct LData {
std::vector<GL::Lines::Vert> verts;
};
GL::Mesh merge(Data &&l, Data &&r);
LData merge(LData &&l, LData &&r);
LData circle(Vec3 color, float r, int sides);
// https://wiki.unity3d.com/index.php/ProceduralPrimitives
Data cube(float r);
Data quad(float x, float y);
Data ico_sphere(float radius, int level);
Data uv_hemisphere(float radius);
Data cone(float bradius, float tradius, float height, int sides, bool caps);
Data torus(float iradius, float oradius, int segments, int sides);
} // namespace Gen
} // namespace Util
#include "animate.h"
#include "manager.h"
#include "../scene/renderer.h"
#include "manager.h"
#include <tuple>
......@@ -17,28 +17,27 @@ Camera Anim_Camera::at(float t) const {
return ret;
}
void Anim_Camera::set(float t, const Camera& cam) {
splines.set(t, cam.pos(),
Quat::euler(Mat4::rotate_z_to(cam.center() - cam.pos()).to_euler()),
void Anim_Camera::set(float t, const Camera &cam) {
splines.set(t, cam.pos(), Quat::euler(Mat4::rotate_z_to(cam.center() - cam.pos()).to_euler()),
cam.get_fov(), cam.get_ar());
}
void Animate::update_dim(Vec2 dim) {
ui_camera.dim(dim);
}
void Animate::update_dim(Vec2 dim) { ui_camera.dim(dim); }
bool Animate::keydown(Widgets& widgets, Undo& undo, Scene_ID sel, SDL_Keysym key) {
bool Animate::keydown(Widgets &widgets, Undo &undo, Scene_ID sel, SDL_Keysym key) {
#ifdef __APPLE__
if(key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
if (key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
#else
if(key.sym == SDLK_DELETE) {
if (key.sym == SDLK_DELETE) {
#endif
if(joint_select) undo.del_bone(sel, joint_select);
else if(sel) undo.del_obj(sel);
if (joint_select)
undo.del_bone(sel, joint_select);
else if (sel)
undo.del_obj(sel);
}
if(key.sym == SDLK_SPACE) {
if (key.sym == SDLK_SPACE) {
playing = !playing;
last_frame = SDL_GetPerformanceCounter();
return true;
......@@ -47,40 +46,45 @@ bool Animate::keydown(Widgets& widgets, Undo& undo, Scene_ID sel, SDL_Keysym key
return false;
}
void Animate::render(Scene& scene, Scene_Maybe obj_opt, Widgets& widgets, Camera& user_cam) {
void Animate::render(Scene &scene, Scene_Maybe obj_opt, Widgets &widgets, Camera &user_cam) {
Mat4 view = user_cam.get_view();
auto& R = Renderer::get();
auto &R = Renderer::get();
ui_camera.render(view);
if(visualize_splines)
for(auto& e : spline_cache) R.lines(e.second, view);
if (visualize_splines)
for (auto &e : spline_cache)
R.lines(e.second, view);
if(!obj_opt.has_value()) return;
Scene_Item& item = obj_opt.value();
if (!obj_opt.has_value())
return;
Scene_Item &item = obj_opt.value();
if(item.is<Scene_Light>()) {
Scene_Light& light = item.get<Scene_Light>();
if(light.is_env()) return;
if (item.is<Scene_Light>()) {
Scene_Light &light = item.get<Scene_Light>();
if (light.is_env())
return;
}
Pose& pose = item.pose();
Pose &pose = item.pose();
float scale = std::min((user_cam.pos() - pose.pos).norm() / 5.5f, 10.0f);
item.render(view);
if(item.is<Scene_Object>() && item.get<Scene_Object>().armature.has_bones()) {
if (item.is<Scene_Object>() && item.get<Scene_Object>().armature.has_bones()) {
Scene_Object& obj = item.get<Scene_Object>();
Scene_Object &obj = item.get<Scene_Object>();
joint_id_offset = scene.used_ids();
obj.armature.render(view * obj.pose.transform(), joint_select, false, true, joint_id_offset);
obj.armature.render(view * obj.pose.transform(), joint_select, false, true,
joint_id_offset);
if(!joint_select) {
if (!joint_select) {
R.begin_outline();
BBox box = obj.bbox();
obj.render(view, false, true);
obj.armature.outline(view * obj.pose.transform(), joint_select, false, true, box, joint_id_offset);
obj.armature.outline(view * obj.pose.transform(), joint_select, false, true, box,
joint_id_offset);
R.end_outline(view, box);
} else {
widgets.active = Widget_Type::rotate;
......@@ -90,28 +94,31 @@ void Animate::render(Scene& scene, Scene_Maybe obj_opt, Widgets& widgets, Camera
R.outline(view, item);
}
if(joint_select) {
if (joint_select) {
Scene_Object& obj = item.get<Scene_Object>();
Scene_Object &obj = item.get<Scene_Object>();
widgets.render(view, pose.transform() * obj.armature.posed_base_of(joint_select), scale);
} else widgets.render(view, pose.pos, scale);
} else {
widgets.render(view, pose.pos, scale);
}
}
void Animate::make_spline(Scene_ID id, const Anim_Pose& pose) {
void Animate::make_spline(Scene_ID id, const Anim_Pose &pose) {
if(!pose.splines.any()) return;
if (!pose.splines.any())
return;
auto entry = spline_cache.find(id);
if(entry == spline_cache.end()) {
if (entry == spline_cache.end()) {
std::tie(entry, std::ignore) = spline_cache.insert({id, GL::Lines()});
}
GL::Lines& lines = entry->second;
GL::Lines &lines = entry->second;
lines.clear();
Vec3 prev = pose.at(0.0f).pos;
for(int i = 1; i < max_frame; i++) {
for (int i = 1; i < max_frame; i++) {
float f = (float)i;
float c = (float)(i % 20) / 19.0f;
......@@ -124,15 +131,15 @@ void Animate::make_spline(Scene_ID id, const Anim_Pose& pose) {
void Animate::camera_spline() {
auto entry = spline_cache.find(0);
if(entry == spline_cache.end()) {
if (entry == spline_cache.end()) {
std::tie(entry, std::ignore) = spline_cache.insert({0, GL::Lines()});
}
GL::Lines& lines = entry->second;
GL::Lines &lines = entry->second;
lines.clear();
Vec3 prev = anim_camera.at(0.0f).pos();
for(int i = 1; i < max_frame; i++) {
for (int i = 1; i < max_frame; i++) {
float f = (float)i;
float c = (float)(i % 20) / 19.0f;
Vec3 cur = anim_camera.at(f).pos();
......@@ -141,29 +148,30 @@ void Animate::camera_spline() {
}
}
void Animate::UIsidebar(Manager& manager, Undo& undo, Scene_Maybe obj_opt, Camera& user_cam) {
void Animate::UIsidebar(Manager &manager, Undo &undo, Scene_Maybe obj_opt, Camera &user_cam) {
if(joint_select) {
if (joint_select) {
ImGui::Text("Edit Joint");
if(ImGui::DragFloat3("Pose", joint_select->pose.data, 1.0f, 0.0f, 0.0f, "%.2f"))
if (ImGui::DragFloat3("Pose", joint_select->pose.data, 1.0f, 0.0f, 0.0f, "%.2f"))
obj_opt.value().get().get<Scene_Object>().set_pose_dirty();
if(ImGui::IsItemActivated())
if (ImGui::IsItemActivated())
old_euler = joint_select->pose;
if(ImGui::IsItemDeactivatedAfterEdit() && old_euler != joint_select->pose) {
if (ImGui::IsItemDeactivatedAfterEdit() && old_euler != joint_select->pose) {
joint_select->pose = joint_select->pose.range(0.0f, 360.0f);
undo.pose_bone(obj_opt.value().get().id(), joint_select, old_euler);
}
ImGui::Separator();
}
if(ui_camera.UI(undo, user_cam)) {
if (ui_camera.UI(undo, user_cam)) {
camera_selected = true;
if(obj_opt.has_value()) prev_selected = obj_opt.value().get().id();
if (obj_opt.has_value())
prev_selected = obj_opt.value().get().id();
}
}
void Animate::end_transform(Undo& undo, Scene_Item& obj) {
if(joint_select) {
void Animate::end_transform(Undo &undo, Scene_Item &obj) {
if (joint_select) {
undo.pose_bone(obj.id(), joint_select, old_euler);
} else {
undo.update_pose(obj.id(), old_pose);
......@@ -172,16 +180,17 @@ void Animate::end_transform(Undo& undo, Scene_Item& obj) {
old_p_to_j = Mat4::I;
}
Vec3 Animate::selected_pos(Scene_Item& item) {
if(joint_select) {
return item.pose().transform() * item.get<Scene_Object>().armature.posed_base_of(joint_select);
Vec3 Animate::selected_pos(Scene_Item &item) {
if (joint_select) {
return item.pose().transform() *
item.get<Scene_Object>().armature.posed_base_of(joint_select);
}
return item.pose().pos;
}
void Animate::apply_transform(Widgets& widgets, Scene_Item& item) {
if(joint_select) {
Scene_Object& obj = item.get<Scene_Object>();
void Animate::apply_transform(Widgets &widgets, Scene_Item &item) {
if (joint_select) {
Scene_Object &obj = item.get<Scene_Object>();
Vec3 euler = widgets.apply_action(old_pose).euler;
joint_select->pose = (old_p_to_j * Mat4::euler(euler)).to_euler();
obj.set_pose_dirty();
......@@ -190,13 +199,14 @@ void Animate::apply_transform(Widgets& widgets, Scene_Item& item) {
}
}
bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir) {
bool Animate::select(Scene &scene, Widgets &widgets, Scene_ID selected, Scene_ID id, Vec3 cam,
Vec2 spos, Vec3 dir) {
if(widgets.want_drag()) {
if (widgets.want_drag()) {
if(joint_select) {
if (joint_select) {
Scene_Object& obj = scene.get_obj(selected);
Scene_Object &obj = scene.get_obj(selected);
Vec3 base = obj.pose.transform() * obj.armature.posed_base_of(joint_select);
widgets.start_drag(base, cam, spos, dir);
......@@ -208,8 +218,8 @@ bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID
} else {
Scene_Item& item = scene.get(selected).value();
Pose& pose = item.pose();
Scene_Item &item = scene.get(selected).value();
Pose &pose = item.pose();
widgets.start_drag(pose.pos, cam, spos, dir);
old_pose = pose;
}
......@@ -218,17 +228,17 @@ bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID
}
Scene_Maybe mb = scene.get(selected);
if(mb.has_value()) {
if (mb.has_value()) {
Scene_Item& item = mb.value().get();
if(item.is<Scene_Object>()) {
Scene_Item &item = mb.value().get();
if (item.is<Scene_Object>()) {
Scene_Object& obj = item.get<Scene_Object>();
if(id >= joint_id_offset && obj.armature.has_bones()) {
Scene_Object &obj = item.get<Scene_Object>();
if (id >= joint_id_offset && obj.armature.has_bones()) {
Scene_ID j_id = id - joint_id_offset;
joint_select = obj.armature.get_joint(j_id);
if(joint_select) {
if (joint_select) {
widgets.active = Widget_Type::rotate;
}
return false;
......@@ -237,7 +247,7 @@ bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID
}
if (id >= n_Widget_IDs) {
if(id == selected) {
if (id == selected) {
joint_select = nullptr;
}
return true;
......@@ -247,7 +257,8 @@ bool Animate::select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID
return false;
}
void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe obj, Camera& user_cam) {
void Animate::timeline(Manager &manager, Undo &undo, Scene &scene, Scene_Maybe obj,
Camera &user_cam) {
// NOTE(max): this is pretty messy
// Would be good to add the ability to set per-component keyframes
......@@ -259,19 +270,19 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::Columns(2);
ImGui::SetColumnWidth(0, 150.0f);
if(!playing) {
if(ImGui::Button("Play")) {
if (!playing) {
if (ImGui::Button("Play")) {
playing = true;
last_frame = SDL_GetPerformanceCounter();
}
} else {
if(ImGui::Button("Stop")) {
if (ImGui::Button("Stop")) {
playing = false;
}
}
ImGui::SameLine();
if(ImGui::Button("Render")) {
if (ImGui::Button("Render")) {
ui_render.open();
}
ui_render.animate(scene, ui_camera, user_cam, max_frame);
......@@ -280,17 +291,17 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::Dummy({1.0f, 4.0f});
ImGui::PopStyleVar();
if(ImGui::Button("Add Frames")) {
if (ImGui::Button("Add Frames")) {
max_frame += 3 * frame_rate;
}
if(ImGui::Button("Crop End")) {
if (ImGui::Button("Crop End")) {
max_frame = current_frame + 1;
current_frame = std::min(current_frame, max_frame - 1);
scene.for_items([this](Scene_Item& item) {
scene.for_items([this](Scene_Item &item) {
item.animation().splines.crop((float)max_frame);
if(item.is<Scene_Object>())
if (item.is<Scene_Object>())
item.get<Scene_Object>().armature.crop((float)max_frame);
else if(item.is<Scene_Light>())
else if (item.is<Scene_Light>())
item.get<Scene_Light>().lanim.splines.crop((float)max_frame);
make_spline(item.id(), item.animation());
});
......@@ -303,11 +314,11 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::NextColumn();
Scene_Item* select = nullptr;
if(obj.has_value()) {
Scene_Item& item = obj.value();
Scene_Item *select = nullptr;
if (obj.has_value()) {
Scene_Item &item = obj.value();
select = &item;
if(item.id() != prev_selected) {
if (item.id() != prev_selected) {
camera_selected = false;
prev_selected = item.id();
}
......@@ -317,36 +328,37 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::Text("Keyframe:");
ImGui::SameLine();
if(ImGui::Button("Clear")) {
if(camera_selected) {
if (ImGui::Button("Clear")) {
if (camera_selected) {
anim_camera.splines.erase((float)current_frame);
camera_spline();
} else if(select) {
} else if (select) {
select->animation().splines.erase((float)current_frame);
make_spline(select->id(), select->animation());
}
}
auto set_item = [&, this](Scene_Item& item) {
if(item.is<Scene_Object>()) {
auto set_item = [&, this](Scene_Item &item) {
if (item.is<Scene_Object>()) {
undo.anim_pose_bones(item.id(), (float)current_frame);
} if(item.is<Scene_Light>()) {
}
if (item.is<Scene_Light>()) {
undo.anim_light(item.id(), (float)current_frame);
}
make_spline(item.id(), item.animation());
};
ImGui::SameLine();
if(ImGui::Button("Set")) {
if(camera_selected) {
if (ImGui::Button("Set")) {
if (camera_selected) {
undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
camera_spline();
} else if(select) {
} else if (select) {
set_item(*select);
}
}
ImGui::SameLine();
if(ImGui::Button("Set All")) {
if (ImGui::Button("Set All")) {
undo.anim_camera(anim_camera, (float)current_frame, ui_camera.get());
camera_spline();
scene.for_items(set_item);
......@@ -355,10 +367,11 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::Separator();
ImGui::Dummy({74.0f, 1.0f});
ImGui::SameLine();
if(ImGui::SliderInt("Frame", &current_frame, 0, max_frame - 1)) {
if (ImGui::SliderInt("Frame", &current_frame, 0, max_frame - 1)) {
frame_changed = true;
}
ImGui::BeginChild("Timeline", {size.x - 20.0f, size.y - 80.0f}, false, ImGuiWindowFlags_HorizontalScrollbar);
ImGui::BeginChild("Timeline", {size.x - 20.0f, size.y - 80.0f}, false,
ImGuiWindowFlags_HorizontalScrollbar);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
......@@ -372,8 +385,9 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
std::string name = "Camera";
ImVec2 sz = ImGui::CalcTextSize(name.c_str());
if(camera_selected)
ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s", name.c_str());
if (camera_selected)
ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
name.c_str());
else
ImGui::Text("%s", name.c_str());
ImGui::SameLine();
......@@ -383,53 +397,56 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
std::set<float> keys = anim_camera.splines.keys();
for(float f : keys) {
for (float f : keys) {
int frame = (int)std::round(f);
if(frame >= 0 && frame < max_frame)
if (frame >= 0 && frame < max_frame)
frames[frame] = true;
}
for(int i = 0; i < max_frame; i++) {
if(i > 0) ImGui::SameLine();
for (int i = 0; i < max_frame; i++) {
if (i > 0)
ImGui::SameLine();
ImGui::PushID(i);
bool color = false;
std::string label = "_";
if(i == current_frame) {
if (i == current_frame) {
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
color = true;
}
if(frames[i]) {
if (frames[i]) {
label = "*";
if(i != current_frame) {
if (i != current_frame) {
color = true;
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered));
ImGui::PushStyleColor(ImGuiCol_Button,
ImGui::GetColorU32(ImGuiCol_ButtonHovered));
}
}
if(ImGui::SmallButton(label.c_str())) {
if (ImGui::SmallButton(label.c_str())) {
current_frame = i;
frame_changed = true;
camera_selected = true;
}
if(color) ImGui::PopStyleColor();
if (color)
ImGui::PopStyleColor();
ImGui::PopID();
}
ImGui::PopID();
}
scene.for_items([&, this](Scene_Item& item) {
scene.for_items([&, this](Scene_Item &item) {
frames.clear();
frames.resize(max_frame);
std::string name = const_cast<const Scene_Item&>(item).name();
std::string name = const_cast<const Scene_Item &>(item).name();
name.resize(name_chars);
ImVec2 size = ImGui::CalcTextSize(name.c_str());
if(!camera_selected && select && item.id() == select->id())
ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s", name.c_str());
if (!camera_selected && select && item.id() == select->id())
ImGui::TextColored({Color::outline.x, Color::outline.y, Color::outline.z, 1.0f}, "%s",
name.c_str());
else
ImGui::Text("%s", name.c_str());
ImGui::SameLine();
......@@ -440,48 +457,51 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
Anim_Pose animation = item.animation();
std::set<float> keys = animation.splines.keys();
if(item.is<Scene_Light>()) {
if (item.is<Scene_Light>()) {
std::set<float> more_keys = item.get<Scene_Light>().lanim.splines.keys();
keys.insert(more_keys.begin(), more_keys.end());
}
if(item.is<Scene_Object>()) {
if (item.is<Scene_Object>()) {
std::set<float> more_keys = item.get<Scene_Object>().armature.keys();
keys.insert(more_keys.begin(), more_keys.end());
}
for(float f : keys) {
for (float f : keys) {
int frame = (int)std::round(f);
if(frame >= 0 && frame < max_frame)
if (frame >= 0 && frame < max_frame)
frames[frame] = true;
}
for(int i = 0; i < max_frame; i++) {
if(i > 0) ImGui::SameLine();
for (int i = 0; i < max_frame; i++) {
if (i > 0)
ImGui::SameLine();
ImGui::PushID(i);
bool color = false;
std::string label = "_";
if(i == current_frame) {
if (i == current_frame) {
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
color = true;
}
if(frames[i]) {
if (frames[i]) {
label = "*";
if(i != current_frame) {
if (i != current_frame) {
color = true;
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered));
ImGui::PushStyleColor(ImGuiCol_Button,
ImGui::GetColorU32(ImGuiCol_ButtonHovered));
}
}
if(ImGui::SmallButton(label.c_str())) {
if (ImGui::SmallButton(label.c_str())) {
current_frame = i;
frame_changed = true;
camera_selected = false;
manager.set_select(item.id());
}
if(color) ImGui::PopStyleColor();
if (color)
ImGui::PopStyleColor();
ImGui::PopID();
}
......@@ -496,27 +516,26 @@ void Animate::timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
ImGui::EndChild();
std::unordered_map<Scene_ID, GL::Lines> new_cache;
for(Scene_ID i : live_ids) {
for (Scene_ID i : live_ids) {
auto entry = spline_cache.find(i);
if(entry != spline_cache.end()) {
if (entry != spline_cache.end()) {
new_cache[i] = std::move(entry->second);
}
}
spline_cache = std::move(new_cache);
if(frame_changed) update(scene);
if (frame_changed)
update(scene);
}
Camera Animate::set_time(Scene& scene, float time) {
Camera Animate::set_time(Scene &scene, float time) {
current_frame = (int)time;
scene.for_items([time](Scene_Item& item) {
item.set_time(time);
});
scene.for_items([time](Scene_Item &item) { item.set_time(time); });
Camera cam = anim_camera.at(time);
if(anim_camera.splines.any()) {
if (anim_camera.splines.any()) {
ui_camera.load(cam.center(), cam.pos(), cam.get_ar(), cam.get_fov());
} else {
cam = ui_camera.get();
......@@ -530,42 +549,30 @@ void Animate::set(int n_frames, int fps) {
current_frame = std::min(current_frame, max_frame - 1);
}
Anim_Camera& Animate::camera() {
return anim_camera;
}
Anim_Camera &Animate::camera() { return anim_camera; }
const Anim_Camera& Animate::camera() const {
return anim_camera;
}
const Anim_Camera &Animate::camera() const { return anim_camera; }
float Animate::fps() const {
return (float)frame_rate;
}
float Animate::fps() const { return (float)frame_rate; }
int Animate::n_frames() const {
return max_frame;
}
int Animate::n_frames() const { return max_frame; }
std::string Animate::pump_output(Scene& scene) {
return ui_render.step(*this, scene);
}
std::string Animate::pump_output(Scene &scene) { return ui_render.step(*this, scene); }
void Animate::refresh(Scene& scene) {
set_time(scene, (float)current_frame);
}
void Animate::refresh(Scene &scene) { set_time(scene, (float)current_frame); }
void Animate::clear() {
anim_camera.splines.clear();
joint_select = nullptr;
}
void Animate::update(Scene& scene) {
void Animate::update(Scene &scene) {
Uint64 time = SDL_GetPerformanceCounter();
if(playing) {
if((time - last_frame) * frame_rate / SDL_GetPerformanceFrequency()) {
if(current_frame == max_frame - 1) {
if (playing) {
if ((time - last_frame) * frame_rate / SDL_GetPerformanceFrequency()) {
if (current_frame == max_frame - 1) {
playing = false;
current_frame = 0;
} else {
......@@ -575,10 +582,10 @@ void Animate::update(Scene& scene) {
}
}
if(displayed_frame != current_frame) {
if (displayed_frame != current_frame) {
set_time(scene, (float)current_frame);
displayed_frame = current_frame;
}
}
}
} // namespace Gui
#pragma once
#include <set>
#include <SDL2/SDL.h>
#include "widgets.h"
#include <SDL2/SDL.h>
#include <set>
namespace Gui {
......@@ -15,7 +15,7 @@ public:
Anim_Camera(Vec2 dim) : dim(dim) {}
Camera at(float t) const;
void set(float t, const Camera& cam);
void set(float t, const Camera &cam);
Splines<Vec3, Quat, float, float> splines;
......@@ -25,31 +25,32 @@ private:
class Animate {
public:
Animate(Vec2 screen_dim) :
ui_camera(screen_dim), anim_camera(screen_dim), ui_render(screen_dim) {}
Animate(Vec2 screen_dim)
: ui_camera(screen_dim), anim_camera(screen_dim), ui_render(screen_dim) {}
void update_dim(Vec2 dim);
bool keydown(Widgets& widgets, Undo& undo, Scene_ID sel, SDL_Keysym key);
bool keydown(Widgets &widgets, Undo &undo, Scene_ID sel, SDL_Keysym key);
Vec3 selected_pos(Scene_Item& item);
void end_transform(Undo& undo, Scene_Item& obj);
void apply_transform(Widgets& widgets, Scene_Item& obj);
bool select(Scene& scene, Widgets& widgets, Scene_ID selected, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir);
Vec3 selected_pos(Scene_Item &item);
void end_transform(Undo &undo, Scene_Item &obj);
void apply_transform(Widgets &widgets, Scene_Item &obj);
bool select(Scene &scene, Widgets &widgets, Scene_ID selected, Scene_ID id, Vec3 cam, Vec2 spos,
Vec3 dir);
void render(Scene& scene, Scene_Maybe obj_opt, Widgets& widgets, Camera& cam);
void timeline(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe obj, Camera& user_cam);
void UIsidebar(Manager& manager, Undo& undo, Scene_Maybe obj_opt, Camera& user_cam);
void render(Scene &scene, Scene_Maybe obj_opt, Widgets &widgets, Camera &cam);
void timeline(Manager &manager, Undo &undo, Scene &scene, Scene_Maybe obj, Camera &user_cam);
void UIsidebar(Manager &manager, Undo &undo, Scene_Maybe obj_opt, Camera &user_cam);
void clear();
void update(Scene& scene);
void refresh(Scene& scene);
void update(Scene &scene);
void refresh(Scene &scene);
std::string pump_output(Scene& scene);
Camera set_time(Scene& scene, float time);
std::string pump_output(Scene &scene);
Camera set_time(Scene &scene, float time);
float fps() const;
int n_frames() const;
const Anim_Camera& camera() const;
Anim_Camera& camera();
const Anim_Camera &camera() const;
Anim_Camera &camera();
void set(int n_frames, int fps);
private:
......@@ -64,7 +65,7 @@ private:
Widget_Render ui_render;
Anim_Camera anim_camera;
Joint* joint_select = nullptr;
Joint *joint_select = nullptr;
unsigned int joint_id_offset = 0;
Pose old_pose;
......@@ -75,7 +76,8 @@ private:
bool camera_selected = false;
Scene_ID prev_selected = 0;
std::unordered_map<Scene_ID, GL::Lines> spline_cache;
void make_spline(Scene_ID id, const Anim_Pose& pose);
void make_spline(Scene_ID id, const Anim_Pose &pose);
void camera_spline();
};
}
} // namespace Gui
......@@ -4,26 +4,26 @@
#include "layout.h"
#include "manager.h"
#include "../scene/undo.h"
#include "../scene/renderer.h"
#include "../scene/undo.h"
namespace Gui {
bool Layout::keydown(Widgets& widgets, SDL_Keysym key) {
return false;
}
bool Layout::keydown(Widgets &widgets, SDL_Keysym key) { return false; }
void Layout::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam) {
void Layout::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {
if(!obj_opt.has_value()) return;
Scene_Item& item = obj_opt.value();
if (!obj_opt.has_value())
return;
Scene_Item &item = obj_opt.value();
if(item.is<Scene_Light>()) {
Scene_Light& light = item.get<Scene_Light>();
if(light.is_env()) return;
if (item.is<Scene_Light>()) {
Scene_Light &light = item.get<Scene_Light>();
if (light.is_env())
return;
}
Pose& pose = item.pose();
Pose &pose = item.pose();
float scale = std::min((cam.pos() - pose.pos).norm() / 5.5f, 10.0f);
Mat4 view = cam.get_view();
......@@ -32,32 +32,26 @@ void Layout::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam) {
widgets.render(view, pose.pos, scale);
}
Scene_ID Layout::selected() const {
return selected_mesh;
}
Scene_ID Layout::selected() const { return selected_mesh; }
void Layout::clear_select() {
selected_mesh = 0;
void Layout::clear_select() { selected_mesh = 0; }
}
void Layout::set_selected(Scene_ID id) { selected_mesh = id; }
void Layout::set_selected(Scene_ID id) {
selected_mesh = id;
}
Vec3 Layout::selected_pos(Scene& scene) {
Vec3 Layout::selected_pos(Scene &scene) {
auto obj = scene.get(selected_mesh);
if(obj.has_value()) return obj->get().pose().pos;
if (obj.has_value())
return obj->get().pose().pos;
return {};
}
void Layout::select(Scene& scene, Widgets& widgets, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir) {
void Layout::select(Scene &scene, Widgets &widgets, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir) {
if (widgets.want_drag()) {
Scene_Item& item = scene.get(selected_mesh).value();
Pose& pose = item.pose();
Scene_Item &item = scene.get(selected_mesh).value();
Pose &pose = item.pose();
widgets.start_drag(pose.pos, cam, spos, dir);
old_pose = pose;
......@@ -66,22 +60,23 @@ void Layout::select(Scene& scene, Widgets& widgets, Scene_ID id, Vec3 cam, Vec2
}
}
void Layout::end_transform(Undo& undo, Scene_Item& obj) {
void Layout::end_transform(Undo &undo, Scene_Item &obj) {
undo.update_pose(obj.id(), old_pose);
old_pose = {};
}
Mode Layout::UIsidebar(Manager& manager, Undo& undo, Widgets& widgets, Scene_Maybe obj_opt) {
Mode Layout::UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe obj_opt) {
if(!obj_opt.has_value()) return Mode::layout;
if (!obj_opt.has_value())
return Mode::layout;
ImGui::Text("Object Options");
Mode ret = manager.item_options(undo, Mode::layout, obj_opt.value(), old_pose);
ImGui::Separator();
return ret;
}
void Layout::apply_transform(Scene_Item& obj, Widgets& widgets) {
void Layout::apply_transform(Scene_Item &obj, Widgets &widgets) {
obj.pose() = widgets.apply_action(old_pose);
}
}
} // namespace Gui
......@@ -3,8 +3,8 @@
#include <SDL2/SDL.h>
#include "../util/camera.h"
#include "../scene/scene.h"
#include "../util/camera.h"
#include "widgets.h"
......@@ -15,14 +15,14 @@ class Manager;
class Layout {
public:
bool keydown(Widgets& widgets, SDL_Keysym key);
void render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam);
void select(Scene& scene, Widgets& widgets, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir);
Vec3 selected_pos(Scene& scene);
bool keydown(Widgets &widgets, SDL_Keysym key);
void render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam);
void select(Scene &scene, Widgets &widgets, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir);
Vec3 selected_pos(Scene &scene);
void apply_transform(Scene_Item& obj, Widgets& widgets);
void end_transform(Undo& undo, Scene_Item& obj);
Mode UIsidebar(Manager& manager, Undo& undo, Widgets& widgets, Scene_Maybe obj);
void apply_transform(Scene_Item &obj, Widgets &widgets);
void end_transform(Undo &undo, Scene_Item &obj);
Mode UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe obj);
Scene_ID selected() const;
void clear_select();
......@@ -33,4 +33,4 @@ private:
Scene_ID selected_mesh = (Scene_ID)Widget_IDs::none;
};
}
} // namespace Gui
......@@ -9,11 +9,8 @@
namespace Gui {
Manager::Manager(Scene& scene, Vec2 dim) :
render(scene, dim),
animate(dim),
baseplane(1.0f),
window_dim(dim) {
Manager::Manager(Scene &scene, Vec2 dim)
: render(scene, dim), animate(dim), baseplane(1.0f), window_dim(dim) {
create_baseplane();
}
......@@ -24,75 +21,104 @@ void Manager::update_dim(Vec2 dim) {
}
Vec3 Color::axis(Axis a) {
switch(a) {
case Axis::X: return red;
case Axis::Y: return green;
case Axis::Z: return blue;
default: assert(false);
switch (a) {
case Axis::X:
return red;
case Axis::Y:
return green;
case Axis::Z:
return blue;
default:
assert(false);
}
return Vec3();
}
void Manager::invalidate_obj(Scene_ID id) {
if(id == layout.selected()) {
if (id == layout.selected()) {
layout.clear_select();
model.unset_mesh();
}
}
bool Manager::keydown(Undo& undo, SDL_Keysym key, Scene& scene, Camera& cam) {
bool Manager::keydown(Undo &undo, SDL_Keysym key, Scene &scene, Camera &cam) {
if(widgets.is_dragging()) return false;
if (widgets.is_dragging())
return false;
#ifdef __APPLE__
Uint16 mod = KMOD_GUI;
if(key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
if (key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
#else
Uint16 mod = KMOD_CTRL;
if(key.sym == SDLK_DELETE && layout.selected()) {
if (key.sym == SDLK_DELETE && layout.selected()) {
#endif
if(mode != Mode::model && mode != Mode::rig && mode != Mode::animate) {
if (mode != Mode::model && mode != Mode::rig && mode != Mode::animate) {
undo.del_obj(layout.selected());
return true;
}
}
if(key.mod & mod) {
switch(key.sym) {
case SDLK_d: debug_shown = true; return true;
case SDLK_e: write_scene(scene); return true;
case SDLK_o: load_scene(scene, undo, true); return true;
case SDLK_s: save_scene(scene); return true;
if (key.mod & mod) {
switch (key.sym) {
case SDLK_d:
debug_shown = true;
return true;
case SDLK_e:
write_scene(scene);
return true;
case SDLK_o:
load_scene(scene, undo, true);
return true;
case SDLK_s:
save_scene(scene);
return true;
}
}
switch(key.sym) {
case SDLK_m: widgets.active = Widget_Type::move; return true;
case SDLK_r: widgets.active = Widget_Type::rotate; return true;
case SDLK_s: widgets.active = Widget_Type::scale; return true;
switch (key.sym) {
case SDLK_m:
widgets.active = Widget_Type::move;
return true;
case SDLK_r:
widgets.active = Widget_Type::rotate;
return true;
case SDLK_s:
widgets.active = Widget_Type::scale;
return true;
case SDLK_f: {
if(mode == Mode::model || mode == Mode::rig) {
if (mode == Mode::rig) {
cam.look_at(Vec3{}, -cam.front() * cam.dist());
} else if(layout.selected()) frame(scene, cam);
} return true;
return true;
} else if (layout.selected()) {
frame(scene, cam);
return true;
}
} break;
}
switch(mode) {
case Mode::layout: return layout.keydown(widgets, key);
case Mode::model: return model.keydown(widgets, key, cam);
case Mode::render: return render.keydown(widgets, key);
case Mode::rig: return rig.keydown(widgets, undo, key);
case Mode::animate: return animate.keydown(widgets, undo, layout.selected(), key);
case Mode::simulate: break;
switch (mode) {
case Mode::layout:
return layout.keydown(widgets, key);
case Mode::model:
return model.keydown(widgets, key, cam);
case Mode::render:
return render.keydown(widgets, key);
case Mode::rig:
return rig.keydown(widgets, undo, key);
case Mode::animate:
return animate.keydown(widgets, undo, layout.selected(), key);
case Mode::simulate:
break;
}
return false;
}
void Manager::save_scene(Scene& scene) {
if(save_file.empty()) {
char* path = nullptr;
void Manager::save_scene(Scene &scene) {
if (save_file.empty()) {
char *path = nullptr;
NFD_SaveDialog("dae", nullptr, &path);
if(path) {
if (path) {
save_file = std::string(path);
free(path);
}
......@@ -101,27 +127,25 @@ void Manager::save_scene(Scene& scene) {
set_error(error);
}
void Manager::write_scene(Scene& scene) {
void Manager::write_scene(Scene &scene) {
char* path = nullptr;
char *path = nullptr;
NFD_SaveDialog("dae", nullptr, &path);
if(path) {
if (path) {
std::string error = scene.write(std::string(path), render.get_cam(), animate);
set_error(error);
free(path);
}
}
void Manager::set_file(std::string save) {
save_file = save;
}
void Manager::set_file(std::string save) { save_file = save; }
void Manager::load_scene(Scene& scene, Undo& undo, bool clear) {
void Manager::load_scene(Scene &scene, Undo &undo, bool clear) {
char* path = nullptr;
char *path = nullptr;
NFD_OpenDialog(scene_file_types, nullptr, &path);
if(path) {
if(clear) {
if (path) {
if (clear) {
save_file = std::string(path);
layout.clear_select();
model.unset_mesh();
......@@ -132,11 +156,11 @@ void Manager::load_scene(Scene& scene, Undo& undo, bool clear) {
}
}
void Manager::load_image(Scene_Light& light) {
void Manager::load_image(Scene_Light &light) {
char* path = nullptr;
char *path = nullptr;
NFD_OpenDialog(image_file_types, nullptr, &path);
if(path) {
if (path) {
std::string error = light.emissive_load(std::string(path));
set_error(error);
free(path);
......@@ -144,27 +168,29 @@ void Manager::load_image(Scene_Light& light) {
light.dirty();
}
void Manager::material_edit_gui(Undo& undo, Scene_ID obj_id, Material& material) {
void Manager::material_edit_gui(Undo &undo, Scene_ID obj_id, Material &material) {
static Material::Options old_opt;
Material::Options start_opt = material.opt;
Material::Options& opt = material.opt;
Material::Options &opt = material.opt;
bool U = false;
auto activate = [&]() {
if(ImGui::IsItemDeactivated() && old_opt != opt) U = true;
else if(ImGui::IsItemActivated()) old_opt = start_opt;
if (ImGui::IsItemDeactivated() && old_opt != opt)
U = true;
else if (ImGui::IsItemActivated())
old_opt = start_opt;
};
if(ImGui::Combo("Type", (int*)&opt.type, Material_Type_Names, (int)Material_Type::count)) {
if(start_opt != opt) {
if (ImGui::Combo("Type", (int *)&opt.type, Material_Type_Names, (int)Material_Type::count)) {
if (start_opt != opt) {
old_opt = start_opt;
U = true;
}
}
switch(opt.type) {
switch (opt.type) {
case Material_Type::lambertian: {
ImGui::ColorEdit3("Albedo", opt.albedo.data);
activate();
......@@ -176,7 +202,8 @@ void Manager::material_edit_gui(Undo& undo, Scene_ID obj_id, Material& material)
case Material_Type::refract: {
ImGui::ColorEdit3("Transmittance", opt.transmittance.data);
activate();
ImGui::DragFloat("Index of Refraction", &opt.ior, 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
ImGui::DragFloat("Index of Refraction", &opt.ior, 0.1f, 0.0f,
std::numeric_limits<float>::max(), "%.2f");
activate();
} break;
case Material_Type::glass: {
......@@ -184,35 +211,41 @@ void Manager::material_edit_gui(Undo& undo, Scene_ID obj_id, Material& material)
activate();
ImGui::ColorEdit3("Transmittance", opt.transmittance.data);
activate();
ImGui::DragFloat("Index of Refraction", &opt.ior, 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
ImGui::DragFloat("Index of Refraction", &opt.ior, 0.1f, 0.0f,
std::numeric_limits<float>::max(), "%.2f");
activate();
} break;
case Material_Type::diffuse_light: {
ImGui::ColorEdit3("Emissive", opt.emissive.data);
activate();
ImGui::DragFloat("Intensity", &opt.intensity, 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
ImGui::DragFloat("Intensity", &opt.intensity, 0.1f, 0.0f, std::numeric_limits<float>::max(),
"%.2f");
activate();
} break;
default: break;
default:
break;
}
if(U) undo.update_material(obj_id, old_opt);
if (U) {
undo.update_material(obj_id, old_opt);
}
}
Mode Manager::item_options(Undo& undo, Mode cur_mode, Scene_Item& item, Pose& old_pose) {
Mode Manager::item_options(Undo &undo, Mode cur_mode, Scene_Item &item, Pose &old_pose) {
Pose& pose = item.pose();
Pose &pose = item.pose();
auto sliders = [&](Widget_Type act, std::string label, Vec3& data, float sens) {
if(ImGui::DragFloat3(label.c_str(), data.data, sens))
auto sliders = [&](Widget_Type act, std::string label, Vec3 &data, float sens) {
if (ImGui::DragFloat3(label.c_str(), data.data, sens))
widgets.active = act;
if(ImGui::IsItemActivated())
if (ImGui::IsItemActivated())
old_pose = pose;
if(ImGui::IsItemDeactivatedAfterEdit() && old_pose != pose)
if (ImGui::IsItemDeactivatedAfterEdit() && old_pose != pose)
undo.update_pose(item.id(), old_pose);
};
if(!(item.is<Scene_Light>() && item.get<Scene_Light>().is_env()) && ImGui::CollapsingHeader("Edit Pose")) {
if (!(item.is<Scene_Light>() && item.get<Scene_Light>().is_env()) &&
ImGui::CollapsingHeader("Edit Pose")) {
ImGui::Indent();
pose.clamp_euler();
......@@ -223,70 +256,78 @@ Mode Manager::item_options(Undo& undo, Mode cur_mode, Scene_Item& item, Pose& ol
widgets.action_button(Widget_Type::move, "Move [m]", false);
widgets.action_button(Widget_Type::rotate, "Rotate [r]");
widgets.action_button(Widget_Type::scale, "Scale [s]");
if(Manager::wrap_button("Delete [del]")) {
if (Manager::wrap_button("Delete [del]")) {
undo.del_obj(item.id());
}
ImGui::Unindent();
}
if(item.is<Scene_Object>()) {
if (item.is<Scene_Object>()) {
Scene_Object& obj = item.get<Scene_Object>();
Scene_Object &obj = item.get<Scene_Object>();
static Scene_Object::Options old_opt;
Scene_Object::Options start_opt = obj.opt;
bool U = false, E = false;
auto activate = [&]() {
if(ImGui::IsItemActive()) E = true;
if(ImGui::IsItemDeactivated() && old_opt != obj.opt) U = true;
else if(ImGui::IsItemActivated()) old_opt = start_opt;
if (ImGui::IsItemActive())
E = true;
if (ImGui::IsItemDeactivated() && old_opt != obj.opt)
U = true;
else if (ImGui::IsItemActivated())
old_opt = start_opt;
};
auto update = [&]() {
obj.set_mesh_dirty();
undo.update_object(obj.id(), start_opt);
};
if((obj.is_editable() || obj.is_shape()) && ImGui::CollapsingHeader("Edit Mesh")) {
if ((obj.is_editable() || obj.is_shape()) && ImGui::CollapsingHeader("Edit Mesh")) {
ImGui::Indent();
if(obj.is_editable()) {
if(ImGui::Button("Edit Mesh##button")) {
if (obj.is_editable()) {
if (ImGui::Button("Edit Mesh##button")) {
cur_mode = Mode::model;
}
ImGui::SameLine();
if(ImGui::Button("Flip Normals")) {
if (ImGui::Button("Flip Normals")) {
obj.get_mesh().flip();
}
if(ImGui::Checkbox("Smooth Normals", &obj.opt.smooth_normals)) {
if (ImGui::Checkbox("Smooth Normals", &obj.opt.smooth_normals)) {
update();
}
if(ImGui::Checkbox("Show Wireframe", &obj.opt.wireframe)) update();
if (ImGui::Checkbox("Show Wireframe", &obj.opt.wireframe))
update();
}
if(ImGui::Combo("Use Implicit Shape", (int*)&obj.opt.shape_type, PT::Shape_Type_Names, (int)PT::Shape_Type::count)) {
if(obj.opt.shape_type == PT::Shape_Type::none)
if (ImGui::Combo("Use Implicit Shape", (int *)&obj.opt.shape_type, PT::Shape_Type_Names,
(int)PT::Shape_Type::count)) {
if (obj.opt.shape_type == PT::Shape_Type::none)
obj.try_make_editable(start_opt.shape_type);
update();
}
if(obj.opt.shape_type == PT::Shape_Type::sphere) {
ImGui::DragFloat("Radius", &obj.opt.shape.get<PT::Sphere>().radius, 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
if (obj.opt.shape_type == PT::Shape_Type::sphere) {
ImGui::DragFloat("Radius", &obj.opt.shape.get<PT::Sphere>().radius, 0.1f, 0.0f,
std::numeric_limits<float>::max(), "%.2f");
activate();
}
ImGui::Unindent();
if(E) obj.set_mesh_dirty();
if(U) undo.update_object(obj.id(), old_opt);
if (E)
obj.set_mesh_dirty();
if (U)
undo.update_object(obj.id(), old_opt);
}
if(ImGui::CollapsingHeader("Edit Material")) {
if (ImGui::CollapsingHeader("Edit Material")) {
ImGui::Indent();
material_edit_gui(undo, obj.id(), obj.material);
ImGui::Unindent();
}
} else if(item.is<Scene_Light>()) {
} else if (item.is<Scene_Light>()) {
Scene_Light& light = item.get<Scene_Light>();
Scene_Light &light = item.get<Scene_Light>();
if(ImGui::CollapsingHeader("Edit Light")) {
if (ImGui::CollapsingHeader("Edit Light")) {
ImGui::Indent();
light_edit_gui(undo, light);
ImGui::Unindent();
......@@ -295,7 +336,7 @@ Mode Manager::item_options(Undo& undo, Mode cur_mode, Scene_Item& item, Pose& ol
return cur_mode;
}
void Manager::light_edit_gui(Undo& undo, Scene_Light& light) {
void Manager::light_edit_gui(Undo &undo, Scene_Light &light) {
static Scene_Light::Options old_opt;
Scene_Light::Options start_opt = light.opt;
......@@ -303,45 +344,49 @@ void Manager::light_edit_gui(Undo& undo, Scene_Light& light) {
bool E = false, U = false;
auto activate = [&]() {
if(ImGui::IsItemActive()) E = true;
if(ImGui::IsItemDeactivated() && old_opt != light.opt) U = true;
else if(ImGui::IsItemActivated()) old_opt = start_opt;
if (ImGui::IsItemActive())
E = true;
if (ImGui::IsItemDeactivated() && old_opt != light.opt)
U = true;
else if (ImGui::IsItemActivated())
old_opt = start_opt;
};
if(ImGui::Combo("Type", (int*)&light.opt.type, Light_Type_Names, (int)Light_Type::count)) {
if(start_opt != light.opt) {
if (ImGui::Combo("Type", (int *)&light.opt.type, Light_Type_Names, (int)Light_Type::count)) {
if (start_opt != light.opt) {
old_opt = start_opt;
U = true;
E = true;
}
}
if(!(light.opt.type == Light_Type::sphere && light.opt.has_emissive_map)) {
if (!(light.opt.type == Light_Type::sphere && light.opt.has_emissive_map)) {
ImGui::ColorEdit3("Spectrum", light.opt.spectrum.data);
activate();
ImGui::DragFloat("Intensity", &light.opt.intensity, 0.1f, 0.0f, std::numeric_limits<float>::max(), "%.2f");
ImGui::DragFloat("Intensity", &light.opt.intensity, 0.1f, 0.0f,
std::numeric_limits<float>::max(), "%.2f");
activate();
}
switch(light.opt.type) {
switch (light.opt.type) {
case Light_Type::sphere: {
if(light.opt.has_emissive_map) {
if (light.opt.has_emissive_map) {
float x = ImGui::GetContentRegionAvail().x;
ImGui::Image((ImTextureID)(long long)light.emissive_texture().get_id(), {x, x / 2.0f});
if(ImGui::Button("Change Map")) {
if (ImGui::Button("Change Map")) {
load_image(light);
}
ImGui::SameLine();
if(ImGui::Button("Remove Map")) {
if (ImGui::Button("Remove Map")) {
light.emissive_clear();
old_opt = start_opt;
U = true;
}
} else {
if(ImGui::Button("Use Texture Map")) {
if (ImGui::Button("Use Texture Map")) {
load_image(light);
if(light.opt.has_emissive_map) {
if (light.opt.has_emissive_map) {
old_opt = start_opt;
U = true;
}
......@@ -353,70 +398,78 @@ void Manager::light_edit_gui(Undo& undo, Scene_Light& light) {
activate();
} break;
case Light_Type::rectangle: {
ImGui::DragFloat2("Size", light.opt.size.data, 0.1f, 0.0f, std::numeric_limits<float>::max());
ImGui::DragFloat2("Size", light.opt.size.data, 0.1f, 0.0f,
std::numeric_limits<float>::max());
activate();
} break;
default: break;
default:
break;
}
if(E) light.dirty();
if(U) undo.update_light(light.id(), old_opt);
if (E)
light.dirty();
if (U)
undo.update_light(light.id(), old_opt);
}
bool Manager::wrap_button(std::string label) {
ImGuiStyle& style = ImGui::GetStyle();
ImGuiStyle &style = ImGui::GetStyle();
float available_w = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
float last_w = ImGui::GetItemRectMax().x;
float next_w = last_w + style.ItemSpacing.x + ImGui::CalcTextSize(label.c_str()).x + style.FramePadding.x * 2;
float next_w = last_w + style.ItemSpacing.x + ImGui::CalcTextSize(label.c_str()).x +
style.FramePadding.x * 2;
if (next_w < available_w)
ImGui::SameLine();
return ImGui::Button(label.c_str());
};
void Manager::frame(Scene& scene, Camera& cam) {
if(!layout.selected()) return;
void Manager::frame(Scene &scene, Camera &cam) {
if (!layout.selected())
return;
Vec3 center = layout.selected_pos(scene);
Vec3 dir = cam.front() * cam.dist();
cam.look_at(center, center - dir);
}
void Manager::UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam) {
void Manager::UIsidebar(Scene &scene, Undo &undo, float menu_height, Camera &cam) {
const ImGuiWindowFlags flags = ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing;
const ImGuiWindowFlags flags =
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing;
static float anim_height = 0.0f;
ImGui::SetNextWindowPos({0.0, menu_height});
float h_cut = menu_height + (mode == Mode::animate ? anim_height : 0.0f);
ImGui::SetNextWindowSizeConstraints(
{window_dim.x / 4.75f, window_dim.y - h_cut},
ImGui::SetNextWindowSizeConstraints({window_dim.x / 4.75f, window_dim.y - h_cut},
{window_dim.x, window_dim.y - h_cut});
ImGui::Begin("Menu", nullptr, flags);
if(mode == Mode::layout) {
if (mode == Mode::layout) {
ImGui::Text("Edit Scene");
if(ImGui::Button("Import New Scene")) load_scene(scene, undo, true);
if(wrap_button("Export Scene")) write_scene(scene);
if(ImGui::Button("Import Objects")) load_scene(scene, undo, false);
if(wrap_button("New Object")) {
if (ImGui::Button("Import New Scene"))
load_scene(scene, undo, true);
if (wrap_button("Export Scene"))
write_scene(scene);
if (ImGui::Button("Import Objects"))
load_scene(scene, undo, false);
if (wrap_button("New Object")) {
new_obj_window = true;
new_obj_focus = true;
}
if(wrap_button("New Light")) {
if (wrap_button("New Light")) {
new_light_window = true;
new_light_focus = true;
}
}
if(!scene.empty()) {
if (!scene.empty()) {
ImGui::Separator();
ImGui::Text("Select an Object");
}
scene.for_items([&](Scene_Item& obj) {
if((mode == Mode::model || mode == Mode::rig) &&
scene.for_items([&](Scene_Item &obj) {
if ((mode == Mode::model || mode == Mode::rig) &&
(!obj.is<Scene_Object>() || !obj.get<Scene_Object>().is_editable()))
return;
......@@ -427,17 +480,18 @@ void Manager::UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam
bool is_selected = obj.id() == layout.selected();
ImGui::SameLine();
if(ImGui::Checkbox("##selected", &is_selected)) {
if(is_selected) layout.set_selected(obj.id());
else layout.clear_select();
if (ImGui::Checkbox("##selected", &is_selected)) {
if (is_selected)
layout.set_selected(obj.id());
else
layout.clear_select();
}
ImGui::PopID();
});
if(!scene.empty()) {
if (!scene.empty()) {
if(mode != Mode::model && mode != Mode::rig &&
layout.selected() &&
if (mode != Mode::model && mode != Mode::rig && layout.selected() &&
ImGui::Button("Center Object [f]")) {
frame(scene, cam);
}
......@@ -447,7 +501,7 @@ void Manager::UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam
auto selected = scene.get(layout.selected());
switch(mode) {
switch (mode) {
case Mode::layout: {
mode = layout.UIsidebar(*this, undo, widgets, selected);
} break;
......@@ -466,7 +520,7 @@ void Manager::UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam
} break;
case Mode::animate: {
if(layout.UIsidebar(*this, undo, widgets, selected) == Mode::model)
if (layout.UIsidebar(*this, undo, widgets, selected) == Mode::model)
mode = Mode::model;
animate.UIsidebar(*this, undo, selected, cam);
ImGui::End();
......@@ -478,30 +532,31 @@ void Manager::UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam
animate.timeline(*this, undo, scene, selected, cam);
} break;
default: break;
default:
break;
}
ImGui::End();
if(mode == Mode::layout) {
if(new_obj_focus) {
if (mode == Mode::layout) {
if (new_obj_focus) {
ImGui::SetNextWindowFocus();
new_obj_focus = false;
}
if(new_obj_window) {
if (new_obj_window) {
UInew_obj(undo);
}
if(new_light_focus) {
if (new_light_focus) {
ImGui::SetNextWindowFocus();
new_light_focus = false;
}
if(new_light_window) {
if (new_light_window) {
UInew_light(scene, undo);
}
}
}
void Manager::UInew_light(Scene& scene, Undo& undo) {
void Manager::UInew_light(Scene &scene, Undo &undo) {
unsigned int idx = 0;
......@@ -519,13 +574,13 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::Text("Light Objects");
if(ImGui::CollapsingHeader("Directional Light")) {
if (ImGui::CollapsingHeader("Directional Light")) {
ImGui::PushID(idx++);
static Vec3 direction = Vec3(0.0f, -1.0f, 0.0f);
ImGui::InputFloat3("Direction", direction.data, "%.2f");
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::directional, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -537,9 +592,9 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Point Light")) {
if (ImGui::CollapsingHeader("Point Light")) {
ImGui::PushID(idx++);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::point, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -549,7 +604,7 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Spot Light")) {
if (ImGui::CollapsingHeader("Spot Light")) {
ImGui::PushID(idx++);
static Vec3 direction = Vec3(0.0f, -1.0f, 0.0f);
static Vec2 angles = Vec2(30.0f, 35.0f);
......@@ -558,7 +613,7 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::InputFloat2("Angle Cutoffs", angles.data, "%.2f");
angles = angles.range(0.0f, 360.0f);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::spot, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -571,14 +626,14 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Area Light (Rectangle)")) {
if (ImGui::CollapsingHeader("Area Light (Rectangle)")) {
ImGui::PushID(idx++);
static Vec2 size = Vec2(1.0f);
ImGui::InputFloat2("Size", size.data, "%.2f");
size = clamp(size, Vec2(0.0f), size);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::rectangle, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -590,14 +645,14 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(!scene.has_env_light()) {
if (!scene.has_env_light()) {
ImGui::Separator();
ImGui::Text("Environment Lights (up to one)");
if(ImGui::CollapsingHeader("Hemisphere Light")) {
if (ImGui::CollapsingHeader("Hemisphere Light")) {
ImGui::PushID(idx++);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::hemisphere, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -608,10 +663,9 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Sphere Light")) {
if (ImGui::CollapsingHeader("Sphere Light")) {
ImGui::PushID(idx++);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::sphere, scene.reserve_id(), {});
light.opt.spectrum = color;
light.opt.intensity = intensity;
......@@ -622,9 +676,9 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::PopID();
}
if(ImGui::CollapsingHeader("Environment Map")) {
if (ImGui::CollapsingHeader("Environment Map")) {
ImGui::PushID(idx++);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
Scene_Light light(Light_Type::sphere, scene.reserve_id(), {});
load_image(light);
undo.add_light(std::move(light));
......@@ -637,52 +691,55 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui::End();
}
void Manager::UInew_obj(Undo& undo) {
void Manager::UInew_obj(Undo &undo) {
unsigned int idx = 0;
auto add_mesh = [&, this](std::string n, GL::Mesh&& mesh, bool flip = false) {
auto add_mesh = [&, this](std::string n, GL::Mesh &&mesh, bool flip = false) {
Halfedge_Mesh hm;
hm.from_mesh(mesh);
if(flip) hm.flip();
if (flip)
hm.flip();
undo.add_obj(std::move(hm), n);
new_obj_window = false;
};
ImGui::Begin("New Object", &new_obj_window, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize);
ImGui::Begin("New Object", &new_obj_window,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize);
if(ImGui::CollapsingHeader("Cube")) {
if (ImGui::CollapsingHeader("Cube")) {
ImGui::PushID(idx++);
static float R = 1.0f;
ImGui::SliderFloat("Side Length", &R, 0.01f, 10.0f, "%.2f");
if(ImGui::Button("Add")) {
add_mesh("Cube", Util::cube_mesh(R/2.0f), true);
if (ImGui::Button("Add")) {
add_mesh("Cube", Util::cube_mesh(R / 2.0f), true);
}
ImGui::PopID();
}
ImGui::Separator();
if(ImGui::CollapsingHeader("Square")) {
if (ImGui::CollapsingHeader("Square")) {
ImGui::PushID(idx++);
static float R = 1.0f;
ImGui::SliderFloat("Side Length", &R, 0.01f, 10.0f, "%.2f");
if(ImGui::Button("Add")) {
add_mesh("Square", Util::square_mesh(R/2.0f));
if (ImGui::Button("Add")) {
add_mesh("Square", Util::square_mesh(R / 2.0f));
}
ImGui::PopID();
}
ImGui::Separator();
if(ImGui::CollapsingHeader("Cylinder")) {
if (ImGui::CollapsingHeader("Cylinder")) {
ImGui::PushID(idx++);
static float R = 0.5f, H = 2.0f;
static int S = 12;
ImGui::SliderFloat("Radius", &R, 0.01f, 10.0f, "%.2f");
ImGui::SliderFloat("Height", &H, 0.01f, 10.0f, "%.2f");
ImGui::SliderInt("Sides", &S, 3, 100);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
add_mesh("Cylinder", Util::cyl_mesh(R, H, S));
}
ImGui::PopID();
......@@ -708,12 +765,12 @@ void Manager::UInew_obj(Undo& undo) {
ImGui::Separator();
#endif
if(ImGui::CollapsingHeader("Sphere")) {
if (ImGui::CollapsingHeader("Sphere")) {
ImGui::PushID(idx++);
static float R = 1.0f;
ImGui::SliderFloat("Radius", &R, 0.01f, 10.0f, "%.2f");
if(ImGui::Button("Add")) {
Scene_Object& obj = undo.add_obj(GL::Mesh(), "Sphere");
if (ImGui::Button("Add")) {
Scene_Object &obj = undo.add_obj(GL::Mesh(), "Sphere");
obj.opt.shape_type = PT::Shape_Type::sphere;
obj.opt.shape = PT::Shape(PT::Sphere(R));
obj.set_mesh_dirty();
......@@ -724,7 +781,7 @@ void Manager::UInew_obj(Undo& undo) {
ImGui::Separator();
if(ImGui::CollapsingHeader("Cone")) {
if (ImGui::CollapsingHeader("Cone")) {
ImGui::PushID(idx++);
static float BR = 1.0f, TR = 0.1f, H = 1.0f;
static int S = 12;
......@@ -732,7 +789,7 @@ void Manager::UInew_obj(Undo& undo) {
ImGui::SliderFloat("Top Radius", &TR, 0.01f, 10.0f, "%.2f");
ImGui::SliderFloat("Height", &H, 0.01f, 10.0f, "%.2f");
ImGui::SliderInt("Sides", &S, 3, 100);
if(ImGui::Button("Add")) {
if (ImGui::Button("Add")) {
add_mesh("Cone", Util::cone_mesh(BR, TR, H, S));
}
ImGui::PopID();
......@@ -741,49 +798,46 @@ void Manager::UInew_obj(Undo& undo) {
}
void Manager::set_error(std::string msg) {
if(msg.empty()) return;
if (msg.empty())
return;
error_msg = msg;
error_shown = true;
}
void Manager::render_ui(Scene& scene, Undo& undo, Camera& cam) {
void Manager::render_ui(Scene &scene, Undo &undo, Camera &cam) {
float height = UImenu(scene, undo);
UIsidebar(scene, undo, height, cam);
UIerror();
UIstudent();
if(settings_shown) UIsettings();
if (settings_shown)
UIsettings();
set_error(animate.pump_output(scene));
}
Rig& Manager::get_rig() {
return rig;
}
Rig &Manager::get_rig() { return rig; }
Render& Manager::get_render() {
return render;
}
Render &Manager::get_render() { return render; }
Animate& Manager::get_animate() {
return animate;
}
Animate &Manager::get_animate() { return animate; }
const Settings& Manager::get_settings() const {
return settings;
}
const Settings &Manager::get_settings() const { return settings; }
void Manager::UIsettings() {
ImGui::Begin("Preferences", &settings_shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
ImGui::Begin("Preferences", &settings_shown,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
ImGui::InputInt("Multisampling", &settings.samples);
int max = GL::max_msaa();
if(settings.samples < 1) settings.samples = 1;
if(settings.samples > max) settings.samples = max;
if (settings.samples < 1)
settings.samples = 1;
if (settings.samples > max)
settings.samples = max;
if(ImGui::Button("Apply")) {
if (ImGui::Button("Apply")) {
Renderer::get().set_samples(settings.samples);
}
......@@ -795,7 +849,8 @@ void Manager::UIsettings() {
}
void Manager::UIstudent() {
if(!debug_shown) return;
if (!debug_shown)
return;
ImGui::Begin("Debug Data", &debug_shown, ImGuiWindowFlags_NoSavedSettings);
#ifndef SCOTTY3D_BUILD_REF
student_debug_ui();
......@@ -804,66 +859,79 @@ void Manager::UIstudent() {
}
void Manager::UIerror() {
if(!error_shown) return;
if (!error_shown)
return;
Vec2 center = window_dim / 2.0f;
ImGui::SetNextWindowPos(Vec2{center.x, center.y}, 0, Vec2{0.5f, 0.5f});
ImGui::Begin("Errors", &error_shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize);
if(!error_msg.empty()) ImGui::Text("%s", error_msg.c_str());
if(ImGui::Button("Close")) {
ImGui::Begin("Errors", &error_shown,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoResize);
if (!error_msg.empty())
ImGui::Text("%s", error_msg.c_str());
if (ImGui::Button("Close")) {
error_shown = false;
}
ImGui::End();
}
float Manager::UImenu(Scene& scene, Undo& undo) {
float Manager::UImenu(Scene &scene, Undo &undo) {
auto mode_button = [this](Gui::Mode m, std::string name) -> bool {
bool active = m == mode;
if(active) ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
if (active)
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
bool clicked = ImGui::Button(name.c_str());
if(active) ImGui::PopStyleColor();
if (active)
ImGui::PopStyleColor();
return clicked;
};
float menu_height = 0.0f;
if(ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMainMenuBar()) {
if(ImGui::BeginMenu("File")) {
if (ImGui::BeginMenu("File")) {
if(ImGui::MenuItem("Open Scene (Ctrl+o)")) load_scene(scene, undo, true);
if(ImGui::MenuItem("Export Scene (Ctrl+e)")) write_scene(scene);
if(ImGui::MenuItem("Save Scene (Ctrl+s)")) save_scene(scene);
if (ImGui::MenuItem("Open Scene (Ctrl+o)"))
load_scene(scene, undo, true);
if (ImGui::MenuItem("Export Scene (Ctrl+e)"))
write_scene(scene);
if (ImGui::MenuItem("Save Scene (Ctrl+s)"))
save_scene(scene);
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Edit")) {
if (ImGui::BeginMenu("Edit")) {
if(ImGui::MenuItem("Undo (Ctrl+z)")) undo.undo();
if(ImGui::MenuItem("Redo (Ctrl+y)")) undo.redo();
if(ImGui::MenuItem("Edit Debug Data (Ctrl+d)")) debug_shown = true;
if(ImGui::MenuItem("Scotty3D Settings")) settings_shown = true;
if (ImGui::MenuItem("Undo (Ctrl+z)"))
undo.undo();
if (ImGui::MenuItem("Redo (Ctrl+y)"))
undo.redo();
if (ImGui::MenuItem("Edit Debug Data (Ctrl+d)"))
debug_shown = true;
if (ImGui::MenuItem("Scotty3D Settings"))
settings_shown = true;
ImGui::EndMenu();
}
if(mode_button(Gui::Mode::layout, "Layout")) {
if (mode_button(Gui::Mode::layout, "Layout")) {
mode = Gui::Mode::layout;
if(widgets.active == Widget_Type::bevel)
if (widgets.active == Widget_Type::bevel)
widgets.active = Widget_Type::move;
}
if(mode_button(Gui::Mode::model, "Model"))
if (mode_button(Gui::Mode::model, "Model"))
mode = Gui::Mode::model;
if(mode_button(Gui::Mode::render, "Render"))
if (mode_button(Gui::Mode::render, "Render"))
mode = Gui::Mode::render;
if(mode_button(Gui::Mode::rig, "Rig"))
if (mode_button(Gui::Mode::rig, "Rig"))
mode = Gui::Mode::rig;
if(mode_button(Gui::Mode::animate, "Animate"))
if (mode_button(Gui::Mode::animate, "Animate"))
mode = Gui::Mode::animate;
if(mode_button(Gui::Mode::simulate, "Simulate"))
if (mode_button(Gui::Mode::simulate, "Simulate"))
mode = Gui::Mode::simulate;
ImGui::Text("FPS: %.0f", ImGui::GetIO().Framerate);
......@@ -878,8 +946,8 @@ float Manager::UImenu(Scene& scene, Undo& undo) {
void Manager::create_baseplane() {
const int R = 25;
for(int i = -R; i <= R; i++) {
if(i == 0) {
for (int i = -R; i <= R; i++) {
if (i == 0) {
baseplane.add(Vec3{-R, 0, i}, Vec3{R, 0, i}, Color::red);
baseplane.add(Vec3{i, 0, -R}, Vec3{i, 0, R}, Color::blue);
continue;
......@@ -889,13 +957,14 @@ void Manager::create_baseplane() {
}
}
void Manager::end_drag(Undo& undo, Scene& scene) {
void Manager::end_drag(Undo &undo, Scene &scene) {
if(!widgets.is_dragging()) return;
if (!widgets.is_dragging())
return;
Scene_Item& obj = *scene.get(layout.selected());
Scene_Item &obj = *scene.get(layout.selected());
switch(mode) {
switch (mode) {
case Mode::animate: {
animate.end_transform(undo, obj);
} break;
......@@ -905,29 +974,31 @@ void Manager::end_drag(Undo& undo, Scene& scene) {
layout.end_transform(undo, obj);
} break;
case Mode::model: {
if(obj.is<Scene_Object>()) {
if (obj.is<Scene_Object>()) {
std::string err = model.end_transform(widgets, undo, obj.get<Scene_Object>());
set_error(err);
}
} break;
case Mode::rig: {
if(obj.is<Scene_Object>()) {
if (obj.is<Scene_Object>()) {
rig.end_transform(widgets, undo, obj.get<Scene_Object>());
}
} break;
default: break;
default:
break;
}
widgets.end_drag();
}
void Manager::drag_to(Scene& scene, Vec3 cam, Vec2 spos, Vec3 dir) {
void Manager::drag_to(Scene &scene, Vec3 cam, Vec2 spos, Vec3 dir) {
if(!widgets.is_dragging()) return;
Scene_Item& obj = *scene.get(layout.selected());
if (!widgets.is_dragging())
return;
Scene_Item &obj = *scene.get(layout.selected());
Vec3 pos;
switch(mode) {
switch (mode) {
case Mode::animate: {
pos = animate.selected_pos(obj);
} break;
......@@ -941,12 +1012,13 @@ void Manager::drag_to(Scene& scene, Vec3 cam, Vec2 spos, Vec3 dir) {
case Mode::rig: {
pos = rig.selected_pos();
} break;
default: break;
default:
break;
}
widgets.drag_to(pos, cam, spos, dir, mode == Mode::model);
switch(mode) {
switch (mode) {
case Mode::animate: {
animate.apply_transform(widgets, obj);
} break;
......@@ -960,15 +1032,16 @@ void Manager::drag_to(Scene& scene, Vec3 cam, Vec2 spos, Vec3 dir) {
case Mode::rig: {
rig.apply_transform(widgets);
} break;
default: break;
default:
break;
}
}
bool Manager::select(Scene& scene, Undo& undo, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir) {
bool Manager::select(Scene &scene, Undo &undo, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir) {
widgets.select(id);
switch(mode) {
switch (mode) {
case Mode::render:
case Mode::layout: {
layout.select(scene, widgets, id, cam, spos, dir);
......@@ -984,11 +1057,12 @@ bool Manager::select(Scene& scene, Undo& undo, Scene_ID id, Vec3 cam, Vec2 spos,
} break;
case Mode::animate: {
if(animate.select(scene, widgets, layout.selected(), id, cam, spos, dir))
if (animate.select(scene, widgets, layout.selected(), id, cam, spos, dir))
layout.set_selected(id);
} break;
default: break;
default:
break;
}
return widgets.is_dragging();
......@@ -1000,33 +1074,40 @@ void Manager::set_select(Scene_ID id) {
}
void Manager::clear_select() {
switch(mode) {
switch (mode) {
case Mode::render:
case Mode::animate:
case Mode::layout: layout.clear_select(); break;
case Mode::rig: rig.clear_select(); break;
case Mode::model: model.clear_select(); break;
default: break;
case Mode::layout:
layout.clear_select();
break;
case Mode::rig:
rig.clear_select();
break;
case Mode::model:
model.clear_select();
break;
default:
break;
}
}
void Manager::render_3d(Scene& scene, Camera& camera) {
void Manager::render_3d(Scene &scene, Camera &camera) {
Mat4 view = camera.get_view();
animate.update(scene);
if(mode == Mode::layout || mode == Mode::render || mode == Mode::animate) {
scene.for_items([&, this](Scene_Item& item) {
if (mode == Mode::layout || mode == Mode::render || mode == Mode::animate) {
scene.for_items([&, this](Scene_Item &item) {
bool render = item.id() != layout.selected();
if(item.is<Scene_Light>()) {
const Scene_Light& light = item.get<Scene_Light>();
if(light.opt.type == Light_Type::sphere || light.opt.type == Light_Type::hemisphere)
if (item.is<Scene_Light>()) {
const Scene_Light &light = item.get<Scene_Light>();
if (light.opt.type == Light_Type::sphere ||
light.opt.type == Light_Type::hemisphere)
render = true;
}
if(render) {
if (render) {
item.render(view);
}
});
......@@ -1035,7 +1116,7 @@ void Manager::render_3d(Scene& scene, Camera& camera) {
Renderer::get().lines(baseplane, view, Mat4::I, 1.0f);
auto selected = scene.get(layout.selected());
switch(mode) {
switch (mode) {
case Mode::layout: {
layout.render(selected, widgets, camera);
} break;
......@@ -1056,16 +1137,17 @@ void Manager::render_3d(Scene& scene, Camera& camera) {
animate.render(scene, selected, widgets, camera);
} break;
default: break;
default:
break;
}
}
void Manager::hover(Vec2 pixel, Vec3 cam, Vec2 spos, Vec3 dir) {
if(mode == Mode::model) {
if (mode == Mode::model) {
model.set_hover(Renderer::get().read_id(pixel));
} else if(mode == Mode::rig) {
} else if (mode == Mode::rig) {
rig.hover(cam, spos, dir);
}
}
}
} // namespace Gui
......@@ -11,15 +11,15 @@
#include "../lib/mathlib.h"
#include "../util/camera.h"
#include "../scene/undo.h"
#include "../scene/scene.h"
#include "../scene/undo.h"
#include "widgets.h"
#include "animate.h"
#include "layout.h"
#include "model.h"
#include "render.h"
#include "rig.h"
#include "animate.h"
#include "widgets.h"
namespace Gui {
......@@ -27,16 +27,9 @@ struct Settings {
int samples = 4;
};
enum class Mode {
layout,
model,
render,
rig,
animate,
simulate
};
enum class Mode { layout, model, render, rig, animate, simulate };
#define RGBv(n,r,g,b) static inline const Vec3 n = Vec3(r##.0f,g##.0f,b##.0f) / 255.0f;
#define RGBv(n, r, g, b) static inline const Vec3 n = Vec3(r##.0f, g##.0f, b##.0f) / 255.0f;
struct Color {
RGBv(black, 0, 0, 0);
RGBv(outline, 242, 153, 41);
......@@ -52,35 +45,35 @@ struct Color {
class Manager {
public:
Manager(Scene& scene, Vec2 window_dim);
Manager(Scene &scene, Vec2 window_dim);
// Input
void update_dim(Vec2 dim);
bool keydown(Undo& undo, SDL_Keysym key, Scene& scene, Camera& cam);
bool keydown(Undo &undo, SDL_Keysym key, Scene &scene, Camera &cam);
Rig& get_rig();
Render& get_render();
Animate& get_animate();
const Settings& get_settings() const;
Rig &get_rig();
Render &get_render();
Animate &get_animate();
const Settings &get_settings() const;
void set_file(std::string save);
// Object interaction
bool select(Scene& scene, Undo& undo, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir);
bool select(Scene &scene, Undo &undo, Scene_ID id, Vec3 cam, Vec2 spos, Vec3 dir);
void clear_select();
void set_select(Scene_ID id);
void hover(Vec2 pixel, Vec3 cam, Vec2 spos, Vec3 dir);
void drag_to(Scene& scene, Vec3 cam, Vec2 spos, Vec3 dir);
void end_drag(Undo& undo, Scene& scene);
void drag_to(Scene &scene, Vec3 cam, Vec2 spos, Vec3 dir);
void end_drag(Undo &undo, Scene &scene);
void render_3d(Scene& scene, Camera& camera);
void render_ui(Scene& scene, Undo& undo, Camera& camera);
void render_3d(Scene &scene, Camera &camera);
void render_ui(Scene &scene, Undo &undo, Camera &camera);
void set_error(std::string msg);
void invalidate_obj(Scene_ID id);
void light_edit_gui(Undo& undo, Scene_Light& light);
void material_edit_gui(Undo& undo, Scene_ID id, Material& material);
Mode item_options(Undo& undo, Mode cur_mode, Scene_Item& item, Pose& old_pose);
void light_edit_gui(Undo &undo, Scene_Light &light);
void material_edit_gui(Undo &undo, Scene_ID id, Material &material);
Mode item_options(Undo &undo, Mode cur_mode, Scene_Item &item, Pose &old_pose);
static bool wrap_button(std::string label);
......@@ -88,20 +81,20 @@ private:
void UIerror();
void UIstudent();
void UIsettings();
void UInew_obj(Undo& undo);
void UInew_light(Scene& scene, Undo& undo);
float UImenu(Scene& scene, Undo& undo);
void UIsidebar(Scene& scene, Undo& undo, float menu_height, Camera& cam);
void load_image(Scene_Light& image);
void frame(Scene& scene, Camera& cam);
void UInew_obj(Undo &undo);
void UInew_light(Scene &scene, Undo &undo);
float UImenu(Scene &scene, Undo &undo);
void UIsidebar(Scene &scene, Undo &undo, float menu_height, Camera &cam);
void load_image(Scene_Light &image);
void frame(Scene &scene, Camera &cam);
static inline const char* scene_file_types = "dae,obj,fbx,glb,gltf,3ds,blend,stl,ply";
static inline const char* image_file_types = "exr,jpg,jpeg,png,tga,bmp,psd,gif";
static inline const char *scene_file_types = "dae,obj,fbx,glb,gltf,3ds,blend,stl,ply";
static inline const char *image_file_types = "exr,jpg,jpeg,png,tga,bmp,psd,gif";
void render_selected(Scene_Object& obj);
void load_scene(Scene& scene, Undo& undo, bool clear);
void write_scene(Scene& scene);
void save_scene(Scene& scene);
void render_selected(Scene_Object &obj);
void load_scene(Scene &scene, Undo &undo, bool clear);
void write_scene(Scene &scene);
void save_scene(Scene &scene);
Mode mode = Mode::layout;
Layout layout;
......@@ -124,4 +117,4 @@ private:
Vec2 window_dim;
};
};
}; // namespace Gui
#include <imgui/imgui.h>
#include <algorithm>
#include <imgui/imgui.h>
#include "manager.h"
#include "model.h"
#include "widgets.h"
#include "manager.h"
#include "../scene/undo.h"
#include "../scene/renderer.h"
#include "../geometry/util.h"
#include "../scene/renderer.h"
#include "../scene/undo.h"
namespace Gui {
Model::Model() :
spheres(Util::sphere_mesh(0.05f, 1)),
cylinders(Util::cyl_mesh(0.05f, 1.0f)),
arrows(Util::arrow_mesh(0.05f, 0.1f, 1.0f))
{}
Model::Model()
: spheres(Util::sphere_mesh(0.05f, 1)), cylinders(Util::cyl_mesh(0.05f, 1.0f)),
arrows(Util::arrow_mesh(0.05f, 0.1f, 1.0f)) {}
void Model::begin_transform() {
......@@ -24,8 +22,7 @@ void Model::begin_transform() {
auto elem = *selected_element();
trans_begin = {};
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) {
trans_begin.verts = {vert->pos};
trans_begin.center = vert->pos;
},
......@@ -40,10 +37,10 @@ void Model::begin_transform() {
do {
trans_begin.verts.push_back(h->vertex()->pos);
h = h->next();
} while(h != face->halfedge());
} while (h != face->halfedge());
},
[&](auto) {}
}, elem);
[&](auto) {}},
elem);
}
void Model::update_vertex(Halfedge_Mesh::VertexRef vert) {
......@@ -51,7 +48,7 @@ void Model::update_vertex(Halfedge_Mesh::VertexRef vert) {
// Update current vertex
float d;
{
GL::Instances::Info& info = spheres.get(id_to_info[vert->id()].instance);
GL::Instances::Info &info = spheres.get(id_to_info[vert->id()].instance);
vertex_viz(vert, d, info.transform);
vert_sizes[vert->id()] = d;
}
......@@ -61,7 +58,7 @@ void Model::update_vertex(Halfedge_Mesh::VertexRef vert) {
// Update surrounding vertices & faces
do {
Halfedge_Mesh::VertexRef v = h->twin()->vertex();
GL::Instances::Info& vi = spheres.get(id_to_info[v->id()].instance);
GL::Instances::Info &vi = spheres.get(id_to_info[v->id()].instance);
vertex_viz(v, d, vi.transform);
vert_sizes[v->id()] = d;
......@@ -69,26 +66,26 @@ void Model::update_vertex(Halfedge_Mesh::VertexRef vert) {
face_viz(h->face(), face_mesh.edit_verts(), face_mesh.edit_indices(), idx);
h = h->twin()->next();
} while(h != vert->halfedge());
} while (h != vert->halfedge());
// Update surrounding halfedges & edges
do {
GL::Instances::Info& hi = arrows.get(id_to_info[h->id()].instance);
GL::Instances::Info &hi = arrows.get(id_to_info[h->id()].instance);
halfedge_viz(h, hi.transform);
GL::Instances::Info& thi = arrows.get(id_to_info[h->twin()->id()].instance);
GL::Instances::Info &thi = arrows.get(id_to_info[h->twin()->id()].instance);
halfedge_viz(h->twin(), thi.transform);
GL::Instances::Info& e = cylinders.get(id_to_info[h->edge()->id()].instance);
GL::Instances::Info &e = cylinders.get(id_to_info[h->edge()->id()].instance);
edge_viz(h->edge(), e.transform);
h = h->twin()->next();
} while(h != vert->halfedge());
} while (h != vert->halfedge());
}
void Model::apply_transform(Widgets& widgets) {
void Model::apply_transform(Widgets &widgets) {
if(widgets.is_dragging() && widgets.active == Widget_Type::bevel) {
if (widgets.is_dragging() && widgets.active == Widget_Type::bevel) {
int x = 0;
info("%d",x);
info("%d", x);
}
auto elem = *selected_element();
......@@ -97,30 +94,29 @@ void Model::apply_transform(Widgets& widgets) {
Pose delta = widgets.apply_action({});
Vec3 abs_pos = trans_begin.center + delta.pos;
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
if(action == Widget_Type::move) {
std::visit(
overloaded{[&](Halfedge_Mesh::VertexRef vert) {
if (action == Widget_Type::move) {
vert->pos = abs_pos;
}
update_vertex(vert);
},
[&](Halfedge_Mesh::EdgeRef edge) {
auto h = edge->halfedge();
Vec3 v0 = trans_begin.verts[0];
Vec3 v1 = trans_begin.verts[1];
Vec3 center = trans_begin.center;
if(action == Widget_Type::move) {
if (action == Widget_Type::move) {
Vec3 off = abs_pos - edge->center();
h->vertex()->pos += off;
h->twin()->vertex()->pos += off;
} else if(action == Widget_Type::rotate) {
} else if (action == Widget_Type::rotate) {
Quat q = Quat::euler(delta.euler);
h->vertex()->pos = q.rotate(v0 - center) + center;
h->twin()->vertex()->pos = q.rotate(v1 - center) + center;
} else if(action == Widget_Type::scale) {
} else if (action == Widget_Type::scale) {
Mat4 s = Mat4::scale(delta.scale);
h->vertex()->pos = s * (v0 - center) + center;
h->twin()->vertex()->pos = s * (v1 - center) + center;
......@@ -130,40 +126,41 @@ void Model::apply_transform(Widgets& widgets) {
},
[&](Halfedge_Mesh::FaceRef face) {
auto h = face->halfedge();
Vec3 center = trans_begin.center;
if(action == Widget_Type::move) {
if (action == Widget_Type::move) {
Vec3 off = abs_pos - face->center();
do {
h->vertex()->pos += off;
h = h->next();
} while(h != face->halfedge());
} else if(action == Widget_Type::rotate) {
} while (h != face->halfedge());
} else if (action == Widget_Type::rotate) {
Quat q = Quat::euler(delta.euler);
int i = 0;
do {
h->vertex()->pos = q.rotate(trans_begin.verts[i] - center) + center;
h = h->next();
i++;
} while(h != face->halfedge());
} else if(action == Widget_Type::scale) {
} while (h != face->halfedge());
} else if (action == Widget_Type::scale) {
Mat4 s = Mat4::scale(delta.scale);
int i = 0;
do {
h->vertex()->pos = s * (trans_begin.verts[i] - center) + center;
h = h->next();
i++;
} while(h != face->halfedge());
} else if(action == Widget_Type::bevel) {
} while (h != face->halfedge());
} else if (action == Widget_Type::bevel) {
if(beveling == Bevel::vert) {
my_mesh->bevel_vertex_positions(trans_begin.verts, face, delta.pos.x);
} else if(beveling == Bevel::edge) {
if (beveling == Bevel::vert) {
my_mesh->bevel_vertex_positions(trans_begin.verts, face,
delta.pos.x);
} else if (beveling == Bevel::edge) {
my_mesh->bevel_edge_positions(trans_begin.verts, face, delta.pos.x);
} else {
my_mesh->bevel_face_positions(trans_begin.verts, face, delta.pos.x, delta.pos.y);
my_mesh->bevel_face_positions(trans_begin.verts, face, delta.pos.x,
delta.pos.y);
}
}
......@@ -172,65 +169,61 @@ void Model::apply_transform(Widgets& widgets) {
update_vertex(h->vertex());
update_vertex(h->twin()->next()->twin()->vertex());
h = h->next();
} while(h != face->halfedge());
} while (h != face->halfedge());
},
[&](auto) {}
}, elem);
[&](auto) {}},
elem);
}
void Model::set_selected(Halfedge_Mesh::ElementRef elem) {
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
selected_elem_id = vert->id();
},
[&](Halfedge_Mesh::EdgeRef edge) {
selected_elem_id = edge->id();
},
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) { selected_elem_id = vert->id(); },
[&](Halfedge_Mesh::EdgeRef edge) { selected_elem_id = edge->id(); },
[&](Halfedge_Mesh::FaceRef face) {
if(!face->is_boundary())
if (!face->is_boundary())
selected_elem_id = face->id();
},
[&](Halfedge_Mesh::HalfedgeRef halfedge) {
if(!halfedge->is_boundary())
if (!halfedge->is_boundary())
selected_elem_id = halfedge->id();
}
}, elem);
}},
elem);
}
std::tuple<GL::Mesh&,GL::Instances&,GL::Instances&,GL::Instances&> Model::shapes() {
std::tuple<GL::Mesh &, GL::Instances &, GL::Instances &, GL::Instances &> Model::shapes() {
return {face_mesh, spheres, cylinders, arrows};
}
std::optional<Halfedge_Mesh::ElementRef> Model::selected_element() {
if(!my_mesh) return std::nullopt;
if(my_mesh->render_dirty_flag) rebuild();
if (!my_mesh)
return std::nullopt;
if (my_mesh->render_dirty_flag)
rebuild();
auto entry = id_to_info.find(selected_elem_id);
if(entry == id_to_info.end()) return std::nullopt;
if (entry == id_to_info.end())
return std::nullopt;
return entry->second.ref;
}
void Model::unset_mesh() {
my_mesh = nullptr;
}
void Model::unset_mesh() { my_mesh = nullptr; }
void Model::set_mesh(Halfedge_Mesh& mesh) {
void Model::set_mesh(Halfedge_Mesh &mesh) {
Halfedge_Mesh* old = my_mesh;
Halfedge_Mesh *old = my_mesh;
my_mesh = &mesh;
if(old != my_mesh) {
if (old != my_mesh) {
selected_elem_id = 0;
hovered_elem_id = 0;
rebuild();
} else if(old->render_dirty_flag) {
} else if (old->render_dirty_flag) {
rebuild();
}
}
void Model::vertex_viz(Halfedge_Mesh::VertexRef v, float& size, Mat4& transform) {
void Model::vertex_viz(Halfedge_Mesh::VertexRef v, float &size, Mat4 &transform) {
// Sphere size ~ 0.05 * min incident edge length
float d = FLT_MAX;
......@@ -240,14 +233,15 @@ void Model::vertex_viz(Halfedge_Mesh::VertexRef v, float& size, Mat4& transform)
float e = (n - v->pos).norm_squared();
d = d < e ? d : e;
he = he->twin()->next();
} while(he != v->halfedge());
} while (he != v->halfedge());
d = std::sqrt(d);
size = d < 2.0f ? d : 2.0f;
transform = Mat4{Vec4{size,0.0f,0.0f,0.0f},Vec4{0.0f,size,0.0f,0.0f},Vec4{0.0f,0.0f,size,0.0f},Vec4{v->pos,1.0f}};
transform = Mat4{Vec4{size, 0.0f, 0.0f, 0.0f}, Vec4{0.0f, size, 0.0f, 0.0f},
Vec4{0.0f, 0.0f, size, 0.0f}, Vec4{v->pos, 1.0f}};
}
void Model::edge_viz(Halfedge_Mesh::EdgeRef e, Mat4& transform) {
void Model::edge_viz(Halfedge_Mesh::EdgeRef e, Mat4 &transform) {
auto v_0 = e->halfedge()->vertex();
auto v_1 = e->halfedge()->twin()->vertex();
......@@ -262,17 +256,18 @@ void Model::edge_viz(Halfedge_Mesh::EdgeRef e, Mat4& transform) {
float v0s = vert_sizes[v_0->id()], v1s = vert_sizes[v_1->id()];
float s = 0.5f * std::min(v0s, v1s);
if(dir.y == 1.0f || dir.y == -1.0f) {
if (dir.y == 1.0f || dir.y == -1.0f) {
l *= sign(dir.y);
transform = Mat4{Vec4{s,0.0f,0.0f,0.0f},Vec4{0.0f,l,0.0f,0.0f},Vec4{0.0f,0.0f,s,0.0f},Vec4{v0,1.0f}};
transform = Mat4{Vec4{s, 0.0f, 0.0f, 0.0f}, Vec4{0.0f, l, 0.0f, 0.0f},
Vec4{0.0f, 0.0f, s, 0.0f}, Vec4{v0, 1.0f}};
} else {
Vec3 x = cross(dir, Vec3{0.0f, 1.0f, 0.0f}).unit();
Vec3 z = cross(x, dir).unit();
transform = Mat4{Vec4{x*s,0.0f},Vec4{dir*l,0.0f},Vec4{z*s,0.0f},Vec4{v0,1.0f}};
transform = Mat4{Vec4{x * s, 0.0f}, Vec4{dir * l, 0.0f}, Vec4{z * s, 0.0f}, Vec4{v0, 1.0f}};
}
}
void Model::halfedge_viz(Halfedge_Mesh::HalfedgeRef h, Mat4& transform) {
void Model::halfedge_viz(Halfedge_Mesh::HalfedgeRef h, Mat4 &transform) {
auto v_0 = h->vertex();
auto v_1 = h->twin()->vertex();
......@@ -295,19 +290,20 @@ void Model::halfedge_viz(Halfedge_Mesh::HalfedgeRef h, Mat4& transform) {
offset += (face - avg).unit() * s * 0.2f;
// Align edge
if(dir.y == 1.0f || dir.y == -1.0f) {
if (dir.y == 1.0f || dir.y == -1.0f) {
l *= sign(dir.y);
transform = Mat4{Vec4{s,0.0f,0.0f,0.0f},Vec4{0.0f,l,0.0f,0.0f},Vec4{0.0f,0.0f,s,0.0f},Vec4{v0+offset,1.0f}};
transform = Mat4{Vec4{s, 0.0f, 0.0f, 0.0f}, Vec4{0.0f, l, 0.0f, 0.0f},
Vec4{0.0f, 0.0f, s, 0.0f}, Vec4{v0 + offset, 1.0f}};
} else {
Vec3 x = cross(dir, Vec3{0.0f, 1.0f, 0.0f});
Vec3 z = cross(x, dir);
transform = Mat4{Vec4{x*s,0.0f},Vec4{dir*l,0.0f},Vec4{z*s,0.0f},Vec4{v0+offset,1.0f}};
transform = Mat4{Vec4{x * s, 0.0f}, Vec4{dir * l, 0.0f}, Vec4{z * s, 0.0f},
Vec4{v0 + offset, 1.0f}};
}
}
void Model::face_viz(Halfedge_Mesh::FaceRef face,
std::vector<GL::Mesh::Vert>& verts, std::vector<GL::Mesh::Index>& idxs,
size_t insert_at) {
void Model::face_viz(Halfedge_Mesh::FaceRef face, std::vector<GL::Mesh::Vert> &verts,
std::vector<GL::Mesh::Index> &idxs, size_t insert_at) {
std::vector<GL::Mesh::Vert> face_verts;
unsigned int id = face->id();
......@@ -321,18 +317,22 @@ void Model::face_viz(Halfedge_Mesh::FaceRef face,
id_to_info[face->id()] = {face, insert_at};
if(face_verts.size() < 3) return;
if (face_verts.size() < 3)
return;
size_t max = insert_at + (face_verts.size() - 2) * 3;
if(verts.size() < max) verts.resize(max);
if(idxs.size() < max) idxs.resize(max);
if (verts.size() < max)
verts.resize(max);
if (idxs.size() < max)
idxs.resize(max);
Vec3 v0 = face_verts[0].pos;
for(size_t i = 1; i <= face_verts.size() - 2; i++) {
for (size_t i = 1; i <= face_verts.size() - 2; i++) {
Vec3 v1 = face_verts[i].pos;
Vec3 v2 = face_verts[i+1].pos;
Vec3 v2 = face_verts[i + 1].pos;
Vec3 n = cross(v1 - v0, v2 - v0).unit();
if(my_mesh->flipped()) n = -n;
if (my_mesh->flipped())
n = -n;
idxs[insert_at] = (GL::Mesh::Index)insert_at;
verts[insert_at++] = {v0, n, id};
......@@ -347,8 +347,9 @@ void Model::face_viz(Halfedge_Mesh::FaceRef face,
void Model::rebuild() {
if(!my_mesh) return;
Halfedge_Mesh& mesh = *my_mesh;
if (!my_mesh)
return;
Halfedge_Mesh &mesh = *my_mesh;
mesh.render_dirty_flag = false;
......@@ -358,17 +359,19 @@ void Model::rebuild() {
std::vector<GL::Mesh::Vert> verts;
std::vector<GL::Mesh::Index> idxs;
for(auto f = mesh.faces_begin(); f != mesh.faces_end(); f++) {
if(f->is_boundary()) continue;
for (auto f = mesh.faces_begin(); f != mesh.faces_end(); f++) {
if (f->is_boundary())
continue;
face_viz(f, verts, idxs, verts.size());
}
face_mesh.recreate(std::move(verts), std::move(idxs));
// Create sphere for each vertex
spheres.clear();
for(auto v = mesh.vertices_begin(); v != mesh.vertices_end(); v++) {
for (auto v = mesh.vertices_begin(); v != mesh.vertices_end(); v++) {
float d; Mat4 transform;
float d;
Mat4 transform;
vertex_viz(v, d, transform);
vert_sizes[v->id()] = d;
id_to_info[v->id()] = {v, spheres.add(transform, v->id())};
......@@ -376,7 +379,7 @@ void Model::rebuild() {
// Create cylinder for each edge
cylinders.clear();
for(auto e = mesh.edges_begin(); e != mesh.edges_end(); e++) {
for (auto e = mesh.edges_begin(); e != mesh.edges_end(); e++) {
Mat4 transform;
edge_viz(e, transform);
......@@ -385,9 +388,10 @@ void Model::rebuild() {
// Create arrow for each halfedge
arrows.clear();
for(auto h = mesh.halfedges_begin(); h != mesh.halfedges_end(); h++) {
for (auto h = mesh.halfedges_begin(); h != mesh.halfedges_end(); h++) {
if(h->is_boundary()) continue;
if (h->is_boundary())
continue;
Mat4 transform;
halfedge_viz(h, transform);
......@@ -395,17 +399,16 @@ void Model::rebuild() {
}
}
bool Model::begin_bevel(std::string& err) {
bool Model::begin_bevel(std::string &err) {
my_mesh->copy_to(old_mesh);
Halfedge_Mesh::FaceRef new_face;
bool succeeded = false;
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) {
auto res = my_mesh->bevel_vertex(vert);
if(res.has_value()) {
if (res.has_value()) {
new_face = *res;
succeeded = true;
beveling = Bevel::vert;
......@@ -413,7 +416,7 @@ bool Model::begin_bevel(std::string& err) {
},
[&](Halfedge_Mesh::EdgeRef edge) {
auto res = my_mesh->bevel_edge(edge);
if(res.has_value()) {
if (res.has_value()) {
new_face = *res;
succeeded = true;
beveling = Bevel::edge;
......@@ -421,17 +424,17 @@ bool Model::begin_bevel(std::string& err) {
},
[&](Halfedge_Mesh::FaceRef face) {
auto res = my_mesh->bevel_face(face);
if(res.has_value()) {
if (res.has_value()) {
new_face = *res;
succeeded = true;
beveling = Bevel::face;
}
},
[&](auto) {}
}, *selected_element());
[&](auto) {}},
*selected_element());
err = my_mesh->validate();
if(!err.empty() || !succeeded) {
if (!err.empty() || !succeeded) {
*my_mesh = std::move(old_mesh);
return false;
......@@ -447,68 +450,74 @@ bool Model::begin_bevel(std::string& err) {
do {
trans_begin.verts.push_back(h->vertex()->pos);
h = h->next();
} while(h != new_face->halfedge());
} while (h != new_face->halfedge());
return true;
}
}
bool Model::keydown(Widgets& widgets, SDL_Keysym key, Camera& cam) {
bool Model::keydown(Widgets &widgets, SDL_Keysym key, Camera &cam) {
auto sel = selected_element();
if(!sel.has_value()) return false;
switch(key.sym) {
case SDLK_b: widgets.active = Widget_Type::bevel; break;
case SDLK_c: zoom_to(*sel, cam); break;
case SDLK_h: {
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
set_selected(vert->halfedge());
},
[&](Halfedge_Mesh::EdgeRef edge) {
set_selected(edge->halfedge());
},
[&](Halfedge_Mesh::FaceRef face) {
set_selected(face->halfedge());
},
[&](auto) {}
}, *sel);
} break;
}
if (!sel.has_value())
return false;
if(std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(*sel)) {
if (std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(*sel)) {
auto h = std::get<Halfedge_Mesh::HalfedgeRef>(*sel);
if(key.sym == SDLK_n) {
if (key.sym == SDLK_n) {
set_selected(h->next());
return true;
} else if(key.sym == SDLK_t) {
} else if (key.sym == SDLK_t) {
set_selected(h->twin());
return true;
} else if(key.sym == SDLK_v) {
} else if (key.sym == SDLK_v) {
set_selected(h->vertex());
return true;
} else if(key.sym == SDLK_e) {
} else if (key.sym == SDLK_e) {
set_selected(h->edge());
return true;
} else if(key.sym == SDLK_f) {
} else if (key.sym == SDLK_f) {
set_selected(h->face());
return true;
}
}
switch (key.sym) {
case SDLK_b:
widgets.active = Widget_Type::bevel;
return true;
case SDLK_c:
zoom_to(*sel, cam);
return true;
case SDLK_h: {
std::visit(
overloaded{[&](Halfedge_Mesh::VertexRef vert) { set_selected(vert->halfedge()); },
[&](Halfedge_Mesh::EdgeRef edge) { set_selected(edge->halfedge()); },
[&](Halfedge_Mesh::FaceRef face) { set_selected(face->halfedge()); },
[&](auto) {}},
*sel);
}
return true;
case SDLK_f: {
cam.look_at(Vec3{}, -cam.front() * cam.dist());
}
return true;
}
return false;
}
template<typename T>
std::string Model::update_mesh(Undo& undo, Scene_Object& obj, Halfedge_Mesh&& before, Halfedge_Mesh::ElementRef ref, T&& op) {
template <typename T>
std::string Model::update_mesh(Undo &undo, Scene_Object &obj, Halfedge_Mesh &&before,
Halfedge_Mesh::ElementRef ref, T &&op) {
unsigned int id = Halfedge_Mesh::id_of(ref);
std::optional<Halfedge_Mesh::ElementRef> new_ref = op(*my_mesh, ref);
if(!new_ref.has_value()) return {};
if (!new_ref.has_value())
return {};
std::string err = my_mesh->validate();
if(!err.empty()) {
if (!err.empty()) {
obj.take_mesh(std::move(before));
return err;
} else {
......@@ -520,14 +529,16 @@ std::string Model::update_mesh(Undo& undo, Scene_Object& obj, Halfedge_Mesh&& be
return {};
}
template<typename T>
std::string Model::update_mesh_global(Undo& undo, Scene_Object& obj, Halfedge_Mesh&& before, T&& op) {
template <typename T>
std::string Model::update_mesh_global(Undo &undo, Scene_Object &obj, Halfedge_Mesh &&before,
T &&op) {
bool suc = op(*my_mesh);
if(!suc) return {};
if (!suc)
return {};
std::string err = my_mesh->validate();
if(!err.empty()) {
if (!err.empty()) {
obj.take_mesh(std::move(before));
return err;
} else {
......@@ -539,7 +550,7 @@ std::string Model::update_mesh_global(Undo& undo, Scene_Object& obj, Halfedge_Me
return {};
}
void Model::zoom_to(Halfedge_Mesh::ElementRef ref, Camera& cam) {
void Model::zoom_to(Halfedge_Mesh::ElementRef ref, Camera &cam) {
float d = cam.dist();
Vec3 center = Halfedge_Mesh::center_of(ref);
......@@ -547,65 +558,64 @@ void Model::zoom_to(Halfedge_Mesh::ElementRef ref, Camera& cam) {
cam.look_at(center, pos);
}
std::string Model::UIsidebar(Undo& undo, Widgets& widgets, Scene_Maybe obj_opt, Camera& camera) {
std::string Model::UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj_opt, Camera &camera) {
if(!obj_opt.has_value()) return {};
if (!obj_opt.has_value())
return {};
Scene_Item& item = obj_opt.value();
if(!item.is<Scene_Object>()) return {};
Scene_Item &item = obj_opt.value();
if (!item.is<Scene_Object>())
return {};
Scene_Object& obj = item.get<Scene_Object>();
if(obj.opt.shape_type != PT::Shape_Type::none) return {};
Scene_Object &obj = item.get<Scene_Object>();
if (obj.opt.shape_type != PT::Shape_Type::none)
return {};
if(!my_mesh || !obj.is_editable()) return {};
if (!my_mesh || !obj.is_editable())
return {};
assert(my_mesh == &obj.get_mesh());
Halfedge_Mesh& mesh = *my_mesh;
Halfedge_Mesh &mesh = *my_mesh;
Halfedge_Mesh before;
auto sel = selected_element();
ImGui::Text("Global Operations");
if(ImGui::Button("Triangulate")) {
if (ImGui::Button("Triangulate")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh &m) {
m.triangulate();
return true;
});
}
if(ImGui::Button("Subdivide: Linear")) {
if (ImGui::Button("Subdivide: Linear")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return m.subdivide(SubD::linear);
});
return update_mesh_global(undo, obj, std::move(before),
[](Halfedge_Mesh &m) { return m.subdivide(SubD::linear); });
}
if(ImGui::Button("Subdivide: Catmull-Clark ")) {
if (ImGui::Button("Subdivide: Catmull-Clark ")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return m.subdivide(SubD::catmullclark);
});
return update_mesh_global(undo, obj, std::move(before),
[](Halfedge_Mesh &m) { return m.subdivide(SubD::catmullclark); });
}
if(ImGui::Button("Subdivide: Loop")) {
if (ImGui::Button("Subdivide: Loop")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return m.subdivide(SubD::loop);
});
return update_mesh_global(undo, obj, std::move(before),
[](Halfedge_Mesh &m) { return m.subdivide(SubD::loop); });
}
if(ImGui::Button("Remesh")) {
if (ImGui::Button("Remesh")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return m.isotropic_remesh();
});
return update_mesh_global(undo, obj, std::move(before),
[](Halfedge_Mesh &m) { return m.isotropic_remesh(); });
}
if(ImGui::Button("Simplify")) {
if (ImGui::Button("Simplify")) {
mesh.copy_to(before);
return update_mesh_global(undo, obj, std::move(before), [](Halfedge_Mesh& m) {
return m.simplify();
});
return update_mesh_global(undo, obj, std::move(before),
[](Halfedge_Mesh &m) { return m.simplify(); });
}
ImGui::Separator();
if(sel.has_value()) {
if (sel.has_value()) {
ImGui::Text("Local Operations");
widgets.action_button(Widget_Type::move, "Move [m]", false);
......@@ -613,95 +623,107 @@ std::string Model::UIsidebar(Undo& undo, Widgets& widgets, Scene_Maybe obj_opt,
widgets.action_button(Widget_Type::scale, "Scale [s]");
widgets.action_button(Widget_Type::bevel, "Bevel [b]");
std::string err = std::visit(overloaded {
std::string err = std::visit(
overloaded{
[&](Halfedge_Mesh::VertexRef vert) -> std::string {
if(ImGui::Button("Erase")) {
if (ImGui::Button("Erase")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), vert, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef vert) {
return m.erase_vertex(std::get<Halfedge_Mesh::VertexRef>(vert));
return update_mesh(undo, obj, std::move(before), vert,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef vert) {
return m.erase_vertex(
std::get<Halfedge_Mesh::VertexRef>(vert));
});
}
return {};
},
[&](Halfedge_Mesh::EdgeRef edge) -> std::string {
if(ImGui::Button("Erase")) {
if (ImGui::Button("Erase")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), edge, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef edge) {
return m.erase_edge(std::get<Halfedge_Mesh::EdgeRef>(edge));
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
return m.erase_edge(
std::get<Halfedge_Mesh::EdgeRef>(edge));
});
}
if(Manager::wrap_button("Collapse")) {
if (Manager::wrap_button("Collapse")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), edge, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef edge) {
return m.collapse_edge(std::get<Halfedge_Mesh::EdgeRef>(edge));
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
return m.collapse_edge(
std::get<Halfedge_Mesh::EdgeRef>(edge));
});
}
if(Manager::wrap_button("Flip")) {
if (Manager::wrap_button("Flip")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), edge, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef edge) {
return m.flip_edge(std::get<Halfedge_Mesh::EdgeRef>(edge));
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
return m.flip_edge(
std::get<Halfedge_Mesh::EdgeRef>(edge));
});
}
if(Manager::wrap_button("Split")) {
if (Manager::wrap_button("Split")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), edge, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef edge) {
return m.split_edge(std::get<Halfedge_Mesh::EdgeRef>(edge));
return update_mesh(undo, obj, std::move(before), edge,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef edge) {
return m.split_edge(
std::get<Halfedge_Mesh::EdgeRef>(edge));
});
}
return {};
},
[&](Halfedge_Mesh::FaceRef face) -> std::string {
if(ImGui::Button("Collapse")) {
if (ImGui::Button("Collapse")) {
mesh.copy_to(before);
return update_mesh(undo, obj, std::move(before), face, [](Halfedge_Mesh& m, Halfedge_Mesh::ElementRef face) {
return m.collapse_face(std::get<Halfedge_Mesh::FaceRef>(face));
return update_mesh(undo, obj, std::move(before), face,
[](Halfedge_Mesh &m, Halfedge_Mesh::ElementRef face) {
return m.collapse_face(
std::get<Halfedge_Mesh::FaceRef>(face));
});
}
return {};
},
[&](auto) -> std::string { return {}; }
}, *sel);
[&](auto) -> std::string { return {}; }},
*sel);
ImGui::Separator();
ImGui::Text("Navigation");
if(ImGui::Button("Center Camera [c]")) {
if (ImGui::Button("Center Camera [c]")) {
zoom_to(*sel, camera);
}
std::visit(overloaded {
[&](Halfedge_Mesh::VertexRef vert) {
if(ImGui::Button("Halfedge [h]")) {
std::visit(overloaded{[&](Halfedge_Mesh::VertexRef vert) {
if (ImGui::Button("Halfedge [h]")) {
set_selected(vert->halfedge());
}
},
[&](Halfedge_Mesh::EdgeRef edge) {
if(ImGui::Button("Halfedge [h]")) {
if (ImGui::Button("Halfedge [h]")) {
set_selected(edge->halfedge());
}
},
[&](Halfedge_Mesh::FaceRef face) {
if(ImGui::Button("Halfedge [h]")) {
if (ImGui::Button("Halfedge [h]")) {
set_selected(face->halfedge());
}
},
[&](Halfedge_Mesh::HalfedgeRef halfedge) {
if(ImGui::Button("Vertex [v]")) {
if (ImGui::Button("Vertex [v]")) {
set_selected(halfedge->vertex());
}
if(Manager::wrap_button("Edge [e]")) {
if (Manager::wrap_button("Edge [e]")) {
set_selected(halfedge->edge());
}
if(Manager::wrap_button("Face [f]")) {
if (Manager::wrap_button("Face [f]")) {
set_selected(halfedge->face());
}
if(ImGui::Button("Twin [t]")) {
if (ImGui::Button("Twin [t]")) {
set_selected(halfedge->twin());
}
if(Manager::wrap_button("Next [n]")) {
if (Manager::wrap_button("Next [n]")) {
set_selected(halfedge->next());
}
}
}, *sel);
}},
*sel);
ImGui::Separator();
return err;
......@@ -710,19 +732,20 @@ std::string Model::UIsidebar(Undo& undo, Widgets& widgets, Scene_Maybe obj_opt,
return {};
}
void Model::clear_select() {
selected_elem_id = 0;
}
void Model::clear_select() { selected_elem_id = 0; }
void Model::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam) {
void Model::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {
if(!obj_opt.has_value()) return;
if (!obj_opt.has_value())
return;
Scene_Item& item = obj_opt.value();
if(!item.is<Scene_Object>()) return;
Scene_Item &item = obj_opt.value();
if (!item.is<Scene_Object>())
return;
Scene_Object& obj = item.get<Scene_Object>();
if(obj.opt.shape_type != PT::Shape_Type::none) return;
Scene_Object &obj = item.get<Scene_Object>();
if (obj.opt.shape_type != PT::Shape_Type::none)
return;
Mat4 view = cam.get_view();
......@@ -734,22 +757,22 @@ void Model::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam) {
Renderer::get().halfedge_editor(opts);
auto elem = selected_element();
if(elem.has_value()) {
if (elem.has_value()) {
auto e = *elem;
Vec3 pos = Halfedge_Mesh::center_of(e);
if(!std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(e)) {
if (!std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(e)) {
float scl = std::min((cam.pos() - pos).norm() / 5.5f, 10.0f);
widgets.render(view, pos, scl);
}
}
}
std::string Model::end_transform(Widgets& widgets, Undo& undo, Scene_Object& obj) {
std::string Model::end_transform(Widgets &widgets, Undo &undo, Scene_Object &obj) {
if(widgets.is_dragging() && widgets.active == Widget_Type::bevel) {
if (widgets.is_dragging() && widgets.active == Widget_Type::bevel) {
std::string err = obj.get_mesh().validate();
if(!err.empty()) {
if (!err.empty()) {
obj.take_mesh(std::move(old_mesh));
obj.set_mesh_dirty();
my_mesh->render_dirty_flag = true;
......@@ -769,28 +792,27 @@ Vec3 Model::selected_pos() {
return Halfedge_Mesh::center_of(*elem);
}
std::string Model::select(Widgets& widgets, Scene_ID click, Vec3 cam, Vec2 spos, Vec3 dir) {
std::string Model::select(Widgets &widgets, Scene_ID click, Vec3 cam, Vec2 spos, Vec3 dir) {
if(click && widgets.active == Widget_Type::bevel &&
click == selected_elem_id) {
if (click && widgets.active == Widget_Type::bevel && click == selected_elem_id) {
std::string err;
if(!begin_bevel(err)) {
if (!begin_bevel(err)) {
widgets.set_dragging(false, false);
return err;
} else {
widgets.set_dragging(true, true);
}
} else if(!widgets.is_dragging() && click >= n_Widget_IDs) {
} else if (!widgets.is_dragging() && click >= n_Widget_IDs) {
selected_elem_id = (unsigned int)click;
}
if(widgets.want_drag()) {
if (widgets.want_drag()) {
auto e = selected_element();
if(e.has_value() && !std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(*e)) {
if (e.has_value() && !std::holds_alternative<Halfedge_Mesh::HalfedgeRef>(*e)) {
widgets.start_drag(Halfedge_Mesh::center_of(*e), cam, spos, dir);
if(widgets.active != Widget_Type::bevel) {
if (widgets.active != Widget_Type::bevel) {
begin_transform();
}
}
......@@ -798,16 +820,10 @@ std::string Model::select(Widgets& widgets, Scene_ID click, Vec3 cam, Vec2 spos,
return {};
}
unsigned int Model::select_id() const {
return selected_elem_id;
}
unsigned int Model::select_id() const { return selected_elem_id; }
unsigned int Model::hover_id() const {
return hovered_elem_id;
}
unsigned int Model::hover_id() const { return hovered_elem_id; }
void Model::set_hover(unsigned int id) {
hovered_elem_id = id;
}
void Model::set_hover(unsigned int id) { hovered_elem_id = id; }
}
} // namespace Gui
......@@ -7,10 +7,10 @@
#include <optional>
#include <unordered_map>
#include "../util/camera.h"
#include "../geometry/halfedge.h"
#include "../platform/gl.h"
#include "../scene/scene.h"
#include "../util/camera.h"
namespace Gui {
......@@ -19,52 +19,49 @@ public:
Model();
// Gui view API
bool keydown(Widgets& widgets, SDL_Keysym key, Camera& cam);
bool keydown(Widgets &widgets, SDL_Keysym key, Camera &cam);
void unset_mesh();
std::string UIsidebar(Undo& undo, Widgets& widgets, Scene_Maybe obj, Camera& cam);
void render(Scene_Maybe obj_opt, Widgets& widgets, Camera& cam);
std::string UIsidebar(Undo &undo, Widgets &widgets, Scene_Maybe obj, Camera &cam);
void render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam);
Vec3 selected_pos();
void clear_select();
std::string end_transform(Widgets& widgets, Undo& undo, Scene_Object& obj);
void apply_transform(Widgets& widgets);
std::string select(Widgets& widgets, Scene_ID click, Vec3 cam, Vec2 spos, Vec3 dir);
std::string end_transform(Widgets &widgets, Undo &undo, Scene_Object &obj);
void apply_transform(Widgets &widgets);
std::string select(Widgets &widgets, Scene_ID click, Vec3 cam, Vec2 spos, Vec3 dir);
std::tuple<GL::Mesh&,GL::Instances&,GL::Instances&,GL::Instances&> shapes();
std::tuple<GL::Mesh &, GL::Instances &, GL::Instances &, GL::Instances &> shapes();
unsigned int select_id() const;
unsigned int hover_id() const;
void set_hover(unsigned int id);
private:
template<typename T>
std::string update_mesh(Undo& undo, Scene_Object& obj, Halfedge_Mesh&& before, Halfedge_Mesh::ElementRef ref, T&& op);
template<typename T>
std::string update_mesh_global(Undo& undo, Scene_Object& obj, Halfedge_Mesh&& before, T&& op);
void zoom_to(Halfedge_Mesh::ElementRef ref, Camera& cam);
void set_mesh(Halfedge_Mesh& mesh);
template <typename T>
std::string update_mesh(Undo &undo, Scene_Object &obj, Halfedge_Mesh &&before,
Halfedge_Mesh::ElementRef ref, T &&op);
template <typename T>
std::string update_mesh_global(Undo &undo, Scene_Object &obj, Halfedge_Mesh &&before, T &&op);
void zoom_to(Halfedge_Mesh::ElementRef ref, Camera &cam);
void set_mesh(Halfedge_Mesh &mesh);
void begin_transform();
bool begin_bevel(std::string& err);
bool begin_bevel(std::string &err);
void set_selected(Halfedge_Mesh::ElementRef elem);
std::optional<Halfedge_Mesh::ElementRef> selected_element();
void rebuild();
void update_vertex(Halfedge_Mesh::VertexRef vert);
void vertex_viz(Halfedge_Mesh::VertexRef v, float& size, Mat4& transform);
void edge_viz(Halfedge_Mesh::EdgeRef e, Mat4& transform);
void halfedge_viz(Halfedge_Mesh::HalfedgeRef h, Mat4& transform);
void face_viz(Halfedge_Mesh::FaceRef face, std::vector<GL::Mesh::Vert>& verts,
std::vector<GL::Mesh::Index>& idxs, size_t insert_at);
void vertex_viz(Halfedge_Mesh::VertexRef v, float &size, Mat4 &transform);
void edge_viz(Halfedge_Mesh::EdgeRef e, Mat4 &transform);
void halfedge_viz(Halfedge_Mesh::HalfedgeRef h, Mat4 &transform);
void face_viz(Halfedge_Mesh::FaceRef face, std::vector<GL::Mesh::Vert> &verts,
std::vector<GL::Mesh::Index> &idxs, size_t insert_at);
Halfedge_Mesh* my_mesh = nullptr;
Halfedge_Mesh *my_mesh = nullptr;
Halfedge_Mesh old_mesh;
enum class Bevel {
face,
edge,
vert
};
enum class Bevel { face, edge, vert };
Bevel beveling;
struct Transform_Data {
......@@ -92,4 +89,4 @@ private:
std::unordered_map<unsigned int, float> vert_sizes;
};
}
} // namespace Gui
#include <nfd/nfd.h>
#include <imgui/imgui.h>
#include <nfd/nfd.h>
#include <sf_libs/stb_image_write.h>
#include "../platform/platform.h"
#include "../scene/renderer.h"
#include "render.h"
#include "manager.h"
#include "render.h"
namespace Gui {
Render::Render(Scene& scene, Vec2 dim) :
ui_camera(dim), ui_render(dim) {}
Render::Render(Scene &scene, Vec2 dim) : ui_camera(dim), ui_render(dim) {}
void Render::update_dim(Vec2 dim) {
ui_camera.dim(dim);
}
void Render::update_dim(Vec2 dim) { ui_camera.dim(dim); }
bool Render::keydown(Widgets& widgets, SDL_Keysym key) {
return false;
}
bool Render::keydown(Widgets &widgets, SDL_Keysym key) { return false; }
void Render::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& user_cam) {
void Render::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &user_cam) {
Mat4 view = user_cam.get_view();
Renderer& renderer = Renderer::get();
Renderer &renderer = Renderer::get();
if(!ui_camera.moving()) {
if (!ui_camera.moving()) {
ui_camera.render(view);
if(render_ray_log && !ui_render.in_progress()) {
if (render_ray_log && !ui_render.in_progress()) {
ui_render.render_log(view);
}
if(visualize_bvh) {
if (visualize_bvh) {
GL::disable(GL::Opt::depth_write);
renderer.lines(bvh_viz, view);
renderer.lines(bvh_active, view);
......@@ -43,14 +38,15 @@ void Render::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& user_cam) {
}
}
if(obj_opt.has_value()) {
if (obj_opt.has_value()) {
Scene_Item& item = obj_opt.value();
Scene_Item &item = obj_opt.value();
float scale = std::min((user_cam.pos() - item.pose().pos).norm() / 5.5f, 10.0f);
if(item.is<Scene_Light>()) {
Scene_Light& light = item.get<Scene_Light>();
if(light.is_env()) return;
if (item.is<Scene_Light>()) {
Scene_Light &light = item.get<Scene_Light>();
if (light.is_env())
return;
}
item.render(view);
......@@ -59,13 +55,12 @@ void Render::render(Scene_Maybe obj_opt, Widgets& widgets, Camera& user_cam) {
}
}
const Camera& Render::get_cam() const {
return ui_camera.get();
}
const Camera &Render::get_cam() const { return ui_camera.get(); }
void Render::load_cam(Vec3 pos, Vec3 center, float ar, float hfov) {
if(ar == 0.0f) ar = ui_render.wh_ar();
if (ar == 0.0f)
ar = ui_render.wh_ar();
float fov = 2.0f * std::atan((1.0f / ar) * std::tan(hfov / 2.0f));
fov = Degrees(fov);
......@@ -73,11 +68,12 @@ void Render::load_cam(Vec3 pos, Vec3 center, float ar, float hfov) {
ui_camera.load(center, pos, ar, fov);
}
Mode Render::UIsidebar(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe obj_opt, Camera& user_cam) {
Mode Render::UIsidebar(Manager &manager, Undo &undo, Scene &scene, Scene_Maybe obj_opt,
Camera &user_cam) {
Mode mode = Mode::render;
if(obj_opt.has_value()) {
if (obj_opt.has_value()) {
ImGui::Text("Object Options");
mode = manager.item_options(undo, mode, obj_opt.value(), old_pose);
ImGui::Separator();
......@@ -93,8 +89,8 @@ Mode Render::UIsidebar(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
bool update_bvh = false;
if(visualize_bvh) {
if(ImGui::SliderInt("Level", &bvh_level, 0, (int)bvh_levels)) {
if (visualize_bvh) {
if (ImGui::SliderInt("Level", &bvh_level, 0, (int)bvh_levels)) {
update_bvh = true;
}
}
......@@ -104,29 +100,27 @@ Mode Render::UIsidebar(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe o
update_bvh = update_bvh || ui_render.UI(scene, ui_camera, user_cam, err);
manager.set_error(err);
if(update_bvh) {
if (update_bvh) {
update_bvh = false;
bvh_viz.clear();
bvh_active.clear();
bvh_levels = ui_render.tracer().visualize_bvh(bvh_viz, bvh_active, (size_t)bvh_level);
}
if(ImGui::Button("Open Render Window")) {
if (ImGui::Button("Open Render Window")) {
ui_render.open();
}
return mode;
}
std::pair<float,float> Render::completion_time() const {
return ui_render.completion_time();
}
std::pair<float, float> Render::completion_time() const { return ui_render.completion_time(); }
std::string Render::headless_render(Animate& animate, Scene& scene, std::string output,
bool a, int w, int h, int s, int ls, int d, float exp, bool w_from_ar) {
if(w_from_ar) {
std::string Render::headless_render(Animate &animate, Scene &scene, std::string output, bool a,
int w, int h, int s, int ls, int d, float exp, bool w_from_ar) {
if (w_from_ar) {
w = (int)std::ceil(ui_camera.get_ar() * h);
}
return ui_render.headless(animate, scene, ui_camera.get(), output, a, w, h, s, ls, d, exp);
}
}
} // namespace Gui
#pragma once
#include <mutex>
#include <SDL2/SDL.h>
#include <mutex>
#include "../util/camera.h"
#include "../scene/scene.h"
#include "../platform/gl.h"
#include "../rays/pathtracer.h"
#include "../scene/scene.h"
#include "../util/camera.h"
#include "widgets.h"
......@@ -18,19 +18,20 @@ class Manager;
class Render {
public:
Render(Scene& scene, Vec2 dim);
Render(Scene &scene, Vec2 dim);
std::string headless_render(Animate& animate, Scene& scene, std::string output,
bool a, int w, int h, int s, int ls, int d, float exp, bool w_from_ar);
std::pair<float,float> completion_time() const;
std::string headless_render(Animate &animate, Scene &scene, std::string output, bool a, int w,
int h, int s, int ls, int d, float exp, bool w_from_ar);
std::pair<float, float> completion_time() const;
bool keydown(Widgets& widgets, SDL_Keysym key);
Mode UIsidebar(Manager& manager, Undo& undo, Scene& scene, Scene_Maybe selected, Camera& user_cam);
void render(Scene_Maybe obj, Widgets& widgets, Camera& user_cam);
bool keydown(Widgets &widgets, SDL_Keysym key);
Mode UIsidebar(Manager &manager, Undo &undo, Scene &scene, Scene_Maybe selected,
Camera &user_cam);
void render(Scene_Maybe obj, Widgets &widgets, Camera &user_cam);
void update_dim(Vec2 dim);
void load_cam(Vec3 pos, Vec3 front, float ar, float fov);
const Camera& get_cam() const;
const Camera &get_cam() const;
private:
GL::Lines bvh_viz, bvh_active;
......@@ -45,4 +46,4 @@ private:
size_t bvh_levels = 0;
};
}
} // namespace Gui
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment