Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Courses
Scotty3D
Commits
c2535f0f
Commit
c2535f0f
authored
Sep 26, 2020
by
TheNumbat
Browse files
upstream changes
parent
8b8ee1f1
Changes
93
Show whitespace changes
Inline
Side-by-side
.clang-format
0 → 100644
View file @
c2535f0f
---
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
...
.gitignore
View file @
c2535f0f
...
...
@@ -19,3 +19,4 @@ settings.json
media/test.*
media/env_maps/
media/test/
debug.log
docs/building.md
View file @
c2535f0f
...
...
@@ -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
```
...
...
src/app.cpp
View file @
c2535f0f
...
...
@@ -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.0
f
}),
camera
(
plt
?
plt
->
window_draw
()
:
Vec2
{
1.0
f
}),
plt
(
plt
),
scene
(
Gui
::
n_Widget_IDs
),
gui
(
scene
,
plt
?
plt
->
window_size
()
:
Vec2
{
1.0
f
}),
undo
(
scene
,
gui
)
{
App
::
App
(
Settings
set
,
Platform
*
plt
)
:
window_dim
(
plt
?
plt
->
window_draw
()
:
Vec2
{
1.0
f
}),
camera
(
plt
?
plt
->
window_draw
()
:
Vec2
{
1.0
f
}),
plt
(
plt
),
scene
(
Gui
::
n_Widget_IDs
),
gui
(
scene
,
plt
?
plt
->
window_size
()
:
Vec2
{
1.0
f
}),
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.0
f
,
1.0
f
});
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.0
f
*
p
.
x
/
dim
.
x
-
1.0
f
,
2.0
f
*
p
.
y
/
dim
.
y
-
1.0
f
);
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.0
f
*
p
.
x
/
dim
.
x
-
1.0
f
,
2.0
f
*
p
.
y
/
dim
.
y
-
1.0
f
);
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.0
f
*
p
.
x
/
dim
.
x
-
1.0
f
,
2.0
f
*
p
.
y
/
dim
.
y
-
1.0
f
);
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.0
f
*
mouse
.
x
/
window_dim
.
x
-
1.0
f
,
1.0
f
-
2.0
f
*
mouse
.
y
/
window_dim
.
y
);
Vec2
t
(
2.0
f
*
mouse
.
x
/
window_dim
.
x
-
1.0
f
,
1.0
f
-
2.0
f
*
mouse
.
y
/
window_dim
.
y
);
Vec3
p
=
iviewproj
*
Vec3
(
t
.
x
,
t
.
y
,
0.1
f
);
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
);
}
src/app.h
View file @
c2535f0f
#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
;
...
...
src/geometry/halfedge.cpp
View file @
c2535f0f
...
...
@@ -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)
...
...
src/geometry/halfedge.h
View file @
c2535f0f
...
...
@@ -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
src/geometry/spline.h
View file @
c2535f0f
#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.0
f
));
if
(
values
.
size
()
==
1
)
return
values
.
begin
()
->
second
;
if
(
values
.
begin
()
->
first
>
time
)
if
(
values
.
empty
())
return
Quat
::
euler
(
Vec3
(
0.0
f
));
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.0
f
*
norm_t
*
(
1.0
f
-
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
;
...
...
src/geometry/util.cpp
View file @
c2535f0f
...
...
@@ -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.75
f
*
height
,
10
,
true
);
Gen
::
Data
tip
=
Gen
::
cone
(
rtip
,
0.001
f
,
0.25
f
*
height
,
10
,
true
);
for
(
auto
&
v
:
tip
.
verts
)
v
.
pos
.
y
+=
0.7
f
;
for
(
auto
&
v
:
tip
.
verts
)
v
.
pos
.
y
+=
0.7
f
;
return
Gen
::
merge
(
std
::
move
(
base
),
std
::
move
(
tip
));
}
}
GL
::
Mesh
scale_mesh
()
{
GL
::
Mesh
scale_mesh
()
{
Gen
::
Data
base
=
Gen
::
cone
(
0.03
f
,
0.03
f
,
0.7
f
,
10
,
true
);
Gen
::
Data
tip
=
Gen
::
cube
(
0.1
f
);
for
(
auto
&
v
:
tip
.
verts
)
v
.
pos
.
y
+=
0.7
f
;
for
(
auto
&
v
:
tip
.
verts
)
v
.
pos
.
y
+=
0.7
f
;
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.0
f
*
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.0
f
;
for
(
auto
&
v
:
rings
.
verts
)
v
.
pos
.
y
+=
5.0
f
;
float
t
=
0.0
f
;
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.0
f
,
std
::
cos
(
t
));
rings
.
verts
.
push_back
({{},
color
});
rings
.
verts
.
push_back
({
Vec3
(
point
.
x
,
5.0
f
,
point
.
z
),
color
});
t
+=
step
*
(
steps
/
4
);
}
return
GL
::
Lines
(
std
::
move
(
rings
.
verts
),
1.0
f
);
}
}
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.0
f
;
float
step
=
(
2.0
f
*
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.0
f
,
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.0
f
,
-
y
},
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
},
0
},
Data
quad
(
float
x
,
float
y
)
{
return
{{{
Vec3
{
-
x
,
0.0
f
,
-
y
},
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
},
0
},
{
Vec3
{
-
x
,
0.0
f
,
y
},
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
},
0
},
{
Vec3
{
x
,
0.0
f
,
-
y
},
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
},
0
},
{
Vec3
{
x
,
0.0
f
,
y
},
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
},
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.0
f
;
...
...
@@ -175,23 +176,23 @@ namespace Util {
size_t
vert
=
0
;
vertices
[
vert
++
]
=
Vec3
(
0.0
f
,
0.0
f
,
0.0
f
);
while
(
vert
<=
n_sides
)
{
while
(
vert
<=
n_sides
)
{
float
rad
=
(
float
)
vert
/
n_sides
*
_2pi
;
vertices
[
vert
]
=
Vec3
(
std
::
cos
(
rad
)
*
bradius
,
0.0
f
,
std
::
sin
(
rad
)
*
bradius
);
vert
++
;
}
vertices
[
vert
++
]
=
Vec3
(
0.0
f
,
height
,
0.0
f
);
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.0
f
,
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.0
f
,
-
1.0
f
,
0.0
f
);
}
while
(
vert
<=
n_sides
*
2
+
1
)
{
while
(
vert
<=
n_sides
*
2
+
1
)
{
normals
[
vert
++
]
=
Vec3
(
0.0
f
,
1.0
f
,
0.0
f
);
}
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.0
f
,
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.0
f
;
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.0
f
,
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.0
f
,
1.0
f
,
0.0
f
})
*
Vec3
(
std
::
sin
(
t2
)
*
iradius
,
std
::
cos
(
t2
)
*
iradius
,
0.0
f
);
Vec3
r2
=
Mat4
::
rotate
(
Degrees
(
-
t1
),
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
})
*
Vec3
(
std
::
sin
(
t2
)
*
iradius
,
std
::
cos
(
t2
)
*
iradius
,
0.0
f
);
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.0
f
,
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.0
f
;
vertices
[
0
]
=
Vec3
{
0.0
f
,
radius
,
0.0
f
};
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.0
f
,
-
radius
,
0.0
f
};
vertices
[
vertices
.
size
()
-
1
]
=
Vec3
{
0.0
f
,
-
radius
,
0.0
f
};
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.0
f
,
(
point1
.
y
+
point2
.
y
)
/
2.0
f
,
(
point1
.
z
+
point2
.
z
)
/
2.0
f
);
Vec3
middle
((
point1
.
x
+
point2
.
x
)
/
2.0
f
,
(
point1
.
y
+
point2
.
y
)
/
2.0
f
,
(
point1
.
z
+
point2
.
z
)
/
2.0
f
);
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.0
f
+
std
::
sqrt
(
5.0
f
))
/
2.0
f
;
vertices
.
push_back
(
Vec3
(
-
1.0
f
,
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
1.0
f
,
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
1.0
f
,
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
-
1.0
f
,
-
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
1.0
f
,
-
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
1.0
f
,
-
t
,
0.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
0.0
f
,
-
1.0
f
,
t
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
0.0
f
,
1.0
f
,
t
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
0.0
f
,
-
1.0
f
,
-
t
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
0.0
f
,
1.0
f
,
-
t
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
t
,
0.0
f
,
-
1.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
t
,
0.0
f
,
1.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
t
,
0.0
f
,
-
1.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
t
,
0.0
f
,
1.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
-
t
,
0.0
f
,
-
1.0
f
).
unit
()
*
radius
);
vertices
.
push_back
(
Vec3
(
-
t
,
0.0
f
,
1.0
f
).
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
src/geometry/util.h
View file @
c2535f0f
...
...
@@ -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
src/gui/animate.cpp
View file @
c2535f0f
#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.5
f
,
10.0
f
);
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.0
f
).
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.0
f
;
...
...
@@ -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.0
f
).
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.0
f
;
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.0
f
,
0.0
f
,
0.0
f
,
"%.2f"
))
if
(
ImGui
::
DragFloat3
(
"Pose"
,
joint_select
->
pose
.
data
,
1.0
f
,
0.0
f
,
0.0
f
,
"%.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.0
f
,
360.0
f
);
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.0
f
);
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.0
f
,
4.0
f
});
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.0
f
,
1.0
f
});
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.0
f
,
size
.
y
-
80.0
f
},
false
,
ImGuiWindowFlags_HorizontalScrollbar
);
ImGui
::
BeginChild
(
"Timeline"
,
{
size
.
x
-
20.0
f
,
size
.
y
-
80.0
f
},
false
,
ImGuiWindowFlags_HorizontalScrollbar
);
ImGui
::
PushStyleVar
(
ImGuiStyleVar_ItemSpacing
,
{
0.0
f
,
0.0
f
});
...
...
@@ -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.0
f
},
"%s"
,
name
.
c_str
());
if
(
camera_selected
)
ImGui
::
TextColored
({
Color
::
outline
.
x
,
Color
::
outline
.
y
,
Color
::
outline
.
z
,
1.0
f
},
"%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.0
f
},
"%s"
,
name
.
c_str
());
if
(
!
camera_selected
&&
select
&&
item
.
id
()
==
select
->
id
())
ImGui
::
TextColored
({
Color
::
outline
.
x
,
Color
::
outline
.
y
,
Color
::
outline
.
z
,
1.0
f
},
"%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
src/gui/animate.h
View file @
c2535f0f
#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
src/gui/layout.cpp
View file @
c2535f0f
...
...
@@ -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.5
f
,
10.0
f
);
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
src/gui/layout.h
View file @
c2535f0f
...
...
@@ -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
src/gui/manager.cpp
View file @
c2535f0f
...
...
@@ -9,11 +9,8 @@
namespace
Gui
{
Manager
::
Manager
(
Scene
&
scene
,
Vec2
dim
)
:
render
(
scene
,
dim
),
animate
(
dim
),
baseplane
(
1.0
f
),
window_dim
(
dim
)
{
Manager
::
Manager
(
Scene
&
scene
,
Vec2
dim
)
:
render
(
scene
,
dim
),
animate
(
dim
),
baseplane
(
1.0
f
),
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.1
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
(),
"%.2f"
);
ImGui
::
DragFloat
(
"Index of Refraction"
,
&
opt
.
ior
,
0.1
f
,
0.0
f
,
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.1
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
(),
"%.2f"
);
ImGui
::
DragFloat
(
"Index of Refraction"
,
&
opt
.
ior
,
0.1
f
,
0.0
f
,
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.1
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
(),
"%.2f"
);
ImGui
::
DragFloat
(
"Intensity"
,
&
opt
.
intensity
,
0.1
f
,
0.0
f
,
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.1
f
,
0.0
f
,
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.1
f
,
0.0
f
,
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.1
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
(),
"%.2f"
);
ImGui
::
DragFloat
(
"Intensity"
,
&
light
.
opt
.
intensity
,
0.1
f
,
0.0
f
,
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.0
f
});
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.1
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
());
ImGui
::
DragFloat2
(
"Size"
,
light
.
opt
.
size
.
data
,
0.1
f
,
0.0
f
,
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.0
f
;
ImGui
::
SetNextWindowPos
({
0.0
,
menu_height
});
float
h_cut
=
menu_height
+
(
mode
==
Mode
::
animate
?
anim_height
:
0.0
f
);
ImGui
::
SetNextWindowSizeConstraints
(
{
window_dim
.
x
/
4.75
f
,
window_dim
.
y
-
h_cut
},
ImGui
::
SetNextWindowSizeConstraints
({
window_dim
.
x
/
4.75
f
,
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.0
f
,
-
1.0
f
,
0.0
f
);
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.0
f
,
-
1.0
f
,
0.0
f
);
static
Vec2
angles
=
Vec2
(
30.0
f
,
35.0
f
);
...
...
@@ -558,7 +613,7 @@ void Manager::UInew_light(Scene& scene, Undo& undo) {
ImGui
::
InputFloat2
(
"Angle Cutoffs"
,
angles
.
data
,
"%.2f"
);
angles
=
angles
.
range
(
0.0
f
,
360.0
f
);
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.0
f
);
ImGui
::
InputFloat2
(
"Size"
,
size
.
data
,
"%.2f"
);
size
=
clamp
(
size
,
Vec2
(
0.0
f
),
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.0
f
;
ImGui
::
SliderFloat
(
"Side Length"
,
&
R
,
0.01
f
,
10.0
f
,
"%.2f"
);
if
(
ImGui
::
Button
(
"Add"
))
{
add_mesh
(
"Cube"
,
Util
::
cube_mesh
(
R
/
2.0
f
),
true
);
if
(
ImGui
::
Button
(
"Add"
))
{
add_mesh
(
"Cube"
,
Util
::
cube_mesh
(
R
/
2.0
f
),
true
);
}
ImGui
::
PopID
();
}
ImGui
::
Separator
();
if
(
ImGui
::
CollapsingHeader
(
"Square"
))
{
if
(
ImGui
::
CollapsingHeader
(
"Square"
))
{
ImGui
::
PushID
(
idx
++
);
static
float
R
=
1.0
f
;
ImGui
::
SliderFloat
(
"Side Length"
,
&
R
,
0.01
f
,
10.0
f
,
"%.2f"
);
if
(
ImGui
::
Button
(
"Add"
))
{
add_mesh
(
"Square"
,
Util
::
square_mesh
(
R
/
2.0
f
));
if
(
ImGui
::
Button
(
"Add"
))
{
add_mesh
(
"Square"
,
Util
::
square_mesh
(
R
/
2.0
f
));
}
ImGui
::
PopID
();
}
ImGui
::
Separator
();
if
(
ImGui
::
CollapsingHeader
(
"Cylinder"
))
{
if
(
ImGui
::
CollapsingHeader
(
"Cylinder"
))
{
ImGui
::
PushID
(
idx
++
);
static
float
R
=
0.5
f
,
H
=
2.0
f
;
static
int
S
=
12
;
ImGui
::
SliderFloat
(
"Radius"
,
&
R
,
0.01
f
,
10.0
f
,
"%.2f"
);
ImGui
::
SliderFloat
(
"Height"
,
&
H
,
0.01
f
,
10.0
f
,
"%.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.0
f
;
ImGui
::
SliderFloat
(
"Radius"
,
&
R
,
0.01
f
,
10.0
f
,
"%.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.0
f
,
TR
=
0.1
f
,
H
=
1.0
f
;
static
int
S
=
12
;
...
...
@@ -732,7 +789,7 @@ void Manager::UInew_obj(Undo& undo) {
ImGui
::
SliderFloat
(
"Top Radius"
,
&
TR
,
0.01
f
,
10.0
f
,
"%.2f"
);
ImGui
::
SliderFloat
(
"Height"
,
&
H
,
0.01
f
,
10.0
f
,
"%.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.0
f
;
ImGui
::
SetNextWindowPos
(
Vec2
{
center
.
x
,
center
.
y
},
0
,
Vec2
{
0.5
f
,
0.5
f
});
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.0
f
;
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.0
f
);
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
src/gui/manager.h
View file @
c2535f0f
...
...
@@ -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
src/gui/model.cpp
View file @
c2535f0f
#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.05
f
,
1
)),
cylinders
(
Util
::
cyl_mesh
(
0.05
f
,
1.0
f
)),
arrows
(
Util
::
arrow_mesh
(
0.05
f
,
0.1
f
,
1.0
f
))
{}
Model
::
Model
()
:
spheres
(
Util
::
sphere_mesh
(
0.05
f
,
1
)),
cylinders
(
Util
::
cyl_mesh
(
0.05
f
,
1.0
f
)),
arrows
(
Util
::
arrow_mesh
(
0.05
f
,
0.1
f
,
1.0
f
))
{}
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.0
f
?
d
:
2.0
f
;
transform
=
Mat4
{
Vec4
{
size
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
size
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
size
,
0.0
f
},
Vec4
{
v
->
pos
,
1.0
f
}};
transform
=
Mat4
{
Vec4
{
size
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
size
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
size
,
0.0
f
},
Vec4
{
v
->
pos
,
1.0
f
}};
}
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.5
f
*
std
::
min
(
v0s
,
v1s
);
if
(
dir
.
y
==
1.0
f
||
dir
.
y
==
-
1.0
f
)
{
if
(
dir
.
y
==
1.0
f
||
dir
.
y
==
-
1.0
f
)
{
l
*=
sign
(
dir
.
y
);
transform
=
Mat4
{
Vec4
{
s
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
l
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
s
,
0.0
f
},
Vec4
{
v0
,
1.0
f
}};
transform
=
Mat4
{
Vec4
{
s
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
l
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
s
,
0.0
f
},
Vec4
{
v0
,
1.0
f
}};
}
else
{
Vec3
x
=
cross
(
dir
,
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
}).
unit
();
Vec3
z
=
cross
(
x
,
dir
).
unit
();
transform
=
Mat4
{
Vec4
{
x
*
s
,
0.0
f
},
Vec4
{
dir
*
l
,
0.0
f
},
Vec4
{
z
*
s
,
0.0
f
},
Vec4
{
v0
,
1.0
f
}};
transform
=
Mat4
{
Vec4
{
x
*
s
,
0.0
f
},
Vec4
{
dir
*
l
,
0.0
f
},
Vec4
{
z
*
s
,
0.0
f
},
Vec4
{
v0
,
1.0
f
}};
}
}
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.2
f
;
// Align edge
if
(
dir
.
y
==
1.0
f
||
dir
.
y
==
-
1.0
f
)
{
if
(
dir
.
y
==
1.0
f
||
dir
.
y
==
-
1.0
f
)
{
l
*=
sign
(
dir
.
y
);
transform
=
Mat4
{
Vec4
{
s
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
l
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
s
,
0.0
f
},
Vec4
{
v0
+
offset
,
1.0
f
}};
transform
=
Mat4
{
Vec4
{
s
,
0.0
f
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
l
,
0.0
f
,
0.0
f
},
Vec4
{
0.0
f
,
0.0
f
,
s
,
0.0
f
},
Vec4
{
v0
+
offset
,
1.0
f
}};
}
else
{
Vec3
x
=
cross
(
dir
,
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
Vec3
z
=
cross
(
x
,
dir
);
transform
=
Mat4
{
Vec4
{
x
*
s
,
0.0
f
},
Vec4
{
dir
*
l
,
0.0
f
},
Vec4
{
z
*
s
,
0.0
f
},
Vec4
{
v0
+
offset
,
1.0
f
}};
transform
=
Mat4
{
Vec4
{
x
*
s
,
0.0
f
},
Vec4
{
dir
*
l
,
0.0
f
},
Vec4
{
z
*
s
,
0.0
f
},
Vec4
{
v0
+
offset
,
1.0
f
}};
}
}
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.5
f
,
10.0
f
);
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
src/gui/model.h
View file @
c2535f0f
...
...
@@ -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
src/gui/render.cpp
View file @
c2535f0f
#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.5
f
,
10.0
f
);
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.0
f
)
ar
=
ui_render
.
wh_ar
();
if
(
ar
==
0.0
f
)
ar
=
ui_render
.
wh_ar
();
float
fov
=
2.0
f
*
std
::
atan
((
1.0
f
/
ar
)
*
std
::
tan
(
hfov
/
2.0
f
));
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
src/gui/render.h
View file @
c2535f0f
#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
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment