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
Hide whitespace changes
Inline
Side-by-side
src/gui/rig.cpp
View file @
c2535f0f
#include "rig.h"
#include "rig.h"
#include "manager.h"
#include "../scene/renderer.h"
#include "../scene/renderer.h"
#include "manager.h"
namespace
Gui
{
namespace
Gui
{
bool
Rig
::
keydown
(
Widgets
&
widgets
,
Undo
&
undo
,
SDL_Keysym
key
)
{
bool
Rig
::
keydown
(
Widgets
&
widgets
,
Undo
&
undo
,
SDL_Keysym
key
)
{
if
(
!
my_obj
)
return
false
;
if
(
!
my_obj
)
return
false
;
#ifdef __APPLE__
#ifdef __APPLE__
if
(
key
.
sym
==
SDLK_BACKSPACE
&&
key
.
mod
&
KMOD_GUI
)
{
if
(
key
.
sym
==
SDLK_BACKSPACE
&&
key
.
mod
&
KMOD_GUI
)
{
#else
#else
if
(
key
.
sym
==
SDLK_DELETE
&&
selected
)
{
if
(
key
.
sym
==
SDLK_DELETE
&&
selected
)
{
#endif
#endif
undo
.
del_bone
(
my_obj
->
id
(),
selected
);
undo
.
del_bone
(
my_obj
->
id
(),
selected
);
selected
=
nullptr
;
selected
=
nullptr
;
return
true
;
return
true
;
}
}
return
false
;
return
false
;
}
}
void
Rig
::
render
(
Scene_Maybe
obj_opt
,
Widgets
&
widgets
,
Camera
&
cam
)
{
void
Rig
::
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
>
())
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
return
;
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
)
return
;
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
if
(
my_obj
!=
&
obj
)
{
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
)
my_obj
=
&
obj
;
return
;
selected
=
nullptr
;
}
if
(
my_obj
!=
&
obj
)
{
if
(
my_obj
->
rig_dirty
)
{
my_obj
=
&
obj
;
mesh_bvh
.
build
(
obj
.
mesh
());
selected
=
nullptr
;
my_obj
->
rig_dirty
=
false
;
}
}
if
(
my_obj
->
rig_dirty
)
{
mesh_bvh
.
build
(
obj
.
mesh
());
Mat4
view
=
cam
.
get_view
();
my_obj
->
rig_dirty
=
false
;
}
Mat4
view
=
cam
.
get_view
();
obj
.
render
(
view
,
false
,
false
,
false
,
false
);
obj
.
render
(
view
,
false
,
false
,
false
,
false
);
obj
.
armature
.
render
(
view
,
selected
,
root_selected
,
false
);
obj
.
armature
.
render
(
view
,
selected
,
root_selected
,
false
);
if
(
selected
||
root_selected
)
{
if
(
selected
||
root_selected
)
{
widgets
.
active
=
Widget_Type
::
move
;
widgets
.
active
=
Widget_Type
::
move
;
Vec3
pos
;
Vec3
pos
;
if
(
selected
)
pos
=
obj
.
armature
.
end_of
(
selected
);
if
(
selected
)
else
pos
=
obj
.
armature
.
base
();
pos
=
obj
.
armature
.
end_of
(
selected
);
else
float
scale
=
std
::
min
((
cam
.
pos
()
-
pos
).
norm
()
/
5.5
f
,
10.0
f
);
pos
=
obj
.
armature
.
base
();
widgets
.
render
(
view
,
pos
,
scale
);
}
float
scale
=
std
::
min
((
cam
.
pos
()
-
pos
).
norm
()
/
5.5
f
,
10.0
f
);
widgets
.
render
(
view
,
pos
,
scale
);
}
}
}
void
Rig
::
invalidate
(
Joint
*
j
)
{
void
Rig
::
invalidate
(
Joint
*
j
)
{
if
(
selected
==
j
)
selected
=
nullptr
;
if
(
selected
==
j
)
if
(
new_joint
==
j
)
new_joint
=
nullptr
;
selected
=
nullptr
;
if
(
new_joint
==
j
)
new_joint
=
nullptr
;
}
}
void
Rig
::
end_transform
(
Widgets
&
widgets
,
Undo
&
undo
,
Scene_Object
&
obj
)
{
void
Rig
::
end_transform
(
Widgets
&
widgets
,
Undo
&
undo
,
Scene_Object
&
obj
)
{
if
(
root_selected
)
undo
.
move_root
(
obj
.
id
(),
old_ext
);
if
(
root_selected
)
else
undo
.
move_bone
(
obj
.
id
(),
selected
,
old_ext
);
undo
.
move_root
(
obj
.
id
(),
old_ext
);
obj
.
set_skel_dirty
();
else
undo
.
move_bone
(
obj
.
id
(),
selected
,
old_ext
);
obj
.
set_skel_dirty
();
}
}
void
Rig
::
apply_transform
(
Widgets
&
widgets
)
{
void
Rig
::
apply_transform
(
Widgets
&
widgets
)
{
if
(
root_selected
)
{
if
(
root_selected
)
{
my_obj
->
armature
.
base
()
=
widgets
.
apply_action
(
Pose
::
moved
(
old_pos
)).
pos
;
my_obj
->
armature
.
base
()
=
widgets
.
apply_action
(
Pose
::
moved
(
old_pos
)).
pos
;
my_obj
->
set_skel_dirty
();
my_obj
->
set_skel_dirty
();
}
else
if
(
selected
)
{
}
else
if
(
selected
)
{
Vec3
new_pos
=
widgets
.
apply_action
(
Pose
::
moved
(
old_pos
)).
pos
;
Vec3
new_pos
=
widgets
.
apply_action
(
Pose
::
moved
(
old_pos
)).
pos
;
selected
->
extent
=
new_pos
-
old_base
;
selected
->
extent
=
new_pos
-
old_base
;
my_obj
->
set_skel_dirty
();
my_obj
->
set_skel_dirty
();
}
}
}
}
Vec3
Rig
::
selected_pos
()
{
Vec3
Rig
::
selected_pos
()
{
if
(
root_selected
)
{
if
(
root_selected
)
{
return
my_obj
->
armature
.
base
();
return
my_obj
->
armature
.
base
();
}
else
{
}
else
{
assert
(
selected
);
assert
(
selected
);
return
my_obj
->
armature
.
end_of
(
selected
);
return
my_obj
->
armature
.
end_of
(
selected
);
}
}
}
}
void
Rig
::
select
(
Scene
&
scene
,
Widgets
&
widgets
,
Undo
&
undo
,
Scene_ID
id
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
void
Rig
::
select
(
Scene
&
scene
,
Widgets
&
widgets
,
Undo
&
undo
,
Scene_ID
id
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
if
(
!
my_obj
)
return
;
if
(
!
my_obj
)
return
;
if
(
creating_bone
)
{
if
(
creating_bone
)
{
undo
.
add_bone
(
my_obj
->
id
(),
new_joint
);
undo
.
add_bone
(
my_obj
->
id
(),
new_joint
);
selected
=
new_joint
;
selected
=
new_joint
;
new_joint
=
nullptr
;
new_joint
=
nullptr
;
creating_bone
=
false
;
creating_bone
=
false
;
root_selected
=
false
;
root_selected
=
false
;
}
else
if
(
widgets
.
want_drag
())
{
}
else
if
(
widgets
.
want_drag
())
{
if
(
root_selected
)
{
if
(
root_selected
)
{
old_pos
=
my_obj
->
armature
.
base
();
old_pos
=
my_obj
->
armature
.
base
();
}
else
{
}
else
{
assert
(
selected
);
assert
(
selected
);
old_pos
=
my_obj
->
armature
.
end_of
(
selected
);
old_pos
=
my_obj
->
armature
.
end_of
(
selected
);
old_base
=
my_obj
->
armature
.
base_of
(
selected
);
old_base
=
my_obj
->
armature
.
base_of
(
selected
);
old_ext
=
selected
->
extent
;
old_ext
=
selected
->
extent
;
}
}
widgets
.
start_drag
(
old_pos
,
cam
,
spos
,
dir
);
widgets
.
start_drag
(
old_pos
,
cam
,
spos
,
dir
);
}
else
if
(
!
id
||
id
>=
n_Widget_IDs
)
{
}
else
if
(
!
id
||
id
>=
n_Widget_IDs
)
{
selected
=
my_obj
->
armature
.
get_joint
(
id
);
selected
=
my_obj
->
armature
.
get_joint
(
id
);
root_selected
=
my_obj
->
armature
.
is_root_id
(
id
);
root_selected
=
my_obj
->
armature
.
is_root_id
(
id
);
}
}
}
}
void
Rig
::
clear
()
{
void
Rig
::
clear
()
{
my_obj
=
nullptr
;
my_obj
=
nullptr
;
selected
=
nullptr
;
selected
=
nullptr
;
}
}
void
Rig
::
clear_select
()
{
void
Rig
::
clear_select
()
{
selected
=
nullptr
;
}
selected
=
nullptr
;
}
void
Rig
::
hover
(
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
void
Rig
::
hover
(
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
if
(
creating_bone
)
{
if
(
creating_bone
)
{
assert
(
new_joint
);
assert
(
new_joint
);
assert
(
my_obj
);
assert
(
my_obj
);
Ray
f
(
cam
,
dir
);
Ray
f
(
cam
,
dir
);
PT
::
Trace
hit1
=
mesh_bvh
.
hit
(
f
);
PT
::
Trace
hit1
=
mesh_bvh
.
hit
(
f
);
if
(
!
hit1
.
hit
)
return
;
if
(
!
hit1
.
hit
)
return
;
Ray
s
(
hit1
.
position
+
dir
*
EPS_F
,
dir
);
Ray
s
(
hit1
.
position
+
dir
*
EPS_F
,
dir
);
PT
::
Trace
hit2
=
mesh_bvh
.
hit
(
s
);
PT
::
Trace
hit2
=
mesh_bvh
.
hit
(
s
);
Vec3
pos
=
hit1
.
position
;
Vec3
pos
=
hit1
.
position
;
if
(
hit2
.
hit
)
pos
=
0.5
f
*
(
hit1
.
position
+
hit2
.
position
);
if
(
hit2
.
hit
)
pos
=
0.5
f
*
(
hit1
.
position
+
hit2
.
position
);
new_joint
->
extent
=
pos
-
old_base
;
new_joint
->
extent
=
pos
-
old_base
;
my_obj
->
set_skel_dirty
();
my_obj
->
set_skel_dirty
();
}
}
}
}
Mode
Rig
::
UIsidebar
(
Manager
&
manager
,
Undo
&
undo
,
Widgets
&
widgets
,
Scene_Maybe
obj_opt
)
{
Mode
Rig
::
UIsidebar
(
Manager
&
manager
,
Undo
&
undo
,
Widgets
&
widgets
,
Scene_Maybe
obj_opt
)
{
if
(
!
my_obj
)
return
Mode
::
rig
;
if
(
!
my_obj
)
return
Mode
::
rig
;
if
(
!
obj_opt
.
has_value
())
return
Mode
::
rig
;
if
(
!
obj_opt
.
has_value
())
Scene_Item
&
item
=
obj_opt
.
value
();
return
Mode
::
rig
;
if
(
!
item
.
is
<
Scene_Object
>
())
return
Mode
::
rig
;
Scene_Item
&
item
=
obj_opt
.
value
();
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
if
(
!
item
.
is
<
Scene_Object
>
())
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
)
return
Mode
::
rig
;
return
Mode
::
rig
;
if
(
my_obj
!=
&
obj
)
{
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
my_obj
=
&
obj
;
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
)
selected
=
nullptr
;
return
Mode
::
rig
;
}
if
(
my_obj
->
rig_dirty
)
{
if
(
my_obj
!=
&
obj
)
{
mesh_bvh
.
build
(
obj
.
mesh
());
my_obj
=
&
obj
;
my_obj
->
rig_dirty
=
false
;
selected
=
nullptr
;
}
}
if
(
my_obj
->
rig_dirty
)
{
ImGui
::
Text
(
"Edit Skeleton"
);
mesh_bvh
.
build
(
obj
.
mesh
());
my_obj
->
rig_dirty
=
false
;
if
(
creating_bone
)
{
}
if
(
ImGui
::
Button
(
"Cancel"
))
{
creating_bone
=
false
;
ImGui
::
Text
(
"Edit Skeleton"
);
my_obj
->
armature
.
erase
(
new_joint
);
new_joint
=
nullptr
;
if
(
creating_bone
)
{
my_obj
->
set_skel_dirty
();
if
(
ImGui
::
Button
(
"Cancel"
))
{
}
creating_bone
=
false
;
}
else
if
(
ImGui
::
Button
(
"New Bone"
))
{
my_obj
->
armature
.
erase
(
new_joint
);
new_joint
=
nullptr
;
creating_bone
=
true
;
my_obj
->
set_skel_dirty
();
}
if
(
!
selected
||
root_selected
)
{
}
else
if
(
ImGui
::
Button
(
"New Bone"
))
{
new_joint
=
my_obj
->
armature
.
add_root
(
Vec3
{
0.0
f
});
old_base
=
my_obj
->
armature
.
base
();
creating_bone
=
true
;
}
else
{
new_joint
=
my_obj
->
armature
.
add_child
(
selected
,
Vec3
{
0.0
f
});
if
(
!
selected
||
root_selected
)
{
old_base
=
my_obj
->
armature
.
end_of
(
selected
);
new_joint
=
my_obj
->
armature
.
add_root
(
Vec3
{
0.0
f
});
}
old_base
=
my_obj
->
armature
.
base
();
my_obj
->
set_skel_dirty
();
}
else
{
}
new_joint
=
my_obj
->
armature
.
add_child
(
selected
,
Vec3
{
0.0
f
});
old_base
=
my_obj
->
armature
.
end_of
(
selected
);
if
(
selected
)
{
}
my_obj
->
set_skel_dirty
();
ImGui
::
Separator
();
}
ImGui
::
Text
(
"Edit Bone"
);
if
(
selected
)
{
ImGui
::
DragFloat3
(
"Extent"
,
selected
->
extent
.
data
,
0.1
f
);
ImGui
::
DragFloat
(
"Radius"
,
&
selected
->
radius
,
0.05
f
,
0.0
f
,
std
::
numeric_limits
<
float
>::
max
());
ImGui
::
Separator
();
ImGui
::
Text
(
"Edit Bone"
);
ImGui
::
DragFloat3
(
"Pose"
,
selected
->
pose
.
data
,
0.1
f
);
ImGui
::
DragFloat3
(
"Extent"
,
selected
->
extent
.
data
,
0.1
f
);
if
(
ImGui
::
Button
(
"Delete [del]"
))
{
ImGui
::
DragFloat
(
"Radius"
,
&
selected
->
radius
,
0.05
f
,
0.0
f
,
undo
.
del_bone
(
my_obj
->
id
(),
selected
);
std
::
numeric_limits
<
float
>::
max
());
selected
=
nullptr
;
}
ImGui
::
DragFloat3
(
"Pose"
,
selected
->
pose
.
data
,
0.1
f
);
}
if
(
ImGui
::
Button
(
"Delete [del]"
))
{
undo
.
del_bone
(
my_obj
->
id
(),
selected
);
selected
=
nullptr
;
}
}
return
Mode
::
rig
;
return
Mode
::
rig
;
}
}
}
}
// namespace Gui
src/gui/rig.h
View file @
c2535f0f
#pragma once
#pragma once
#include <SDL2/SDL.h>
#include "widgets.h"
#include "../rays/tri_mesh.h"
#include "../rays/tri_mesh.h"
#include "widgets.h"
#include <SDL2/SDL.h>
namespace
Gui
{
namespace
Gui
{
...
@@ -12,31 +12,32 @@ class Manager;
...
@@ -12,31 +12,32 @@ class Manager;
class
Rig
{
class
Rig
{
public:
public:
bool
keydown
(
Widgets
&
widgets
,
Undo
&
undo
,
SDL_Keysym
key
);
bool
keydown
(
Widgets
&
widgets
,
Undo
&
undo
,
SDL_Keysym
key
);
void
select
(
Scene
&
scene
,
Widgets
&
widgets
,
Undo
&
undo
,
Scene_ID
id
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
);
void
select
(
Scene
&
scene
,
Widgets
&
widgets
,
Undo
&
undo
,
Scene_ID
id
,
Vec3
cam
,
Vec2
spos
,
void
hover
(
Vec3
cam
,
Vec2
spos
,
Vec3
dir
);
Vec3
dir
);
void
hover
(
Vec3
cam
,
Vec2
spos
,
Vec3
dir
);
void
end_transform
(
Widgets
&
widgets
,
Undo
&
undo
,
Scene_Object
&
obj
);
void
end_transform
(
Widgets
&
widgets
,
Undo
&
undo
,
Scene_Object
&
obj
);
void
apply_transform
(
Widgets
&
widgets
);
void
apply_transform
(
Widgets
&
widgets
);
Vec3
selected_pos
();
Vec3
selected_pos
();
void
clear_select
();
void
clear_select
();
void
clear
();
void
clear
();
void
invalidate
(
Joint
*
j
);
void
invalidate
(
Joint
*
j
);
void
render
(
Scene_Maybe
obj_opt
,
Widgets
&
widgets
,
Camera
&
cam
);
void
render
(
Scene_Maybe
obj_opt
,
Widgets
&
widgets
,
Camera
&
cam
);
Mode
UIsidebar
(
Manager
&
manager
,
Undo
&
undo
,
Widgets
&
widgets
,
Scene_Maybe
obj
);
Mode
UIsidebar
(
Manager
&
manager
,
Undo
&
undo
,
Widgets
&
widgets
,
Scene_Maybe
obj
);
private:
private:
bool
creating_bone
=
false
;
bool
creating_bone
=
false
;
bool
root_selected
=
false
;
bool
root_selected
=
false
;
Vec3
old_pos
,
old_base
,
old_ext
;
Vec3
old_pos
,
old_base
,
old_ext
;
Scene_Object
*
my_obj
=
nullptr
;
Scene_Object
*
my_obj
=
nullptr
;
Joint
*
selected
=
nullptr
;
Joint
*
selected
=
nullptr
;
Joint
*
new_joint
=
nullptr
;
Joint
*
new_joint
=
nullptr
;
PT
::
Tri_Mesh
mesh_bvh
;
PT
::
Tri_Mesh
mesh_bvh
;
};
};
}
}
// namespace Gui
src/gui/widgets.cpp
View file @
c2535f0f
#include <imgui/imgui.h>
#include <imgui/imgui.h>
#include <iomanip>
#include <iostream>
#include <nfd/nfd.h>
#include <nfd/nfd.h>
#include <sf_libs/stb_image_write.h>
#include <sf_libs/stb_image_write.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <sstream>
#include "animate.h"
#include "manager.h"
#include "manager.h"
#include "widgets.h"
#include "widgets.h"
#include "animate.h"
#include "../geometry/util.h"
#include "../platform/platform.h"
#include "../platform/platform.h"
#include "../scene/renderer.h"
#include "../scene/renderer.h"
#include "../geometry/util.h"
namespace
Gui
{
namespace
Gui
{
Widgets
::
Widgets
()
:
lines
(
1.0
f
)
{
Widgets
::
Widgets
()
:
lines
(
1.0
f
)
{
x_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_mov
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
x_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_mov
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
y_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_mov
,
{},
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
z_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_mov
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
y_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_mov
,
{},
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
z_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_mov
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
xy_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
xy_mov
,
Pose
::
rotated
(
Vec3
{
-
90.0
f
,
0.0
f
,
0.0
f
}),
Util
::
square_mesh
(
0.1
f
));
Util
::
arrow_mesh
(
0.03
f
,
0.075
f
,
1.0
f
));
yz_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
yz_mov
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
Util
::
square_mesh
(
0.1
f
));
xz_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
xz_mov
,
{},
Util
::
square_mesh
(
0.1
f
));
xy_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
xy_mov
,
Pose
::
rotated
(
Vec3
{
-
90.0
f
,
0.0
f
,
0.0
f
}),
Util
::
square_mesh
(
0.1
f
));
x_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_rot
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
yz_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
yz_mov
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
y_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_rot
,
{},
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
Util
::
square_mesh
(
0.1
f
));
z_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_rot
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
xz_mov
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
xz_mov
,
{},
Util
::
square_mesh
(
0.1
f
));
x_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_scl
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
Util
::
scale_mesh
());
x_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_rot
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
y_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_scl
,
{},
Util
::
scale_mesh
());
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
z_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_scl
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
Util
::
scale_mesh
());
y_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_rot
,
{},
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
z_rot
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_rot
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
#define setcolor(o,c) o.material.opt.albedo = Spectrum((c).x,(c).y,(c).z);
Util
::
torus_mesh
(
0.975
f
,
1.0
f
));
setcolor
(
x_mov
,
Color
::
red
);
setcolor
(
y_mov
,
Color
::
green
);
x_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
x_scl
,
Pose
::
rotated
(
Vec3
{
0.0
f
,
0.0
f
,
-
90.0
f
}),
setcolor
(
z_mov
,
Color
::
blue
);
Util
::
scale_mesh
());
setcolor
(
xy_mov
,
Color
::
blue
);
y_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
y_scl
,
{},
Util
::
scale_mesh
());
setcolor
(
yz_mov
,
Color
::
red
);
z_scl
=
Scene_Object
((
Scene_ID
)
Widget_IDs
::
z_scl
,
Pose
::
rotated
(
Vec3
{
90.0
f
,
0.0
f
,
0.0
f
}),
setcolor
(
xz_mov
,
Color
::
green
);
Util
::
scale_mesh
());
setcolor
(
x_rot
,
Color
::
red
);
setcolor
(
y_rot
,
Color
::
green
);
#define setcolor(o, c) o.material.opt.albedo = Spectrum((c).x, (c).y, (c).z);
setcolor
(
z_rot
,
Color
::
blue
);
setcolor
(
x_mov
,
Color
::
red
);
setcolor
(
x_scl
,
Color
::
red
);
setcolor
(
y_mov
,
Color
::
green
);
setcolor
(
y_scl
,
Color
::
green
);
setcolor
(
z_mov
,
Color
::
blue
);
setcolor
(
z_scl
,
Color
::
blue
);
setcolor
(
xy_mov
,
Color
::
blue
);
setcolor
(
yz_mov
,
Color
::
red
);
setcolor
(
xz_mov
,
Color
::
green
);
setcolor
(
x_rot
,
Color
::
red
);
setcolor
(
y_rot
,
Color
::
green
);
setcolor
(
z_rot
,
Color
::
blue
);
setcolor
(
x_scl
,
Color
::
red
);
setcolor
(
y_scl
,
Color
::
green
);
setcolor
(
z_scl
,
Color
::
blue
);
#undef setcolor
#undef setcolor
}
}
void
Widgets
::
generate_lines
(
Vec3
pos
)
{
void
Widgets
::
generate_lines
(
Vec3
pos
)
{
auto
add_axis
=
[
&
](
int
axis
)
{
auto
add_axis
=
[
&
](
int
axis
)
{
Vec3
start
=
pos
;
start
[
axis
]
-=
10000.0
f
;
Vec3
start
=
pos
;
Vec3
end
=
pos
;
end
[
axis
]
+=
10000.0
f
;
start
[
axis
]
-=
10000.0
f
;
Vec3
color
=
Color
::
axis
((
Axis
)
axis
);
Vec3
end
=
pos
;
lines
.
add
(
start
,
end
,
color
);
end
[
axis
]
+=
10000.0
f
;
};
Vec3
color
=
Color
::
axis
((
Axis
)
axis
);
if
(
drag_plane
)
{
lines
.
add
(
start
,
end
,
color
);
add_axis
(((
int
)
axis
+
1
)
%
3
);
};
add_axis
(((
int
)
axis
+
2
)
%
3
);
if
(
drag_plane
)
{
}
else
{
add_axis
(((
int
)
axis
+
1
)
%
3
);
add_axis
((
int
)
axis
);
add_axis
(((
int
)
axis
+
2
)
%
3
);
}
}
else
{
add_axis
((
int
)
axis
);
}
}
}
bool
Widgets
::
action_button
(
Widget_Type
act
,
std
::
string
name
,
bool
wrap
)
{
bool
Widgets
::
action_button
(
Widget_Type
act
,
std
::
string
name
,
bool
wrap
)
{
bool
is_active
=
act
==
active
;
bool
is_active
=
act
==
active
;
if
(
is_active
)
ImGui
::
PushStyleColor
(
ImGuiCol_Button
,
ImGui
::
GetColorU32
(
ImGuiCol_ButtonActive
));
if
(
is_active
)
bool
clicked
=
wrap
?
Manager
::
wrap_button
(
name
)
:
ImGui
::
Button
(
name
.
c_str
());
ImGui
::
PushStyleColor
(
ImGuiCol_Button
,
ImGui
::
GetColorU32
(
ImGuiCol_ButtonActive
));
if
(
is_active
)
ImGui
::
PopStyleColor
();
bool
clicked
=
wrap
?
Manager
::
wrap_button
(
name
)
:
ImGui
::
Button
(
name
.
c_str
());
if
(
clicked
)
active
=
act
;
if
(
is_active
)
return
clicked
;
ImGui
::
PopStyleColor
();
if
(
clicked
)
active
=
act
;
return
clicked
;
};
};
void
Widgets
::
render
(
const
Mat4
&
view
,
Vec3
pos
,
float
scl
)
{
void
Widgets
::
render
(
const
Mat4
&
view
,
Vec3
pos
,
float
scl
)
{
Renderer
&
r
=
Renderer
::
get
();
r
.
reset_depth
();
Vec3
scale
(
scl
);
r
.
lines
(
lines
,
view
,
Mat4
::
I
,
0.5
f
);
if
(
dragging
&&
(
active
==
Widget_Type
::
move
||
active
==
Widget_Type
::
scale
))
return
;
if
(
active
==
Widget_Type
::
move
)
{
x_mov
.
pose
.
scale
=
scale
;
x_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.15
f
*
scl
,
0.0
f
,
0.0
f
);
x_mov
.
render
(
view
,
true
);
y_mov
.
pose
.
scale
=
scale
;
y_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.15
f
*
scl
,
0.0
f
);
y_mov
.
render
(
view
,
true
);
z_mov
.
pose
.
scale
=
scale
;
z_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.0
f
,
0.15
f
*
scl
);
z_mov
.
render
(
view
,
true
);
xy_mov
.
pose
.
scale
=
scale
;
xy_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.45
f
*
scl
,
0.45
f
*
scl
,
0.0
f
);
xy_mov
.
render
(
view
,
true
);
yz_mov
.
pose
.
scale
=
scale
;
yz_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.45
f
*
scl
,
0.45
f
*
scl
);
yz_mov
.
render
(
view
,
true
);
xz_mov
.
pose
.
scale
=
scale
;
xz_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.45
f
*
scl
,
0.0
f
,
0.45
f
*
scl
);
xz_mov
.
render
(
view
,
true
);
}
else
if
(
active
==
Widget_Type
::
rotate
)
{
if
(
!
dragging
||
axis
==
Axis
::
X
)
{
x_rot
.
pose
.
scale
=
scale
;
x_rot
.
pose
.
pos
=
pos
;
x_rot
.
render
(
view
,
true
);
}
if
(
!
dragging
||
axis
==
Axis
::
Y
)
{
y_rot
.
pose
.
scale
=
scale
;
y_rot
.
pose
.
pos
=
pos
;
y_rot
.
render
(
view
,
true
);
}
if
(
!
dragging
||
axis
==
Axis
::
Z
)
{
z_rot
.
pose
.
scale
=
scale
;
z_rot
.
pose
.
pos
=
pos
;
z_rot
.
render
(
view
,
true
);
}
}
else
if
(
active
==
Widget_Type
::
scale
)
{
x_scl
.
pose
.
scale
=
scale
;
x_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.15
f
*
scl
,
0.0
f
,
0.0
f
);
x_scl
.
render
(
view
,
true
);
y_scl
.
pose
.
scale
=
scale
;
y_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.15
f
*
scl
,
0.0
f
);
y_scl
.
render
(
view
,
true
);
z_scl
.
pose
.
scale
=
scale
;
z_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.0
f
,
0.15
f
*
scl
);
z_scl
.
render
(
view
,
true
);
}
}
Pose
Widgets
::
apply_action
(
const
Pose
&
pose
)
{
Renderer
&
r
=
Renderer
::
get
();
r
.
reset_depth
();
Pose
result
=
pose
;
Vec3
vaxis
;
Vec3
scale
(
scl
);
vaxis
[(
int
)
axis
]
=
1.0
f
;
r
.
lines
(
lines
,
view
,
Mat4
::
I
,
0.5
f
);
switch
(
active
)
{
if
(
dragging
&&
(
active
==
Widget_Type
::
move
||
active
==
Widget_Type
::
scale
))
case
Widget_Type
::
move
:
{
return
;
result
.
pos
=
pose
.
pos
+
drag_end
-
drag_start
;
}
break
;
if
(
active
==
Widget_Type
::
move
)
{
case
Widget_Type
::
rotate
:
{
Quat
rot
=
Quat
::
axis_angle
(
vaxis
,
drag_end
[(
int
)
axis
]);
x_mov
.
pose
.
scale
=
scale
;
Quat
combined
=
rot
*
pose
.
rotation_quat
();
x_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.15
f
*
scl
,
0.0
f
,
0.0
f
);
result
.
euler
=
combined
.
to_euler
();
x_mov
.
render
(
view
,
true
);
}
break
;
case
Widget_Type
::
scale
:
{
y_mov
.
pose
.
scale
=
scale
;
result
.
scale
=
Vec3
{
1.0
f
};
y_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.15
f
*
scl
,
0.0
f
);
result
.
scale
[(
int
)
axis
]
=
drag_end
[(
int
)
axis
];
y_mov
.
render
(
view
,
true
);
Mat4
rot
=
pose
.
rotation_mat
();
Mat4
trans
=
Mat4
::
transpose
(
rot
)
*
Mat4
::
scale
(
result
.
scale
)
*
rot
*
Mat4
::
scale
(
pose
.
scale
);
z_mov
.
pose
.
scale
=
scale
;
result
.
scale
=
Vec3
(
trans
[
0
][
0
],
trans
[
1
][
1
],
trans
[
2
][
2
]);
z_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.0
f
,
0.15
f
*
scl
);
}
break
;
z_mov
.
render
(
view
,
true
);
case
Widget_Type
::
bevel
:
{
Vec2
off
=
bevel_start
-
bevel_end
;
xy_mov
.
pose
.
scale
=
scale
;
result
.
pos
=
2.0
f
*
Vec3
(
off
.
x
,
-
off
.
y
,
0.0
f
);
xy_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.45
f
*
scl
,
0.45
f
*
scl
,
0.0
f
);
}
break
;
xy_mov
.
render
(
view
,
true
);
default:
assert
(
false
);
}
yz_mov
.
pose
.
scale
=
scale
;
yz_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.45
f
*
scl
,
0.45
f
*
scl
);
return
result
;
yz_mov
.
render
(
view
,
true
);
}
xz_mov
.
pose
.
scale
=
scale
;
xz_mov
.
pose
.
pos
=
pos
+
Vec3
(
0.45
f
*
scl
,
0.0
f
,
0.45
f
*
scl
);
xz_mov
.
render
(
view
,
true
);
}
else
if
(
active
==
Widget_Type
::
rotate
)
{
if
(
!
dragging
||
axis
==
Axis
::
X
)
{
x_rot
.
pose
.
scale
=
scale
;
x_rot
.
pose
.
pos
=
pos
;
x_rot
.
render
(
view
,
true
);
}
if
(
!
dragging
||
axis
==
Axis
::
Y
)
{
y_rot
.
pose
.
scale
=
scale
;
y_rot
.
pose
.
pos
=
pos
;
y_rot
.
render
(
view
,
true
);
}
if
(
!
dragging
||
axis
==
Axis
::
Z
)
{
z_rot
.
pose
.
scale
=
scale
;
z_rot
.
pose
.
pos
=
pos
;
z_rot
.
render
(
view
,
true
);
}
bool
Widgets
::
to_axis
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
&
hit
)
{
}
else
if
(
active
==
Widget_Type
::
scale
)
{
Vec3
axis1
;
axis1
[(
int
)
axis
]
=
1.0
f
;
x_scl
.
pose
.
scale
=
scale
;
Vec3
axis2
;
axis2
[((
int
)
axis
+
1
)
%
3
]
=
1.0
f
;
x_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.15
f
*
scl
,
0.0
f
,
0.0
f
);
Vec3
axis3
;
axis3
[((
int
)
axis
+
2
)
%
3
]
=
1.0
f
;
x_scl
.
render
(
view
,
true
);
Line
select
(
cam_pos
,
dir
);
y_scl
.
pose
.
scale
=
scale
;
Line
target
(
obj_pos
,
axis1
);
y_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.15
f
*
scl
,
0.0
f
);
Plane
l
(
obj_pos
,
axis2
);
y_scl
.
render
(
view
,
true
);
Plane
r
(
obj_pos
,
axis3
);
z_scl
.
pose
.
scale
=
scale
;
Vec3
hit1
,
hit2
;
z_scl
.
pose
.
pos
=
pos
+
Vec3
(
0.0
f
,
0.0
f
,
0.15
f
*
scl
);
bool
hl
=
l
.
hit
(
select
,
hit1
);
z_scl
.
render
(
view
,
true
);
bool
hr
=
r
.
hit
(
select
,
hit2
);
}
if
(
!
hl
&&
!
hr
)
return
false
;
else
if
(
!
hl
)
hit
=
hit2
;
else
if
(
!
hr
)
hit
=
hit1
;
else
hit
=
(
hit1
-
cam_pos
).
norm
()
>
(
hit2
-
cam_pos
).
norm
()
?
hit2
:
hit1
;
hit
=
target
.
closest
(
hit
);
return
hit
.
valid
();
}
}
bool
Widgets
::
to_plane
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
norm
,
Vec3
&
hit
)
{
Pose
Widgets
::
apply_action
(
const
Pose
&
pose
)
{
Pose
result
=
pose
;
Vec3
vaxis
;
vaxis
[(
int
)
axis
]
=
1.0
f
;
switch
(
active
)
{
case
Widget_Type
::
move
:
{
result
.
pos
=
pose
.
pos
+
drag_end
-
drag_start
;
}
break
;
case
Widget_Type
::
rotate
:
{
Quat
rot
=
Quat
::
axis_angle
(
vaxis
,
drag_end
[(
int
)
axis
]);
Quat
combined
=
rot
*
pose
.
rotation_quat
();
result
.
euler
=
combined
.
to_euler
();
}
break
;
case
Widget_Type
::
scale
:
{
result
.
scale
=
Vec3
{
1.0
f
};
result
.
scale
[(
int
)
axis
]
=
drag_end
[(
int
)
axis
];
Mat4
rot
=
pose
.
rotation_mat
();
Mat4
trans
=
Mat4
::
transpose
(
rot
)
*
Mat4
::
scale
(
result
.
scale
)
*
rot
*
Mat4
::
scale
(
pose
.
scale
);
result
.
scale
=
Vec3
(
trans
[
0
][
0
],
trans
[
1
][
1
],
trans
[
2
][
2
]);
}
break
;
case
Widget_Type
::
bevel
:
{
Vec2
off
=
bevel_start
-
bevel_end
;
result
.
pos
=
2.0
f
*
Vec3
(
off
.
x
,
-
off
.
y
,
0.0
f
);
}
break
;
default:
assert
(
false
);
}
Line
look
(
cam_pos
,
dir
);
return
result
;
Plane
p
(
obj_pos
,
norm
);
return
p
.
hit
(
look
,
hit
);
}
}
bool
Widgets
::
is_dragging
()
{
bool
Widgets
::
to_axis
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
&
hit
)
{
return
dragging
;
Vec3
axis1
;
axis1
[(
int
)
axis
]
=
1.0
f
;
Vec3
axis2
;
axis2
[((
int
)
axis
+
1
)
%
3
]
=
1.0
f
;
Vec3
axis3
;
axis3
[((
int
)
axis
+
2
)
%
3
]
=
1.0
f
;
Line
select
(
cam_pos
,
dir
);
Line
target
(
obj_pos
,
axis1
);
Plane
l
(
obj_pos
,
axis2
);
Plane
r
(
obj_pos
,
axis3
);
Vec3
hit1
,
hit2
;
bool
hl
=
l
.
hit
(
select
,
hit1
);
bool
hr
=
r
.
hit
(
select
,
hit2
);
if
(
!
hl
&&
!
hr
)
return
false
;
else
if
(
!
hl
)
hit
=
hit2
;
else
if
(
!
hr
)
hit
=
hit1
;
else
hit
=
(
hit1
-
cam_pos
).
norm
()
>
(
hit2
-
cam_pos
).
norm
()
?
hit2
:
hit1
;
hit
=
target
.
closest
(
hit
);
return
hit
.
valid
();
}
}
bool
Widgets
::
want_drag
()
{
bool
Widgets
::
to_plane
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
norm
,
Vec3
&
hit
)
{
return
start_dragging
;
Line
look
(
cam_pos
,
dir
);
Plane
p
(
obj_pos
,
norm
);
return
p
.
hit
(
look
,
hit
);
}
}
bool
Widgets
::
is_dragging
()
{
return
dragging
;
}
bool
Widgets
::
want_drag
()
{
return
start_dragging
;
}
void
Widgets
::
set_dragging
(
bool
drag
,
bool
plane
)
{
void
Widgets
::
set_dragging
(
bool
drag
,
bool
plane
)
{
dragging
=
drag
;
dragging
=
drag
;
drag_plane
=
plane
;
drag_plane
=
plane
;
}
}
void
Widgets
::
start_drag
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
void
Widgets
::
start_drag
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
)
{
start_dragging
=
false
;
dragging
=
true
;
Vec3
hit
;
start_dragging
=
false
;
Vec3
norm
;
norm
[(
int
)
axis
]
=
1.0
f
;
dragging
=
true
;
Vec3
hit
;
Vec3
norm
;
norm
[(
int
)
axis
]
=
1.0
f
;
if
(
active
==
Widget_Type
::
rotate
)
{
if
(
active
==
Widget_Type
::
rotate
)
{
if
(
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
))
{
if
(
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
))
{
drag_start
=
(
hit
-
pos
).
unit
();
drag_start
=
(
hit
-
pos
).
unit
();
drag_end
=
Vec3
{
0.0
f
};
drag_end
=
Vec3
{
0.0
f
};
}
}
}
else
{
}
else
{
bool
good
;
bool
good
;
if
(
drag_plane
)
good
=
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
);
if
(
drag_plane
)
else
good
=
to_axis
(
pos
,
cam
,
dir
,
hit
);
good
=
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
);
else
good
=
to_axis
(
pos
,
cam
,
dir
,
hit
);
if
(
!
good
)
return
;
if
(
!
good
)
return
;
if
(
active
==
Widget_Type
::
bevel
)
{
if
(
active
==
Widget_Type
::
bevel
)
{
bevel_start
=
bevel_end
=
spos
;
bevel_start
=
bevel_end
=
spos
;
}
if
(
active
==
Widget_Type
::
move
)
{
}
drag_start
=
drag_end
=
hit
;
if
(
active
==
Widget_Type
::
move
)
{
}
else
{
drag_start
=
drag_end
=
hit
;
drag_start
=
hit
;
}
else
{
drag_end
=
Vec3
{
1.0
f
};
drag_start
=
hit
;
}
drag_end
=
Vec3
{
1.0
f
};
}
if
(
active
!=
Widget_Type
::
bevel
)
if
(
active
!=
Widget_Type
::
bevel
)
generate_lines
(
pos
);
generate_lines
(
pos
);
}
}
}
}
void
Widgets
::
end_drag
()
{
void
Widgets
::
end_drag
()
{
lines
.
clear
();
lines
.
clear
();
drag_start
=
drag_end
=
{};
drag_start
=
drag_end
=
{};
bevel_start
=
bevel_end
=
{};
bevel_start
=
bevel_end
=
{};
dragging
=
false
;
dragging
=
false
;
drag_plane
=
false
;
drag_plane
=
false
;
}
}
void
Widgets
::
drag_to
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
,
bool
scale_invert
)
{
void
Widgets
::
drag_to
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
,
bool
scale_invert
)
{
Vec3
hit
;
Vec3
hit
;
Vec3
norm
;
norm
[(
int
)
axis
]
=
1.0
f
;
Vec3
norm
;
norm
[(
int
)
axis
]
=
1.0
f
;
if
(
active
==
Widget_Type
::
bevel
)
{
if
(
active
==
Widget_Type
::
bevel
)
{
bevel_end
=
spos
;
bevel_end
=
spos
;
}
else
if
(
active
==
Widget_Type
::
rotate
)
{
}
else
if
(
active
==
Widget_Type
::
rotate
)
{
if
(
!
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
))
return
;
Vec3
ang
=
(
hit
-
pos
).
unit
();
if
(
!
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
))
float
sgn
=
sign
(
cross
(
drag_start
,
ang
)[(
int
)
axis
]);
return
;
drag_end
=
Vec3
{};
drag_end
[(
int
)
axis
]
=
sgn
*
Degrees
(
std
::
acos
(
dot
(
drag_start
,
ang
)));
}
else
{
Vec3
ang
=
(
hit
-
pos
).
unit
();
float
sgn
=
sign
(
cross
(
drag_start
,
ang
)[(
int
)
axis
]);
drag_end
=
Vec3
{};
drag_end
[(
int
)
axis
]
=
sgn
*
Degrees
(
std
::
acos
(
dot
(
drag_start
,
ang
)));
}
else
{
bool
good
;
bool
good
;
if
(
drag_plane
)
good
=
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
);
else
good
=
to_axis
(
pos
,
cam
,
dir
,
hit
);
if
(
!
good
)
return
;
if
(
drag_plane
)
good
=
to_plane
(
pos
,
cam
,
dir
,
norm
,
hit
);
else
good
=
to_axis
(
pos
,
cam
,
dir
,
hit
);
if
(
active
==
Widget_Type
::
move
)
{
if
(
!
good
)
drag_end
=
hit
;
return
;
}
else
if
(
active
==
Widget_Type
::
scale
)
{
drag_end
=
Vec3
{
1.0
f
};
drag_end
[(
int
)
axis
]
=
(
hit
-
pos
).
norm
()
/
(
drag_start
-
pos
).
norm
();
}
else
assert
(
false
);
}
if
(
scale_invert
&&
active
==
Widget_Type
::
scale
)
{
if
(
active
==
Widget_Type
::
move
)
{
drag_end
[(
int
)
axis
]
*=
sign
(
dot
(
hit
-
pos
,
drag_start
-
pos
));
drag_end
=
hit
;
}
}
else
if
(
active
==
Widget_Type
::
scale
)
{
drag_end
=
Vec3
{
1.0
f
};
drag_end
[(
int
)
axis
]
=
(
hit
-
pos
).
norm
()
/
(
drag_start
-
pos
).
norm
();
}
else
assert
(
false
);
}
if
(
scale_invert
&&
active
==
Widget_Type
::
scale
)
{
drag_end
[(
int
)
axis
]
*=
sign
(
dot
(
hit
-
pos
,
drag_start
-
pos
));
}
}
}
void
Widgets
::
select
(
Scene_ID
id
)
{
void
Widgets
::
select
(
Scene_ID
id
)
{
start_dragging
=
true
;
start_dragging
=
true
;
drag_plane
=
false
;
drag_plane
=
false
;
switch
(
id
)
{
switch
(
id
)
{
case
(
Scene_ID
)
Widget_IDs
::
x_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
x_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
X
;
axis
=
Axis
::
X
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
y_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
y_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
Y
;
axis
=
Axis
::
Y
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
z_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
z_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
Z
;
axis
=
Axis
::
Z
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
xy_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
xy_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
Z
;
axis
=
Axis
::
Z
;
drag_plane
=
true
;
drag_plane
=
true
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
yz_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
yz_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
X
;
axis
=
Axis
::
X
;
drag_plane
=
true
;
drag_plane
=
true
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
xz_mov
:
{
case
(
Scene_ID
)
Widget_IDs
::
xz_mov
:
{
active
=
Widget_Type
::
move
;
active
=
Widget_Type
::
move
;
axis
=
Axis
::
Y
;
axis
=
Axis
::
Y
;
drag_plane
=
true
;
drag_plane
=
true
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
x_rot
:
{
case
(
Scene_ID
)
Widget_IDs
::
x_rot
:
{
active
=
Widget_Type
::
rotate
;
active
=
Widget_Type
::
rotate
;
axis
=
Axis
::
X
;
axis
=
Axis
::
X
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
y_rot
:
{
case
(
Scene_ID
)
Widget_IDs
::
y_rot
:
{
active
=
Widget_Type
::
rotate
;
active
=
Widget_Type
::
rotate
;
axis
=
Axis
::
Y
;
axis
=
Axis
::
Y
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
z_rot
:
{
case
(
Scene_ID
)
Widget_IDs
::
z_rot
:
{
active
=
Widget_Type
::
rotate
;
active
=
Widget_Type
::
rotate
;
axis
=
Axis
::
Z
;
axis
=
Axis
::
Z
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
x_scl
:
{
case
(
Scene_ID
)
Widget_IDs
::
x_scl
:
{
active
=
Widget_Type
::
scale
;
active
=
Widget_Type
::
scale
;
axis
=
Axis
::
X
;
axis
=
Axis
::
X
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
y_scl
:
{
case
(
Scene_ID
)
Widget_IDs
::
y_scl
:
{
active
=
Widget_Type
::
scale
;
active
=
Widget_Type
::
scale
;
axis
=
Axis
::
Y
;
axis
=
Axis
::
Y
;
}
break
;
}
break
;
case
(
Scene_ID
)
Widget_IDs
::
z_scl
:
{
case
(
Scene_ID
)
Widget_IDs
::
z_scl
:
{
active
=
Widget_Type
::
scale
;
active
=
Widget_Type
::
scale
;
axis
=
Axis
::
Z
;
axis
=
Axis
::
Z
;
}
break
;
}
break
;
default:
{
default:
{
start_dragging
=
false
;
start_dragging
=
false
;
}
break
;
}
break
;
}
}
}
}
void
Widget_Camera
::
ar
(
Camera
&
user_cam
,
float
_ar
)
{
void
Widget_Camera
::
ar
(
Camera
&
user_cam
,
float
_ar
)
{
cam_ar
=
_ar
;
cam_ar
=
_ar
;
update_cameras
(
user_cam
);
update_cameras
(
user_cam
);
}
}
bool
Widget_Camera
::
UI
(
Undo
&
undo
,
Camera
&
user_cam
)
{
bool
Widget_Camera
::
UI
(
Undo
&
undo
,
Camera
&
user_cam
)
{
bool
update_cam
=
false
;
bool
update_cam
=
false
;
bool
do_undo
=
false
;
bool
do_undo
=
false
;
static
Camera
old
=
render_cam
;
static
Camera
old
=
render_cam
;
static
float
old_ar
,
old_fov
;
static
float
old_ar
,
old_fov
;
ImGui
::
Text
(
"Camera Settings"
);
ImGui
::
Text
(
"Camera Settings"
);
if
(
moving_camera
)
{
if
(
moving_camera
)
{
if
(
ImGui
::
Button
(
"Confirm Move"
))
{
if
(
ImGui
::
Button
(
"Confirm Move"
))
{
moving_camera
=
false
;
moving_camera
=
false
;
old
=
render_cam
;
old
=
render_cam
;
render_cam
=
user_cam
;
render_cam
=
user_cam
;
user_cam
.
set_ar
(
screen_dim
);
user_cam
.
set_ar
(
screen_dim
);
user_cam
.
set_fov
(
90.0
f
);
user_cam
.
set_fov
(
90.0
f
);
update_cam
=
true
;
update_cam
=
true
;
do_undo
=
true
;
do_undo
=
true
;
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
if
(
ImGui
::
Button
(
"Cancel Move"
))
{
if
(
ImGui
::
Button
(
"Cancel Move"
))
{
moving_camera
=
false
;
moving_camera
=
false
;
user_cam
=
saved_cam
;
user_cam
=
saved_cam
;
user_cam
.
set_ar
(
screen_dim
);
user_cam
.
set_ar
(
screen_dim
);
user_cam
.
set_fov
(
90.0
f
);
user_cam
.
set_fov
(
90.0
f
);
}
}
}
else
{
}
else
{
if
(
ImGui
::
Button
(
"Free Move"
))
{
if
(
ImGui
::
Button
(
"Free Move"
))
{
moving_camera
=
true
;
moving_camera
=
true
;
user_cam
=
render_cam
;
user_cam
=
render_cam
;
saved_cam
=
render_cam
;
saved_cam
=
render_cam
;
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
if
(
ImGui
::
Button
(
"Move to View"
))
{
if
(
ImGui
::
Button
(
"Move to View"
))
{
old
=
render_cam
;
old
=
render_cam
;
render_cam
=
user_cam
;
render_cam
=
user_cam
;
update_cam
=
true
;
update_cam
=
true
;
do_undo
=
true
;
do_undo
=
true
;
cam_fov
=
user_cam
.
get_fov
();
cam_fov
=
user_cam
.
get_fov
();
cam_ar
=
user_cam
.
get_ar
();
cam_ar
=
user_cam
.
get_ar
();
}
}
}
}
if
(
ImGui
::
Button
(
"Reset"
))
{
if
(
ImGui
::
Button
(
"Reset"
))
{
old
=
render_cam
;
old
=
render_cam
;
render_cam
.
reset
();
render_cam
.
reset
();
update_cam
=
true
;
update_cam
=
true
;
do_undo
=
true
;
do_undo
=
true
;
undo
.
update_camera
(
*
this
,
old
);
undo
.
update_camera
(
*
this
,
old
);
}
}
update_cam
|=
ImGui
::
DragFloat
(
"Aspect Ratio"
,
&
cam_ar
,
0.1
f
,
0.1
f
,
10.0
f
,
"%.2f"
);
update_cam
|=
ImGui
::
DragFloat
(
"Aspect Ratio"
,
&
cam_ar
,
0.1
f
,
0.1
f
,
10.0
f
,
"%.2f"
);
if
(
ImGui
::
IsItemActivated
())
{
if
(
ImGui
::
IsItemActivated
())
{
old
=
render_cam
;
old
=
render_cam
;
old_ar
=
cam_ar
;
old_ar
=
cam_ar
;
}
}
if
(
ImGui
::
IsItemDeactivated
()
&&
old_ar
!=
cam_ar
)
do_undo
=
true
;
if
(
ImGui
::
IsItemDeactivated
()
&&
old_ar
!=
cam_ar
)
do_undo
=
true
;
update_cam
|=
ImGui
::
DragFloat
(
"FOV"
,
&
cam_fov
,
1.0
f
,
10.0
f
,
160.0
f
,
"%.2f"
);
update_cam
|=
ImGui
::
DragFloat
(
"FOV"
,
&
cam_fov
,
1.0
f
,
10.0
f
,
160.0
f
,
"%.2f"
);
if
(
ImGui
::
IsItemActivated
())
{
if
(
ImGui
::
IsItemActivated
())
{
old
=
render_cam
;
old
=
render_cam
;
old_fov
=
cam_fov
;
old_fov
=
cam_fov
;
}
}
if
(
ImGui
::
IsItemDeactivated
()
&&
old_fov
!=
cam_fov
)
do_undo
=
true
;
if
(
ImGui
::
IsItemDeactivated
()
&&
old_fov
!=
cam_fov
)
do_undo
=
true
;
cam_ar
=
clamp
(
cam_ar
,
0.1
f
,
10.0
f
);
cam_ar
=
clamp
(
cam_ar
,
0.1
f
,
10.0
f
);
cam_fov
=
clamp
(
cam_fov
,
10.0
f
,
160.0
f
);
cam_fov
=
clamp
(
cam_fov
,
10.0
f
,
160.0
f
);
if
(
update_cam
)
if
(
update_cam
)
update_cameras
(
user_cam
);
update_cameras
(
user_cam
);
if
(
do_undo
)
if
(
do_undo
)
undo
.
update_camera
(
*
this
,
old
);
undo
.
update_camera
(
*
this
,
old
);
return
update_cam
;
return
update_cam
;
}
}
void
Widget_Camera
::
update_cameras
(
Camera
&
user_cam
)
{
void
Widget_Camera
::
update_cameras
(
Camera
&
user_cam
)
{
render_cam
.
set_ar
(
cam_ar
);
render_cam
.
set_ar
(
cam_ar
);
render_cam
.
set_fov
(
cam_fov
);
render_cam
.
set_fov
(
cam_fov
);
if
(
moving_camera
)
{
if
(
moving_camera
)
{
user_cam
.
set_ar
(
cam_ar
);
user_cam
.
set_ar
(
cam_ar
);
user_cam
.
set_fov
(
cam_fov
);
user_cam
.
set_fov
(
cam_fov
);
}
}
...
@@ -462,16 +493,17 @@ void Widget_Camera::update_cameras(Camera& user_cam) {
...
@@ -462,16 +493,17 @@ void Widget_Camera::update_cameras(Camera& user_cam) {
}
}
void
Widget_Camera
::
load
(
Vec3
center
,
Vec3
pos
,
float
ar
,
float
vfov
)
{
void
Widget_Camera
::
load
(
Vec3
center
,
Vec3
pos
,
float
ar
,
float
vfov
)
{
render_cam
.
look_at
(
center
,
pos
);
render_cam
.
look_at
(
center
,
pos
);
render_cam
.
set_ar
(
ar
);
render_cam
.
set_ar
(
ar
);
render_cam
.
set_fov
(
vfov
);
render_cam
.
set_fov
(
vfov
);
cam_fov
=
vfov
;
cam_fov
=
vfov
;
cam_ar
=
ar
;
cam_ar
=
ar
;
generate_cage
();
generate_cage
();
}
}
void
Widget_Camera
::
render
(
const
Mat4
&
view
)
{
void
Widget_Camera
::
render
(
const
Mat4
&
view
)
{
if
(
!
moving_camera
)
Renderer
::
get
().
lines
(
cam_cage
,
view
);
if
(
!
moving_camera
)
Renderer
::
get
().
lines
(
cam_cage
,
view
);
}
}
void
Widget_Camera
::
generate_cage
()
{
void
Widget_Camera
::
generate_cage
()
{
...
@@ -481,7 +513,7 @@ void Widget_Camera::generate_cage() {
...
@@ -481,7 +513,7 @@ void Widget_Camera::generate_cage() {
float
fov
=
render_cam
.
get_fov
();
float
fov
=
render_cam
.
get_fov
();
float
h
=
2.0
f
*
std
::
tan
(
Radians
(
fov
)
/
2.0
f
);
float
h
=
2.0
f
*
std
::
tan
(
Radians
(
fov
)
/
2.0
f
);
float
w
=
ar
*
h
;
float
w
=
ar
*
h
;
Vec3
pos
=
render_cam
.
pos
();
Vec3
pos
=
render_cam
.
pos
();
Mat4
iview
=
render_cam
.
get_view
().
inverse
();
Mat4
iview
=
render_cam
.
get_view
().
inverse
();
...
@@ -500,44 +532,43 @@ void Widget_Camera::generate_cage() {
...
@@ -500,44 +532,43 @@ void Widget_Camera::generate_cage() {
cam_cage
.
add
(
br
,
bl
,
Gui
::
Color
::
black
);
cam_cage
.
add
(
br
,
bl
,
Gui
::
Color
::
black
);
}
}
Widget_Render
::
Widget_Render
(
Vec2
dim
)
Widget_Render
::
Widget_Render
(
Vec2
dim
)
:
pathtracer
(
*
this
,
dim
)
{
:
pathtracer
(
*
this
,
dim
)
{
out_w
=
(
size_t
)
dim
.
x
/
2
;
out_w
=
(
size_t
)
dim
.
x
/
2
;
out_h
=
(
size_t
)
dim
.
y
/
2
;
out_h
=
(
size_t
)
dim
.
y
/
2
;
}
}
void
Widget_Render
::
open
()
{
void
Widget_Render
::
open
()
{
render_window
=
true
;
render_window
=
true
;
render_window_focus
=
true
;
render_window_focus
=
true
;
}
}
void
Widget_Render
::
log_ray
(
const
Ray
&
ray
,
float
t
,
Spectrum
color
)
{
void
Widget_Render
::
log_ray
(
const
Ray
&
ray
,
float
t
,
Spectrum
color
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
log_mut
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
log_mut
);
ray_log
.
add
(
ray
.
point
,
ray
.
at
(
t
),
Vec3
(
color
.
r
,
color
.
g
,
color
.
b
));
ray_log
.
add
(
ray
.
point
,
ray
.
at
(
t
),
Vec3
(
color
.
r
,
color
.
g
,
color
.
b
));
}
}
void
Widget_Render
::
begin
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
)
{
void
Widget_Render
::
begin
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
)
{
if
(
render_window_focus
)
{
if
(
render_window_focus
)
{
ImGui
::
SetNextWindowFocus
();
ImGui
::
SetNextWindowFocus
();
render_window_focus
=
false
;
render_window_focus
=
false
;
}
}
ImGui
::
Begin
(
"Render Image"
,
&
render_window
,
ImGuiWindowFlags_NoCollapse
);
ImGui
::
Begin
(
"Render Image"
,
&
render_window
,
ImGuiWindowFlags_NoCollapse
);
static
const
char
*
method_names
[]
=
{
"Rasterize"
,
"Path Trace"
};
static
const
char
*
method_names
[]
=
{
"Rasterize"
,
"Path Trace"
};
ImGui
::
Combo
(
"Method"
,
&
method
,
method_names
,
2
);
ImGui
::
Combo
(
"Method"
,
&
method
,
method_names
,
2
);
ImGui
::
InputInt
(
"Width"
,
&
out_w
,
1
,
100
);
ImGui
::
InputInt
(
"Width"
,
&
out_w
,
1
,
100
);
ImGui
::
InputInt
(
"Height"
,
&
out_h
,
1
,
100
);
ImGui
::
InputInt
(
"Height"
,
&
out_h
,
1
,
100
);
ImGui
::
InputInt
(
"Samples"
,
&
out_samples
,
1
,
100
);
ImGui
::
InputInt
(
"Samples"
,
&
out_samples
,
1
,
100
);
if
(
method
==
1
)
{
if
(
method
==
1
)
{
ImGui
::
InputInt
(
"Area Light Samples"
,
&
out_area_samples
,
1
,
100
);
ImGui
::
InputInt
(
"Area Light Samples"
,
&
out_area_samples
,
1
,
100
);
ImGui
::
InputInt
(
"Max Ray Depth"
,
&
out_depth
,
1
,
32
);
ImGui
::
InputInt
(
"Max Ray Depth"
,
&
out_depth
,
1
,
32
);
ImGui
::
SliderFloat
(
"Exposure"
,
&
exposure
,
0.01
f
,
10.0
f
,
"%.2f"
,
2.5
f
);
ImGui
::
SliderFloat
(
"Exposure"
,
&
exposure
,
0.01
f
,
10.0
f
,
"%.2f"
,
2.5
f
);
}
else
{
}
else
{
out_samples
=
std
::
min
(
out_samples
,
32
);
out_samples
=
std
::
min
(
out_samples
,
32
);
}
}
out_w
=
std
::
max
(
1
,
out_w
);
out_w
=
std
::
max
(
1
,
out_w
);
out_h
=
std
::
max
(
1
,
out_h
);
out_h
=
std
::
max
(
1
,
out_h
);
...
@@ -545,151 +576,157 @@ void Widget_Render::begin(Scene& scene, Widget_Camera& cam, Camera& user_cam) {
...
@@ -545,151 +576,157 @@ void Widget_Render::begin(Scene& scene, Widget_Camera& cam, Camera& user_cam) {
out_area_samples
=
std
::
max
(
1
,
out_area_samples
);
out_area_samples
=
std
::
max
(
1
,
out_area_samples
);
out_depth
=
std
::
max
(
1
,
out_depth
);
out_depth
=
std
::
max
(
1
,
out_depth
);
if
(
ImGui
::
Button
(
"Set Width via AR"
))
{
if
(
ImGui
::
Button
(
"Set Width via AR"
))
{
out_w
=
(
size_t
)
std
::
ceil
(
cam
.
get_ar
()
*
out_h
);
out_w
=
(
size_t
)
std
::
ceil
(
cam
.
get_ar
()
*
out_h
);
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
if
(
ImGui
::
Button
(
"Set AR via W/H"
))
{
if
(
ImGui
::
Button
(
"Set AR via W/H"
))
{
cam
.
ar
(
user_cam
,
(
float
)
out_w
/
(
float
)
out_h
);
cam
.
ar
(
user_cam
,
(
float
)
out_w
/
(
float
)
out_h
);
}
}
}
}
std
::
string
Widget_Render
::
step
(
Animate
&
animate
,
Scene
&
scene
)
{
std
::
string
Widget_Render
::
step
(
Animate
&
animate
,
Scene
&
scene
)
{
if
(
animating
)
{
if
(
animating
)
{
if
(
next_frame
==
max_frame
)
{
if
(
next_frame
==
max_frame
)
{
animating
=
false
;
animating
=
false
;
return
{};
return
{};
}
}
if
(
folder
.
empty
())
{
if
(
folder
.
empty
())
{
animating
=
false
;
animating
=
false
;
return
"No output folder!"
;
return
"No output folder!"
;
}
}
Camera
cam
=
animate
.
set_time
(
scene
,
(
float
)
next_frame
);
Camera
cam
=
animate
.
set_time
(
scene
,
(
float
)
next_frame
);
if
(
method
==
0
)
{
if
(
method
==
0
)
{
std
::
vector
<
unsigned
char
>
data
;
std
::
vector
<
unsigned
char
>
data
;
Renderer
::
get
().
save
(
scene
,
cam
,
out_w
,
out_h
,
out_samples
);
Renderer
::
get
().
save
(
scene
,
cam
,
out_w
,
out_h
,
out_samples
);
Renderer
::
get
().
saved
(
data
);
Renderer
::
get
().
saved
(
data
);
std
::
stringstream
str
;
std
::
stringstream
str
;
str
<<
std
::
setfill
(
'0'
)
<<
std
::
setw
(
4
)
<<
next_frame
;
str
<<
std
::
setfill
(
'0'
)
<<
std
::
setw
(
4
)
<<
next_frame
;
std
::
string
path
=
folder
+
"
\\
"
+
str
.
str
()
+
".png"
;
std
::
string
path
=
folder
+
"
\\
"
+
str
.
str
()
+
".png"
;
stbi_flip_vertically_on_write
(
true
);
stbi_flip_vertically_on_write
(
true
);
if
(
!
stbi_write_png
(
path
.
c_str
(),
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
(
int
)
out_w
*
4
))
{
if
(
!
stbi_write_png
(
path
.
c_str
(),
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
animating
=
false
;
(
int
)
out_w
*
4
))
{
return
"Failed to write output!"
;
animating
=
false
;
}
return
"Failed to write output!"
;
}
next_frame
++
;
}
else
{
next_frame
++
;
}
else
{
if
(
init
)
{
pathtracer
.
begin_render
(
scene
,
cam
);
if
(
init
)
{
init
=
false
;
pathtracer
.
begin_render
(
scene
,
cam
);
}
init
=
false
;
}
if
(
!
pathtracer
.
in_progress
())
{
std
::
vector
<
unsigned
char
>
data
;
if
(
!
pathtracer
.
in_progress
())
{
std
::
vector
<
unsigned
char
>
data
;
pathtracer
.
get_output
().
tonemap_to
(
data
,
exposure
);
std
::
stringstream
str
;
pathtracer
.
get_output
().
tonemap_to
(
data
,
exposure
);
str
<<
std
::
setfill
(
'0'
)
<<
std
::
setw
(
4
)
<<
next_frame
;
std
::
stringstream
str
;
std
::
string
path
=
folder
+
"
\\
"
+
str
.
str
()
+
".png"
;
str
<<
std
::
setfill
(
'0'
)
<<
std
::
setw
(
4
)
<<
next_frame
;
std
::
string
path
=
folder
+
"
\\
"
+
str
.
str
()
+
".png"
;
stbi_flip_vertically_on_write
(
false
);
if
(
!
stbi_write_png
(
path
.
c_str
(),
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
(
int
)
out_w
*
4
))
{
stbi_flip_vertically_on_write
(
false
);
animating
=
false
;
if
(
!
stbi_write_png
(
path
.
c_str
(),
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
return
"Failed to write output!"
;
(
int
)
out_w
*
4
))
{
}
animating
=
false
;
return
"Failed to write output!"
;
pathtracer
.
begin_render
(
scene
,
cam
,
true
);
}
next_frame
++
;
}
pathtracer
.
begin_render
(
scene
,
cam
,
true
);
}
next_frame
++
;
}
}
return
{};
}
}
return
{};
}
}
void
Widget_Render
::
animate
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
int
last_frame
)
{
void
Widget_Render
::
animate
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
int
last_frame
)
{
if
(
!
render_window
)
return
;
if
(
!
render_window
)
return
;
begin
(
scene
,
cam
,
user_cam
);
begin
(
scene
,
cam
,
user_cam
);
if
(
ImGui
::
Button
(
"Output Folder"
))
{
if
(
ImGui
::
Button
(
"Output Folder"
))
{
char
*
path
=
nullptr
;
char
*
path
=
nullptr
;
NFD_OpenDirectoryDialog
(
nullptr
,
nullptr
,
&
path
);
NFD_OpenDirectoryDialog
(
nullptr
,
nullptr
,
&
path
);
if
(
path
)
{
if
(
path
)
{
Platform
::
strcpy
(
output_path
,
path
,
sizeof
(
output_path
));
Platform
::
strcpy
(
output_path
,
path
,
sizeof
(
output_path
));
free
(
path
);
free
(
path
);
}
}
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
ImGui
::
InputText
(
"##path"
,
output_path
,
sizeof
(
output_path
));
ImGui
::
InputText
(
"##path"
,
output_path
,
sizeof
(
output_path
));
ImGui
::
Separator
();
ImGui
::
Separator
();
ImGui
::
Text
(
"Render"
);
ImGui
::
Text
(
"Render"
);
if
(
animating
)
{
if
(
animating
)
{
if
(
ImGui
::
Button
(
"Cancel"
))
{
if
(
ImGui
::
Button
(
"Cancel"
))
{
pathtracer
.
cancel
();
pathtracer
.
cancel
();
animating
=
false
;
animating
=
false
;
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
if
(
method
==
1
)
{
if
(
method
==
1
)
{
ImGui
::
ProgressBar
(((
float
)
next_frame
+
pathtracer
.
progress
())
/
(
max_frame
+
1
));
ImGui
::
ProgressBar
(((
float
)
next_frame
+
pathtracer
.
progress
())
/
(
max_frame
+
1
));
}
else
{
}
else
{
ImGui
::
ProgressBar
((
float
)
next_frame
/
(
max_frame
+
1
));
ImGui
::
ProgressBar
((
float
)
next_frame
/
(
max_frame
+
1
));
}
}
}
else
{
}
else
{
if
(
ImGui
::
Button
(
"Start Render"
))
{
if
(
ImGui
::
Button
(
"Start Render"
))
{
animating
=
true
;
animating
=
true
;
max_frame
=
last_frame
;
max_frame
=
last_frame
;
next_frame
=
0
;
next_frame
=
0
;
folder
=
std
::
string
(
output_path
);
folder
=
std
::
string
(
output_path
);
if
(
method
==
1
)
{
if
(
method
==
1
)
{
init
=
true
;
init
=
true
;
ray_log
.
clear
();
ray_log
.
clear
();
pathtracer
.
set_sizes
(
out_w
,
out_h
,
out_samples
,
out_area_samples
,
out_depth
);
pathtracer
.
set_sizes
(
out_w
,
out_h
,
out_samples
,
out_area_samples
,
out_depth
);
}
}
}
}
}
}
float
avail
=
ImGui
::
GetContentRegionAvail
().
x
;
float
avail
=
ImGui
::
GetContentRegionAvail
().
x
;
float
w
=
std
::
min
(
avail
,
(
float
)
out_w
);
float
w
=
std
::
min
(
avail
,
(
float
)
out_w
);
float
h
=
(
w
/
out_w
)
*
out_h
;
float
h
=
(
w
/
out_w
)
*
out_h
;
if
(
method
==
1
)
{
if
(
method
==
1
)
{
ImGui
::
Image
((
ImTextureID
)(
long
long
)
pathtracer
.
get_output_texture
(
exposure
).
get_id
(),
{
w
,
h
});
ImGui
::
Image
((
ImTextureID
)(
long
long
)
pathtracer
.
get_output_texture
(
exposure
).
get_id
(),
}
else
{
{
w
,
h
});
ImGui
::
Image
((
ImTextureID
)(
long
long
)
Renderer
::
get
().
saved
(),
{
w
,
h
},
{
0.0
f
,
1.0
f
},
{
1.0
f
,
0.0
f
});
}
else
{
}
ImGui
::
Image
((
ImTextureID
)(
long
long
)
Renderer
::
get
().
saved
(),
{
w
,
h
},
{
0.0
f
,
1.0
f
},
{
1.0
f
,
0.0
f
});
}
ImGui
::
End
();
ImGui
::
End
();
}
}
bool
Widget_Render
::
UI
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
std
::
string
&
err
)
{
bool
Widget_Render
::
UI
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
std
::
string
&
err
)
{
bool
ret
=
false
;
bool
ret
=
false
;
if
(
!
render_window
)
return
ret
;
if
(
!
render_window
)
return
ret
;
begin
(
scene
,
cam
,
user_cam
);
begin
(
scene
,
cam
,
user_cam
);
ImGui
::
Separator
();
ImGui
::
Separator
();
ImGui
::
Text
(
"Render"
);
ImGui
::
Text
(
"Render"
);
if
(
pathtracer
.
in_progress
())
{
if
(
pathtracer
.
in_progress
())
{
if
(
ImGui
::
Button
(
"Cancel"
))
{
if
(
ImGui
::
Button
(
"Cancel"
))
{
pathtracer
.
cancel
();
pathtracer
.
cancel
();
has_rendered
=
false
;
has_rendered
=
false
;
}
}
...
@@ -699,40 +736,40 @@ bool Widget_Render::UI(Scene& scene, Widget_Camera& cam, Camera& user_cam, std::
...
@@ -699,40 +736,40 @@ bool Widget_Render::UI(Scene& scene, Widget_Camera& cam, Camera& user_cam, std::
}
else
{
}
else
{
if
(
ImGui
::
Button
(
"Start Render"
))
{
if
(
ImGui
::
Button
(
"Start Render"
))
{
if
(
method
==
1
)
{
if
(
method
==
1
)
{
has_rendered
=
true
;
has_rendered
=
true
;
ret
=
true
;
ret
=
true
;
ray_log
.
clear
();
ray_log
.
clear
();
pathtracer
.
set_sizes
(
out_w
,
out_h
,
out_samples
,
out_area_samples
,
out_depth
);
pathtracer
.
set_sizes
(
out_w
,
out_h
,
out_samples
,
out_area_samples
,
out_depth
);
pathtracer
.
begin_render
(
scene
,
cam
.
get
());
pathtracer
.
begin_render
(
scene
,
cam
.
get
());
}
else
{
}
else
{
Renderer
::
get
().
save
(
scene
,
cam
.
get
(),
out_w
,
out_h
,
out_samples
);
Renderer
::
get
().
save
(
scene
,
cam
.
get
(),
out_w
,
out_h
,
out_samples
);
}
}
}
}
}
}
ImGui
::
SameLine
();
ImGui
::
SameLine
();
if
(
ImGui
::
Button
(
"Save Image"
))
{
if
(
ImGui
::
Button
(
"Save Image"
))
{
char
*
path
=
nullptr
;
char
*
path
=
nullptr
;
NFD_SaveDialog
(
"png"
,
nullptr
,
&
path
);
NFD_SaveDialog
(
"png"
,
nullptr
,
&
path
);
if
(
path
)
{
if
(
path
)
{
std
::
vector
<
unsigned
char
>
data
;
std
::
vector
<
unsigned
char
>
data
;
if
(
method
==
1
)
{
if
(
method
==
1
)
{
pathtracer
.
get_output
().
tonemap_to
(
data
,
exposure
);
pathtracer
.
get_output
().
tonemap_to
(
data
,
exposure
);
stbi_flip_vertically_on_write
(
false
);
stbi_flip_vertically_on_write
(
false
);
}
else
{
}
else
{
Renderer
::
get
().
saved
(
data
);
Renderer
::
get
().
saved
(
data
);
stbi_flip_vertically_on_write
(
true
);
stbi_flip_vertically_on_write
(
true
);
}
}
if
(
!
stbi_write_png
(
path
,
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
(
int
)
out_w
*
4
))
{
if
(
!
stbi_write_png
(
path
,
(
int
)
out_w
,
(
int
)
out_h
,
4
,
data
.
data
(),
(
int
)
out_w
*
4
))
{
err
=
"Failed to write png!"
;
err
=
"Failed to write png!"
;
}
}
free
(
path
);
free
(
path
);
}
}
}
}
...
@@ -740,23 +777,26 @@ bool Widget_Render::UI(Scene& scene, Widget_Camera& cam, Camera& user_cam, std::
...
@@ -740,23 +777,26 @@ bool Widget_Render::UI(Scene& scene, Widget_Camera& cam, Camera& user_cam, std::
float
w
=
std
::
min
(
avail
,
(
float
)
out_w
);
float
w
=
std
::
min
(
avail
,
(
float
)
out_w
);
float
h
=
(
w
/
out_w
)
*
out_h
;
float
h
=
(
w
/
out_w
)
*
out_h
;
if
(
method
==
1
)
{
if
(
method
==
1
)
{
ImGui
::
Image
((
ImTextureID
)(
long
long
)
pathtracer
.
get_output_texture
(
exposure
).
get_id
(),
{
w
,
h
});
ImGui
::
Image
((
ImTextureID
)(
long
long
)
pathtracer
.
get_output_texture
(
exposure
).
get_id
(),
{
w
,
h
});
if
(
!
pathtracer
.
in_progress
()
&&
has_rendered
)
{
if
(
!
pathtracer
.
in_progress
()
&&
has_rendered
)
{
auto
[
build
,
render
]
=
pathtracer
.
completion_time
();
auto
[
build
,
render
]
=
pathtracer
.
completion_time
();
ImGui
::
Text
(
"Scene built in %.2fs, rendered in %.2fs."
,
build
,
render
);
ImGui
::
Text
(
"Scene built in %.2fs, rendered in %.2fs."
,
build
,
render
);
}
}
}
else
{
}
else
{
ImGui
::
Image
((
ImTextureID
)(
long
long
)
Renderer
::
get
().
saved
(),
{
w
,
h
},
{
0.0
f
,
1.0
f
},
{
1.0
f
,
0.0
f
});
ImGui
::
Image
((
ImTextureID
)(
long
long
)
Renderer
::
get
().
saved
(),
{
w
,
h
},
{
0.0
f
,
1.0
f
},
}
{
1.0
f
,
0.0
f
});
}
ImGui
::
End
();
ImGui
::
End
();
return
ret
;
return
ret
;
}
}
std
::
string
Widget_Render
::
headless
(
Animate
&
animate
,
Scene
&
scene
,
const
Camera
&
cam
,
std
::
string
output
,
std
::
string
Widget_Render
::
headless
(
Animate
&
animate
,
Scene
&
scene
,
const
Camera
&
cam
,
bool
a
,
int
w
,
int
h
,
int
s
,
int
ls
,
int
d
,
float
exp
)
{
std
::
string
output
,
bool
a
,
int
w
,
int
h
,
int
s
,
int
ls
,
int
d
,
float
exp
)
{
info
(
"Render settings:"
);
info
(
"Render settings:"
);
info
(
"
\t
width: %d"
,
w
);
info
(
"
\t
width: %d"
,
w
);
...
@@ -767,66 +807,70 @@ std::string Widget_Render::headless(Animate& animate, Scene& scene, const Camera
...
@@ -767,66 +807,70 @@ std::string Widget_Render::headless(Animate& animate, Scene& scene, const Camera
info
(
"
\t
exposure: %f"
,
exp
);
info
(
"
\t
exposure: %f"
,
exp
);
info
(
"
\t
render threads: %u"
,
std
::
thread
::
hardware_concurrency
());
info
(
"
\t
render threads: %u"
,
std
::
thread
::
hardware_concurrency
());
out_w
=
w
;
out_w
=
w
;
out_h
=
h
;
out_h
=
h
;
pathtracer
.
set_sizes
(
w
,
h
,
s
,
ls
,
d
);
pathtracer
.
set_sizes
(
w
,
h
,
s
,
ls
,
d
);
auto
print_progress
=
[](
float
f
)
{
auto
print_progress
=
[](
float
f
)
{
std
::
cout
<<
"Progress: ["
;
std
::
cout
<<
"Progress: ["
;
int
width
=
std
::
min
(
Platform
::
console_width
()
-
30
,
50
);
int
width
=
std
::
min
(
Platform
::
console_width
()
-
30
,
50
);
if
(
width
)
{
if
(
width
)
{
int
bar
=
(
int
)(
width
*
f
);
int
bar
=
(
int
)(
width
*
f
);
for
(
int
i
=
0
;
i
<
bar
;
i
++
)
std
::
cout
<<
"-"
;
for
(
int
i
=
0
;
i
<
bar
;
i
++
)
for
(
int
i
=
bar
;
i
<
width
;
i
++
)
std
::
cout
<<
" "
;
std
::
cout
<<
"-"
;
std
::
cout
<<
"] "
;
for
(
int
i
=
bar
;
i
<
width
;
i
++
)
}
std
::
cout
<<
" "
;
std
::
cout
<<
"] "
;
float
percent
=
100.0
f
*
f
;
}
if
(
percent
<
10.0
f
)
std
::
cout
<<
"0"
;
std
::
cout
<<
percent
<<
"%
\r
"
;
float
percent
=
100.0
f
*
f
;
std
::
cout
.
flush
();
if
(
percent
<
10.0
f
)
};
std
::
cout
<<
"0"
;
std
::
cout
<<
percent
<<
"%
\r
"
;
std
::
cout
<<
std
::
fixed
<<
std
::
setw
(
2
)
<<
std
::
setprecision
(
2
)
<<
std
::
setfill
(
'0'
);
std
::
cout
.
flush
();
if
(
a
)
{
};
method
=
1
;
std
::
cout
<<
std
::
fixed
<<
std
::
setw
(
2
)
<<
std
::
setprecision
(
2
)
<<
std
::
setfill
(
'0'
);
init
=
true
;
if
(
a
)
{
animating
=
true
;
max_frame
=
animate
.
n_frames
();
method
=
1
;
next_frame
=
0
;
init
=
true
;
folder
=
output
;
animating
=
true
;
while
(
next_frame
<
max_frame
)
{
max_frame
=
animate
.
n_frames
();
std
::
string
err
=
step
(
animate
,
scene
);
next_frame
=
0
;
if
(
!
err
.
empty
())
return
err
;
folder
=
output
;
print_progress
(((
float
)
next_frame
+
pathtracer
.
progress
())
/
(
max_frame
+
1
));
while
(
next_frame
<
max_frame
)
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
250
));
std
::
string
err
=
step
(
animate
,
scene
);
}
if
(
!
err
.
empty
())
std
::
cout
<<
std
::
endl
;
return
err
;
print_progress
(((
float
)
next_frame
+
pathtracer
.
progress
())
/
(
max_frame
+
1
));
}
else
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
250
));
}
pathtracer
.
begin_render
(
scene
,
cam
);
std
::
cout
<<
std
::
endl
;
while
(
pathtracer
.
in_progress
())
{
print_progress
(
pathtracer
.
progress
());
}
else
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
250
));
}
pathtracer
.
begin_render
(
scene
,
cam
);
std
::
cout
<<
std
::
endl
;
while
(
pathtracer
.
in_progress
())
{
print_progress
(
pathtracer
.
progress
());
std
::
vector
<
unsigned
char
>
data
;
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
250
));
pathtracer
.
get_output
().
tonemap_to
(
data
,
exp
);
}
if
(
!
stbi_write_png
(
output
.
c_str
(),
w
,
h
,
4
,
data
.
data
(),
w
*
4
))
{
std
::
cout
<<
std
::
endl
;
return
"Failed to write output!"
;
}
std
::
vector
<
unsigned
char
>
data
;
}
pathtracer
.
get_output
().
tonemap_to
(
data
,
exp
);
if
(
!
stbi_write_png
(
output
.
c_str
(),
w
,
h
,
4
,
data
.
data
(),
w
*
4
))
{
return
"Failed to write output!"
;
}
}
return
{};
return
{};
}
}
void
Widget_Render
::
render_log
(
const
Mat4
&
view
)
const
{
void
Widget_Render
::
render_log
(
const
Mat4
&
view
)
const
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
log_mut
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
log_mut
);
Renderer
::
get
().
lines
(
ray_log
,
view
);
Renderer
::
get
().
lines
(
ray_log
,
view
);
}
}
}
}
// namespace Gui
src/gui/widgets.h
View file @
c2535f0f
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
#pragma once
#pragma once
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
#include "../scene/scene.h"
#include "../rays/pathtracer.h"
#include "../rays/pathtracer.h"
#include "../scene/scene.h"
class
Undo
;
class
Undo
;
...
@@ -11,44 +11,45 @@ namespace Gui {
...
@@ -11,44 +11,45 @@ namespace Gui {
class
Animate
;
class
Animate
;
enum
class
Axis
{
enum
class
Axis
{
X
,
Y
,
Z
};
X
,
Y
,
Z
};
enum
class
Widget_Type
{
enum
class
Widget_Type
{
move
,
rotate
,
scale
,
bevel
,
count
};
move
,
rotate
,
scale
,
bevel
,
count
};
static
const
int
n_Widget_Types
=
(
int
)
Widget_Type
::
count
;
static
const
int
n_Widget_Types
=
(
int
)
Widget_Type
::
count
;
enum
class
Widget_IDs
:
Scene_ID
{
enum
class
Widget_IDs
:
Scene_ID
{
none
,
none
,
x_mov
,
y_mov
,
z_mov
,
x_mov
,
xy_mov
,
yz_mov
,
xz_mov
,
y_mov
,
x_rot
,
y_rot
,
z_rot
,
z_mov
,
x_scl
,
y_scl
,
z_scl
,
xy_mov
,
count
yz_mov
,
xz_mov
,
x_rot
,
y_rot
,
z_rot
,
x_scl
,
y_scl
,
z_scl
,
count
};
};
static
const
int
n_Widget_IDs
=
(
int
)
Widget_IDs
::
count
;
static
const
int
n_Widget_IDs
=
(
int
)
Widget_IDs
::
count
;
class
Widget_Camera
{
class
Widget_Camera
{
public:
public:
Widget_Camera
(
Vec2
screen_dim
)
:
Widget_Camera
(
Vec2
screen_dim
)
screen_dim
(
screen_dim
),
render_cam
(
screen_dim
),
saved_cam
(
screen_dim
)
:
screen_dim
(
screen_dim
),
render_cam
(
screen_dim
),
saved_cam
(
screen_dim
)
{
{
generate_cage
();
}
generate_cage
();
}
bool
UI
(
Undo
&
undo
,
Camera
&
user_cam
);
void
render
(
const
Mat4
&
view
);
bool
UI
(
Undo
&
undo
,
Camera
&
user_cam
);
void
render
(
const
Mat4
&
view
);
void
load
(
Vec3
center
,
Vec3
pos
,
float
ar
,
float
vfov
);
const
Camera
&
get
()
const
{
return
render_cam
;
}
void
load
(
Vec3
center
,
Vec3
pos
,
float
ar
,
float
vfov
);
void
ar
(
Camera
&
user_cam
,
float
_ar
);
const
Camera
&
get
()
const
{
return
render_cam
;
}
float
get_ar
()
const
{
return
cam_ar
;
}
void
ar
(
Camera
&
user_cam
,
float
_ar
);
bool
moving
()
const
{
return
moving_camera
;
}
float
get_ar
()
const
{
return
cam_ar
;
}
void
dim
(
Vec2
d
)
{
screen_dim
=
d
;
}
bool
moving
()
const
{
return
moving_camera
;
}
void
dim
(
Vec2
d
)
{
screen_dim
=
d
;
}
private:
private:
float
cam_fov
=
90.0
f
,
cam_ar
=
1.7778
f
;
float
cam_fov
=
90.0
f
,
cam_ar
=
1.7778
f
;
...
@@ -57,89 +58,89 @@ private:
...
@@ -57,89 +58,89 @@ private:
Camera
render_cam
,
saved_cam
;
Camera
render_cam
,
saved_cam
;
GL
::
Lines
cam_cage
;
GL
::
Lines
cam_cage
;
void
update_cameras
(
Camera
&
user_cam
);
void
update_cameras
(
Camera
&
user_cam
);
void
generate_cage
();
void
generate_cage
();
};
};
class
Widget_Render
{
class
Widget_Render
{
public:
public:
Widget_Render
(
Vec2
dim
);
Widget_Render
(
Vec2
dim
);
void
open
();
void
open
();
bool
UI
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
std
::
string
&
err
);
bool
UI
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
std
::
string
&
err
);
void
animate
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
int
max_frame
);
void
animate
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
,
int
max_frame
);
std
::
string
step
(
Animate
&
animate
,
Scene
&
scene
);
std
::
string
step
(
Animate
&
animate
,
Scene
&
scene
);
std
::
string
headless
(
Animate
&
animate
,
Scene
&
scene
,
const
Camera
&
cam
,
std
::
string
output
,
std
::
string
headless
(
Animate
&
animate
,
Scene
&
scene
,
const
Camera
&
cam
,
std
::
string
output
,
bool
a
,
int
w
,
int
h
,
int
s
,
int
ls
,
int
d
,
float
exp
);
bool
a
,
int
w
,
int
h
,
int
s
,
int
ls
,
int
d
,
float
exp
);
void
log_ray
(
const
Ray
&
ray
,
float
t
,
Spectrum
color
=
Spectrum
{
1.0
f
});
void
log_ray
(
const
Ray
&
ray
,
float
t
,
Spectrum
color
=
Spectrum
{
1.0
f
});
void
render_log
(
const
Mat4
&
view
)
const
;
void
render_log
(
const
Mat4
&
view
)
const
;
PT
::
Pathtracer
&
tracer
()
{
return
pathtracer
;
}
PT
::
Pathtracer
&
tracer
()
{
return
pathtracer
;
}
bool
rendered
()
const
{
return
has_rendered
;
}
bool
rendered
()
const
{
return
has_rendered
;
}
std
::
pair
<
float
,
float
>
completion_time
()
const
{
return
pathtracer
.
completion_time
();
}
std
::
pair
<
float
,
float
>
completion_time
()
const
{
return
pathtracer
.
completion_time
();
}
bool
in_progress
()
const
{
return
pathtracer
.
in_progress
();
}
bool
in_progress
()
const
{
return
pathtracer
.
in_progress
();
}
float
wh_ar
()
const
{
return
(
float
)
out_w
/
(
float
)
out_h
;
}
float
wh_ar
()
const
{
return
(
float
)
out_w
/
(
float
)
out_h
;
}
private:
private:
void
begin
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
);
void
begin
(
Scene
&
scene
,
Widget_Camera
&
cam
,
Camera
&
user_cam
);
mutable
std
::
mutex
log_mut
;
mutable
std
::
mutex
log_mut
;
GL
::
Lines
ray_log
;
GL
::
Lines
ray_log
;
int
out_w
,
out_h
,
out_samples
=
32
,
out_area_samples
=
8
,
out_depth
=
4
;
int
out_w
,
out_h
,
out_samples
=
32
,
out_area_samples
=
8
,
out_depth
=
4
;
float
exposure
=
1.0
f
;
float
exposure
=
1.0
f
;
bool
has_rendered
=
false
;
bool
has_rendered
=
false
;
bool
render_window
=
false
,
render_window_focus
=
false
;
bool
render_window
=
false
,
render_window_focus
=
false
;
int
method
=
1
;
int
method
=
1
;
bool
animating
=
false
,
init
=
false
;
bool
animating
=
false
,
init
=
false
;
int
next_frame
=
0
,
max_frame
=
0
;
int
next_frame
=
0
,
max_frame
=
0
;
char
output_path
[
256
]
=
{};
char
output_path
[
256
]
=
{};
std
::
string
folder
;
std
::
string
folder
;
PT
::
Pathtracer
pathtracer
;
PT
::
Pathtracer
pathtracer
;
};
};
class
Widgets
{
class
Widgets
{
public:
public:
Widgets
();
Widgets
();
Widget_Type
active
=
Widget_Type
::
move
;
Widget_Type
active
=
Widget_Type
::
move
;
void
end_drag
();
void
end_drag
();
Pose
apply_action
(
const
Pose
&
pose
);
Pose
apply_action
(
const
Pose
&
pose
);
void
start_drag
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
);
void
start_drag
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
);
void
drag_to
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
,
bool
scale_invert
);
void
drag_to
(
Vec3
pos
,
Vec3
cam
,
Vec2
spos
,
Vec3
dir
,
bool
scale_invert
);
void
select
(
Scene_ID
id
);
void
select
(
Scene_ID
id
);
void
render
(
const
Mat4
&
view
,
Vec3
pos
,
float
scl
);
void
render
(
const
Mat4
&
view
,
Vec3
pos
,
float
scl
);
bool
action_button
(
Widget_Type
act
,
std
::
string
name
,
bool
wrap
=
true
);
bool
action_button
(
Widget_Type
act
,
std
::
string
name
,
bool
wrap
=
true
);
bool
want_drag
();
bool
want_drag
();
bool
is_dragging
();
bool
is_dragging
();
void
set_dragging
(
bool
dragging
,
bool
plane
);
void
set_dragging
(
bool
dragging
,
bool
plane
);
private:
private:
void
generate_lines
(
Vec3
pos
);
void
generate_lines
(
Vec3
pos
);
bool
to_axis
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
&
hit
);
bool
to_axis
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
&
hit
);
bool
to_plane
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
norm
,
Vec3
&
hit
);
bool
to_plane
(
Vec3
obj_pos
,
Vec3
cam_pos
,
Vec3
dir
,
Vec3
norm
,
Vec3
&
hit
);
// interface data
// interface data
Axis
axis
=
Axis
::
X
;
Axis
axis
=
Axis
::
X
;
Vec3
drag_start
,
drag_end
;
Vec3
drag_start
,
drag_end
;
Vec2
bevel_start
,
bevel_end
;
Vec2
bevel_start
,
bevel_end
;
bool
dragging
=
false
,
drag_plane
=
false
;
bool
dragging
=
false
,
drag_plane
=
false
;
bool
start_dragging
=
false
;
bool
start_dragging
=
false
;
// render data
// render data
GL
::
Lines
lines
;
GL
::
Lines
lines
;
Scene_Object
x_mov
,
y_mov
,
z_mov
;
Scene_Object
x_mov
,
y_mov
,
z_mov
;
Scene_Object
xy_mov
,
yz_mov
,
xz_mov
;
Scene_Object
xy_mov
,
yz_mov
,
xz_mov
;
Scene_Object
x_rot
,
y_rot
,
z_rot
;
Scene_Object
x_rot
,
y_rot
,
z_rot
;
Scene_Object
x_scl
,
z_scl
,
y_scl
;
Scene_Object
x_scl
,
z_scl
,
y_scl
;
};
};
}
}
// namespace Gui
src/lib/bbox.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <vector>
#include <algorithm>
#include <algorithm>
#include <ostream>
#include <cfloat>
#include <cfloat>
#include <cmath>
#include <ostream>
#include <vector>
#include "vec2.h"
#include "vec3.h"
#include "mat4.h"
#include "mat4.h"
#include "ray.h"
#include "ray.h"
#include "vec2.h"
#include "vec3.h"
struct
BBox
{
struct
BBox
{
/// Default min is max float value, default max is negative max float value
/// Default min is max float value, default max is negative max float value
BBox
()
:
BBox
()
:
min
(
FLT_MAX
),
max
(
-
FLT_MAX
)
{}
min
(
FLT_MAX
),
max
(
-
FLT_MAX
)
{
}
/// Set minimum and maximum extent
/// Set minimum and maximum extent
explicit
BBox
(
Vec3
min
,
Vec3
max
)
:
explicit
BBox
(
Vec3
min
,
Vec3
max
)
:
min
(
min
),
max
(
max
)
{}
min
(
min
),
max
(
max
)
{
}
BBox
(
const
BBox
&
src
)
=
default
;
~
BBox
()
=
default
;
BBox
operator
=
(
BBox
v
)
{
BBox
(
const
BBox
&
)
=
default
;
min
=
v
.
min
;
BBox
&
operator
=
(
const
BBox
&
)
=
default
;
max
=
v
.
max
;
~
BBox
()
=
default
;
return
*
this
;
}
/// Rest min to max float, max to negative max float
/// Rest min to max float, max to negative max float
void
reset
()
{
void
reset
()
{
...
@@ -42,7 +32,7 @@ struct BBox {
...
@@ -42,7 +32,7 @@ struct BBox {
/// Expand bounding box to include point
/// Expand bounding box to include point
void
enclose
(
Vec3
point
)
{
void
enclose
(
Vec3
point
)
{
min
=
hmin
(
min
,
point
);
min
=
hmin
(
min
,
point
);
max
=
hmax
(
max
,
point
);
max
=
hmax
(
max
,
point
);
}
}
void
enclose
(
BBox
box
)
{
void
enclose
(
BBox
box
)
{
min
=
hmin
(
min
,
box
.
min
);
min
=
hmin
(
min
,
box
.
min
);
...
@@ -50,35 +40,32 @@ struct BBox {
...
@@ -50,35 +40,32 @@ struct BBox {
}
}
/// Get center point of box
/// Get center point of box
Vec3
center
()
const
{
Vec3
center
()
const
{
return
(
min
+
max
)
*
0
.
5
f
;
}
return
(
min
+
max
)
*
0
.
5
f
;
}
// Check whether box has no volume
// Check whether box has no volume
bool
empty
()
const
{
bool
empty
()
const
{
return
min
.
x
>
max
.
x
||
min
.
y
>
max
.
y
||
min
.
z
>
max
.
z
;
}
return
min
.
x
>
max
.
x
||
min
.
y
>
max
.
y
||
min
.
z
>
max
.
z
;
}
/// Get surface area of the box
/// Get surface area of the box
float
surface_area
()
const
{
float
surface_area
()
const
{
if
(
empty
())
return
0
.
0
f
;
if
(
empty
())
return
0
.
0
f
;
Vec3
extent
=
max
-
min
;
Vec3
extent
=
max
-
min
;
return
2
.
0
f
*
(
extent
.
x
*
extent
.
z
+
extent
.
x
*
extent
.
y
+
extent
.
y
*
extent
.
z
);
return
2
.
0
f
*
(
extent
.
x
*
extent
.
z
+
extent
.
x
*
extent
.
y
+
extent
.
y
*
extent
.
z
);
}
}
/// Transform box by a matrix
/// Transform box by a matrix
void
transform
(
const
Mat4
&
trans
)
{
void
transform
(
const
Mat4
&
trans
)
{
Vec3
amin
=
min
,
amax
=
max
;
Vec3
amin
=
min
,
amax
=
max
;
min
=
max
=
trans
[
3
].
xyz
();
min
=
max
=
trans
[
3
].
xyz
();
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
float
a
=
trans
[
j
][
i
]
*
amin
[
j
];
float
a
=
trans
[
j
][
i
]
*
amin
[
j
];
float
b
=
trans
[
j
][
i
]
*
amax
[
j
];
float
b
=
trans
[
j
][
i
]
*
amax
[
j
];
if
(
a
<
b
)
{
if
(
a
<
b
)
{
min
[
i
]
+=
a
;
min
[
i
]
+=
a
;
max
[
i
]
+=
b
;
max
[
i
]
+=
b
;
}
else
{
}
else
{
min
[
i
]
+=
b
;
min
[
i
]
+=
b
;
max
[
i
]
+=
a
;
max
[
i
]
+=
a
;
}
}
}
}
...
@@ -86,7 +73,7 @@ struct BBox {
...
@@ -86,7 +73,7 @@ struct BBox {
}
}
// TODO (PathTracer): see student/bbox.cpp
// TODO (PathTracer): see student/bbox.cpp
bool
hit
(
const
Ray
&
ray
,
Vec2
&
times
)
const
;
bool
hit
(
const
Ray
&
ray
,
Vec2
&
times
)
const
;
/// Get the eight corner points of the bounding box
/// Get the eight corner points of the bounding box
std
::
vector
<
Vec3
>
corners
()
const
{
std
::
vector
<
Vec3
>
corners
()
const
{
...
@@ -102,17 +89,17 @@ struct BBox {
...
@@ -102,17 +89,17 @@ struct BBox {
return
ret
;
return
ret
;
}
}
/// Given a screen transformation (projection), calculate screen-space ([-1,1]x[-1,1])
/// Given a screen transformation (projection), calculate screen-space ([-1,1]x[-1,1])
/// bounds that will always contain the bounding box on screen
/// bounds that will always contain the bounding box on screen
void
screen_rect
(
const
Mat4
&
transform
,
Vec2
&
min_out
,
Vec2
&
max_out
)
const
{
void
screen_rect
(
const
Mat4
&
transform
,
Vec2
&
min_out
,
Vec2
&
max_out
)
const
{
min_out
=
Vec2
(
FLT_MAX
);
min_out
=
Vec2
(
FLT_MAX
);
max_out
=
Vec2
(
-
FLT_MAX
);
max_out
=
Vec2
(
-
FLT_MAX
);
auto
c
=
corners
();
auto
c
=
corners
();
bool
partially_behind
=
false
,
all_behind
=
true
;
bool
partially_behind
=
false
,
all_behind
=
true
;
for
(
auto
&
v
:
c
)
{
for
(
auto
&
v
:
c
)
{
Vec3
p
=
transform
*
v
;
Vec3
p
=
transform
*
v
;
if
(
p
.
z
<
0
)
{
if
(
p
.
z
<
0
)
{
partially_behind
=
true
;
partially_behind
=
true
;
}
else
{
}
else
{
all_behind
=
false
;
all_behind
=
false
;
...
@@ -121,10 +108,10 @@ struct BBox {
...
@@ -121,10 +108,10 @@ struct BBox {
max_out
=
hmax
(
max_out
,
Vec2
(
p
.
x
,
p
.
y
));
max_out
=
hmax
(
max_out
,
Vec2
(
p
.
x
,
p
.
y
));
}
}
if
(
partially_behind
&&
!
all_behind
)
{
if
(
partially_behind
&&
!
all_behind
)
{
min_out
=
Vec2
(
-
1
.
0
f
,
-
1
.
0
f
);
min_out
=
Vec2
(
-
1
.
0
f
,
-
1
.
0
f
);
max_out
=
Vec2
(
1
.
0
f
,
1
.
0
f
);
max_out
=
Vec2
(
1
.
0
f
,
1
.
0
f
);
}
else
if
(
all_behind
)
{
}
else
if
(
all_behind
)
{
min_out
=
Vec2
(
0
.
0
f
,
0
.
0
f
);
min_out
=
Vec2
(
0
.
0
f
,
0
.
0
f
);
max_out
=
Vec2
(
0
.
0
f
,
0
.
0
f
);
max_out
=
Vec2
(
0
.
0
f
,
0
.
0
f
);
}
}
...
@@ -133,8 +120,7 @@ struct BBox {
...
@@ -133,8 +120,7 @@ struct BBox {
Vec3
min
,
max
;
Vec3
min
,
max
;
};
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
BBox
b
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
BBox
b
)
{
out
<<
"BBox{"
<<
b
.
min
<<
","
<<
b
.
max
<<
"}"
;
out
<<
"BBox{"
<<
b
.
min
<<
","
<<
b
.
max
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/line.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "vec3.h"
#include "vec3.h"
struct
Line
{
struct
Line
{
Line
()
{
Line
()
{}
}
/// Create line from point and unit direction
/// Create line from point and unit direction
explicit
Line
(
Vec3
point
,
Vec3
dir
)
:
point
(
point
),
dir
(
dir
.
unit
())
{}
explicit
Line
(
Vec3
point
,
Vec3
dir
)
:
point
(
point
),
Line
(
const
Line
&
)
=
default
;
dir
(
dir
.
unit
())
{
Line
&
operator
=
(
const
Line
&
)
=
default
;
}
~
Line
()
=
default
;
Line
(
const
Line
&
src
)
=
default
;
~
Line
()
=
default
;
/// Get point on line at time t
Vec3
at
(
float
t
)
const
{
return
point
+
t
*
dir
;
}
Line
operator
=
(
Line
v
)
{
point
=
v
.
point
;
/// Get closest point on line to pt
dir
=
v
.
dir
;
Vec3
closest
(
Vec3
pt
)
const
{
return
*
this
;
Vec3
p
=
pt
-
point
;
}
float
t
=
dot
(
p
,
dir
);
return
at
(
t
);
/// Get point on line at time t
}
Vec3
at
(
float
t
)
const
{
return
point
+
t
*
dir
;
/// Get closest point on line to another line.
}
/// Returns false if the closest point is 'backward' relative to the line's direction
bool
closest
(
Line
other
,
Vec3
&
pt
)
const
{
/// Get closest point on line to pt
Vec3
closest
(
Vec3
pt
)
const
{
Vec3
p
=
pt
-
point
;
float
t
=
dot
(
p
,
dir
);
return
at
(
t
);
}
/// Get closest point on line to another line.
/// Returns false if the closest point is 'backward' relative to the line's direction
bool
closest
(
Line
other
,
Vec3
&
pt
)
const
{
Vec3
p0
=
point
-
other
.
point
;
Vec3
p0
=
point
-
other
.
point
;
float
a
=
dot
(
dir
,
other
.
dir
);
float
a
=
dot
(
dir
,
other
.
dir
);
float
b
=
dot
(
dir
,
p0
);
float
b
=
dot
(
dir
,
p0
);
float
c
=
dot
(
other
.
dir
,
p0
);
float
c
=
dot
(
other
.
dir
,
p0
);
float
t0
=
(
a
*
c
-
b
)
/
(
1
.
0
f
-
a
*
a
);
float
t0
=
(
a
*
c
-
b
)
/
(
1
.
0
f
-
a
*
a
);
float
t1
=
(
c
-
a
*
b
)
/
(
1
.
0
f
-
a
*
a
);
float
t1
=
(
c
-
a
*
b
)
/
(
1
.
0
f
-
a
*
a
);
pt
=
at
(
t0
);
pt
=
at
(
t0
);
return
t1
>=
0
.
0
f
;
return
t1
>=
0
.
0
f
;
}
}
Vec3
point
,
dir
;
Vec3
point
,
dir
;
};
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Line
l
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Line
l
)
{
out
<<
"Line{"
<<
l
.
point
<<
","
<<
l
.
dir
<<
"}"
;
out
<<
"Line{"
<<
l
.
point
<<
","
<<
l
.
dir
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/log.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cstdio>
#include <cstdarg>
#include <cstdarg>
#include <cstdio>
#include <mutex>
#include <mutex>
#include <string>
#include <string>
inline
std
::
mutex
printf_lock
;
inline
std
::
mutex
printf_lock
;
inline
void
log
(
std
::
string
fmt
,
...)
{
inline
void
log
(
std
::
string
fmt
,
...)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
printf_lock
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
printf_lock
);
va_list
args
;
va_list
args
;
va_start
(
args
,
fmt
);
va_start
(
args
,
fmt
);
vprintf
(
fmt
.
c_str
(),
args
);
vprintf
(
fmt
.
c_str
(),
args
);
va_end
(
args
);
va_end
(
args
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
inline
std
::
string
last_file
(
std
::
string
path
)
{
inline
std
::
string
last_file
(
std
::
string
path
)
{
size_t
p
=
path
.
find_last_of
(
"
\\
/"
)
+
1
;
size_t
p
=
path
.
find_last_of
(
"
\\
/"
)
+
1
;
return
path
.
substr
(
p
,
path
.
size
()
-
p
);
return
path
.
substr
(
p
,
path
.
size
()
-
p
);
}
}
/// Log informational message
/// Log informational message
#define info(fmt, ...)
(void)(
\
#define info(fmt, ...)
\
log("%s:%u [info] " fmt "\n", last_file(__FILE__).c_str(), __LINE__, ##__VA_ARGS__))
(void)(
log("%s:%u [info] " fmt "\n", last_file(__FILE__).c_str(), __LINE__, ##__VA_ARGS__))
/// Log warning (red)
/// Log warning (red)
#define warn(fmt, ...) (void)( \
#define warn(fmt, ...) \
log("\033[0;31m%s:%u [warn] " fmt "\033[0m\n", last_file(__FILE__).c_str(), __LINE__, ##__VA_ARGS__))
(void)(log("\033[0;31m%s:%u [warn] " fmt "\033[0m\n", last_file(__FILE__).c_str(), __LINE__, \
##__VA_ARGS__))
/// Log fatal error and exit program
/// Log fatal error and exit program
#define die(fmt, ...) (void)( \
#define die(fmt, ...) \
log("\033[0;31m%s:%u [fatal] " fmt "\033[0m\n", last_file(__FILE__).c_str(), __LINE__, ##__VA_ARGS__), \
(void)(log("\033[0;31m%s:%u [fatal] " fmt "\033[0m\n", last_file(__FILE__).c_str(), __LINE__, \
std::exit(__LINE__));
##__VA_ARGS__), \
std::exit(__LINE__));
#ifdef _MSC_VER
#ifdef _MSC_VER
#define DEBUG_BREAK __debugbreak()
#define DEBUG_BREAK __debugbreak()
...
@@ -45,10 +47,10 @@ inline std::string last_file(std::string path) {
...
@@ -45,10 +47,10 @@ inline std::string last_file(std::string path) {
#error Unsupported compiler.
#error Unsupported compiler.
#endif
#endif
#define fail_assert(msg, file, line) (void)( \
#define fail_assert(msg, file, line) \
log("\033[1;31m%s:%u [ASSERT] " msg "\033[0m\n", file, line), DEBUG_BREAK, std::exit(__LINE__), 0)
(void)(log("\033[1;31m%s:%u [ASSERT] " msg "\033[0m\n", file, line), DEBUG_BREAK, \
std::exit(__LINE__), 0)
#undef assert
#undef assert
#define assert(expr) (void)( \
#define assert(expr) \
(!!(expr)) || \
(void)((!!(expr)) || (fail_assert(#expr, last_file(__FILE__).c_str(), __LINE__), 0))
(fail_assert(#expr, last_file(__FILE__).c_str(), __LINE__), 0))
src/lib/mat4.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "log.h"
#include "log.h"
...
@@ -10,435 +10,465 @@
...
@@ -10,435 +10,465 @@
struct
Mat4
{
struct
Mat4
{
/// Identity matrix
/// Identity matrix
static
const
Mat4
I
;
static
const
Mat4
I
;
/// Zero matrix
/// Zero matrix
static
const
Mat4
Zero
;
static
const
Mat4
Zero
;
/// Return transposed matrix
/// Return transposed matrix
static
Mat4
transpose
(
const
Mat4
&
m
);
static
Mat4
transpose
(
const
Mat4
&
m
);
/// Return inverse matrix (will be NaN if m is not invertible)
/// Return inverse matrix (will be NaN if m is not invertible)
static
Mat4
inverse
(
const
Mat4
&
m
);
static
Mat4
inverse
(
const
Mat4
&
m
);
/// Return transformation matrix for given translation vector
/// Return transformation matrix for given translation vector
static
Mat4
translate
(
Vec3
t
);
static
Mat4
translate
(
Vec3
t
);
/// Return transformation matrix for given angle (degrees) and axis
/// Return transformation matrix for given angle (degrees) and axis
static
Mat4
rotate
(
float
t
,
Vec3
axis
);
static
Mat4
rotate
(
float
t
,
Vec3
axis
);
/// Return transformation matrix for given XYZ Euler angle rotation
/// Return transformation matrix for given XYZ Euler angle rotation
static
Mat4
euler
(
Vec3
angles
);
static
Mat4
euler
(
Vec3
angles
);
/// Return transformation matrix that rotates the Y axis to dir
/// Return transformation matrix that rotates the Y axis to dir
static
Mat4
rotate_to
(
Vec3
dir
);
static
Mat4
rotate_to
(
Vec3
dir
);
/// Return transformation matrix that rotates the -Z axis to dir
/// Return transformation matrix that rotates the -Z axis to dir
static
Mat4
rotate_z_to
(
Vec3
dir
);
static
Mat4
rotate_z_to
(
Vec3
dir
);
/// Return transformation matrix for given scale factors
/// Return transformation matrix for given scale factors
static
Mat4
scale
(
Vec3
s
);
static
Mat4
scale
(
Vec3
s
);
/// Return transformation matrix with given axes
/// Return transformation matrix with given axes
static
Mat4
axes
(
Vec3
x
,
Vec3
y
,
Vec3
z
);
static
Mat4
axes
(
Vec3
x
,
Vec3
y
,
Vec3
z
);
/// Return transformation matrix for viewing a scene from $pos looking at $at,
/// Return transformation matrix for viewing a scene from $pos looking at $at,
/// where straight up is defined as $up
/// where straight up is defined as $up
static
Mat4
look_at
(
Vec3
pos
,
Vec3
at
,
Vec3
up
=
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
});
static
Mat4
look_at
(
Vec3
pos
,
Vec3
at
,
Vec3
up
=
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
});
/// Return orthogonal projection matrix with given left, right, bottom, top,
/// Return orthogonal projection matrix with given left, right, bottom, top,
/// near, and far planes.
/// near, and far planes.
static
Mat4
ortho
(
float
l
,
float
r
,
float
b
,
float
t
,
float
n
,
float
f
);
static
Mat4
ortho
(
float
l
,
float
r
,
float
b
,
float
t
,
float
n
,
float
f
);
/// Return perspective projection matrix with given field of view, aspect ratio,
/// Return perspective projection matrix with given field of view, aspect ratio,
/// and near plane. The far plane is assumed to be at infinity. This projection
/// and near plane. The far plane is assumed to be at infinity. This projection
/// also outputs n/z for better precision with floating point depth buffers, so we use
/// also outputs n/z for better precision with floating point depth buffers, so we use
/// a depth mapping where 0 is the far plane (infinity) and 1 is the near plane, and
/// a depth mapping where 0 is the far plane (infinity) and 1 is the near plane, and
/// an object is closer if is depth is greater.
/// an object is closer if is depth is greater.
static
Mat4
project
(
float
fov
,
float
ar
,
float
n
);
static
Mat4
project
(
float
fov
,
float
ar
,
float
n
);
Mat4
()
{
Mat4
()
{
*
this
=
I
;
}
*
this
=
I
;
explicit
Mat4
(
Vec4
x
,
Vec4
y
,
Vec4
z
,
Vec4
w
)
{
}
cols
[
0
]
=
x
;
explicit
Mat4
(
Vec4
x
,
Vec4
y
,
Vec4
z
,
Vec4
w
)
{
cols
[
1
]
=
y
;
cols
[
0
]
=
x
;
cols
[
2
]
=
z
;
cols
[
1
]
=
y
;
cols
[
3
]
=
w
;
cols
[
2
]
=
z
;
}
cols
[
3
]
=
w
;
}
Mat4
(
const
Mat4
&
)
=
default
;
Mat4
(
const
Mat4
&
src
)
{
Mat4
&
operator
=
(
const
Mat4
&
)
=
default
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
~
Mat4
()
=
default
;
cols
[
i
]
=
src
.
cols
[
i
];
}
Vec4
&
operator
[](
int
idx
)
{
~
Mat4
()
=
default
;
assert
(
idx
>=
0
&&
idx
<=
3
);
return
cols
[
idx
];
Mat4
operator
=
(
const
Mat4
&
m
)
{
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Vec4
operator
[](
int
idx
)
const
{
cols
[
i
]
=
m
.
cols
[
i
];
assert
(
idx
>=
0
&&
idx
<=
3
);
return
*
this
;
return
cols
[
idx
];
}
}
Vec4
&
operator
[](
int
idx
)
{
Mat4
operator
+=
(
const
Mat4
&
m
)
{
assert
(
idx
>=
0
&&
idx
<=
3
);
for
(
int
i
=
0
;
i
<
4
;
i
++
)
return
cols
[
idx
];
cols
[
i
]
+=
m
.
cols
[
i
];
}
return
*
this
;
Vec4
operator
[](
int
idx
)
const
{
}
assert
(
idx
>=
0
&&
idx
<=
3
);
Mat4
operator
-=
(
const
Mat4
&
m
)
{
return
cols
[
idx
];
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
cols
[
i
]
-=
m
.
cols
[
i
];
return
*
this
;
Mat4
operator
+=
(
const
Mat4
&
m
)
{
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
cols
[
i
]
+=
m
.
cols
[
i
];
Mat4
operator
+=
(
float
s
)
{
return
*
this
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
cols
[
i
]
+=
s
;
Mat4
operator
-=
(
const
Mat4
&
m
)
{
return
*
this
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
cols
[
i
]
-=
m
.
cols
[
i
];
Mat4
operator
-=
(
float
s
)
{
return
*
this
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
cols
[
i
]
-=
s
;
return
*
this
;
Mat4
operator
+=
(
float
s
)
{
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
*=
(
float
s
)
{
cols
[
i
]
+=
s
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
return
*
this
;
cols
[
i
]
*=
s
;
}
return
*
this
;
Mat4
operator
-=
(
float
s
)
{
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
/=
(
float
s
)
{
cols
[
i
]
-=
s
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
return
*
this
;
cols
[
i
]
/=
s
;
}
return
*
this
;
Mat4
operator
*=
(
float
s
)
{
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
cols
[
i
]
*=
s
;
Mat4
operator
+
(
const
Mat4
&
m
)
const
{
return
*
this
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
/=
(
float
s
)
{
r
.
cols
[
i
]
=
cols
[
i
]
+
m
.
cols
[
i
];
for
(
int
i
=
0
;
i
<
4
;
i
++
)
return
r
;
cols
[
i
]
/=
s
;
}
return
*
this
;
Mat4
operator
-
(
const
Mat4
&
m
)
const
{
}
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
cols
[
i
]
-
m
.
cols
[
i
];
Mat4
operator
+
(
const
Mat4
&
m
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
cols
[
i
]
+
m
.
cols
[
i
];
Mat4
operator
+
(
float
s
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
-
(
const
Mat4
&
m
)
const
{
r
.
cols
[
i
]
=
cols
[
i
]
+
s
;
Mat4
r
;
return
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
r
.
cols
[
i
]
=
cols
[
i
]
-
m
.
cols
[
i
];
Mat4
operator
-
(
float
s
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
cols
[
i
]
-
s
;
Mat4
operator
+
(
float
s
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
*
(
float
s
)
const
{
r
.
cols
[
i
]
=
cols
[
i
]
+
s
;
Mat4
r
;
return
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
r
.
cols
[
i
]
=
cols
[
i
]
*
s
;
Mat4
operator
-
(
float
s
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
operator
/
(
float
s
)
const
{
r
.
cols
[
i
]
=
cols
[
i
]
-
s
;
Mat4
r
;
return
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
}
r
.
cols
[
i
]
=
cols
[
i
]
/
s
;
Mat4
operator
*
(
float
s
)
const
{
return
r
;
Mat4
r
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
cols
[
i
]
*
s
;
Mat4
operator
*=
(
const
Mat4
&
v
)
{
return
r
;
*
this
=
*
this
*
v
;
}
return
*
this
;
Mat4
operator
/
(
float
s
)
const
{
}
Mat4
r
;
Mat4
operator
*
(
const
Mat4
&
m
)
const
{
for
(
int
i
=
0
;
i
<
4
;
i
++
)
Mat4
ret
;
r
.
cols
[
i
]
=
cols
[
i
]
/
s
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
return
r
;
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
}
ret
[
i
][
j
]
=
0
.
0
f
;
for
(
int
k
=
0
;
k
<
4
;
k
++
)
{
Mat4
operator
*=
(
const
Mat4
&
v
)
{
ret
[
i
][
j
]
+=
m
[
i
][
k
]
*
cols
[
k
][
j
];
*
this
=
*
this
*
v
;
}
return
*
this
;
}
}
}
Mat4
operator
*
(
const
Mat4
&
m
)
const
{
return
ret
;
Mat4
ret
;
}
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
Vec4
operator
*
(
Vec4
v
)
const
{
ret
[
i
][
j
]
=
0
.
0
f
;
return
v
[
0
]
*
cols
[
0
]
+
v
[
1
]
*
cols
[
1
]
+
v
[
2
]
*
cols
[
2
]
+
v
[
3
]
*
cols
[
3
];
for
(
int
k
=
0
;
k
<
4
;
k
++
)
{
}
ret
[
i
][
j
]
+=
m
[
i
][
k
]
*
cols
[
k
][
j
];
}
/// Expands v to Vec4(v, 1.0), multiplies, and projects back to 3D
}
Vec3
operator
*
(
Vec3
v
)
const
{
return
operator
*
(
Vec4
(
v
,
1
.
0
f
)).
project
();
}
}
/// Expands v to Vec4(v, 0.0), multiplies, and projects back to 3D
return
ret
;
Vec3
rotate
(
Vec3
v
)
const
{
return
operator
*
(
Vec4
(
v
,
0
.
0
f
)).
xyz
();
}
}
/// Converts rotation (orthonormal 3x3) matrix to equivalent Euler angles
Vec4
operator
*
(
Vec4
v
)
const
{
Vec3
to_euler
()
const
{
return
v
[
0
]
*
cols
[
0
]
+
v
[
1
]
*
cols
[
1
]
+
v
[
2
]
*
cols
[
2
]
+
v
[
3
]
*
cols
[
3
];
bool
single
=
true
;
}
static
const
float
singularity
[]
=
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
};
/// Expands v to Vec4(v, 1.0), multiplies, and projects back to 3D
for
(
int
i
=
0
;
i
<
12
&&
single
;
i
++
)
{
Vec3
operator
*
(
Vec3
v
)
const
{
single
=
single
&&
std
::
abs
(
data
[
i
]
-
singularity
[
i
])
<
16
.
0
f
*
FLT_EPSILON
;
return
operator
*
(
Vec4
(
v
,
1
.
0
f
)).
project
();
}
}
if
(
single
)
/// Expands v to Vec4(v, 0.0), multiplies, and projects back to 3D
return
Vec3
{
0
.
0
f
,
0
.
0
f
,
180
.
0
f
};
Vec3
rotate
(
Vec3
v
)
const
{
return
operator
*
(
Vec4
(
v
,
0
.
0
f
)).
xyz
();
Vec3
eul1
,
eul2
;
}
float
cy
=
std
::
hypotf
(
cols
[
0
][
0
],
cols
[
0
][
1
]);
/// Converts rotation (orthonormal 3x3) matrix to equivalent Euler angles
if
(
cy
>
16
.
0
f
*
FLT_EPSILON
)
{
Vec3
to_euler
()
const
{
eul1
[
0
]
=
std
::
atan2
(
cols
[
1
][
2
],
cols
[
2
][
2
]);
eul1
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
cy
);
bool
single
=
true
;
eul1
[
2
]
=
std
::
atan2
(
cols
[
0
][
1
],
cols
[
0
][
0
]);
static
const
float
singularity
[]
=
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
};
eul2
[
0
]
=
std
::
atan2
(
-
cols
[
1
][
2
],
-
cols
[
2
][
2
]);
for
(
int
i
=
0
;
i
<
12
&&
single
;
i
++
)
{
eul2
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
-
cy
);
single
=
single
&&
std
::
abs
(
data
[
i
]
-
singularity
[
i
])
<
16
.
0
f
*
FLT_EPSILON
;
eul2
[
2
]
=
std
::
atan2
(
-
cols
[
0
][
1
],
-
cols
[
0
][
0
]);
}
}
else
{
if
(
single
)
return
Vec3
{
0
.
0
f
,
0
.
0
f
,
180
.
0
f
};
eul1
[
0
]
=
std
::
atan2
(
-
cols
[
2
][
1
],
cols
[
1
][
1
]);
eul1
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
cy
);
Vec3
eul1
,
eul2
;
eul1
[
2
]
=
0
;
eul2
=
eul1
;
float
cy
=
std
::
hypotf
(
cols
[
0
][
0
],
cols
[
0
][
1
]);
}
if
(
cy
>
16
.
0
f
*
FLT_EPSILON
)
{
float
d1
=
std
::
abs
(
eul1
[
0
])
+
std
::
abs
(
eul1
[
1
])
+
std
::
abs
(
eul1
[
2
]);
eul1
[
0
]
=
std
::
atan2
(
cols
[
1
][
2
],
cols
[
2
][
2
]);
float
d2
=
std
::
abs
(
eul2
[
0
])
+
std
::
abs
(
eul2
[
1
])
+
std
::
abs
(
eul2
[
2
]);
eul1
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
cy
);
if
(
d1
>
d2
)
eul1
[
2
]
=
std
::
atan2
(
cols
[
0
][
1
],
cols
[
0
][
0
]);
return
Degrees
(
eul2
);
else
eul2
[
0
]
=
std
::
atan2
(
-
cols
[
1
][
2
],
-
cols
[
2
][
2
]);
return
Degrees
(
eul1
);
eul2
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
-
cy
);
}
eul2
[
2
]
=
std
::
atan2
(
-
cols
[
0
][
1
],
-
cols
[
0
][
0
]);
}
else
{
/// Returns matrix transpose
eul1
[
0
]
=
std
::
atan2
(
-
cols
[
2
][
1
],
cols
[
1
][
1
]);
Mat4
T
()
const
{
return
transpose
(
*
this
);
}
eul1
[
1
]
=
std
::
atan2
(
-
cols
[
0
][
2
],
cy
);
/// Returns matrix inverse (will be NaN if m is not invertible)
eul1
[
2
]
=
0
;
Mat4
inverse
()
const
{
return
inverse
(
*
this
);
}
eul2
=
eul1
;
}
/// Returns determinant (brute force).
float
d1
=
std
::
abs
(
eul1
[
0
])
+
std
::
abs
(
eul1
[
1
])
+
std
::
abs
(
eul1
[
2
]);
float
det
()
const
{
float
d2
=
std
::
abs
(
eul2
[
0
])
+
std
::
abs
(
eul2
[
1
])
+
std
::
abs
(
eul2
[
2
]);
return
cols
[
0
][
3
]
*
cols
[
1
][
2
]
*
cols
[
2
][
1
]
*
cols
[
3
][
0
]
-
if
(
d1
>
d2
)
return
Degrees
(
eul2
);
cols
[
0
][
2
]
*
cols
[
1
][
3
]
*
cols
[
2
][
1
]
*
cols
[
3
][
0
]
-
else
return
Degrees
(
eul1
);
cols
[
0
][
3
]
*
cols
[
1
][
1
]
*
cols
[
2
][
2
]
*
cols
[
3
][
0
]
+
}
cols
[
0
][
1
]
*
cols
[
1
][
3
]
*
cols
[
2
][
2
]
*
cols
[
3
][
0
]
+
cols
[
0
][
2
]
*
cols
[
1
][
1
]
*
cols
[
2
][
3
]
*
cols
[
3
][
0
]
-
/// Returns matrix transpose
cols
[
0
][
1
]
*
cols
[
1
][
2
]
*
cols
[
2
][
3
]
*
cols
[
3
][
0
]
-
Mat4
T
()
const
{
cols
[
0
][
3
]
*
cols
[
1
][
2
]
*
cols
[
2
][
0
]
*
cols
[
3
][
1
]
+
return
transpose
(
*
this
);
cols
[
0
][
2
]
*
cols
[
1
][
3
]
*
cols
[
2
][
0
]
*
cols
[
3
][
1
]
+
}
cols
[
0
][
3
]
*
cols
[
1
][
0
]
*
cols
[
2
][
2
]
*
cols
[
3
][
1
]
-
/// Returns matrix inverse (will be NaN if m is not invertible)
cols
[
0
][
0
]
*
cols
[
1
][
3
]
*
cols
[
2
][
2
]
*
cols
[
3
][
1
]
-
Mat4
inverse
()
const
{
cols
[
0
][
2
]
*
cols
[
1
][
0
]
*
cols
[
2
][
3
]
*
cols
[
3
][
1
]
+
return
inverse
(
*
this
);
cols
[
0
][
0
]
*
cols
[
1
][
2
]
*
cols
[
2
][
3
]
*
cols
[
3
][
1
]
+
}
cols
[
0
][
3
]
*
cols
[
1
][
1
]
*
cols
[
2
][
0
]
*
cols
[
3
][
2
]
-
cols
[
0
][
1
]
*
cols
[
1
][
3
]
*
cols
[
2
][
0
]
*
cols
[
3
][
2
]
-
/// Returns determinant (brute force).
cols
[
0
][
3
]
*
cols
[
1
][
0
]
*
cols
[
2
][
1
]
*
cols
[
3
][
2
]
+
float
det
()
const
{
cols
[
0
][
0
]
*
cols
[
1
][
3
]
*
cols
[
2
][
1
]
*
cols
[
3
][
2
]
+
return
cols
[
0
][
3
]
*
cols
[
1
][
2
]
*
cols
[
2
][
1
]
*
cols
[
3
][
0
]
-
cols
[
0
][
2
]
*
cols
[
1
][
3
]
*
cols
[
2
][
1
]
*
cols
[
3
][
0
]
-
cols
[
0
][
1
]
*
cols
[
1
][
0
]
*
cols
[
2
][
3
]
*
cols
[
3
][
2
]
-
cols
[
0
][
3
]
*
cols
[
1
][
1
]
*
cols
[
2
][
2
]
*
cols
[
3
][
0
]
+
cols
[
0
][
1
]
*
cols
[
1
][
3
]
*
cols
[
2
][
2
]
*
cols
[
3
][
0
]
+
cols
[
0
][
0
]
*
cols
[
1
][
1
]
*
cols
[
2
][
3
]
*
cols
[
3
][
2
]
-
cols
[
0
][
2
]
*
cols
[
1
][
1
]
*
cols
[
2
][
3
]
*
cols
[
3
][
0
]
-
cols
[
0
][
1
]
*
cols
[
1
][
2
]
*
cols
[
2
][
3
]
*
cols
[
3
][
0
]
-
cols
[
0
][
2
]
*
cols
[
1
][
1
]
*
cols
[
2
][
0
]
*
cols
[
3
][
3
]
+
cols
[
0
][
3
]
*
cols
[
1
][
2
]
*
cols
[
2
][
0
]
*
cols
[
3
][
1
]
+
cols
[
0
][
2
]
*
cols
[
1
][
3
]
*
cols
[
2
][
0
]
*
cols
[
3
][
1
]
+
cols
[
0
][
1
]
*
cols
[
1
][
2
]
*
cols
[
2
][
0
]
*
cols
[
3
][
3
]
+
cols
[
0
][
3
]
*
cols
[
1
][
0
]
*
cols
[
2
][
2
]
*
cols
[
3
][
1
]
-
cols
[
0
][
0
]
*
cols
[
1
][
3
]
*
cols
[
2
][
2
]
*
cols
[
3
][
1
]
-
cols
[
0
][
2
]
*
cols
[
1
][
0
]
*
cols
[
2
][
1
]
*
cols
[
3
][
3
]
-
cols
[
0
][
2
]
*
cols
[
1
][
0
]
*
cols
[
2
][
3
]
*
cols
[
3
][
1
]
+
cols
[
0
][
0
]
*
cols
[
1
][
2
]
*
cols
[
2
][
3
]
*
cols
[
3
][
1
]
+
cols
[
0
][
0
]
*
cols
[
1
][
2
]
*
cols
[
2
][
1
]
*
cols
[
3
][
3
]
-
cols
[
0
][
3
]
*
cols
[
1
][
1
]
*
cols
[
2
][
0
]
*
cols
[
3
][
2
]
-
cols
[
0
][
1
]
*
cols
[
1
][
3
]
*
cols
[
2
][
0
]
*
cols
[
3
][
2
]
-
cols
[
0
][
1
]
*
cols
[
1
][
0
]
*
cols
[
2
][
2
]
*
cols
[
3
][
3
]
+
cols
[
0
][
3
]
*
cols
[
1
][
0
]
*
cols
[
2
][
1
]
*
cols
[
3
][
2
]
+
cols
[
0
][
0
]
*
cols
[
1
][
3
]
*
cols
[
2
][
1
]
*
cols
[
3
][
2
]
+
cols
[
0
][
0
]
*
cols
[
1
][
1
]
*
cols
[
2
][
2
]
*
cols
[
3
][
3
];
cols
[
0
][
1
]
*
cols
[
1
][
0
]
*
cols
[
2
][
3
]
*
cols
[
3
][
2
]
-
cols
[
0
][
0
]
*
cols
[
1
][
1
]
*
cols
[
2
][
3
]
*
cols
[
3
][
2
]
-
}
cols
[
0
][
2
]
*
cols
[
1
][
1
]
*
cols
[
2
][
0
]
*
cols
[
3
][
3
]
+
cols
[
0
][
1
]
*
cols
[
1
][
2
]
*
cols
[
2
][
0
]
*
cols
[
3
][
3
]
+
cols
[
0
][
2
]
*
cols
[
1
][
0
]
*
cols
[
2
][
1
]
*
cols
[
3
][
3
]
-
cols
[
0
][
0
]
*
cols
[
1
][
2
]
*
cols
[
2
][
1
]
*
cols
[
3
][
3
]
-
union
{
cols
[
0
][
1
]
*
cols
[
1
][
0
]
*
cols
[
2
][
2
]
*
cols
[
3
][
3
]
+
cols
[
0
][
0
]
*
cols
[
1
][
1
]
*
cols
[
2
][
2
]
*
cols
[
3
][
3
];
Vec4
cols
[
4
];
}
float
data
[
16
]
=
{};
};
union
{
Vec4
cols
[
4
];
float
data
[
16
]
=
{};
};
};
};
inline
bool
operator
==
(
const
Mat4
&
l
,
const
Mat4
&
r
)
{
inline
bool
operator
==
(
const
Mat4
&
l
,
const
Mat4
&
r
)
{
for
(
int
i
=
0
;
i
<
16
;
i
++
)
if
(
l
.
data
[
i
]
!=
r
.
data
[
i
])
return
false
;
for
(
int
i
=
0
;
i
<
16
;
i
++
)
return
true
;
if
(
l
.
data
[
i
]
!=
r
.
data
[
i
])
return
false
;
return
true
;
}
}
inline
bool
operator
!=
(
const
Mat4
&
l
,
const
Mat4
&
r
)
{
inline
bool
operator
!=
(
const
Mat4
&
l
,
const
Mat4
&
r
)
{
for
(
int
i
=
0
;
i
<
16
;
i
++
)
if
(
l
.
data
[
i
]
!=
r
.
data
[
i
])
return
true
;
for
(
int
i
=
0
;
i
<
16
;
i
++
)
return
false
;
if
(
l
.
data
[
i
]
!=
r
.
data
[
i
])
return
true
;
return
false
;
}
}
inline
Mat4
operator
+
(
float
s
,
const
Mat4
&
m
)
{
inline
Mat4
operator
+
(
float
s
,
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
m
.
cols
[
i
]
+
s
;
r
.
cols
[
i
]
=
m
.
cols
[
i
]
+
s
;
return
r
;
return
r
;
}
}
inline
Mat4
operator
-
(
float
s
,
const
Mat4
&
m
)
{
inline
Mat4
operator
-
(
float
s
,
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
m
.
cols
[
i
]
-
s
;
r
.
cols
[
i
]
=
m
.
cols
[
i
]
-
s
;
return
r
;
return
r
;
}
}
inline
Mat4
operator
*
(
float
s
,
const
Mat4
&
m
)
{
inline
Mat4
operator
*
(
float
s
,
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
m
.
cols
[
i
]
*
s
;
r
.
cols
[
i
]
=
m
.
cols
[
i
]
*
s
;
return
r
;
return
r
;
}
}
inline
Mat4
operator
/
(
float
s
,
const
Mat4
&
m
)
{
inline
Mat4
operator
/
(
float
s
,
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
i
=
0
;
i
<
4
;
i
++
)
r
.
cols
[
i
]
=
m
.
cols
[
i
]
/
s
;
r
.
cols
[
i
]
=
m
.
cols
[
i
]
/
s
;
return
r
;
return
r
;
}
}
const
inline
Mat4
Mat4
::
I
=
Mat4
{
Vec4
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
const
inline
Mat4
Mat4
::
I
=
Mat4
{
Vec4
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
Vec4
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
f
},
const
inline
Mat4
Mat4
::
Zero
=
Mat4
{
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
}};
const
inline
Mat4
Mat4
::
Zero
=
Mat4
{
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
}};
inline
Mat4
outer
(
Vec4
u
,
Vec4
v
)
{
inline
Mat4
outer
(
Vec4
u
,
Vec4
v
)
{
Mat4
B
;
Mat4
B
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
B
[
i
][
j
]
=
u
[
i
]
*
v
[
j
];
B
[
i
][
j
]
=
u
[
i
]
*
v
[
j
];
return
B
;
return
B
;
}
}
inline
Mat4
Mat4
::
transpose
(
const
Mat4
&
m
)
{
inline
Mat4
Mat4
::
transpose
(
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
for
(
int
j
=
0
;
j
<
4
;
j
++
)
{
r
[
i
][
j
]
=
m
[
j
][
i
];
r
[
i
][
j
]
=
m
[
j
][
i
];
}
}
}
}
return
r
;
return
r
;
}
}
inline
Mat4
Mat4
::
inverse
(
const
Mat4
&
m
)
{
inline
Mat4
Mat4
::
inverse
(
const
Mat4
&
m
)
{
Mat4
r
;
Mat4
r
;
r
[
0
][
0
]
=
m
[
1
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
m
[
1
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
+
m
[
1
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
2
]
-
m
[
1
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
-
m
[
1
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
3
]
+
m
[
1
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
r
[
0
][
0
]
=
m
[
1
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
m
[
1
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
+
r
[
0
][
1
]
=
m
[
0
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
-
m
[
0
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
m
[
0
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
2
]
+
m
[
0
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
+
m
[
0
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
3
]
-
m
[
0
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
m
[
1
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
2
]
-
m
[
1
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
-
r
[
0
][
2
]
=
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
3
][
1
]
-
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
3
][
1
]
+
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
3
][
2
]
-
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
3
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
3
][
3
]
+
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
3
][
3
];
m
[
1
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
3
]
+
m
[
1
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
r
[
0
][
3
]
=
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
2
][
1
]
-
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
2
][
1
]
-
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
2
][
2
]
+
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
2
][
2
]
+
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
2
][
3
]
-
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
2
][
3
];
r
[
0
][
1
]
=
m
[
0
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
-
m
[
0
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
r
[
1
][
0
]
=
m
[
1
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
1
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
1
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
+
m
[
1
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
+
m
[
1
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
-
m
[
1
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
m
[
0
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
2
]
+
m
[
0
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
+
r
[
1
][
1
]
=
m
[
0
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
+
m
[
0
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
-
m
[
0
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
-
m
[
0
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
+
m
[
0
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
m
[
0
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
3
]
-
m
[
0
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
r
[
1
][
2
]
=
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
3
][
2
]
+
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
3
][
2
]
+
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
3
][
3
]
-
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
3
][
3
];
r
[
0
][
2
]
=
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
3
][
1
]
-
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
3
][
1
]
+
r
[
1
][
3
]
=
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
2
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
2
][
0
]
+
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
2
][
2
]
-
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
2
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
2
][
3
]
+
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
2
][
3
];
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
3
][
2
]
-
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
3
][
2
]
-
r
[
2
][
0
]
=
m
[
1
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
1
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
+
m
[
1
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
-
m
[
1
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
m
[
1
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
+
m
[
1
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
3
];
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
3
][
3
]
+
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
3
][
3
];
r
[
2
][
1
]
=
m
[
0
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
-
m
[
0
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
+
m
[
0
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
+
m
[
0
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
-
m
[
0
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
3
];
r
[
0
][
3
]
=
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
2
][
1
]
-
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
2
][
1
]
-
r
[
2
][
2
]
=
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
3
][
0
]
+
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
3
][
1
]
-
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
3
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
3
][
3
]
+
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
3
][
3
];
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
2
][
2
]
+
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
2
][
2
]
+
r
[
2
][
3
]
=
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
2
][
0
]
-
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
2
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
2
][
1
]
+
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
2
][
1
]
+
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
2
][
3
]
-
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
2
][
3
];
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
2
][
3
]
-
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
2
][
3
];
r
[
3
][
0
]
=
m
[
1
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
-
m
[
1
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
1
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
+
m
[
1
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
+
m
[
1
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
-
m
[
1
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
2
];
r
[
1
][
0
]
=
m
[
1
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
1
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
r
[
3
][
1
]
=
m
[
0
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
+
m
[
0
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
-
m
[
0
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
-
m
[
0
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
+
m
[
0
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
2
];
m
[
1
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
+
m
[
1
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
+
r
[
3
][
2
]
=
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
3
][
0
]
-
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
3
][
1
]
+
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
3
][
1
]
+
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
3
][
2
]
-
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
3
][
2
];
m
[
1
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
-
m
[
1
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
r
[
3
][
3
]
=
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
2
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
2
][
0
]
+
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
2
][
1
]
-
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
2
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
2
][
2
]
+
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
2
][
2
];
r
[
1
][
1
]
=
m
[
0
][
2
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
+
r
/=
m
.
det
();
m
[
0
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
-
m
[
0
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
2
]
-
return
r
;
m
[
0
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
+
m
[
0
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
3
];
r
[
1
][
2
]
=
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
3
][
2
]
+
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
3
][
2
]
+
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
3
][
3
]
-
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
3
][
3
];
r
[
1
][
3
]
=
m
[
0
][
2
]
*
m
[
1
][
3
]
*
m
[
2
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
2
]
*
m
[
2
][
0
]
+
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
2
][
2
]
-
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
2
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
2
][
3
]
+
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
2
][
3
];
r
[
2
][
0
]
=
m
[
1
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
1
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
+
m
[
1
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
-
m
[
1
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
-
m
[
1
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
+
m
[
1
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
3
];
r
[
2
][
1
]
=
m
[
0
][
3
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
-
m
[
0
][
1
]
*
m
[
2
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
+
m
[
0
][
0
]
*
m
[
2
][
3
]
*
m
[
3
][
1
]
+
m
[
0
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
3
]
-
m
[
0
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
3
];
r
[
2
][
2
]
=
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
3
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
3
][
0
]
+
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
3
][
1
]
-
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
3
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
3
][
3
]
+
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
3
][
3
];
r
[
2
][
3
]
=
m
[
0
][
3
]
*
m
[
1
][
1
]
*
m
[
2
][
0
]
-
m
[
0
][
1
]
*
m
[
1
][
3
]
*
m
[
2
][
0
]
-
m
[
0
][
3
]
*
m
[
1
][
0
]
*
m
[
2
][
1
]
+
m
[
0
][
0
]
*
m
[
1
][
3
]
*
m
[
2
][
1
]
+
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
2
][
3
]
-
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
2
][
3
];
r
[
3
][
0
]
=
m
[
1
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
-
m
[
1
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
1
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
+
m
[
1
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
+
m
[
1
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
-
m
[
1
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
2
];
r
[
3
][
1
]
=
m
[
0
][
1
]
*
m
[
2
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
2
][
1
]
*
m
[
3
][
0
]
+
m
[
0
][
2
]
*
m
[
2
][
0
]
*
m
[
3
][
1
]
-
m
[
0
][
0
]
*
m
[
2
][
2
]
*
m
[
3
][
1
]
-
m
[
0
][
1
]
*
m
[
2
][
0
]
*
m
[
3
][
2
]
+
m
[
0
][
0
]
*
m
[
2
][
1
]
*
m
[
3
][
2
];
r
[
3
][
2
]
=
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
3
][
0
]
-
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
3
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
3
][
1
]
+
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
3
][
1
]
+
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
3
][
2
]
-
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
3
][
2
];
r
[
3
][
3
]
=
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
2
][
0
]
-
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
2
][
0
]
+
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
2
][
1
]
-
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
2
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
2
][
2
]
+
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
2
][
2
];
r
/=
m
.
det
();
return
r
;
}
}
inline
Mat4
Mat4
::
rotate_to
(
Vec3
dir
)
{
inline
Mat4
Mat4
::
rotate_to
(
Vec3
dir
)
{
dir
.
normalize
();
dir
.
normalize
();
if
(
dir
.
y
==
1
.
0
f
)
return
Mat4
::
I
;
if
(
dir
.
y
==
1
.
0
f
)
else
if
(
dir
.
y
==
-
1
.
0
f
)
return
Mat4
{
Vec4
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
,
0
.
0
f
},
return
Mat4
::
I
;
Vec4
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
else
if
(
dir
.
y
==
-
1
.
0
f
)
else
{
return
Mat4
{
Vec4
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
,
0
.
0
f
},
Vec3
x
=
cross
(
dir
,
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
}).
unit
();
Vec4
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
,
0
.
0
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
Vec3
z
=
cross
(
x
,
dir
).
unit
();
else
{
return
Mat4
{
Vec4
{
x
,
0
.
0
f
},
Vec4
{
dir
,
0
.
0
f
},
Vec4
{
z
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
Vec3
x
=
cross
(
dir
,
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
}).
unit
();
}
Vec3
z
=
cross
(
x
,
dir
).
unit
();
return
Mat4
{
Vec4
{
x
,
0
.
0
f
},
Vec4
{
dir
,
0
.
0
f
},
Vec4
{
z
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
}
}
}
inline
Mat4
Mat4
::
rotate_z_to
(
Vec3
dir
)
{
inline
Mat4
Mat4
::
rotate_z_to
(
Vec3
dir
)
{
Mat4
y
=
rotate_to
(
dir
);
Mat4
y
=
rotate_to
(
dir
);
Vec4
_y
=
y
[
1
];
Vec4
_y
=
y
[
1
];
Vec4
_z
=
y
[
2
];
Vec4
_z
=
y
[
2
];
y
[
1
]
=
_z
;
y
[
1
]
=
_z
;
y
[
2
]
=
-
_y
;
y
[
2
]
=
-
_y
;
return
y
;
return
y
;
}
}
inline
Mat4
Mat4
::
axes
(
Vec3
x
,
Vec3
y
,
Vec3
z
)
{
inline
Mat4
Mat4
::
axes
(
Vec3
x
,
Vec3
y
,
Vec3
z
)
{
return
Mat4
{
Vec4
{
x
,
0
.
0
f
},
Vec4
{
y
,
0
.
0
f
},
Vec4
{
z
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
return
Mat4
{
Vec4
{
x
,
0
.
0
f
},
Vec4
{
y
,
0
.
0
f
},
Vec4
{
z
,
0
.
0
f
},
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
}
}
inline
Mat4
Mat4
::
translate
(
Vec3
t
)
{
inline
Mat4
Mat4
::
translate
(
Vec3
t
)
{
Mat4
r
;
Mat4
r
;
r
[
3
]
=
Vec4
(
t
,
1
.
0
f
);
r
[
3
]
=
Vec4
(
t
,
1
.
0
f
);
return
r
;
return
r
;
}
}
inline
Mat4
Mat4
::
euler
(
Vec3
angles
)
{
inline
Mat4
Mat4
::
euler
(
Vec3
angles
)
{
return
Mat4
::
rotate
(
angles
.
z
,
Vec3
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
})
*
return
Mat4
::
rotate
(
angles
.
z
,
Vec3
{
0
.
0
f
,
0
.
0
f
,
1
.
0
f
})
*
Mat4
::
rotate
(
angles
.
y
,
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
})
*
Mat4
::
rotate
(
angles
.
y
,
Vec3
{
0
.
0
f
,
1
.
0
f
,
0
.
0
f
})
*
Mat4
::
rotate
(
angles
.
x
,
Vec3
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
});
Mat4
::
rotate
(
angles
.
x
,
Vec3
{
1
.
0
f
,
0
.
0
f
,
0
.
0
f
});
}
}
inline
Mat4
Mat4
::
rotate
(
float
t
,
Vec3
axis
)
{
inline
Mat4
Mat4
::
rotate
(
float
t
,
Vec3
axis
)
{
Mat4
ret
;
Mat4
ret
;
float
c
=
std
::
cos
(
Radians
(
t
));
float
c
=
std
::
cos
(
Radians
(
t
));
float
s
=
std
::
sin
(
Radians
(
t
));
float
s
=
std
::
sin
(
Radians
(
t
));
axis
.
normalize
();
axis
.
normalize
();
Vec3
temp
=
axis
*
(
1
.
0
f
-
c
);
Vec3
temp
=
axis
*
(
1
.
0
f
-
c
);
ret
[
0
][
0
]
=
c
+
temp
[
0
]
*
axis
[
0
];
ret
[
0
][
0
]
=
c
+
temp
[
0
]
*
axis
[
0
];
ret
[
0
][
1
]
=
temp
[
0
]
*
axis
[
1
]
+
s
*
axis
[
2
];
ret
[
0
][
1
]
=
temp
[
0
]
*
axis
[
1
]
+
s
*
axis
[
2
];
ret
[
0
][
2
]
=
temp
[
0
]
*
axis
[
2
]
-
s
*
axis
[
1
];
ret
[
0
][
2
]
=
temp
[
0
]
*
axis
[
2
]
-
s
*
axis
[
1
];
ret
[
1
][
0
]
=
temp
[
1
]
*
axis
[
0
]
-
s
*
axis
[
2
];
ret
[
1
][
0
]
=
temp
[
1
]
*
axis
[
0
]
-
s
*
axis
[
2
];
ret
[
1
][
1
]
=
c
+
temp
[
1
]
*
axis
[
1
];
ret
[
1
][
1
]
=
c
+
temp
[
1
]
*
axis
[
1
];
ret
[
1
][
2
]
=
temp
[
1
]
*
axis
[
2
]
+
s
*
axis
[
0
];
ret
[
1
][
2
]
=
temp
[
1
]
*
axis
[
2
]
+
s
*
axis
[
0
];
ret
[
2
][
0
]
=
temp
[
2
]
*
axis
[
0
]
+
s
*
axis
[
1
];
ret
[
2
][
0
]
=
temp
[
2
]
*
axis
[
0
]
+
s
*
axis
[
1
];
ret
[
2
][
1
]
=
temp
[
2
]
*
axis
[
1
]
-
s
*
axis
[
0
];
ret
[
2
][
1
]
=
temp
[
2
]
*
axis
[
1
]
-
s
*
axis
[
0
];
ret
[
2
][
2
]
=
c
+
temp
[
2
]
*
axis
[
2
];
ret
[
2
][
2
]
=
c
+
temp
[
2
]
*
axis
[
2
];
return
ret
;
return
ret
;
}
}
inline
Mat4
Mat4
::
scale
(
Vec3
s
)
{
inline
Mat4
Mat4
::
scale
(
Vec3
s
)
{
Mat4
r
;
Mat4
r
;
r
[
0
][
0
]
=
s
.
x
;
r
[
0
][
0
]
=
s
.
x
;
r
[
1
][
1
]
=
s
.
y
;
r
[
1
][
1
]
=
s
.
y
;
r
[
2
][
2
]
=
s
.
z
;
r
[
2
][
2
]
=
s
.
z
;
return
r
;
return
r
;
}
}
inline
Mat4
Mat4
::
ortho
(
float
l
,
float
r
,
float
b
,
float
t
,
float
n
,
float
f
)
{
inline
Mat4
Mat4
::
ortho
(
float
l
,
float
r
,
float
b
,
float
t
,
float
n
,
float
f
)
{
Mat4
rs
;
Mat4
rs
;
rs
[
0
][
0
]
=
2
.
0
f
/
(
r
-
l
);
rs
[
0
][
0
]
=
2
.
0
f
/
(
r
-
l
);
rs
[
1
][
1
]
=
2
.
0
f
/
(
t
-
b
);
rs
[
1
][
1
]
=
2
.
0
f
/
(
t
-
b
);
rs
[
2
][
2
]
=
2
.
0
f
/
(
n
-
f
);
rs
[
2
][
2
]
=
2
.
0
f
/
(
n
-
f
);
rs
[
3
][
0
]
=
(
-
l
-
r
)
/
(
r
-
l
);
rs
[
3
][
0
]
=
(
-
l
-
r
)
/
(
r
-
l
);
rs
[
3
][
1
]
=
(
-
b
-
t
)
/
(
t
-
b
);
rs
[
3
][
1
]
=
(
-
b
-
t
)
/
(
t
-
b
);
rs
[
3
][
2
]
=
-
n
/
(
f
-
n
);
rs
[
3
][
2
]
=
-
n
/
(
f
-
n
);
return
rs
;
return
rs
;
}
}
inline
Mat4
Mat4
::
project
(
float
fov
,
float
ar
,
float
n
)
{
inline
Mat4
Mat4
::
project
(
float
fov
,
float
ar
,
float
n
)
{
float
f
=
1
.
0
f
/
std
::
tan
(
Radians
(
fov
)
/
2
.
0
f
);
float
f
=
1
.
0
f
/
std
::
tan
(
Radians
(
fov
)
/
2
.
0
f
);
Mat4
r
;
Mat4
r
;
r
[
0
][
0
]
=
f
/
ar
;
r
[
0
][
0
]
=
f
/
ar
;
r
[
1
][
1
]
=
f
;
r
[
1
][
1
]
=
f
;
r
[
2
][
2
]
=
0
.
0
f
;
r
[
2
][
2
]
=
0
.
0
f
;
r
[
3
][
3
]
=
0
.
0
f
;
r
[
3
][
3
]
=
0
.
0
f
;
r
[
3
][
2
]
=
n
;
r
[
3
][
2
]
=
n
;
r
[
2
][
3
]
=
-
1
.
0
f
;
r
[
2
][
3
]
=
-
1
.
0
f
;
return
r
;
return
r
;
}
}
inline
Mat4
Mat4
::
look_at
(
Vec3
pos
,
Vec3
at
,
Vec3
up
)
{
inline
Mat4
Mat4
::
look_at
(
Vec3
pos
,
Vec3
at
,
Vec3
up
)
{
Mat4
r
=
Mat4
::
Zero
;
Mat4
r
=
Mat4
::
Zero
;
Vec3
F
=
(
at
-
pos
).
unit
();
Vec3
F
=
(
at
-
pos
).
unit
();
Vec3
S
=
cross
(
F
,
up
).
unit
();
Vec3
S
=
cross
(
F
,
up
).
unit
();
Vec3
U
=
cross
(
S
,
F
).
unit
();
Vec3
U
=
cross
(
S
,
F
).
unit
();
r
[
0
][
0
]
=
S
.
x
;
r
[
0
][
0
]
=
S
.
x
;
r
[
0
][
1
]
=
U
.
x
;
r
[
0
][
1
]
=
U
.
x
;
r
[
0
][
2
]
=
-
F
.
x
;
r
[
0
][
2
]
=
-
F
.
x
;
r
[
1
][
0
]
=
S
.
y
;
r
[
1
][
0
]
=
S
.
y
;
r
[
1
][
1
]
=
U
.
y
;
r
[
1
][
1
]
=
U
.
y
;
r
[
1
][
2
]
=
-
F
.
y
;
r
[
1
][
2
]
=
-
F
.
y
;
r
[
2
][
0
]
=
S
.
z
;
r
[
2
][
0
]
=
S
.
z
;
r
[
2
][
1
]
=
U
.
z
;
r
[
2
][
1
]
=
U
.
z
;
r
[
2
][
2
]
=
-
F
.
z
;
r
[
2
][
2
]
=
-
F
.
z
;
r
[
3
][
0
]
=
-
dot
(
S
,
pos
);
r
[
3
][
0
]
=
-
dot
(
S
,
pos
);
r
[
3
][
1
]
=
-
dot
(
U
,
pos
);
r
[
3
][
1
]
=
-
dot
(
U
,
pos
);
r
[
3
][
2
]
=
dot
(
F
,
pos
);
r
[
3
][
2
]
=
dot
(
F
,
pos
);
r
[
3
][
3
]
=
1
.
0
f
;
r
[
3
][
3
]
=
1
.
0
f
;
return
r
;
return
r
;
}
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Mat4
m
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Mat4
m
)
{
out
<<
"{"
<<
m
[
0
]
<<
","
<<
m
[
1
]
<<
","
<<
m
[
2
]
<<
","
<<
m
[
3
]
<<
"}"
;
out
<<
"{"
<<
m
[
0
]
<<
","
<<
m
[
1
]
<<
","
<<
m
[
2
]
<<
","
<<
m
[
3
]
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/mathlib.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
template
<
class
...
Ts
>
struct
overloaded
:
Ts
...
{
using
Ts
::
operator
()...;
};
template
<
class
...
Ts
>
struct
overloaded
:
Ts
...
{
using
Ts
::
operator
()...;
};
template
<
class
...
Ts
>
overloaded
(
Ts
...)
->
overloaded
<
Ts
...
>
;
template
<
class
...
Ts
>
overloaded
(
Ts
...)
->
overloaded
<
Ts
...
>
;
#include "line.h"
#include "plane.h"
#include "vec2.h"
#include "vec2.h"
#include "vec3.h"
#include "vec3.h"
#include "vec4.h"
#include "vec4.h"
#include "line.h"
#include "plane.h"
#define EPS_F 0.00001f
#define EPS_F 0.00001f
#define PI_F 3.14159265358979323846264338327950288f
#define PI_F 3.14159265358979323846264338327950288f
#define Radians(v) ((v) * (PI_F / 180.0f))
#define Radians(v) ((v) * (PI_F / 180.0f))
#define Degrees(v) ((v) * (180.0f / PI_F))
#define Degrees(v) ((v) * (180.0f / PI_F))
template
<
typename
T
>
template
<
typename
T
>
inline
T
clamp
(
T
x
,
T
min
,
T
max
)
{
return
std
::
min
(
std
::
max
(
x
,
min
),
max
);
}
inline
T
clamp
(
T
x
,
T
min
,
T
max
)
{
template
<
>
inline
Vec2
clamp
(
Vec2
v
,
Vec2
min
,
Vec2
max
)
{
return
std
::
min
(
std
::
max
(
x
,
min
),
max
);
return
Vec2
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
));
}
template
<
>
inline
Vec2
clamp
(
Vec2
v
,
Vec2
min
,
Vec2
max
)
{
return
Vec2
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
));
}
template
<
>
inline
Vec3
clamp
(
Vec3
v
,
Vec3
min
,
Vec3
max
)
{
return
Vec3
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
),
clamp
(
v
.
z
,
min
.
z
,
max
.
z
));
}
}
template
<
>
template
<
>
inline
Vec3
clamp
(
Vec3
v
,
Vec3
min
,
Vec3
max
)
{
inline
Vec4
clamp
(
Vec4
v
,
Vec4
min
,
Vec4
max
)
{
return
Vec3
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
),
clamp
(
v
.
z
,
min
.
z
,
max
.
z
));
return
Vec4
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
),
clamp
(
v
.
z
,
min
.
z
,
max
.
z
),
clamp
(
v
.
w
,
min
.
w
,
max
.
w
));
}
}
template
<
typename
T
>
template
<
>
inline
Vec4
clamp
(
Vec4
v
,
Vec4
min
,
Vec4
max
)
{
T
lerp
(
T
start
,
T
end
,
float
t
)
{
return
Vec4
(
clamp
(
v
.
x
,
min
.
x
,
max
.
x
),
clamp
(
v
.
y
,
min
.
y
,
max
.
y
),
clamp
(
v
.
z
,
min
.
z
,
max
.
z
),
return
start
+
(
end
-
start
)
*
t
;
clamp
(
v
.
w
,
min
.
w
,
max
.
w
));
}
inline
float
sign
(
float
x
)
{
return
x
>
0.0
f
?
1.0
f
:
x
<
0.0
f
?
-
1.0
f
:
0.0
f
;
}
inline
float
frac
(
float
x
)
{
return
x
-
(
long
long
)
x
;
}
}
template
<
typename
T
>
T
lerp
(
T
start
,
T
end
,
float
t
)
{
return
start
+
(
end
-
start
)
*
t
;
}
inline
float
sign
(
float
x
)
{
return
x
>
0.0
f
?
1.0
f
:
x
<
0.0
f
?
-
1.0
f
:
0.0
f
;
}
inline
float
frac
(
float
x
)
{
return
x
-
(
long
long
)
x
;
}
inline
float
smoothstep
(
float
e0
,
float
e1
,
float
x
)
{
inline
float
smoothstep
(
float
e0
,
float
e1
,
float
x
)
{
float
t
=
clamp
((
x
-
e0
)
/
(
e1
-
e0
),
0.0
f
,
1.0
f
);
float
t
=
clamp
((
x
-
e0
)
/
(
e1
-
e0
),
0.0
f
,
1.0
f
);
return
t
*
t
*
(
3.0
f
-
2.0
f
*
t
);
return
t
*
t
*
(
3.0
f
-
2.0
f
*
t
);
}
}
#include "bbox.h"
#include "bbox.h"
#include "mat4.h"
#include "mat4.h"
#include "quat.h"
#include "quat.h"
#include "ray.h"
#include "ray.h"
src/lib/plane.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "line.h"
#include "line.h"
...
@@ -10,11 +10,10 @@
...
@@ -10,11 +10,10 @@
struct
Plane
{
struct
Plane
{
Plane
()
=
default
;
Plane
()
=
default
;
/// Create plane from (a,b,c,d)
/// Create plane from (a,b,c,d)
explicit
Plane
(
Vec4
p
)
:
explicit
Plane
(
Vec4
p
)
:
p
(
p
)
{}
p
(
p
)
{
}
/// Create plane from point and unit normal
/// Create plane from point and unit normal
explicit
Plane
(
Vec3
point
,
Vec3
n
)
{
explicit
Plane
(
Vec3
point
,
Vec3
n
)
{
p
.
x
=
n
.
x
;
p
.
x
=
n
.
x
;
...
@@ -22,17 +21,14 @@ struct Plane {
...
@@ -22,17 +21,14 @@ struct Plane {
p
.
z
=
n
.
z
;
p
.
z
=
n
.
z
;
p
.
w
=
dot
(
point
,
n
.
unit
());
p
.
w
=
dot
(
point
,
n
.
unit
());
}
}
Plane
(
const
Plane
&
src
)
=
default
;
~
Plane
()
=
default
;
Plane
operator
=
(
Plane
v
)
{
Plane
(
const
Plane
&
)
=
default
;
p
=
v
.
p
;
Plane
&
operator
=
(
const
Plane
&
)
=
default
;
return
*
this
;
~
Plane
()
=
default
;
}
/// Calculate intersection point between plane and line.
/// Calculate intersection point between plane and line.
/// Returns false if the hit point is 'backward' along the line relative to pt.dir
/// Returns false if the hit point is 'backward' along the line relative to pt.dir
bool
hit
(
Line
line
,
Vec3
&
pt
)
const
{
bool
hit
(
Line
line
,
Vec3
&
pt
)
const
{
Vec3
n
=
p
.
xyz
();
Vec3
n
=
p
.
xyz
();
float
t
=
(
p
.
w
-
dot
(
line
.
point
,
n
))
/
dot
(
line
.
dir
,
n
);
float
t
=
(
p
.
w
-
dot
(
line
.
point
,
n
))
/
dot
(
line
.
dir
,
n
);
pt
=
line
.
at
(
t
);
pt
=
line
.
at
(
t
);
...
@@ -42,7 +38,7 @@ struct Plane {
...
@@ -42,7 +38,7 @@ struct Plane {
Vec4
p
;
Vec4
p
;
};
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Plane
v
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Plane
v
)
{
out
<<
"Plane"
<<
v
.
p
;
out
<<
"Plane"
<<
v
.
p
;
return
out
;
return
out
;
}
}
src/lib/quat.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include "log.h"
#include "log.h"
#include "mat4.h"
#include "vec3.h"
#include "vec3.h"
#include "vec4.h"
#include "vec4.h"
#include "mat4.h"
struct
Quat
{
struct
Quat
{
Quat
()
{
Quat
()
{
x
=
0
.
0
f
;
x
=
0
.
0
f
;
y
=
0
.
0
f
;
y
=
0
.
0
f
;
z
=
0
.
0
f
;
z
=
0
.
0
f
;
w
=
1
.
0
f
;
w
=
1
.
0
f
;
}
}
explicit
Quat
(
float
_x
,
float
_y
,
float
_z
,
float
_w
)
{
explicit
Quat
(
float
_x
,
float
_y
,
float
_z
,
float
_w
)
{
x
=
_x
;
x
=
_x
;
y
=
_y
;
y
=
_y
;
z
=
_z
;
z
=
_z
;
w
=
_w
;
w
=
_w
;
}
}
explicit
Quat
(
Vec3
complex
,
float
real
)
{
explicit
Quat
(
Vec3
complex
,
float
real
)
{
x
=
complex
.
x
;
x
=
complex
.
x
;
y
=
complex
.
y
;
y
=
complex
.
y
;
z
=
complex
.
z
;
z
=
complex
.
z
;
w
=
real
;
w
=
real
;
}
}
explicit
Quat
(
const
Vec4
&
src
)
{
explicit
Quat
(
const
Vec4
&
src
)
{
x
=
src
.
x
;
x
=
src
.
x
;
y
=
src
.
y
;
y
=
src
.
y
;
z
=
src
.
z
;
z
=
src
.
z
;
w
=
src
.
w
;
w
=
src
.
w
;
}
}
Quat
(
const
Quat
&
src
)
{
x
=
src
.
x
;
Quat
(
const
Quat
&
)
=
default
;
y
=
src
.
y
;
Quat
&
operator
=
(
const
Quat
&
)
=
default
;
z
=
src
.
z
;
~
Quat
()
=
default
;
w
=
src
.
w
;
}
/// Create unit quaternion representing given axis-angle rotation
~
Quat
()
=
default
;
static
Quat
axis_angle
(
Vec3
axis
,
float
angle
)
{
axis
.
normalize
();
/// Create unit quaternion representing given axis-angle rotation
angle
=
Radians
(
angle
)
/
2
.
0
f
;
static
Quat
axis_angle
(
Vec3
axis
,
float
angle
)
{
float
sin
=
std
::
sin
(
angle
);
axis
.
normalize
();
float
x
=
sin
*
axis
.
x
;
angle
=
Radians
(
angle
)
/
2
.
0
f
;
float
y
=
sin
*
axis
.
y
;
float
sin
=
std
::
sin
(
angle
);
float
z
=
sin
*
axis
.
z
;
float
x
=
sin
*
axis
.
x
;
float
w
=
std
::
cos
(
angle
);
float
y
=
sin
*
axis
.
y
;
return
Quat
(
x
,
y
,
z
,
w
).
unit
();
float
z
=
sin
*
axis
.
z
;
}
float
w
=
std
::
cos
(
angle
);
return
Quat
(
x
,
y
,
z
,
w
).
unit
();
/// Create unit quaternion representing given euler angles (XYZ)
}
static
Quat
euler
(
Vec3
angles
)
{
if
(
angles
==
Vec3
{
0
.
0
f
,
0
.
0
f
,
180
.
0
f
}
||
angles
==
Vec3
{
180
.
0
f
,
0
.
0
f
,
0
.
0
f
})
/// Create unit quaternion representing given euler angles (XYZ)
return
Quat
{
0
.
0
f
,
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
};
static
Quat
euler
(
Vec3
angles
)
{
float
c1
=
std
::
cos
(
Radians
(
angles
[
2
]
*
0
.
5
f
));
if
(
angles
==
Vec3
{
0
.
0
f
,
0
.
0
f
,
180
.
0
f
}
||
angles
==
Vec3
{
180
.
0
f
,
0
.
0
f
,
0
.
0
f
})
float
c2
=
std
::
cos
(
Radians
(
angles
[
1
]
*
0
.
5
f
));
return
Quat
{
0
.
0
f
,
0
.
0
f
,
-
1
.
0
f
,
0
.
0
f
};
float
c3
=
std
::
cos
(
Radians
(
angles
[
0
]
*
0
.
5
f
));
float
c1
=
std
::
cos
(
Radians
(
angles
[
2
]
*
0
.
5
f
));
float
s1
=
std
::
sin
(
Radians
(
angles
[
2
]
*
0
.
5
f
));
float
c2
=
std
::
cos
(
Radians
(
angles
[
1
]
*
0
.
5
f
));
float
s2
=
std
::
sin
(
Radians
(
angles
[
1
]
*
0
.
5
f
));
float
c3
=
std
::
cos
(
Radians
(
angles
[
0
]
*
0
.
5
f
));
float
s3
=
std
::
sin
(
Radians
(
angles
[
0
]
*
0
.
5
f
));
float
s1
=
std
::
sin
(
Radians
(
angles
[
2
]
*
0
.
5
f
));
float
x
=
c1
*
c2
*
s3
-
s1
*
s2
*
c3
;
float
s2
=
std
::
sin
(
Radians
(
angles
[
1
]
*
0
.
5
f
));
float
y
=
c1
*
s2
*
c3
+
s1
*
c2
*
s3
;
float
s3
=
std
::
sin
(
Radians
(
angles
[
0
]
*
0
.
5
f
));
float
z
=
s1
*
c2
*
c3
-
c1
*
s2
*
s3
;
float
x
=
c1
*
c2
*
s3
-
s1
*
s2
*
c3
;
float
w
=
c1
*
c2
*
c3
+
s1
*
s2
*
s3
;
float
y
=
c1
*
s2
*
c3
+
s1
*
c2
*
s3
;
return
Quat
(
x
,
y
,
z
,
w
);
float
z
=
s1
*
c2
*
c3
-
c1
*
s2
*
s3
;
}
float
w
=
c1
*
c2
*
c3
+
s1
*
s2
*
s3
;
return
Quat
(
x
,
y
,
z
,
w
);
float
&
operator
[](
int
idx
)
{
}
assert
(
idx
>=
0
&&
idx
<=
3
);
return
data
[
idx
];
Quat
operator
=
(
const
Quat
&
v
)
{
}
x
=
v
.
x
;
float
operator
[](
int
idx
)
const
{
y
=
v
.
y
;
assert
(
idx
>=
0
&&
idx
<=
3
);
z
=
v
.
z
;
return
data
[
idx
];
w
=
v
.
w
;
}
return
*
this
;
}
Quat
conjugate
()
const
{
return
Quat
(
-
x
,
-
y
,
-
z
,
w
);
}
Quat
inverse
()
const
{
return
conjugate
().
unit
();
}
float
&
operator
[](
int
idx
)
{
Vec3
complex
()
const
{
return
Vec3
(
x
,
y
,
z
);
}
assert
(
idx
>=
0
&&
idx
<=
3
);
float
real
()
const
{
return
w
;
}
return
data
[
idx
];
}
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
+
z
*
z
+
w
*
w
;
}
float
operator
[](
int
idx
)
const
{
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
assert
(
idx
>=
0
&&
idx
<=
3
);
Quat
unit
()
const
{
return
data
[
idx
];
float
n
=
norm
();
}
return
Quat
(
x
/
n
,
y
/
n
,
z
/
n
,
w
/
n
);
}
Quat
conjugate
()
const
{
return
Quat
(
-
x
,
-
y
,
-
z
,
w
);
Quat
operator
*
(
const
Quat
&
r
)
const
{
}
return
Quat
(
y
*
r
.
z
-
z
*
r
.
y
+
x
*
r
.
w
+
w
*
r
.
x
,
z
*
r
.
x
-
x
*
r
.
z
+
y
*
r
.
w
+
w
*
r
.
y
,
Quat
inverse
()
const
{
x
*
r
.
y
-
y
*
r
.
x
+
z
*
r
.
w
+
w
*
r
.
z
,
w
*
r
.
w
-
x
*
r
.
x
-
y
*
r
.
y
-
z
*
r
.
z
);
return
conjugate
().
unit
();
}
}
Vec3
complex
()
const
{
Quat
operator
+
(
const
Quat
&
r
)
const
{
return
Quat
(
x
+
r
.
x
,
y
+
r
.
y
,
z
+
r
.
z
,
w
+
r
.
w
);
}
return
Vec3
(
x
,
y
,
z
);
Quat
operator
-
(
const
Quat
&
r
)
const
{
return
Quat
(
x
-
r
.
x
,
y
-
r
.
y
,
z
-
r
.
z
,
w
-
r
.
w
);
}
}
float
real
()
const
{
void
scale
(
float
f
)
{
return
w
;
x
*=
f
;
}
y
*=
f
;
z
*=
f
;
float
norm_squared
()
const
{
w
*=
f
;
return
x
*
x
+
y
*
y
+
z
*
z
+
w
*
w
;
}
}
void
make_log
()
{
float
norm
()
const
{
float
a0
=
w
;
return
std
::
sqrt
(
norm_squared
());
w
=
0
.
0
f
;
}
if
(
std
::
abs
(
a0
)
<
1
.
0
f
)
{
Quat
unit
()
const
{
float
angle
=
std
::
acos
(
a0
);
float
n
=
norm
();
float
sin_angle
=
std
::
sin
(
angle
);
return
Quat
(
x
/
n
,
y
/
n
,
z
/
n
,
w
/
n
);
if
(
std
::
abs
(
sin_angle
)
>
EPS_F
)
{
}
float
coeff
=
angle
/
sin_angle
;
x
*=
coeff
;
Quat
operator
*
(
const
Quat
&
r
)
const
{
y
*=
coeff
;
return
Quat
(
y
*
r
.
z
-
z
*
r
.
y
+
x
*
r
.
w
+
w
*
r
.
x
,
z
*=
coeff
;
z
*
r
.
x
-
x
*
r
.
z
+
y
*
r
.
w
+
w
*
r
.
y
,
}
x
*
r
.
y
-
y
*
r
.
x
+
z
*
r
.
w
+
w
*
r
.
z
,
}
w
*
r
.
w
-
x
*
r
.
x
-
y
*
r
.
y
-
z
*
r
.
z
);
}
}
void
make_exp
()
{
float
angle
=
std
::
sqrt
(
x
*
x
+
y
*
y
+
z
*
z
);
Quat
operator
+
(
const
Quat
&
r
)
const
{
float
sin_angle
=
std
::
sin
(
angle
);
return
Quat
(
x
+
r
.
x
,
y
+
r
.
y
,
z
+
r
.
z
,
w
+
r
.
w
);
w
=
std
::
cos
(
angle
);
}
if
(
sin_angle
>
EPS_F
)
{
Quat
operator
-
(
const
Quat
&
r
)
const
{
float
coeff
=
sin_angle
/
angle
;
return
Quat
(
x
-
r
.
x
,
y
-
r
.
y
,
z
-
r
.
z
,
w
-
r
.
w
);
x
*=
coeff
;
}
y
*=
coeff
;
z
*=
coeff
;
void
scale
(
float
f
)
{
}
x
*=
f
;
}
y
*=
f
;
z
*=
f
;
/// Convert quaternion to equivalent euler angle rotation (XYZ)
w
*=
f
;
Vec3
to_euler
()
const
{
return
unit
().
to_mat
().
to_euler
();
}
}
void
make_log
()
{
/// Convert quaternion to equivalent rotation matrix (orthonormal, 3x3)
float
a0
=
w
;
Mat4
to_mat
()
const
{
w
=
0
.
0
f
;
return
Mat4
{
if
(
std
::
abs
(
a0
)
<
1
.
0
f
)
{
Vec4
{
1
-
2
*
y
*
y
-
2
*
z
*
z
,
2
*
x
*
y
+
2
*
z
*
w
,
2
*
x
*
z
-
2
*
y
*
w
,
0
.
0
f
},
float
angle
=
std
::
acos
(
a0
);
Vec4
{
2
*
x
*
y
-
2
*
z
*
w
,
1
-
2
*
x
*
x
-
2
*
z
*
z
,
2
*
y
*
z
+
2
*
x
*
w
,
0
.
0
f
},
float
sin_angle
=
std
::
sin
(
angle
);
Vec4
{
2
*
x
*
z
+
2
*
y
*
w
,
2
*
y
*
z
-
2
*
x
*
w
,
1
-
2
*
x
*
x
-
2
*
y
*
y
,
0
.
0
f
},
if
(
std
::
abs
(
sin_angle
)
>
EPS_F
)
{
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}};
float
coeff
=
angle
/
sin_angle
;
}
x
*=
coeff
;
y
*=
coeff
;
/// Apply rotation to given vector
z
*=
coeff
;
Vec3
rotate
(
Vec3
v
)
const
{
return
(((
*
this
)
*
Quat
(
v
,
0
))
*
conjugate
()).
complex
();
}
}
}
/// Spherical linear interpolation between this and another quaternion weighted by t.
}
Quat
slerp
(
Quat
q
,
float
t
)
{
void
make_exp
()
{
float
omega
=
std
::
acos
(
clamp
(
x
*
q
.
x
+
y
*
q
.
y
+
z
*
q
.
z
+
w
*
q
.
w
,
-
1
.
0
f
,
1
.
0
f
));
float
angle
=
std
::
sqrt
(
x
*
x
+
y
*
y
+
z
*
z
);
float
sin_angle
=
std
::
sin
(
angle
);
if
(
std
::
abs
(
omega
)
<
16
.
0
f
*
FLT_EPSILON
)
{
w
=
std
::
cos
(
angle
);
omega
=
16
.
0
f
*
FLT_EPSILON
;
if
(
sin_angle
>
EPS_F
)
{
}
float
coeff
=
sin_angle
/
angle
;
float
som
=
std
::
sin
(
omega
);
x
*=
coeff
;
float
st0
=
std
::
sin
((
1
-
t
)
*
omega
)
/
som
;
y
*=
coeff
;
float
st1
=
std
::
sin
(
t
*
omega
)
/
som
;
z
*=
coeff
;
}
return
Quat
(
x
*
st0
+
q
.
x
*
st1
,
y
*
st0
+
q
.
y
*
st1
,
z
*
st0
+
q
.
z
*
st1
,
}
w
*
st0
+
q
.
w
*
st1
);
}
/// Convert quaternion to equivalent euler angle rotation (XYZ)
Vec3
to_euler
()
const
{
/// Are all members real numbers?
return
unit
().
to_mat
().
to_euler
();
bool
valid
()
const
{
}
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
std
::
isinf
(
w
));
}
/// Convert quaternion to equivalent rotation matrix (orthonormal, 3x3)
Mat4
to_mat
()
const
{
union
{
return
Mat4
{
struct
{
Vec4
{
1
-
2
*
y
*
y
-
2
*
z
*
z
,
2
*
x
*
y
+
2
*
z
*
w
,
2
*
x
*
z
-
2
*
y
*
w
,
0
.
0
f
},
float
x
;
Vec4
{
2
*
x
*
y
-
2
*
z
*
w
,
1
-
2
*
x
*
x
-
2
*
z
*
z
,
2
*
y
*
z
+
2
*
x
*
w
,
0
.
0
f
},
float
y
;
Vec4
{
2
*
x
*
z
+
2
*
y
*
w
,
2
*
y
*
z
-
2
*
x
*
w
,
1
-
2
*
x
*
x
-
2
*
y
*
y
,
0
.
0
f
},
float
z
;
Vec4
{
0
.
0
f
,
0
.
0
f
,
0
.
0
f
,
1
.
0
f
}
float
w
;
};
};
}
float
data
[
4
]
=
{};
};
/// Apply rotation to given vector
Vec3
rotate
(
Vec3
v
)
const
{
return
(((
*
this
)
*
Quat
(
v
,
0
))
*
conjugate
()).
complex
();
}
/// Spherical linear interpolation between this and another quaternion weighted by t.
Quat
slerp
(
Quat
q
,
float
t
)
{
float
omega
=
std
::
acos
(
clamp
(
x
*
q
.
x
+
y
*
q
.
y
+
z
*
q
.
z
+
w
*
q
.
w
,
-
1
.
0
f
,
1
.
0
f
));
if
(
std
::
abs
(
omega
)
<
16
.
0
f
*
FLT_EPSILON
)
{
omega
=
16
.
0
f
*
FLT_EPSILON
;
}
float
som
=
std
::
sin
(
omega
);
float
st0
=
std
::
sin
((
1
-
t
)
*
omega
)
/
som
;
float
st1
=
std
::
sin
(
t
*
omega
)
/
som
;
return
Quat
(
x
*
st0
+
q
.
x
*
st1
,
y
*
st0
+
q
.
y
*
st1
,
z
*
st0
+
q
.
z
*
st1
,
w
*
st0
+
q
.
w
*
st1
);
}
/// Are all members real numbers?
bool
valid
()
const
{
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
std
::
isinf
(
w
));
}
union
{
struct
{
float
x
;
float
y
;
float
z
;
float
w
;
};
float
data
[
4
]
=
{};
};
};
};
inline
Quat
slerp
(
Quat
q0
,
Quat
q1
,
float
t
)
{
inline
Quat
slerp
(
Quat
q0
,
Quat
q1
,
float
t
)
{
return
q0
.
slerp
(
q1
,
t
);
}
return
q0
.
slerp
(
q1
,
t
);
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Quat
q
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Quat
q
)
{
out
<<
"Quat{"
<<
q
.
x
<<
","
<<
q
.
y
<<
","
<<
q
.
z
<<
","
<<
q
.
w
<<
"}"
;
out
<<
"Quat{"
<<
q
.
x
<<
","
<<
q
.
y
<<
","
<<
q
.
z
<<
","
<<
q
.
w
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/ray.h
View file @
c2535f0f
...
@@ -2,50 +2,43 @@
...
@@ -2,50 +2,43 @@
#pragma once
#pragma once
#include <cmath>
#include <cmath>
#include <ostream>
#include <limits>
#include <limits>
#include <ostream>
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
struct
Ray
{
struct
Ray
{
Ray
()
:
time_bounds
(
0
.
0
f
,
std
::
numeric_limits
<
float
>::
max
())
{}
Ray
()
:
time_bounds
(
0
.
0
f
,
std
::
numeric_limits
<
float
>::
max
())
{}
/// Create Ray from point and direction
explicit
Ray
(
Vec3
point
,
Vec3
dir
)
:
/// Create Ray from point and direction
point
(
point
),
explicit
Ray
(
Vec3
point
,
Vec3
dir
)
dir
(
dir
.
unit
()),
:
point
(
point
),
dir
(
dir
.
unit
()),
time_bounds
(
0
.
0
f
,
std
::
numeric_limits
<
float
>::
max
())
{}
time_bounds
(
0
.
0
f
,
std
::
numeric_limits
<
float
>::
max
())
{
}
Ray
(
const
Ray
&
)
=
default
;
Ray
(
const
Ray
&
src
)
=
default
;
Ray
&
operator
=
(
const
Ray
&
)
=
default
;
~
Ray
()
=
default
;
Ray
operator
=
(
Ray
v
)
{
point
=
v
.
point
;
/// Get point on Ray at time t
dir
=
v
.
dir
;
Vec3
at
(
float
t
)
const
{
return
point
+
t
*
dir
;
}
return
*
this
;
}
/// Move ray into the space defined by this tranform matrix
void
transform
(
const
Mat4
&
trans
)
{
/// Get point on Ray at time t
point
=
trans
*
point
;
Vec3
at
(
float
t
)
const
{
dir
=
trans
.
rotate
(
dir
);
return
point
+
t
*
dir
;
}
}
/// Move ray into the space defined by this tranform matrix
void
transform
(
const
Mat4
&
trans
)
{
point
=
trans
*
point
;
dir
=
trans
.
rotate
(
dir
);
}
/// The origin or starting point of this ray
/// The origin or starting point of this ray
Vec3
point
;
Vec3
point
;
/// The unit direction the ray travels in
/// The unit direction the ray travels in
Vec3
dir
;
Vec3
dir
;
/// The minimum and maximum time/distance at which this ray should exist
/// The minimum and maximum time/distance at which this ray should exist
Vec2
time_bounds
;
Vec2
time_bounds
;
/// Recursive depth of ray
/// Recursive depth of ray
size_t
depth
=
0
;
size_t
depth
=
0
;
};
};
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Ray
r
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Ray
r
)
{
out
<<
"Ray{"
<<
r
.
point
<<
","
<<
r
.
dir
<<
"}"
;
out
<<
"Ray{"
<<
r
.
point
<<
","
<<
r
.
dir
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/spectrum.h
View file @
c2535f0f
...
@@ -9,127 +9,93 @@
...
@@ -9,127 +9,93 @@
struct
Spectrum
{
struct
Spectrum
{
Spectrum
()
{
Spectrum
()
{
r
=
0
.
0
f
;
r
=
0
.
0
f
;
g
=
0
.
0
f
;
g
=
0
.
0
f
;
b
=
0
.
0
f
;
b
=
0
.
0
f
;
}
}
explicit
Spectrum
(
float
_r
,
float
_g
,
float
_b
)
{
explicit
Spectrum
(
float
_r
,
float
_g
,
float
_b
)
{
r
=
_r
;
r
=
_r
;
g
=
_g
;
g
=
_g
;
b
=
_b
;
b
=
_b
;
}
}
explicit
Spectrum
(
float
f
)
{
explicit
Spectrum
(
float
f
)
{
r
=
g
=
b
=
f
;
}
r
=
g
=
b
=
f
;
}
Spectrum
(
const
Spectrum
&
)
=
default
;
Spectrum
(
const
Spectrum
&
src
)
{
Spectrum
&
operator
=
(
const
Spectrum
&
)
=
default
;
r
=
src
.
r
;
~
Spectrum
()
=
default
;
g
=
src
.
g
;
b
=
src
.
b
;
Spectrum
operator
+=
(
Spectrum
v
)
{
}
r
+=
v
.
r
;
~
Spectrum
()
=
default
;
g
+=
v
.
g
;
b
+=
v
.
b
;
Spectrum
operator
=
(
Spectrum
v
)
{
return
*
this
;
r
=
v
.
r
;
}
g
=
v
.
g
;
Spectrum
operator
*=
(
Spectrum
v
)
{
b
=
v
.
b
;
r
*=
v
.
r
;
return
*
this
;
g
*=
v
.
g
;
}
b
*=
v
.
b
;
Spectrum
operator
+=
(
Spectrum
v
)
{
return
*
this
;
r
+=
v
.
r
;
}
g
+=
v
.
g
;
Spectrum
operator
*=
(
float
s
)
{
b
+=
v
.
b
;
r
*=
s
;
return
*
this
;
g
*=
s
;
}
b
*=
s
;
Spectrum
operator
*=
(
Spectrum
v
)
{
return
*
this
;
r
*=
v
.
r
;
}
g
*=
v
.
g
;
b
*=
v
.
b
;
static
Spectrum
direction
(
Vec3
v
)
{
return
*
this
;
v
.
normalize
();
}
Spectrum
s
(
std
::
abs
(
v
.
x
),
std
::
abs
(
v
.
y
),
std
::
abs
(
v
.
z
));
Spectrum
operator
*=
(
float
s
)
{
s
.
make_linear
();
r
*=
s
;
return
s
;
g
*=
s
;
}
b
*=
s
;
return
*
this
;
void
make_srgb
()
{
}
r
=
std
::
pow
(
r
,
1
.
0
f
/
GAMMA
);
g
=
std
::
pow
(
g
,
1
.
0
f
/
GAMMA
);
static
Spectrum
direction
(
Vec3
v
)
{
b
=
std
::
pow
(
b
,
1
.
0
f
/
GAMMA
);
v
.
normalize
();
}
Spectrum
s
(
std
::
abs
(
v
.
x
),
std
::
abs
(
v
.
y
),
std
::
abs
(
v
.
z
));
void
make_linear
()
{
s
.
make_linear
();
r
=
std
::
pow
(
r
,
GAMMA
);
return
s
;
g
=
std
::
pow
(
g
,
GAMMA
);
}
b
=
std
::
pow
(
b
,
GAMMA
);
}
void
make_srgb
()
{
r
=
std
::
pow
(
r
,
1
.
0
f
/
GAMMA
);
Spectrum
operator
+
(
Spectrum
v
)
const
{
return
Spectrum
(
r
+
v
.
r
,
g
+
v
.
g
,
b
+
v
.
b
);
}
g
=
std
::
pow
(
g
,
1
.
0
f
/
GAMMA
);
Spectrum
operator
-
(
Spectrum
v
)
const
{
return
Spectrum
(
r
-
v
.
r
,
g
-
v
.
g
,
b
-
v
.
b
);
}
b
=
std
::
pow
(
b
,
1
.
0
f
/
GAMMA
);
Spectrum
operator
*
(
Spectrum
v
)
const
{
return
Spectrum
(
r
*
v
.
r
,
g
*
v
.
g
,
b
*
v
.
b
);
}
}
void
make_linear
()
{
Spectrum
operator
+
(
float
s
)
const
{
return
Spectrum
(
r
+
s
,
g
+
s
,
b
+
s
);
}
r
=
std
::
pow
(
r
,
GAMMA
);
Spectrum
operator
*
(
float
s
)
const
{
return
Spectrum
(
r
*
s
,
g
*
s
,
b
*
s
);
}
g
=
std
::
pow
(
g
,
GAMMA
);
Spectrum
operator
/
(
float
s
)
const
{
return
Spectrum
(
r
/
s
,
g
/
s
,
b
/
s
);
}
b
=
std
::
pow
(
b
,
GAMMA
);
}
bool
operator
==
(
Spectrum
v
)
const
{
return
r
==
v
.
r
&&
g
==
v
.
g
&&
b
==
v
.
b
;
}
bool
operator
!=
(
Spectrum
v
)
const
{
return
r
!=
v
.
r
||
g
!=
v
.
g
||
b
!=
v
.
b
;
}
Spectrum
operator
+
(
Spectrum
v
)
const
{
return
Spectrum
(
r
+
v
.
r
,
g
+
v
.
g
,
b
+
v
.
b
);
float
luma
()
const
{
return
0
.
2126
f
*
r
+
0
.
7152
f
*
g
+
0
.
0722
f
*
b
;
}
}
Spectrum
operator
-
(
Spectrum
v
)
const
{
bool
valid
()
const
{
return
Spectrum
(
r
-
v
.
r
,
g
-
v
.
g
,
b
-
v
.
b
);
return
!
(
std
::
isinf
(
r
)
||
std
::
isinf
(
g
)
||
std
::
isinf
(
b
)
||
std
::
isnan
(
r
)
||
}
std
::
isnan
(
g
)
||
std
::
isnan
(
b
));
Spectrum
operator
*
(
Spectrum
v
)
const
{
}
return
Spectrum
(
r
*
v
.
r
,
g
*
v
.
g
,
b
*
v
.
b
);
}
Vec3
to_vec
()
const
{
return
Vec3
(
r
,
g
,
b
);
}
Spectrum
operator
+
(
float
s
)
const
{
union
{
return
Spectrum
(
r
+
s
,
g
+
s
,
b
+
s
);
struct
{
}
float
r
;
Spectrum
operator
*
(
float
s
)
const
{
float
g
;
return
Spectrum
(
r
*
s
,
g
*
s
,
b
*
s
);
float
b
;
}
};
Spectrum
operator
/
(
float
s
)
const
{
float
data
[
3
]
=
{};
return
Spectrum
(
r
/
s
,
g
/
s
,
b
/
s
);
};
}
bool
operator
==
(
Spectrum
v
)
const
{
return
r
==
v
.
r
&&
g
==
v
.
g
&&
b
==
v
.
b
;
}
bool
operator
!=
(
Spectrum
v
)
const
{
return
r
!=
v
.
r
||
g
!=
v
.
g
||
b
!=
v
.
b
;
}
float
luma
()
const
{
return
0
.
2126
f
*
r
+
0
.
7152
f
*
g
+
0
.
0722
f
*
b
;
}
bool
valid
()
const
{
return
!
(
std
::
isinf
(
r
)
||
std
::
isinf
(
g
)
||
std
::
isinf
(
b
)
||
std
::
isnan
(
r
)
||
std
::
isnan
(
g
)
||
std
::
isnan
(
b
));
}
Vec3
to_vec
()
const
{
return
Vec3
(
r
,
g
,
b
);
}
union
{
struct
{
float
r
;
float
g
;
float
b
;
};
float
data
[
3
]
=
{};
};
};
};
inline
Spectrum
operator
+
(
float
s
,
Spectrum
v
)
{
inline
Spectrum
operator
+
(
float
s
,
Spectrum
v
)
{
return
Spectrum
(
v
.
r
+
s
,
v
.
g
+
s
,
v
.
b
+
s
);
}
return
Spectrum
(
v
.
r
+
s
,
v
.
g
+
s
,
v
.
b
+
s
);
inline
Spectrum
operator
*
(
float
s
,
Spectrum
v
)
{
return
Spectrum
(
v
.
r
*
s
,
v
.
g
*
s
,
v
.
b
*
s
);
}
}
inline
Spectrum
operator
*
(
float
s
,
Spectrum
v
)
{
return
Spectrum
(
v
.
r
*
s
,
v
.
g
*
s
,
v
.
b
*
s
);
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Spectrum
v
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Spectrum
v
)
{
out
<<
"Spectrum{"
<<
v
.
r
<<
","
<<
v
.
g
<<
","
<<
v
.
b
<<
"}"
;
out
<<
"Spectrum{"
<<
v
.
r
<<
","
<<
v
.
g
<<
","
<<
v
.
b
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/vec2.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "log.h"
#include "log.h"
struct
Vec2
{
struct
Vec2
{
Vec2
()
{
Vec2
()
{
x
=
0
.
0
f
;
x
=
0
.
0
f
;
y
=
0
.
0
f
;
y
=
0
.
0
f
;
}
}
explicit
Vec2
(
float
_x
,
float
_y
)
{
explicit
Vec2
(
float
_x
,
float
_y
)
{
x
=
_x
;
x
=
_x
;
y
=
_y
;
y
=
_y
;
}
}
explicit
Vec2
(
float
f
)
{
explicit
Vec2
(
float
f
)
{
x
=
y
=
f
;
}
x
=
y
=
f
;
explicit
Vec2
(
int
_x
,
int
_y
)
{
}
x
=
(
float
)
_x
;
explicit
Vec2
(
int
_x
,
int
_y
)
{
y
=
(
float
)
_y
;
x
=
(
float
)
_x
;
}
y
=
(
float
)
_y
;
}
Vec2
(
const
Vec2
&
)
=
default
;
Vec2
(
const
Vec2
&
src
)
{
Vec2
&
operator
=
(
const
Vec2
&
)
=
default
;
x
=
src
.
x
;
~
Vec2
()
=
default
;
y
=
src
.
y
;
}
float
&
operator
[](
int
idx
)
{
~
Vec2
()
=
default
;
assert
(
idx
>=
0
&&
idx
<=
1
);
return
data
[
idx
];
Vec2
operator
=
(
Vec2
v
)
{
}
x
=
v
.
x
;
float
operator
[](
int
idx
)
const
{
y
=
v
.
y
;
assert
(
idx
>=
0
&&
idx
<=
1
);
return
*
this
;
return
data
[
idx
];
}
}
float
&
operator
[](
int
idx
)
{
Vec2
operator
+=
(
Vec2
v
)
{
assert
(
idx
>=
0
&&
idx
<=
1
);
x
+=
v
.
x
;
return
data
[
idx
];
y
+=
v
.
y
;
}
return
*
this
;
float
operator
[](
int
idx
)
const
{
}
assert
(
idx
>=
0
&&
idx
<=
1
);
Vec2
operator
-=
(
Vec2
v
)
{
return
data
[
idx
];
x
-=
v
.
x
;
}
y
-=
v
.
y
;
return
*
this
;
Vec2
operator
+=
(
Vec2
v
)
{
}
x
+=
v
.
x
;
Vec2
operator
*=
(
Vec2
v
)
{
y
+=
v
.
y
;
x
*=
v
.
x
;
return
*
this
;
y
*=
v
.
y
;
}
return
*
this
;
Vec2
operator
-=
(
Vec2
v
)
{
}
x
-=
v
.
x
;
Vec2
operator
/=
(
Vec2
v
)
{
y
-=
v
.
y
;
x
/=
v
.
x
;
return
*
this
;
y
/=
v
.
y
;
}
return
*
this
;
Vec2
operator
*=
(
Vec2
v
)
{
}
x
*=
v
.
x
;
y
*=
v
.
y
;
Vec2
operator
+=
(
float
s
)
{
return
*
this
;
x
+=
s
;
}
y
+=
s
;
Vec2
operator
/=
(
Vec2
v
)
{
return
*
this
;
x
/=
v
.
x
;
}
y
/=
v
.
y
;
Vec2
operator
-=
(
float
s
)
{
return
*
this
;
x
-=
s
;
}
y
-=
s
;
return
*
this
;
Vec2
operator
+=
(
float
s
)
{
}
x
+=
s
;
Vec2
operator
*=
(
float
s
)
{
y
+=
s
;
x
*=
s
;
return
*
this
;
y
*=
s
;
}
return
*
this
;
Vec2
operator
-=
(
float
s
)
{
}
x
-=
s
;
Vec2
operator
/=
(
float
s
)
{
y
-=
s
;
x
/=
s
;
return
*
this
;
y
/=
s
;
}
return
*
this
;
Vec2
operator
*=
(
float
s
)
{
}
x
*=
s
;
y
*=
s
;
Vec2
operator
+
(
Vec2
v
)
const
{
return
Vec2
(
x
+
v
.
x
,
y
+
v
.
y
);
}
return
*
this
;
Vec2
operator
-
(
Vec2
v
)
const
{
return
Vec2
(
x
-
v
.
x
,
y
-
v
.
y
);
}
}
Vec2
operator
*
(
Vec2
v
)
const
{
return
Vec2
(
x
*
v
.
x
,
y
*
v
.
y
);
}
Vec2
operator
/=
(
float
s
)
{
Vec2
operator
/
(
Vec2
v
)
const
{
return
Vec2
(
x
/
v
.
x
,
y
/
v
.
y
);
}
x
/=
s
;
y
/=
s
;
Vec2
operator
+
(
float
s
)
const
{
return
Vec2
(
x
+
s
,
y
+
s
);
}
return
*
this
;
Vec2
operator
-
(
float
s
)
const
{
return
Vec2
(
x
-
s
,
y
-
s
);
}
}
Vec2
operator
*
(
float
s
)
const
{
return
Vec2
(
x
*
s
,
y
*
s
);
}
Vec2
operator
/
(
float
s
)
const
{
return
Vec2
(
x
/
s
,
y
/
s
);
}
Vec2
operator
+
(
Vec2
v
)
const
{
return
Vec2
(
x
+
v
.
x
,
y
+
v
.
y
);
bool
operator
==
(
Vec2
v
)
const
{
return
x
==
v
.
x
&&
y
==
v
.
y
;
}
}
bool
operator
!=
(
Vec2
v
)
const
{
return
x
!=
v
.
x
||
y
!=
v
.
y
;
}
Vec2
operator
-
(
Vec2
v
)
const
{
return
Vec2
(
x
-
v
.
x
,
y
-
v
.
y
);
/// Absolute value
}
Vec2
abs
()
const
{
return
Vec2
(
std
::
abs
(
x
),
std
::
abs
(
y
));
}
Vec2
operator
*
(
Vec2
v
)
const
{
/// Negation
return
Vec2
(
x
*
v
.
x
,
y
*
v
.
y
);
Vec2
operator
-
()
const
{
return
Vec2
(
-
x
,
-
y
);
}
}
/// Are all members real numbers?
Vec2
operator
/
(
Vec2
v
)
const
{
bool
valid
()
const
{
return
Vec2
(
x
/
v
.
x
,
y
/
v
.
y
);
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isnan
(
x
)
||
std
::
isnan
(
y
));
}
}
Vec2
operator
+
(
float
s
)
const
{
/// Modify vec to have unit length
return
Vec2
(
x
+
s
,
y
+
s
);
Vec2
normalize
()
{
}
float
n
=
norm
();
Vec2
operator
-
(
float
s
)
const
{
x
/=
n
;
return
Vec2
(
x
-
s
,
y
-
s
);
y
/=
n
;
}
return
*
this
;
Vec2
operator
*
(
float
s
)
const
{
}
return
Vec2
(
x
*
s
,
y
*
s
);
/// Return unit length vec in the same direction
}
Vec2
unit
()
const
{
Vec2
operator
/
(
float
s
)
const
{
float
n
=
norm
();
return
Vec2
(
x
/
s
,
y
/
s
);
return
Vec2
(
x
/
n
,
y
/
n
);
}
}
bool
operator
==
(
Vec2
v
)
const
{
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
;
}
return
x
==
v
.
x
&&
y
==
v
.
y
;
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
}
bool
operator
!=
(
Vec2
v
)
const
{
Vec2
range
(
float
min
,
float
max
)
const
{
return
x
!=
v
.
x
||
y
!=
v
.
y
;
if
(
!
valid
())
}
return
Vec2
();
Vec2
r
=
*
this
;
/// Absolute value
float
range
=
max
-
min
;
Vec2
abs
()
const
{
while
(
r
.
x
<
min
)
return
Vec2
(
std
::
abs
(
x
),
std
::
abs
(
y
));
r
.
x
+=
range
;
}
while
(
r
.
x
>=
max
)
/// Negation
r
.
x
-=
range
;
Vec2
operator
-
()
const
{
while
(
r
.
y
<
min
)
return
Vec2
(
-
x
,
-
y
);
r
.
y
+=
range
;
}
while
(
r
.
y
>=
max
)
/// Are all members real numbers?
r
.
y
-=
range
;
bool
valid
()
const
{
return
r
;
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
}
std
::
isnan
(
x
)
||
std
::
isnan
(
y
));
}
union
{
struct
{
/// Modify vec to have unit length
float
x
;
Vec2
normalize
()
{
float
y
;
float
n
=
norm
();
};
x
/=
n
;
float
data
[
2
]
=
{};
y
/=
n
;
};
return
*
this
;
}
/// Return unit length vec in the same direction
Vec2
unit
()
const
{
float
n
=
norm
();
return
Vec2
(
x
/
n
,
y
/
n
);
}
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
;
}
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
Vec2
range
(
float
min
,
float
max
)
const
{
if
(
!
valid
())
return
Vec2
();
Vec2
r
=
*
this
;
float
range
=
max
-
min
;
while
(
r
.
x
<
min
)
r
.
x
+=
range
;
while
(
r
.
x
>=
max
)
r
.
x
-=
range
;
while
(
r
.
y
<
min
)
r
.
y
+=
range
;
while
(
r
.
y
>=
max
)
r
.
y
-=
range
;
return
r
;
}
union
{
struct
{
float
x
;
float
y
;
};
float
data
[
2
]
=
{};
};
};
};
inline
Vec2
operator
+
(
float
s
,
Vec2
v
)
{
inline
Vec2
operator
+
(
float
s
,
Vec2
v
)
{
return
Vec2
(
v
.
x
+
s
,
v
.
y
+
s
);
}
return
Vec2
(
v
.
x
+
s
,
v
.
y
+
s
);
inline
Vec2
operator
-
(
float
s
,
Vec2
v
)
{
return
Vec2
(
v
.
x
-
s
,
v
.
y
-
s
);
}
}
inline
Vec2
operator
*
(
float
s
,
Vec2
v
)
{
return
Vec2
(
v
.
x
*
s
,
v
.
y
*
s
);
}
inline
Vec2
operator
-
(
float
s
,
Vec2
v
)
{
inline
Vec2
operator
/
(
float
s
,
Vec2
v
)
{
return
Vec2
(
s
/
v
.
x
,
s
/
v
.
y
);
}
return
Vec2
(
v
.
x
-
s
,
v
.
y
-
s
);
}
inline
Vec2
operator
*
(
float
s
,
Vec2
v
)
{
return
Vec2
(
v
.
x
*
s
,
v
.
y
*
s
);
}
inline
Vec2
operator
/
(
float
s
,
Vec2
v
)
{
return
Vec2
(
s
/
v
.
x
,
s
/
v
.
y
);
}
/// Take minimum of each component
/// Take minimum of each component
inline
Vec2
hmin
(
Vec2
l
,
Vec2
r
)
{
inline
Vec2
hmin
(
Vec2
l
,
Vec2
r
)
{
return
Vec2
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
));
}
return
Vec2
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
));
}
/// Take maximum of each component
/// Take maximum of each component
inline
Vec2
hmax
(
Vec2
l
,
Vec2
r
)
{
inline
Vec2
hmax
(
Vec2
l
,
Vec2
r
)
{
return
Vec2
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
));
}
return
Vec2
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
));
}
/// 2D dot product
/// 2D dot product
inline
float
dot
(
Vec2
l
,
Vec2
r
)
{
inline
float
dot
(
Vec2
l
,
Vec2
r
)
{
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
;
}
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
;
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec2
v
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec2
v
)
{
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
"}"
;
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/vec3.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "log.h"
#include "log.h"
struct
Vec3
{
struct
Vec3
{
Vec3
()
{
Vec3
()
{
x
=
0
.
0
f
;
x
=
0
.
0
f
;
y
=
0
.
0
f
;
y
=
0
.
0
f
;
z
=
0
.
0
f
;
z
=
0
.
0
f
;
}
}
explicit
Vec3
(
float
_x
,
float
_y
,
float
_z
)
{
explicit
Vec3
(
float
_x
,
float
_y
,
float
_z
)
{
x
=
_x
;
x
=
_x
;
y
=
_y
;
y
=
_y
;
z
=
_z
;
z
=
_z
;
}
}
explicit
Vec3
(
int
_x
,
int
_y
,
int
_z
)
{
explicit
Vec3
(
int
_x
,
int
_y
,
int
_z
)
{
x
=
(
float
)
_x
;
x
=
(
float
)
_x
;
y
=
(
float
)
_y
;
y
=
(
float
)
_y
;
z
=
(
float
)
_z
;
z
=
(
float
)
_z
;
}
}
explicit
Vec3
(
float
f
)
{
explicit
Vec3
(
float
f
)
{
x
=
y
=
z
=
f
;
}
x
=
y
=
z
=
f
;
}
Vec3
(
const
Vec3
&
)
=
default
;
Vec3
(
const
Vec3
&
src
)
{
Vec3
&
operator
=
(
const
Vec3
&
)
=
default
;
x
=
src
.
x
;
~
Vec3
()
=
default
;
y
=
src
.
y
;
z
=
src
.
z
;
float
&
operator
[](
int
idx
)
{
}
assert
(
idx
>=
0
&&
idx
<=
2
);
~
Vec3
()
=
default
;
return
data
[
idx
];
}
Vec3
operator
=
(
Vec3
v
)
{
float
operator
[](
int
idx
)
const
{
x
=
v
.
x
;
assert
(
idx
>=
0
&&
idx
<=
2
);
y
=
v
.
y
;
return
data
[
idx
];
z
=
v
.
z
;
}
return
*
this
;
}
Vec3
operator
+=
(
Vec3
v
)
{
x
+=
v
.
x
;
float
&
operator
[](
int
idx
)
{
y
+=
v
.
y
;
assert
(
idx
>=
0
&&
idx
<=
2
);
z
+=
v
.
z
;
return
data
[
idx
];
return
*
this
;
}
}
float
operator
[](
int
idx
)
const
{
Vec3
operator
-=
(
Vec3
v
)
{
assert
(
idx
>=
0
&&
idx
<=
2
);
x
-=
v
.
x
;
return
data
[
idx
];
y
-=
v
.
y
;
}
z
-=
v
.
z
;
return
*
this
;
Vec3
operator
+=
(
Vec3
v
)
{
}
x
+=
v
.
x
;
Vec3
operator
*=
(
Vec3
v
)
{
y
+=
v
.
y
;
x
*=
v
.
x
;
z
+=
v
.
z
;
y
*=
v
.
y
;
return
*
this
;
z
*=
v
.
z
;
}
return
*
this
;
Vec3
operator
-=
(
Vec3
v
)
{
}
x
-=
v
.
x
;
Vec3
operator
/=
(
Vec3
v
)
{
y
-=
v
.
y
;
x
/=
v
.
x
;
z
-=
v
.
z
;
y
/=
v
.
y
;
return
*
this
;
z
/=
v
.
z
;
}
return
*
this
;
Vec3
operator
*=
(
Vec3
v
)
{
}
x
*=
v
.
x
;
y
*=
v
.
y
;
Vec3
operator
+=
(
float
s
)
{
z
*=
v
.
z
;
x
+=
s
;
return
*
this
;
y
+=
s
;
}
z
+=
s
;
Vec3
operator
/=
(
Vec3
v
)
{
return
*
this
;
x
/=
v
.
x
;
}
y
/=
v
.
y
;
Vec3
operator
-=
(
float
s
)
{
z
/=
v
.
z
;
x
-=
s
;
return
*
this
;
y
-=
s
;
}
z
-=
s
;
return
*
this
;
Vec3
operator
+=
(
float
s
)
{
}
x
+=
s
;
Vec3
operator
*=
(
float
s
)
{
y
+=
s
;
x
*=
s
;
z
+=
s
;
y
*=
s
;
return
*
this
;
z
*=
s
;
}
return
*
this
;
Vec3
operator
-=
(
float
s
)
{
}
x
-=
s
;
Vec3
operator
/=
(
float
s
)
{
y
-=
s
;
x
/=
s
;
z
-=
s
;
y
/=
s
;
return
*
this
;
z
/=
s
;
}
return
*
this
;
Vec3
operator
*=
(
float
s
)
{
}
x
*=
s
;
y
*=
s
;
Vec3
operator
+
(
Vec3
v
)
const
{
return
Vec3
(
x
+
v
.
x
,
y
+
v
.
y
,
z
+
v
.
z
);
}
z
*=
s
;
Vec3
operator
-
(
Vec3
v
)
const
{
return
Vec3
(
x
-
v
.
x
,
y
-
v
.
y
,
z
-
v
.
z
);
}
return
*
this
;
Vec3
operator
*
(
Vec3
v
)
const
{
return
Vec3
(
x
*
v
.
x
,
y
*
v
.
y
,
z
*
v
.
z
);
}
}
Vec3
operator
/
(
Vec3
v
)
const
{
return
Vec3
(
x
/
v
.
x
,
y
/
v
.
y
,
z
/
v
.
z
);
}
Vec3
operator
/=
(
float
s
)
{
x
/=
s
;
Vec3
operator
+
(
float
s
)
const
{
return
Vec3
(
x
+
s
,
y
+
s
,
z
+
s
);
}
y
/=
s
;
Vec3
operator
-
(
float
s
)
const
{
return
Vec3
(
x
-
s
,
y
-
s
,
z
-
s
);
}
z
/=
s
;
Vec3
operator
*
(
float
s
)
const
{
return
Vec3
(
x
*
s
,
y
*
s
,
z
*
s
);
}
return
*
this
;
Vec3
operator
/
(
float
s
)
const
{
return
Vec3
(
x
/
s
,
y
/
s
,
z
/
s
);
}
}
bool
operator
==
(
Vec3
v
)
const
{
return
x
==
v
.
x
&&
y
==
v
.
y
&&
z
==
v
.
z
;
}
Vec3
operator
+
(
Vec3
v
)
const
{
bool
operator
!=
(
Vec3
v
)
const
{
return
x
!=
v
.
x
||
y
!=
v
.
y
||
z
!=
v
.
z
;
}
return
Vec3
(
x
+
v
.
x
,
y
+
v
.
y
,
z
+
v
.
z
);
}
/// Absolute value
Vec3
operator
-
(
Vec3
v
)
const
{
Vec3
abs
()
const
{
return
Vec3
(
std
::
abs
(
x
),
std
::
abs
(
y
),
std
::
abs
(
z
));
}
return
Vec3
(
x
-
v
.
x
,
y
-
v
.
y
,
z
-
v
.
z
);
/// Negation
}
Vec3
operator
-
()
const
{
return
Vec3
(
-
x
,
-
y
,
-
z
);
}
Vec3
operator
*
(
Vec3
v
)
const
{
/// Are all members real numbers?
return
Vec3
(
x
*
v
.
x
,
y
*
v
.
y
,
z
*
v
.
z
);
bool
valid
()
const
{
}
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
std
::
isnan
(
x
)
||
Vec3
operator
/
(
Vec3
v
)
const
{
std
::
isnan
(
y
)
||
std
::
isnan
(
z
));
return
Vec3
(
x
/
v
.
x
,
y
/
v
.
y
,
z
/
v
.
z
);
}
}
/// Modify vec to have unit length
Vec3
operator
+
(
float
s
)
const
{
Vec3
normalize
()
{
return
Vec3
(
x
+
s
,
y
+
s
,
z
+
s
);
float
n
=
norm
();
}
x
/=
n
;
Vec3
operator
-
(
float
s
)
const
{
y
/=
n
;
return
Vec3
(
x
-
s
,
y
-
s
,
z
-
s
);
z
/=
n
;
}
return
*
this
;
Vec3
operator
*
(
float
s
)
const
{
}
return
Vec3
(
x
*
s
,
y
*
s
,
z
*
s
);
/// Return unit length vec in the same direction
}
Vec3
unit
()
const
{
Vec3
operator
/
(
float
s
)
const
{
float
n
=
norm
();
return
Vec3
(
x
/
s
,
y
/
s
,
z
/
s
);
return
Vec3
(
x
/
n
,
y
/
n
,
z
/
n
);
}
}
bool
operator
==
(
Vec3
v
)
const
{
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
+
z
*
z
;
}
return
x
==
v
.
x
&&
y
==
v
.
y
&&
z
==
v
.
z
;
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
}
bool
operator
!=
(
Vec3
v
)
const
{
/// Make sure all components are in the range [min,max) with floating point mod logic
return
x
!=
v
.
x
||
y
!=
v
.
y
||
z
!=
v
.
z
;
Vec3
range
(
float
min
,
float
max
)
const
{
}
if
(
!
valid
())
return
Vec3
();
/// Absolute value
Vec3
r
=
*
this
;
Vec3
abs
()
const
{
float
range
=
max
-
min
;
return
Vec3
(
std
::
abs
(
x
),
std
::
abs
(
y
),
std
::
abs
(
z
));
while
(
r
.
x
<
min
)
}
r
.
x
+=
range
;
/// Negation
while
(
r
.
x
>=
max
)
Vec3
operator
-
()
const
{
r
.
x
-=
range
;
return
Vec3
(
-
x
,
-
y
,
-
z
);
while
(
r
.
y
<
min
)
}
r
.
y
+=
range
;
/// Are all members real numbers?
while
(
r
.
y
>=
max
)
bool
valid
()
const
{
r
.
y
-=
range
;
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
while
(
r
.
z
<
min
)
std
::
isnan
(
x
)
||
std
::
isnan
(
y
)
||
std
::
isnan
(
z
));
r
.
z
+=
range
;
}
while
(
r
.
z
>=
max
)
r
.
z
-=
range
;
/// Modify vec to have unit length
return
r
;
Vec3
normalize
()
{
}
float
n
=
norm
();
x
/=
n
;
union
{
y
/=
n
;
struct
{
z
/=
n
;
float
x
;
return
*
this
;
float
y
;
}
float
z
;
/// Return unit length vec in the same direction
};
Vec3
unit
()
const
{
float
data
[
3
]
=
{};
float
n
=
norm
();
};
return
Vec3
(
x
/
n
,
y
/
n
,
z
/
n
);
}
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
+
z
*
z
;
}
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
/// Make sure all components are in the range [min,max) with floating point mod logic
Vec3
range
(
float
min
,
float
max
)
const
{
if
(
!
valid
())
return
Vec3
();
Vec3
r
=
*
this
;
float
range
=
max
-
min
;
while
(
r
.
x
<
min
)
r
.
x
+=
range
;
while
(
r
.
x
>=
max
)
r
.
x
-=
range
;
while
(
r
.
y
<
min
)
r
.
y
+=
range
;
while
(
r
.
y
>=
max
)
r
.
y
-=
range
;
while
(
r
.
z
<
min
)
r
.
z
+=
range
;
while
(
r
.
z
>=
max
)
r
.
z
-=
range
;
return
r
;
}
union
{
struct
{
float
x
;
float
y
;
float
z
;
};
float
data
[
3
]
=
{};
};
};
};
inline
Vec3
operator
+
(
float
s
,
Vec3
v
)
{
inline
Vec3
operator
+
(
float
s
,
Vec3
v
)
{
return
Vec3
(
v
.
x
+
s
,
v
.
y
+
s
,
v
.
z
+
s
);
}
return
Vec3
(
v
.
x
+
s
,
v
.
y
+
s
,
v
.
z
+
s
);
inline
Vec3
operator
-
(
float
s
,
Vec3
v
)
{
return
Vec3
(
v
.
x
-
s
,
v
.
y
-
s
,
v
.
z
-
s
);
}
}
inline
Vec3
operator
*
(
float
s
,
Vec3
v
)
{
return
Vec3
(
v
.
x
*
s
,
v
.
y
*
s
,
v
.
z
*
s
);
}
inline
Vec3
operator
-
(
float
s
,
Vec3
v
)
{
inline
Vec3
operator
/
(
float
s
,
Vec3
v
)
{
return
Vec3
(
s
/
v
.
x
,
s
/
v
.
y
,
s
/
v
.
z
);
}
return
Vec3
(
v
.
x
-
s
,
v
.
y
-
s
,
v
.
z
-
s
);
}
inline
Vec3
operator
*
(
float
s
,
Vec3
v
)
{
return
Vec3
(
v
.
x
*
s
,
v
.
y
*
s
,
v
.
z
*
s
);
}
inline
Vec3
operator
/
(
float
s
,
Vec3
v
)
{
return
Vec3
(
s
/
v
.
x
,
s
/
v
.
y
,
s
/
v
.
z
);
}
/// Take minimum of each component
/// Take minimum of each component
inline
Vec3
hmin
(
Vec3
l
,
Vec3
r
)
{
inline
Vec3
hmin
(
Vec3
l
,
Vec3
r
)
{
return
Vec3
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
),
std
::
min
(
l
.
z
,
r
.
z
));
return
Vec3
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
),
std
::
min
(
l
.
z
,
r
.
z
));
}
}
/// Take maximum of each component
/// Take maximum of each component
inline
Vec3
hmax
(
Vec3
l
,
Vec3
r
)
{
inline
Vec3
hmax
(
Vec3
l
,
Vec3
r
)
{
return
Vec3
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
),
std
::
max
(
l
.
z
,
r
.
z
));
return
Vec3
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
),
std
::
max
(
l
.
z
,
r
.
z
));
}
}
/// 3D dot product
/// 3D dot product
inline
float
dot
(
Vec3
l
,
Vec3
r
)
{
inline
float
dot
(
Vec3
l
,
Vec3
r
)
{
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
+
l
.
z
*
r
.
z
;
}
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
+
l
.
z
*
r
.
z
;
}
/// 3D cross product
/// 3D cross product
inline
Vec3
cross
(
Vec3
l
,
Vec3
r
)
{
inline
Vec3
cross
(
Vec3
l
,
Vec3
r
)
{
return
Vec3
(
l
.
y
*
r
.
z
-
l
.
z
*
r
.
y
,
l
.
z
*
r
.
x
-
l
.
x
*
r
.
z
,
l
.
x
*
r
.
y
-
l
.
y
*
r
.
x
);
return
Vec3
(
l
.
y
*
r
.
z
-
l
.
z
*
r
.
y
,
l
.
z
*
r
.
x
-
l
.
x
*
r
.
z
,
l
.
x
*
r
.
y
-
l
.
y
*
r
.
x
);
}
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec3
v
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec3
v
)
{
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
","
<<
v
.
z
<<
"}"
;
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
","
<<
v
.
z
<<
"}"
;
return
out
;
return
out
;
}
}
src/lib/vec4.h
View file @
c2535f0f
#pragma once
#pragma once
#include <cmath>
#include <algorithm>
#include <algorithm>
#include <cmath>
#include <ostream>
#include <ostream>
#include "log.h"
#include "log.h"
...
@@ -10,233 +10,178 @@
...
@@ -10,233 +10,178 @@
struct
Vec4
{
struct
Vec4
{
Vec4
()
{
Vec4
()
{
x
=
0
.
0
f
;
x
=
0
.
0
f
;
y
=
0
.
0
f
;
y
=
0
.
0
f
;
z
=
0
.
0
f
;
z
=
0
.
0
f
;
w
=
0
.
0
f
;
w
=
0
.
0
f
;
}
}
explicit
Vec4
(
float
_x
,
float
_y
,
float
_z
,
float
_w
)
{
explicit
Vec4
(
float
_x
,
float
_y
,
float
_z
,
float
_w
)
{
x
=
_x
;
x
=
_x
;
y
=
_y
;
y
=
_y
;
z
=
_z
;
z
=
_z
;
w
=
_w
;
w
=
_w
;
}
}
explicit
Vec4
(
float
f
)
{
explicit
Vec4
(
float
f
)
{
x
=
y
=
z
=
w
=
f
;
}
x
=
y
=
z
=
w
=
f
;
explicit
Vec4
(
int
_x
,
int
_y
,
int
_z
,
int
_w
)
{
}
x
=
(
float
)
_x
;
explicit
Vec4
(
int
_x
,
int
_y
,
int
_z
,
int
_w
)
{
y
=
(
float
)
_y
;
x
=
(
float
)
_x
;
z
=
(
float
)
_z
;
y
=
(
float
)
_y
;
w
=
(
float
)
_w
;
z
=
(
float
)
_z
;
}
w
=
(
float
)
_w
;
explicit
Vec4
(
Vec3
xyz
,
float
_w
)
{
}
x
=
xyz
.
x
;
explicit
Vec4
(
Vec3
xyz
,
float
_w
)
{
y
=
xyz
.
y
;
x
=
xyz
.
x
;
z
=
xyz
.
z
;
y
=
xyz
.
y
;
w
=
_w
;
z
=
xyz
.
z
;
}
w
=
_w
;
}
Vec4
(
const
Vec4
&
)
=
default
;
Vec4
(
const
Vec4
&
src
)
{
Vec4
&
operator
=
(
const
Vec4
&
)
=
default
;
x
=
src
.
x
;
~
Vec4
()
=
default
;
y
=
src
.
y
;
z
=
src
.
z
;
float
&
operator
[](
int
idx
)
{
w
=
src
.
w
;
assert
(
idx
>=
0
&&
idx
<=
3
);
}
return
data
[
idx
];
~
Vec4
()
=
default
;
}
float
operator
[](
int
idx
)
const
{
Vec4
operator
=
(
Vec4
v
)
{
assert
(
idx
>=
0
&&
idx
<=
3
);
x
=
v
.
x
;
return
data
[
idx
];
y
=
v
.
y
;
}
z
=
v
.
z
;
w
=
v
.
w
;
Vec4
operator
+=
(
Vec4
v
)
{
return
*
this
;
x
+=
v
.
x
;
}
y
+=
v
.
y
;
z
+=
v
.
z
;
float
&
operator
[](
int
idx
)
{
w
+=
v
.
w
;
assert
(
idx
>=
0
&&
idx
<=
3
);
return
*
this
;
return
data
[
idx
];
}
}
Vec4
operator
-=
(
Vec4
v
)
{
float
operator
[](
int
idx
)
const
{
x
-=
v
.
x
;
assert
(
idx
>=
0
&&
idx
<=
3
);
y
-=
v
.
y
;
return
data
[
idx
];
z
-=
v
.
z
;
}
w
-=
v
.
w
;
return
*
this
;
Vec4
operator
+=
(
Vec4
v
)
{
}
x
+=
v
.
x
;
Vec4
operator
*=
(
Vec4
v
)
{
y
+=
v
.
y
;
x
*=
v
.
x
;
z
+=
v
.
z
;
y
*=
v
.
y
;
w
+=
v
.
w
;
z
*=
v
.
z
;
return
*
this
;
w
*=
v
.
w
;
}
return
*
this
;
Vec4
operator
-=
(
Vec4
v
)
{
}
x
-=
v
.
x
;
Vec4
operator
/=
(
Vec4
v
)
{
y
-=
v
.
y
;
x
/=
v
.
x
;
z
-=
v
.
z
;
y
/=
v
.
y
;
w
-=
v
.
w
;
z
/=
v
.
z
;
return
*
this
;
w
/=
v
.
w
;
}
return
*
this
;
Vec4
operator
*=
(
Vec4
v
)
{
}
x
*=
v
.
x
;
y
*=
v
.
y
;
Vec4
operator
+=
(
float
s
)
{
z
*=
v
.
z
;
x
+=
s
;
w
*=
v
.
w
;
y
+=
s
;
return
*
this
;
z
+=
s
;
}
w
+=
s
;
Vec4
operator
/=
(
Vec4
v
)
{
return
*
this
;
x
/=
v
.
x
;
}
y
/=
v
.
y
;
Vec4
operator
-=
(
float
s
)
{
z
/=
v
.
z
;
x
-=
s
;
w
/=
v
.
w
;
y
-=
s
;
return
*
this
;
z
-=
s
;
}
w
-=
s
;
return
*
this
;
Vec4
operator
+=
(
float
s
)
{
}
x
+=
s
;
Vec4
operator
*=
(
float
s
)
{
y
+=
s
;
x
*=
s
;
z
+=
s
;
y
*=
s
;
w
+=
s
;
z
*=
s
;
return
*
this
;
w
*=
s
;
}
return
*
this
;
Vec4
operator
-=
(
float
s
)
{
}
x
-=
s
;
Vec4
operator
/=
(
float
s
)
{
y
-=
s
;
x
/=
s
;
z
-=
s
;
y
/=
s
;
w
-=
s
;
z
/=
s
;
return
*
this
;
w
/=
s
;
}
return
*
this
;
Vec4
operator
*=
(
float
s
)
{
}
x
*=
s
;
y
*=
s
;
Vec4
operator
+
(
Vec4
v
)
const
{
return
Vec4
(
x
+
v
.
x
,
y
+
v
.
y
,
z
+
v
.
z
,
w
+
v
.
w
);
}
z
*=
s
;
Vec4
operator
-
(
Vec4
v
)
const
{
return
Vec4
(
x
-
v
.
x
,
y
-
v
.
y
,
z
-
v
.
z
,
w
-
v
.
w
);
}
w
*=
s
;
Vec4
operator
*
(
Vec4
v
)
const
{
return
Vec4
(
x
*
v
.
x
,
y
*
v
.
y
,
z
*
v
.
z
,
w
*
v
.
w
);
}
return
*
this
;
Vec4
operator
/
(
Vec4
v
)
const
{
return
Vec4
(
x
/
v
.
x
,
y
/
v
.
y
,
z
/
v
.
z
,
w
/
v
.
w
);
}
}
Vec4
operator
/=
(
float
s
)
{
Vec4
operator
+
(
float
s
)
const
{
return
Vec4
(
x
+
s
,
y
+
s
,
z
+
s
,
w
+
s
);
}
x
/=
s
;
Vec4
operator
-
(
float
s
)
const
{
return
Vec4
(
x
-
s
,
y
-
s
,
z
-
s
,
w
-
s
);
}
y
/=
s
;
Vec4
operator
*
(
float
s
)
const
{
return
Vec4
(
x
*
s
,
y
*
s
,
z
*
s
,
w
*
s
);
}
z
/=
s
;
Vec4
operator
/
(
float
s
)
const
{
return
Vec4
(
x
/
s
,
y
/
s
,
z
/
s
,
w
/
s
);
}
w
/=
s
;
return
*
this
;
bool
operator
==
(
Vec4
v
)
const
{
return
x
==
v
.
x
&&
y
==
v
.
y
&&
z
==
v
.
z
&&
w
==
v
.
w
;
}
}
bool
operator
!=
(
Vec4
v
)
const
{
return
x
!=
v
.
x
||
y
!=
v
.
y
||
z
!=
v
.
z
||
w
!=
v
.
w
;
}
Vec4
operator
+
(
Vec4
v
)
const
{
/// Absolute value
return
Vec4
(
x
+
v
.
x
,
y
+
v
.
y
,
z
+
v
.
z
,
w
+
v
.
w
);
Vec4
abs
()
const
{
return
Vec4
(
std
::
abs
(
x
),
std
::
abs
(
y
),
std
::
abs
(
z
),
std
::
abs
(
w
));
}
}
/// Negation
Vec4
operator
-
(
Vec4
v
)
const
{
Vec4
operator
-
()
const
{
return
Vec4
(
-
x
,
-
y
,
-
z
,
-
w
);
}
return
Vec4
(
x
-
v
.
x
,
y
-
v
.
y
,
z
-
v
.
z
,
w
-
v
.
w
);
/// Are all members real numbers?
}
bool
valid
()
const
{
Vec4
operator
*
(
Vec4
v
)
const
{
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
std
::
isinf
(
w
)
||
return
Vec4
(
x
*
v
.
x
,
y
*
v
.
y
,
z
*
v
.
z
,
w
*
v
.
w
);
std
::
isnan
(
x
)
||
std
::
isnan
(
y
)
||
std
::
isnan
(
z
)
||
std
::
isnan
(
w
));
}
}
Vec4
operator
/
(
Vec4
v
)
const
{
return
Vec4
(
x
/
v
.
x
,
y
/
v
.
y
,
z
/
v
.
z
,
w
/
v
.
w
);
/// Modify vec to have unit length
}
Vec4
normalize
()
{
float
n
=
norm
();
Vec4
operator
+
(
float
s
)
const
{
x
/=
n
;
return
Vec4
(
x
+
s
,
y
+
s
,
z
+
s
,
w
+
s
);
y
/=
n
;
}
z
/=
n
;
Vec4
operator
-
(
float
s
)
const
{
w
/=
n
;
return
Vec4
(
x
-
s
,
y
-
s
,
z
-
s
,
w
-
s
);
return
*
this
;
}
}
Vec4
operator
*
(
float
s
)
const
{
/// Return unit length vec in the same direction
return
Vec4
(
x
*
s
,
y
*
s
,
z
*
s
,
w
*
s
);
Vec4
unit
()
const
{
}
float
n
=
norm
();
Vec4
operator
/
(
float
s
)
const
{
return
Vec4
(
x
/
n
,
y
/
n
,
z
/
n
,
w
/
n
);
return
Vec4
(
x
/
s
,
y
/
s
,
z
/
s
,
w
/
s
);
}
}
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
+
z
*
z
+
w
*
w
;
}
bool
operator
==
(
Vec4
v
)
const
{
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
return
x
==
v
.
x
&&
y
==
v
.
y
&&
z
==
v
.
z
&&
w
==
v
.
w
;
}
/// Returns first three components
bool
operator
!=
(
Vec4
v
)
const
{
Vec3
xyz
()
const
{
return
Vec3
(
x
,
y
,
z
);
}
return
x
!=
v
.
x
||
y
!=
v
.
y
||
z
!=
v
.
z
||
w
!=
v
.
w
;
/// Performs perspective division (xyz/w)
}
Vec3
project
()
const
{
return
Vec3
(
x
/
w
,
y
/
w
,
z
/
w
);
}
/// Absolute value
union
{
Vec4
abs
()
const
{
struct
{
return
Vec4
(
std
::
abs
(
x
),
std
::
abs
(
y
),
std
::
abs
(
z
),
std
::
abs
(
w
));
float
x
;
}
float
y
;
/// Negation
float
z
;
Vec4
operator
-
()
const
{
float
w
;
return
Vec4
(
-
x
,
-
y
,
-
z
,
-
w
);
};
}
float
data
[
4
]
=
{};
/// Are all members real numbers?
};
bool
valid
()
const
{
return
!
(
std
::
isinf
(
x
)
||
std
::
isinf
(
y
)
||
std
::
isinf
(
z
)
||
std
::
isinf
(
w
)
||
std
::
isnan
(
x
)
||
std
::
isnan
(
y
)
||
std
::
isnan
(
z
)
||
std
::
isnan
(
w
));
}
/// Modify vec to have unit length
Vec4
normalize
()
{
float
n
=
norm
();
x
/=
n
;
y
/=
n
;
z
/=
n
;
w
/=
n
;
return
*
this
;
}
/// Return unit length vec in the same direction
Vec4
unit
()
const
{
float
n
=
norm
();
return
Vec4
(
x
/
n
,
y
/
n
,
z
/
n
,
w
/
n
);
}
float
norm_squared
()
const
{
return
x
*
x
+
y
*
y
+
z
*
z
+
w
*
w
;
}
float
norm
()
const
{
return
std
::
sqrt
(
norm_squared
());
}
/// Returns first three components
Vec3
xyz
()
const
{
return
Vec3
(
x
,
y
,
z
);
}
/// Performs perspective division (xyz/w)
Vec3
project
()
const
{
return
Vec3
(
x
/
w
,
y
/
w
,
z
/
w
);
}
union
{
struct
{
float
x
;
float
y
;
float
z
;
float
w
;
};
float
data
[
4
]
=
{};
};
};
};
inline
Vec4
operator
+
(
float
s
,
Vec4
v
)
{
inline
Vec4
operator
+
(
float
s
,
Vec4
v
)
{
return
Vec4
(
v
.
x
+
s
,
v
.
y
+
s
,
v
.
z
+
s
,
v
.
w
+
s
);
}
return
Vec4
(
v
.
x
+
s
,
v
.
y
+
s
,
v
.
z
+
s
,
v
.
w
+
s
);
inline
Vec4
operator
-
(
float
s
,
Vec4
v
)
{
return
Vec4
(
v
.
x
-
s
,
v
.
y
-
s
,
v
.
z
-
s
,
v
.
w
-
s
);
}
}
inline
Vec4
operator
*
(
float
s
,
Vec4
v
)
{
return
Vec4
(
v
.
x
*
s
,
v
.
y
*
s
,
v
.
z
*
s
,
v
.
w
*
s
);
}
inline
Vec4
operator
-
(
float
s
,
Vec4
v
)
{
inline
Vec4
operator
/
(
float
s
,
Vec4
v
)
{
return
Vec4
(
s
/
v
.
x
,
s
/
v
.
y
,
s
/
v
.
z
,
s
/
v
.
w
);
}
return
Vec4
(
v
.
x
-
s
,
v
.
y
-
s
,
v
.
z
-
s
,
v
.
w
-
s
);
}
inline
Vec4
operator
*
(
float
s
,
Vec4
v
)
{
return
Vec4
(
v
.
x
*
s
,
v
.
y
*
s
,
v
.
z
*
s
,
v
.
w
*
s
);
}
inline
Vec4
operator
/
(
float
s
,
Vec4
v
)
{
return
Vec4
(
s
/
v
.
x
,
s
/
v
.
y
,
s
/
v
.
z
,
s
/
v
.
w
);
}
/// Take minimum of each component
/// Take minimum of each component
inline
Vec4
hmin
(
Vec4
l
,
Vec4
r
)
{
inline
Vec4
hmin
(
Vec4
l
,
Vec4
r
)
{
return
Vec4
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
),
std
::
min
(
l
.
z
,
r
.
z
),
std
::
min
(
l
.
w
,
r
.
w
));
return
Vec4
(
std
::
min
(
l
.
x
,
r
.
x
),
std
::
min
(
l
.
y
,
r
.
y
),
std
::
min
(
l
.
z
,
r
.
z
),
std
::
min
(
l
.
w
,
r
.
w
));
}
}
/// Take maximum of each component
/// Take maximum of each component
inline
Vec4
hmax
(
Vec4
l
,
Vec4
r
)
{
inline
Vec4
hmax
(
Vec4
l
,
Vec4
r
)
{
return
Vec4
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
),
std
::
max
(
l
.
z
,
r
.
z
),
std
::
max
(
l
.
w
,
r
.
w
));
return
Vec4
(
std
::
max
(
l
.
x
,
r
.
x
),
std
::
max
(
l
.
y
,
r
.
y
),
std
::
max
(
l
.
z
,
r
.
z
),
std
::
max
(
l
.
w
,
r
.
w
));
}
}
/// 4D dot product
/// 4D dot product
inline
float
dot
(
Vec4
l
,
Vec4
r
)
{
inline
float
dot
(
Vec4
l
,
Vec4
r
)
{
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
+
l
.
z
*
r
.
z
+
l
.
w
*
r
.
w
;
}
return
l
.
x
*
r
.
x
+
l
.
y
*
r
.
y
+
l
.
z
*
r
.
z
+
l
.
w
*
r
.
w
;
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec4
v
)
{
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
out
,
Vec4
v
)
{
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
","
<<
v
.
z
<<
","
<<
v
.
w
<<
"}"
;
out
<<
"{"
<<
v
.
x
<<
","
<<
v
.
y
<<
","
<<
v
.
z
<<
","
<<
v
.
w
<<
"}"
;
return
out
;
return
out
;
}
}
src/main.cpp
View file @
c2535f0f
#include <sf_libs/CLI11.hpp>
#include "platform/platform.h"
#include "platform/platform.h"
#include "util/rand.h"
#include "util/rand.h"
#include <sf_libs/CLI11.hpp>
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
RNG
::
seed
();
RNG
::
seed
();
App
::
Settings
settings
;
App
::
Settings
settings
;
CLI
::
App
args
{
"Scotty3D - 15-462"
};
CLI
::
App
args
{
"Scotty3D - 15-462"
};
args
.
add_option
(
"-s,--scene"
,
settings
.
scene_file
,
"Scene file to load"
);
args
.
add_option
(
"-s,--scene"
,
settings
.
scene_file
,
"Scene file to load"
);
args
.
add_option
(
"--env_map"
,
settings
.
env_map_file
,
"Override scene environment map"
);
args
.
add_option
(
"--env_map"
,
settings
.
env_map_file
,
"Override scene environment map"
);
args
.
add_flag
(
"--headless"
,
settings
.
headless
,
"Path-trace scene without opening the GUI"
);
args
.
add_flag
(
"--headless"
,
settings
.
headless
,
"Path-trace scene without opening the GUI"
);
args
.
add_option
(
"-o,--output"
,
settings
.
output_file
,
"Image file to write (if headless)"
);
args
.
add_option
(
"-o,--output"
,
settings
.
output_file
,
"Image file to write (if headless)"
);
args
.
add_flag
(
"--animate"
,
settings
.
animate
,
"Output animation frames (if headless)"
);
args
.
add_flag
(
"--animate"
,
settings
.
animate
,
"Output animation frames (if headless)"
);
args
.
add_option
(
"--width"
,
settings
.
w
,
"Output image width (if headless)"
);
args
.
add_option
(
"--width"
,
settings
.
w
,
"Output image width (if headless)"
);
args
.
add_option
(
"--height"
,
settings
.
h
,
"Output image height (if headless)"
);
args
.
add_option
(
"--height"
,
settings
.
h
,
"Output image height (if headless)"
);
args
.
add_flag
(
"--use_ar"
,
settings
.
w_from_ar
,
"Compute output image width based on camera AR (if headless)"
);
args
.
add_flag
(
"--use_ar"
,
settings
.
w_from_ar
,
args
.
add_option
(
"--depth"
,
settings
.
d
,
"Maximum ray depth (if headless)"
);
"Compute output image width based on camera AR (if headless)"
);
args
.
add_option
(
"--samples"
,
settings
.
s
,
"Pixel samples (if headless)"
);
args
.
add_option
(
"--depth"
,
settings
.
d
,
"Maximum ray depth (if headless)"
);
args
.
add_option
(
"--exposure"
,
settings
.
exp
,
"Output exposure (if headless)"
);
args
.
add_option
(
"--samples"
,
settings
.
s
,
"Pixel samples (if headless)"
);
args
.
add_option
(
"--area_samples"
,
settings
.
ls
,
"Area light samples (if headless)"
);
args
.
add_option
(
"--exposure"
,
settings
.
exp
,
"Output exposure (if headless)"
);
args
.
add_option
(
"--area_samples"
,
settings
.
ls
,
"Area light samples (if headless)"
);
CLI11_PARSE
(
args
,
argc
,
argv
);
CLI11_PARSE
(
args
,
argc
,
argv
);
if
(
!
settings
.
headless
)
{
if
(
!
settings
.
headless
)
{
if
(
settings
.
scene_file
.
empty
()
&&
settings
.
env_map_file
.
empty
())
Platform
plt
;
Platform
::
remove_console
();
App
app
(
settings
,
&
plt
);
Platform
plt
;
plt
.
loop
(
app
);
App
app
(
settings
,
&
plt
);
}
else
{
plt
.
loop
(
app
);
App
app
(
settings
);
}
else
{
}
App
app
(
settings
);
return
0
;
}
return
0
;
}
}
src/platform/font.dat
View file @
c2535f0f
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/platform/gl.cpp
View file @
c2535f0f
#include "gl.h"
#include "gl.h"
#include "../lib/log.h"
#include "../lib/log.h"
...
@@ -12,985 +12,989 @@ static bool is_gl45 = false;
...
@@ -12,985 +12,989 @@ static bool is_gl45 = false;
static
bool
is_gl41
=
false
;
static
bool
is_gl41
=
false
;
void
setup
()
{
void
setup
()
{
std
::
string
ver
=
version
();
std
::
string
ver
=
version
();
is_gl45
=
ver
.
find
(
"4.5"
)
!=
std
::
string
::
npos
;
is_gl45
=
ver
.
find
(
"4.5"
)
!=
std
::
string
::
npos
;
is_gl41
=
ver
.
find
(
"4.1"
)
!=
std
::
string
::
npos
;
is_gl41
=
ver
.
find
(
"4.1"
)
!=
std
::
string
::
npos
;
setup_debug_proc
();
setup_debug_proc
();
Effects
::
init
();
Effects
::
init
();
}
}
void
shutdown
()
{
void
shutdown
()
{
Effects
::
destroy
();
Effects
::
destroy
();
check_leaked_handles
();
check_leaked_handles
();
}
}
void
color_mask
(
bool
enable
)
{
void
color_mask
(
bool
enable
)
{
glColorMask
(
enable
,
enable
,
enable
,
enable
);
}
glColorMask
(
enable
,
enable
,
enable
,
enable
);
}
std
::
string
version
()
{
std
::
string
version
()
{
return
std
::
string
((
char
*
)
glGetString
(
GL_VERSION
));
}
return
std
::
string
((
char
*
)
glGetString
(
GL_VERSION
));
std
::
string
renderer
()
{
return
std
::
string
((
char
*
)
glGetString
(
GL_RENDERER
));
}
}
std
::
string
renderer
()
{
return
std
::
string
((
char
*
)
glGetString
(
GL_RENDERER
));
}
void
global_params
()
{
void
global_params
()
{
glEnable
(
GL_BLEND
);
glEnable
(
GL_BLEND
);
glBlendFunc
(
GL_ONE
,
GL_ONE_MINUS_SRC_ALPHA
);
glBlendFunc
(
GL_ONE
,
GL_ONE_MINUS_SRC_ALPHA
);
glPolygonOffset
(
1.0
f
,
1.0
f
);
glPolygonOffset
(
1.0
f
,
1.0
f
);
glEnable
(
GL_DEPTH_TEST
);
glEnable
(
GL_DEPTH_TEST
);
glDepthFunc
(
GL_GREATER
);
glDepthFunc
(
GL_GREATER
);
glClearDepth
(
0.0
);
glClearDepth
(
0.0
);
if
(
glClipControl
)
glClipControl
(
GL_LOWER_LEFT
,
GL_ZERO_TO_ONE
);
if
(
glClipControl
)
glCullFace
(
GL_BACK
);
glClipControl
(
GL_LOWER_LEFT
,
GL_ZERO_TO_ONE
);
glCullFace
(
GL_BACK
);
}
}
void
clear_screen
(
Vec4
col
)
{
void
clear_screen
(
Vec4
col
)
{
Framebuffer
::
bind_screen
();
Framebuffer
::
bind_screen
();
glClearColor
(
col
.
x
,
col
.
y
,
col
.
z
,
col
.
w
);
glClearColor
(
col
.
x
,
col
.
y
,
col
.
z
,
col
.
w
);
glClear
(
GL_COLOR_BUFFER_BIT
|
GL_DEPTH_BUFFER_BIT
);
glClear
(
GL_COLOR_BUFFER_BIT
|
GL_DEPTH_BUFFER_BIT
);
}
}
void
enable
(
Opt
opt
)
{
void
enable
(
Opt
opt
)
{
switch
(
opt
)
{
switch
(
opt
)
{
case
Opt
::
wireframe
:
{
case
Opt
::
wireframe
:
{
glEnable
(
GL_POLYGON_OFFSET_LINE
);
glEnable
(
GL_POLYGON_OFFSET_LINE
);
glPolygonMode
(
GL_FRONT_AND_BACK
,
GL_LINE
);
glPolygonMode
(
GL_FRONT_AND_BACK
,
GL_LINE
);
}
break
;
}
break
;
case
Opt
::
offset
:
{
case
Opt
::
offset
:
{
glEnable
(
GL_POLYGON_OFFSET_FILL
);
glEnable
(
GL_POLYGON_OFFSET_FILL
);
}
break
;
}
break
;
case
Opt
::
culling
:
{
case
Opt
::
culling
:
{
glEnable
(
GL_CULL_FACE
);
glEnable
(
GL_CULL_FACE
);
}
break
;
}
break
;
case
Opt
::
depth_write
:
{
case
Opt
::
depth_write
:
{
glDepthMask
(
GL_TRUE
);
glDepthMask
(
GL_TRUE
);
}
break
;
}
break
;
}
}
}
}
void
disable
(
Opt
opt
)
{
void
disable
(
Opt
opt
)
{
switch
(
opt
)
{
switch
(
opt
)
{
case
Opt
::
wireframe
:
{
case
Opt
::
wireframe
:
{
glPolygonMode
(
GL_FRONT_AND_BACK
,
GL_FILL
);
glPolygonMode
(
GL_FRONT_AND_BACK
,
GL_FILL
);
glDisable
(
GL_POLYGON_OFFSET_LINE
);
glDisable
(
GL_POLYGON_OFFSET_LINE
);
}
break
;
}
break
;
case
Opt
::
offset
:
{
case
Opt
::
offset
:
{
glDisable
(
GL_POLYGON_OFFSET_FILL
);
glDisable
(
GL_POLYGON_OFFSET_FILL
);
}
break
;
}
break
;
case
Opt
::
culling
:
{
case
Opt
::
culling
:
{
glDisable
(
GL_CULL_FACE
);
glDisable
(
GL_CULL_FACE
);
}
break
;
}
break
;
case
Opt
::
depth_write
:
{
case
Opt
::
depth_write
:
{
glDepthMask
(
GL_FALSE
);
glDepthMask
(
GL_FALSE
);
}
break
;
}
break
;
}
}
}
}
void
viewport
(
Vec2
dim
)
{
void
viewport
(
Vec2
dim
)
{
glViewport
(
0
,
0
,
(
GLsizei
)
dim
.
x
,
(
GLsizei
)
dim
.
y
);
}
glViewport
(
0
,
0
,
(
GLsizei
)
dim
.
x
,
(
GLsizei
)
dim
.
y
);
}
int
max_msaa
()
{
int
max_msaa
()
{
int
samples
;
int
samples
;
glGetIntegerv
(
GL_MAX_SAMPLES
,
&
samples
);
glGetIntegerv
(
GL_MAX_SAMPLES
,
&
samples
);
return
samples
;
return
samples
;
}
}
Tex2D
::
Tex2D
()
{
Tex2D
::
Tex2D
()
{
id
=
0
;
}
id
=
0
;
}
Tex2D
::
Tex2D
(
Tex2D
&&
src
)
{
Tex2D
::
Tex2D
(
Tex2D
&&
src
)
{
id
=
src
.
id
;
src
.
id
=
0
;
id
=
src
.
id
;
src
.
id
=
0
;
}
}
Tex2D
::~
Tex2D
()
{
Tex2D
::~
Tex2D
()
{
if
(
id
)
glDeleteTextures
(
1
,
&
id
);
if
(
id
)
id
=
0
;
glDeleteTextures
(
1
,
&
id
);
id
=
0
;
}
}
void
Tex2D
::
operator
=
(
Tex2D
&&
src
)
{
void
Tex2D
::
operator
=
(
Tex2D
&&
src
)
{
if
(
id
)
glDeleteTextures
(
1
,
&
id
);
if
(
id
)
id
=
src
.
id
;
src
.
id
=
0
;
glDeleteTextures
(
1
,
&
id
);
id
=
src
.
id
;
src
.
id
=
0
;
}
}
void
Tex2D
::
bind
(
int
idx
)
const
{
void
Tex2D
::
bind
(
int
idx
)
const
{
glActiveTexture
(
GL_TEXTURE0
+
idx
);
glActiveTexture
(
GL_TEXTURE0
+
idx
);
glBindTexture
(
GL_TEXTURE_2D
,
id
);
glBindTexture
(
GL_TEXTURE_2D
,
id
);
}
}
void
Tex2D
::
image
(
int
w
,
int
h
,
unsigned
char
*
img
)
{
void
Tex2D
::
image
(
int
w
,
int
h
,
unsigned
char
*
img
)
{
if
(
!
id
)
glGenTextures
(
1
,
&
id
);
if
(
!
id
)
glBindTexture
(
GL_TEXTURE_2D
,
id
);
glGenTextures
(
1
,
&
id
);
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA8
,
w
,
h
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
img
);
glBindTexture
(
GL_TEXTURE_2D
,
id
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_S
,
GL_CLAMP_TO_EDGE
);
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA8
,
w
,
h
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
img
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_T
,
GL_CLAMP_TO_EDGE
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_S
,
GL_CLAMP_TO_EDGE
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_LINEAR
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_T
,
GL_CLAMP_TO_EDGE
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_LINEAR
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_LINEAR
);
glBindTexture
(
GL_TEXTURE_2D
,
0
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_LINEAR
);
}
glBindTexture
(
GL_TEXTURE_2D
,
0
);
}
TexID
Tex2D
::
get_id
()
const
{
return
id
;
TexID
Tex2D
::
get_id
()
const
{
return
id
;
}
}
Mesh
::
Mesh
()
{
create
();
}
Mesh
::
Mesh
()
{
create
();
Mesh
::
Mesh
(
std
::
vector
<
Vert
>
&&
vertices
,
std
::
vector
<
Index
>
&&
indices
)
{
}
create
();
recreate
(
std
::
move
(
vertices
),
std
::
move
(
indices
));
Mesh
::
Mesh
(
std
::
vector
<
Vert
>&&
vertices
,
std
::
vector
<
Index
>&&
indices
)
{
}
create
();
recreate
(
std
::
move
(
vertices
),
std
::
move
(
indices
));
Mesh
::
Mesh
(
Mesh
&&
src
)
{
}
vao
=
src
.
vao
;
src
.
vao
=
0
;
Mesh
::
Mesh
(
Mesh
&&
src
)
{
ebo
=
src
.
ebo
;
vao
=
src
.
vao
;
src
.
vao
=
0
;
src
.
ebo
=
0
;
ebo
=
src
.
ebo
;
src
.
ebo
=
0
;
vbo
=
src
.
vbo
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
src
.
vbo
=
0
;
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
dirty
=
src
.
dirty
;
n_elem
=
src
.
n_elem
;
src
.
n_elem
=
0
;
src
.
dirty
=
true
;
_bbox
=
src
.
_bbox
;
src
.
_bbox
.
reset
();
n_elem
=
src
.
n_elem
;
_verts
=
std
::
move
(
src
.
_verts
);
src
.
n_elem
=
0
;
_idxs
=
std
::
move
(
src
.
_idxs
);
_bbox
=
src
.
_bbox
;
}
src
.
_bbox
.
reset
();
_verts
=
std
::
move
(
src
.
_verts
);
void
Mesh
::
operator
=
(
Mesh
&&
src
)
{
_idxs
=
std
::
move
(
src
.
_idxs
);
destroy
();
}
vao
=
src
.
vao
;
src
.
vao
=
0
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
void
Mesh
::
operator
=
(
Mesh
&&
src
)
{
ebo
=
src
.
ebo
;
src
.
ebo
=
0
;
destroy
();
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
vao
=
src
.
vao
;
n_elem
=
src
.
n_elem
;
src
.
n_elem
=
0
;
src
.
vao
=
0
;
_bbox
=
src
.
_bbox
;
src
.
_bbox
.
reset
();
vbo
=
src
.
vbo
;
_verts
=
std
::
move
(
src
.
_verts
);
src
.
vbo
=
0
;
_idxs
=
std
::
move
(
src
.
_idxs
);
ebo
=
src
.
ebo
;
}
src
.
ebo
=
0
;
dirty
=
src
.
dirty
;
Mesh
::~
Mesh
()
{
src
.
dirty
=
true
;
destroy
();
n_elem
=
src
.
n_elem
;
}
src
.
n_elem
=
0
;
_bbox
=
src
.
_bbox
;
src
.
_bbox
.
reset
();
_verts
=
std
::
move
(
src
.
_verts
);
_idxs
=
std
::
move
(
src
.
_idxs
);
}
Mesh
::~
Mesh
()
{
destroy
();
}
void
Mesh
::
create
()
{
void
Mesh
::
create
()
{
// Hack to let stuff get created for headless mode
// Hack to let stuff get created for headless mode
if
(
!
glGenVertexArrays
)
return
;
if
(
!
glGenVertexArrays
)
return
;
glGenVertexArrays
(
1
,
&
vao
);
glGenVertexArrays
(
1
,
&
vao
);
glGenBuffers
(
1
,
&
vbo
);
glGenBuffers
(
1
,
&
vbo
);
glGenBuffers
(
1
,
&
ebo
);
glGenBuffers
(
1
,
&
ebo
);
glBindVertexArray
(
vao
);
glBindVertexArray
(
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glVertexAttribPointer
(
0
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
0
);
glVertexAttribPointer
(
0
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
0
);
glEnableVertexAttribArray
(
0
);
glEnableVertexAttribArray
(
0
);
glVertexAttribPointer
(
1
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
sizeof
(
Vec3
));
glVertexAttribPointer
(
1
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
sizeof
(
Vec3
));
glEnableVertexAttribArray
(
1
);
glEnableVertexAttribArray
(
1
);
glVertexAttribIPointer
(
2
,
1
,
GL_UNSIGNED_INT
,
sizeof
(
Vert
),
(
GLvoid
*
)(
2
*
sizeof
(
Vec3
)));
glVertexAttribIPointer
(
2
,
1
,
GL_UNSIGNED_INT
,
sizeof
(
Vert
),
(
GLvoid
*
)(
2
*
sizeof
(
Vec3
)));
glEnableVertexAttribArray
(
2
);
glEnableVertexAttribArray
(
2
);
glBindBuffer
(
GL_ELEMENT_ARRAY_BUFFER
,
ebo
);
glBindBuffer
(
GL_ELEMENT_ARRAY_BUFFER
,
ebo
);
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
}
}
void
Mesh
::
destroy
()
{
void
Mesh
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glDeleteBuffers
)
return
;
if
(
!
glDeleteBuffers
)
return
;
glDeleteBuffers
(
1
,
&
ebo
);
glDeleteBuffers
(
1
,
&
ebo
);
glDeleteBuffers
(
1
,
&
vbo
);
glDeleteBuffers
(
1
,
&
vbo
);
glDeleteVertexArrays
(
1
,
&
vao
);
glDeleteVertexArrays
(
1
,
&
vao
);
ebo
=
vao
=
vbo
=
0
;
ebo
=
vao
=
vbo
=
0
;
}
}
void
Mesh
::
update
()
{
void
Mesh
::
update
()
{
glBindVertexArray
(
vao
);
glBindVertexArray
(
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Vert
)
*
_verts
.
size
(),
_verts
.
data
(),
GL_DYNAMIC_DRAW
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Vert
)
*
_verts
.
size
(),
_verts
.
data
(),
GL_DYNAMIC_DRAW
);
glBindBuffer
(
GL_ELEMENT_ARRAY_BUFFER
,
ebo
);
glBindBuffer
(
GL_ELEMENT_ARRAY_BUFFER
,
ebo
);
glBufferData
(
GL_ELEMENT_ARRAY_BUFFER
,
sizeof
(
Index
)
*
_idxs
.
size
(),
_idxs
.
data
(),
GL_DYNAMIC_DRAW
);
glBufferData
(
GL_ELEMENT_ARRAY_BUFFER
,
sizeof
(
Index
)
*
_idxs
.
size
(),
_idxs
.
data
(),
GL_DYNAMIC_DRAW
);
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
dirty
=
false
;
dirty
=
false
;
}
}
void
Mesh
::
recreate
(
std
::
vector
<
Vert
>&&
vertices
,
std
::
vector
<
Index
>&&
indices
)
{
void
Mesh
::
recreate
(
std
::
vector
<
Vert
>
&&
vertices
,
std
::
vector
<
Index
>
&&
indices
)
{
dirty
=
true
;
dirty
=
true
;
_verts
=
std
::
move
(
vertices
);
_verts
=
std
::
move
(
vertices
);
_idxs
=
std
::
move
(
indices
);
_idxs
=
std
::
move
(
indices
);
_bbox
.
reset
();
_bbox
.
reset
();
for
(
auto
&
v
:
_verts
)
{
for
(
auto
&
v
:
_verts
)
{
_bbox
.
enclose
(
v
.
pos
);
_bbox
.
enclose
(
v
.
pos
);
}
}
n_elem
=
(
GLuint
)
_idxs
.
size
();
n_elem
=
(
GLuint
)
_idxs
.
size
();
}
}
GLuint
Mesh
::
tris
()
const
{
GLuint
Mesh
::
tris
()
const
{
return
n_elem
/
3
;
}
return
n_elem
/
3
;
}
std
::
vector
<
Mesh
::
Vert
>
&
Mesh
::
edit_verts
()
{
std
::
vector
<
Mesh
::
Vert
>
&
Mesh
::
edit_verts
()
{
dirty
=
true
;
dirty
=
true
;
return
_verts
;
return
_verts
;
}
}
std
::
vector
<
Mesh
::
Index
>
&
Mesh
::
edit_indices
()
{
std
::
vector
<
Mesh
::
Index
>
&
Mesh
::
edit_indices
()
{
dirty
=
true
;
dirty
=
true
;
return
_idxs
;
return
_idxs
;
}
}
const
std
::
vector
<
Mesh
::
Vert
>&
Mesh
::
verts
()
const
{
const
std
::
vector
<
Mesh
::
Vert
>
&
Mesh
::
verts
()
const
{
return
_verts
;
}
return
_verts
;
}
const
std
::
vector
<
Mesh
::
Index
>&
Mesh
::
indices
()
const
{
const
std
::
vector
<
Mesh
::
Index
>
&
Mesh
::
indices
()
const
{
return
_idxs
;
}
return
_idxs
;
}
BBox
Mesh
::
bbox
()
const
{
BBox
Mesh
::
bbox
()
const
{
return
_bbox
;
}
return
_bbox
;
}
void
Mesh
::
render
()
{
void
Mesh
::
render
()
{
if
(
dirty
)
update
();
if
(
dirty
)
glBindVertexArray
(
vao
);
update
();
glDrawElements
(
GL_TRIANGLES
,
n_elem
,
GL_UNSIGNED_INT
,
nullptr
);
glBindVertexArray
(
vao
);
glBindVertexArray
(
0
);
glDrawElements
(
GL_TRIANGLES
,
n_elem
,
GL_UNSIGNED_INT
,
nullptr
);
glBindVertexArray
(
0
);
}
}
Instances
::
Instances
(
GL
::
Mesh
&&
mesh
)
:
mesh
(
std
::
move
(
mesh
))
{
Instances
::
Instances
(
GL
::
Mesh
&&
mesh
)
:
mesh
(
std
::
move
(
mesh
))
{
create
();
}
create
();
}
Instances
::
Instances
(
Instances
&&
src
)
{
Instances
::
Instances
(
Instances
&&
src
)
{
mesh
=
std
::
move
(
src
.
mesh
);
mesh
=
std
::
move
(
src
.
mesh
);
data
=
std
::
move
(
src
.
data
);
data
=
std
::
move
(
src
.
data
);
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
vbo
=
src
.
vbo
;
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
src
.
vbo
=
0
;
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
}
}
Instances
::~
Instances
()
{
Instances
::~
Instances
()
{
destroy
();
}
destroy
();
}
void
Instances
::
operator
=
(
Instances
&&
src
)
{
void
Instances
::
operator
=
(
Instances
&&
src
)
{
destroy
();
destroy
();
mesh
=
std
::
move
(
src
.
mesh
);
mesh
=
std
::
move
(
src
.
mesh
);
data
=
std
::
move
(
src
.
data
);
data
=
std
::
move
(
src
.
data
);
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
vbo
=
src
.
vbo
;
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
src
.
vbo
=
0
;
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
}
}
void
Instances
::
create
()
{
void
Instances
::
create
()
{
// Hack to let stuff get created for headless mode
// Hack to let stuff get created for headless mode
if
(
!
glGenBuffers
)
return
;
if
(
!
glGenBuffers
)
return
;
glGenBuffers
(
1
,
&
vbo
);
glBindVertexArray
(
mesh
.
vao
);
glGenBuffers
(
1
,
&
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindVertexArray
(
mesh
.
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glEnableVertexAttribArray
(
3
);
glVertexAttribIPointer
(
3
,
1
,
GL_UNSIGNED_INT
,
sizeof
(
Info
),
(
GLvoid
*
)
0
);
glEnableVertexAttribArray
(
3
);
glVertexAttribDivisor
(
3
,
1
);
glVertexAttribIPointer
(
3
,
1
,
GL_UNSIGNED_INT
,
sizeof
(
Info
),
(
GLvoid
*
)
0
);
glVertexAttribDivisor
(
3
,
1
);
const
int
base_idx
=
4
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
const
int
base_idx
=
4
;
glEnableVertexAttribArray
(
base_idx
+
i
);
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
glVertexAttribPointer
(
base_idx
+
i
,
4
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Info
),
(
void
*
)(
sizeof
(
GLuint
)
+
sizeof
(
Vec4
)
*
i
));
glEnableVertexAttribArray
(
base_idx
+
i
);
glVertexAttribDivisor
(
base_idx
+
i
,
1
);
glVertexAttribPointer
(
base_idx
+
i
,
4
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Info
),
}
(
void
*
)(
sizeof
(
GLuint
)
+
sizeof
(
Vec4
)
*
i
));
glBindVertexArray
(
0
);
glVertexAttribDivisor
(
base_idx
+
i
,
1
);
}
glBindVertexArray
(
0
);
}
}
void
Instances
::
render
()
{
void
Instances
::
render
()
{
if
(
mesh
.
dirty
)
mesh
.
update
();
if
(
dirty
)
update
();
glBindVertexArray
(
mesh
.
vao
);
if
(
mesh
.
dirty
)
glDrawElementsInstanced
(
GL_TRIANGLES
,
mesh
.
n_elem
,
GL_UNSIGNED_INT
,
nullptr
,
(
GLsizei
)
data
.
size
());
mesh
.
update
();
glBindVertexArray
(
0
);
if
(
dirty
)
update
();
glBindVertexArray
(
mesh
.
vao
);
glDrawElementsInstanced
(
GL_TRIANGLES
,
mesh
.
n_elem
,
GL_UNSIGNED_INT
,
nullptr
,
(
GLsizei
)
data
.
size
());
glBindVertexArray
(
0
);
}
}
Instances
::
Info
&
Instances
::
get
(
size_t
idx
)
{
Instances
::
Info
&
Instances
::
get
(
size_t
idx
)
{
dirty
=
true
;
dirty
=
true
;
return
data
[
idx
];
return
data
[
idx
];
}
}
size_t
Instances
::
add
(
const
Mat4
&
transform
,
GLuint
id
)
{
size_t
Instances
::
add
(
const
Mat4
&
transform
,
GLuint
id
)
{
data
.
push_back
({
id
,
transform
});
data
.
push_back
({
id
,
transform
});
dirty
=
true
;
dirty
=
true
;
return
data
.
size
()
-
1
;
return
data
.
size
()
-
1
;
}
}
void
Instances
::
clear
()
{
void
Instances
::
clear
()
{
data
.
clear
();
data
.
clear
();
dirty
=
true
;
dirty
=
true
;
}
}
void
Instances
::
update
()
{
void
Instances
::
update
()
{
glBindVertexArray
(
mesh
.
vao
);
glBindVertexArray
(
mesh
.
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Info
)
*
data
.
size
(),
data
.
data
(),
GL_DYNAMIC_DRAW
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Info
)
*
data
.
size
(),
data
.
data
(),
GL_DYNAMIC_DRAW
);
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
dirty
=
false
;
dirty
=
false
;
}
}
void
Instances
::
destroy
()
{
void
Instances
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glDeleteBuffers
)
return
;
if
(
!
glDeleteBuffers
)
return
;
glDeleteBuffers
(
1
,
&
vbo
);
glDeleteBuffers
(
1
,
&
vbo
);
vbo
=
0
;
vbo
=
0
;
mesh
.
destroy
();
mesh
.
destroy
();
}
}
Lines
::
Lines
(
std
::
vector
<
Vert
>&&
verts
,
float
thickness
)
Lines
::
Lines
(
std
::
vector
<
Vert
>
&&
verts
,
float
thickness
)
:
thickness
(
thickness
),
vertices
(
std
::
move
(
verts
))
{
:
thickness
(
thickness
),
vertices
(
std
::
move
(
verts
))
{
create
();
create
();
dirty
=
true
;
dirty
=
true
;
}
}
Lines
::
Lines
(
float
thickness
)
:
thickness
(
thickness
)
{
Lines
::
Lines
(
float
thickness
)
:
thickness
(
thickness
)
{
create
();
}
create
();
}
Lines
::
Lines
(
Lines
&&
src
)
{
Lines
::
Lines
(
Lines
&&
src
)
{
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
dirty
=
src
.
dirty
;
thickness
=
src
.
thickness
;
src
.
thickness
=
0.0
f
;
src
.
dirty
=
true
;
vao
=
src
.
vao
;
src
.
vao
=
0
;
thickness
=
src
.
thickness
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
src
.
thickness
=
0.0
f
;
vertices
=
std
::
move
(
src
.
vertices
);
vao
=
src
.
vao
;
src
.
vao
=
0
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
vertices
=
std
::
move
(
src
.
vertices
);
}
}
void
Lines
::
operator
=
(
Lines
&&
src
)
{
void
Lines
::
operator
=
(
Lines
&&
src
)
{
destroy
();
destroy
();
dirty
=
src
.
dirty
;
src
.
dirty
=
true
;
dirty
=
src
.
dirty
;
thickness
=
src
.
thickness
;
src
.
thickness
=
0.0
f
;
src
.
dirty
=
true
;
vao
=
src
.
vao
;
src
.
vao
=
0
;
thickness
=
src
.
thickness
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
src
.
thickness
=
0.0
f
;
vertices
=
std
::
move
(
src
.
vertices
);
vao
=
src
.
vao
;
src
.
vao
=
0
;
vbo
=
src
.
vbo
;
src
.
vbo
=
0
;
vertices
=
std
::
move
(
src
.
vertices
);
}
}
Lines
::~
Lines
()
{
Lines
::~
Lines
()
{
destroy
();
}
destroy
();
}
void
Lines
::
update
()
const
{
void
Lines
::
update
()
const
{
glBindVertexArray
(
vao
);
glBindVertexArray
(
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Vert
)
*
vertices
.
size
(),
vertices
.
data
(),
GL_DYNAMIC_DRAW
);
glBufferData
(
GL_ARRAY_BUFFER
,
sizeof
(
Vert
)
*
vertices
.
size
(),
vertices
.
data
(),
GL_DYNAMIC_DRAW
);
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
dirty
=
false
;
dirty
=
false
;
}
}
void
Lines
::
render
(
bool
smooth
)
const
{
void
Lines
::
render
(
bool
smooth
)
const
{
if
(
dirty
)
update
();
if
(
dirty
)
update
();
glLineWidth
(
thickness
);
glLineWidth
(
thickness
);
if
(
smooth
)
glEnable
(
GL_LINE_SMOOTH
);
if
(
smooth
)
else
glDisable
(
GL_LINE_SMOOTH
);
glEnable
(
GL_LINE_SMOOTH
);
else
glDisable
(
GL_LINE_SMOOTH
);
glBindVertexArray
(
vao
);
glBindVertexArray
(
vao
);
glDrawArrays
(
GL_LINES
,
0
,
(
GLsizei
)
vertices
.
size
());
glDrawArrays
(
GL_LINES
,
0
,
(
GLsizei
)
vertices
.
size
());
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
}
}
void
Lines
::
clear
()
{
void
Lines
::
clear
()
{
vertices
.
clear
();
vertices
.
clear
();
dirty
=
true
;
dirty
=
true
;
}
}
void
Lines
::
pop
()
{
void
Lines
::
pop
()
{
vertices
.
pop_back
();
vertices
.
pop_back
();
vertices
.
pop_back
();
vertices
.
pop_back
();
dirty
=
true
;
dirty
=
true
;
}
}
void
Lines
::
add
(
Vec3
start
,
Vec3
end
,
Vec3
color
)
{
void
Lines
::
add
(
Vec3
start
,
Vec3
end
,
Vec3
color
)
{
vertices
.
push_back
({
start
,
color
});
vertices
.
push_back
({
start
,
color
});
vertices
.
push_back
({
end
,
color
});
vertices
.
push_back
({
end
,
color
});
dirty
=
true
;
dirty
=
true
;
}
}
void
Lines
::
create
()
{
void
Lines
::
create
()
{
// Hack to let stuff get created for headless mode
// Hack to let stuff get created for headless mode
if
(
!
glGenBuffers
)
return
;
if
(
!
glGenBuffers
)
return
;
glGenVertexArrays
(
1
,
&
vao
);
glGenVertexArrays
(
1
,
&
vao
);
glGenBuffers
(
1
,
&
vbo
);
glGenBuffers
(
1
,
&
vbo
);
glBindVertexArray
(
vao
);
glBindVertexArray
(
vao
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glBindBuffer
(
GL_ARRAY_BUFFER
,
vbo
);
glVertexAttribPointer
(
0
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
0
);
glVertexAttribPointer
(
0
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
0
);
glEnableVertexAttribArray
(
0
);
glEnableVertexAttribArray
(
0
);
glVertexAttribPointer
(
1
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
sizeof
(
Vec3
));
glVertexAttribPointer
(
1
,
3
,
GL_FLOAT
,
GL_FALSE
,
sizeof
(
Vert
),
(
GLvoid
*
)
sizeof
(
Vec3
));
glEnableVertexAttribArray
(
1
);
glEnableVertexAttribArray
(
1
);
glBindVertexArray
(
0
);
glBindVertexArray
(
0
);
}
}
void
Lines
::
destroy
()
{
void
Lines
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glDeleteBuffers
)
return
;
if
(
!
glDeleteBuffers
)
return
;
glDeleteBuffers
(
1
,
&
vbo
);
glDeleteBuffers
(
1
,
&
vbo
);
glDeleteVertexArrays
(
1
,
&
vao
);
glDeleteVertexArrays
(
1
,
&
vao
);
vao
=
vbo
=
0
;
vao
=
vbo
=
0
;
vertices
.
clear
();
vertices
.
clear
();
dirty
=
false
;
dirty
=
false
;
}
}
Shader
::
Shader
()
{}
Shader
::
Shader
()
{}
Shader
::
Shader
(
std
::
string
vertex
,
std
::
string
fragment
)
{
Shader
::
Shader
(
std
::
string
vertex
,
std
::
string
fragment
)
{
load
(
vertex
,
fragment
);
}
load
(
vertex
,
fragment
);
}
Shader
::
Shader
(
Shader
&&
src
)
{
Shader
::
Shader
(
Shader
&&
src
)
{
program
=
src
.
program
;
src
.
program
=
0
;
program
=
src
.
program
;
v
=
src
.
v
;
src
.
v
=
0
;
src
.
program
=
0
;
f
=
src
.
f
;
src
.
f
=
0
;
v
=
src
.
v
;
src
.
v
=
0
;
f
=
src
.
f
;
src
.
f
=
0
;
}
}
void
Shader
::
operator
=
(
Shader
&&
src
)
{
void
Shader
::
operator
=
(
Shader
&&
src
)
{
destroy
();
destroy
();
program
=
src
.
program
;
src
.
program
=
0
;
program
=
src
.
program
;
v
=
src
.
v
;
src
.
v
=
0
;
src
.
program
=
0
;
f
=
src
.
f
;
src
.
f
=
0
;
v
=
src
.
v
;
src
.
v
=
0
;
f
=
src
.
f
;
src
.
f
=
0
;
}
}
Shader
::~
Shader
()
{
Shader
::~
Shader
()
{
destroy
();
}
destroy
();
}
void
Shader
::
bind
()
const
{
void
Shader
::
bind
()
const
{
glUseProgram
(
program
);
}
glUseProgram
(
program
);
}
void
Shader
::
destroy
()
{
void
Shader
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glUseProgram
)
return
;
if
(
!
glUseProgram
)
return
;
glUseProgram
(
0
);
glUseProgram
(
0
);
glDeleteShader
(
v
);
glDeleteShader
(
v
);
glDeleteShader
(
f
);
glDeleteShader
(
f
);
glDeleteProgram
(
program
);
glDeleteProgram
(
program
);
v
=
f
=
program
=
0
;
v
=
f
=
program
=
0
;
}
}
void
Shader
::
uniform_block
(
std
::
string
name
,
GLuint
i
)
const
{
void
Shader
::
uniform_block
(
std
::
string
name
,
GLuint
i
)
const
{
GLuint
idx
=
glGetUniformBlockIndex
(
program
,
name
.
c_str
());
GLuint
idx
=
glGetUniformBlockIndex
(
program
,
name
.
c_str
());
glUniformBlockBinding
(
program
,
idx
,
i
);
glUniformBlockBinding
(
program
,
idx
,
i
);
}
}
void
Shader
::
uniform
(
std
::
string
name
,
int
count
,
const
Vec2
items
[])
const
{
void
Shader
::
uniform
(
std
::
string
name
,
int
count
,
const
Vec2
items
[])
const
{
glUniform2fv
(
loc
(
name
),
count
,
(
GLfloat
*
)
items
);
glUniform2fv
(
loc
(
name
),
count
,
(
GLfloat
*
)
items
);
}
}
void
Shader
::
uniform
(
std
::
string
name
,
GLfloat
fl
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
GLfloat
fl
)
const
{
glUniform1f
(
loc
(
name
),
fl
);
}
glUniform1f
(
loc
(
name
),
fl
);
}
void
Shader
::
uniform
(
std
::
string
name
,
const
Mat4
&
mat
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
const
Mat4
&
mat
)
const
{
glUniformMatrix4fv
(
loc
(
name
),
1
,
GL_FALSE
,
mat
.
data
);
glUniformMatrix4fv
(
loc
(
name
),
1
,
GL_FALSE
,
mat
.
data
);
}
}
void
Shader
::
uniform
(
std
::
string
name
,
Vec3
vec3
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
Vec3
vec3
)
const
{
glUniform3fv
(
loc
(
name
),
1
,
vec3
.
data
);
}
glUniform3fv
(
loc
(
name
),
1
,
vec3
.
data
);
}
void
Shader
::
uniform
(
std
::
string
name
,
Vec2
vec2
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
Vec2
vec2
)
const
{
glUniform2fv
(
loc
(
name
),
1
,
vec2
.
data
);
}
glUniform2fv
(
loc
(
name
),
1
,
vec2
.
data
);
}
void
Shader
::
uniform
(
std
::
string
name
,
GLint
i
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
GLint
i
)
const
{
glUniform1i
(
loc
(
name
),
i
);
}
glUniform1i
(
loc
(
name
),
i
);
}
void
Shader
::
uniform
(
std
::
string
name
,
GLuint
i
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
GLuint
i
)
const
{
glUniform1ui
(
loc
(
name
),
i
);
}
glUniform1ui
(
loc
(
name
),
i
);
}
void
Shader
::
uniform
(
std
::
string
name
,
bool
b
)
const
{
void
Shader
::
uniform
(
std
::
string
name
,
bool
b
)
const
{
glUniform1i
(
loc
(
name
),
b
);
}
glUniform1i
(
loc
(
name
),
b
);
}
GLuint
Shader
::
loc
(
std
::
string
name
)
const
{
return
glGetUniformLocation
(
program
,
name
.
c_str
());
GLuint
Shader
::
loc
(
std
::
string
name
)
const
{
return
glGetUniformLocation
(
program
,
name
.
c_str
());
}
}
void
Shader
::
load
(
std
::
string
vertex
,
std
::
string
fragment
)
{
void
Shader
::
load
(
std
::
string
vertex
,
std
::
string
fragment
)
{
v
=
glCreateShader
(
GL_VERTEX_SHADER
);
v
=
glCreateShader
(
GL_VERTEX_SHADER
);
f
=
glCreateShader
(
GL_FRAGMENT_SHADER
);
f
=
glCreateShader
(
GL_FRAGMENT_SHADER
);
const
GLchar
*
vs_c
=
vertex
.
c_str
();
const
GLchar
*
vs_c
=
vertex
.
c_str
();
const
GLchar
*
fs_c
=
fragment
.
c_str
();
const
GLchar
*
fs_c
=
fragment
.
c_str
();
glShaderSource
(
v
,
1
,
&
vs_c
,
NULL
);
glShaderSource
(
v
,
1
,
&
vs_c
,
NULL
);
glShaderSource
(
f
,
1
,
&
fs_c
,
NULL
);
glShaderSource
(
f
,
1
,
&
fs_c
,
NULL
);
glCompileShader
(
v
);
glCompileShader
(
v
);
glCompileShader
(
f
);
glCompileShader
(
f
);
if
(
!
validate
(
v
))
{
if
(
!
validate
(
v
))
{
destroy
();
destroy
();
return
;
return
;
}
}
if
(
!
validate
(
f
))
{
if
(
!
validate
(
f
))
{
destroy
();
destroy
();
return
;
return
;
}
}
program
=
glCreateProgram
();
program
=
glCreateProgram
();
glAttachShader
(
program
,
v
);
glAttachShader
(
program
,
v
);
glAttachShader
(
program
,
f
);
glAttachShader
(
program
,
f
);
glLinkProgram
(
program
);
glLinkProgram
(
program
);
}
}
bool
Shader
::
validate
(
GLuint
program
)
{
bool
Shader
::
validate
(
GLuint
program
)
{
GLint
compiled
=
0
;
GLint
compiled
=
0
;
glGetShaderiv
(
program
,
GL_COMPILE_STATUS
,
&
compiled
);
glGetShaderiv
(
program
,
GL_COMPILE_STATUS
,
&
compiled
);
if
(
compiled
==
GL_FALSE
)
{
if
(
compiled
==
GL_FALSE
)
{
GLint
len
=
0
;
glGetShaderiv
(
program
,
GL_INFO_LOG_LENGTH
,
&
len
);
GLchar
*
msg
=
new
GLchar
[
len
]
;
GLint
len
=
0
;
glGetShader
InfoLog
(
program
,
len
,
&
len
,
msg
);
glGetShader
iv
(
program
,
GL_INFO_LOG_LENGTH
,
&
len
);
warn
(
"Shader %d failed to compile: %s"
,
program
,
msg
)
;
GLchar
*
msg
=
new
GLchar
[
len
]
;
delete
[]
msg
;
glGetShaderInfoLog
(
program
,
len
,
&
len
,
msg
)
;
return
false
;
warn
(
"Shader %d failed to compile: %s"
,
program
,
msg
);
}
delete
[]
msg
;
return
true
;
return
false
;
}
return
true
;
}
}
Framebuffer
::
Framebuffer
()
{}
Framebuffer
::
Framebuffer
()
{}
Framebuffer
::
Framebuffer
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
)
{
Framebuffer
::
Framebuffer
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
)
{
setup
(
outputs
,
dim
,
samples
,
d
);
setup
(
outputs
,
dim
,
samples
,
d
);
}
}
void
Framebuffer
::
setup
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
)
{
void
Framebuffer
::
setup
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
)
{
destroy
();
destroy
();
assert
(
outputs
>=
0
&&
outputs
<
31
);
assert
(
outputs
>=
0
&&
outputs
<
31
);
depth
=
d
;
depth
=
d
;
output_textures
.
resize
(
outputs
);
output_textures
.
resize
(
outputs
);
resize
(
dim
,
samples
);
resize
(
dim
,
samples
);
}
}
Framebuffer
::
Framebuffer
(
Framebuffer
&&
src
)
{
Framebuffer
::
Framebuffer
(
Framebuffer
&&
src
)
{
output_textures
=
std
::
move
(
src
.
output_textures
);
output_textures
=
std
::
move
(
src
.
output_textures
);
depth_tex
=
src
.
depth_tex
;
src
.
depth_tex
=
0
;
depth_tex
=
src
.
depth_tex
;
framebuffer
=
src
.
framebuffer
;
src
.
framebuffer
=
0
;
src
.
depth_tex
=
0
;
w
=
src
.
w
;
src
.
w
=
0
;
framebuffer
=
src
.
framebuffer
;
h
=
src
.
h
;
src
.
h
=
0
;
src
.
framebuffer
=
0
;
s
=
src
.
s
;
src
.
s
=
0
;
w
=
src
.
w
;
}
src
.
w
=
0
;
h
=
src
.
h
;
void
Framebuffer
::
operator
=
(
Framebuffer
&&
src
)
{
src
.
h
=
0
;
destroy
();
s
=
src
.
s
;
output_textures
=
std
::
move
(
src
.
output_textures
);
src
.
s
=
0
;
depth_tex
=
src
.
depth_tex
;
src
.
depth_tex
=
0
;
}
framebuffer
=
src
.
framebuffer
;
src
.
framebuffer
=
0
;
w
=
src
.
w
;
src
.
w
=
0
;
void
Framebuffer
::
operator
=
(
Framebuffer
&&
src
)
{
h
=
src
.
h
;
src
.
h
=
0
;
destroy
();
s
=
src
.
s
;
src
.
s
=
0
;
output_textures
=
std
::
move
(
src
.
output_textures
);
}
depth_tex
=
src
.
depth_tex
;
src
.
depth_tex
=
0
;
Framebuffer
::~
Framebuffer
()
{
framebuffer
=
src
.
framebuffer
;
destroy
();
src
.
framebuffer
=
0
;
}
w
=
src
.
w
;
src
.
w
=
0
;
h
=
src
.
h
;
src
.
h
=
0
;
s
=
src
.
s
;
src
.
s
=
0
;
}
Framebuffer
::~
Framebuffer
()
{
destroy
();
}
void
Framebuffer
::
create
()
{
void
Framebuffer
::
create
()
{
// Hack to let stuff get created for headless mode
// Hack to let stuff get created for headless mode
if
(
!
glGenFramebuffers
)
return
;
if
(
!
glGenFramebuffers
)
return
;
glGenFramebuffers
(
1
,
&
framebuffer
);
glGenFramebuffers
(
1
,
&
framebuffer
);
glGenTextures
((
GLsizei
)
output_textures
.
size
(),
(
GLuint
*
)
output_textures
.
data
());
glGenTextures
((
GLsizei
)
output_textures
.
size
(),
(
GLuint
*
)
output_textures
.
data
());
if
(
depth
)
glGenTextures
(
1
,
&
depth_tex
);
if
(
depth
)
glGenTextures
(
1
,
&
depth_tex
);
}
}
void
Framebuffer
::
destroy
()
{
void
Framebuffer
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glDeleteFramebuffers
)
return
;
if
(
!
glDeleteFramebuffers
)
return
;
glDeleteTextures
(
1
,
&
depth_tex
);
glDeleteTextures
(
1
,
&
depth_tex
);
glDeleteTextures
((
GLsizei
)
output_textures
.
size
(),
(
GLuint
*
)
output_textures
.
data
());
glDeleteTextures
((
GLsizei
)
output_textures
.
size
(),
(
GLuint
*
)
output_textures
.
data
());
glDeleteFramebuffers
(
1
,
&
framebuffer
);
glDeleteFramebuffers
(
1
,
&
framebuffer
);
depth_tex
=
framebuffer
=
0
;
depth_tex
=
framebuffer
=
0
;
}
}
void
Framebuffer
::
resize
(
Vec2
dim
,
int
samples
)
{
void
Framebuffer
::
resize
(
Vec2
dim
,
int
samples
)
{
destroy
();
destroy
();
create
();
create
();
w
=
(
int
)
dim
.
x
;
h
=
(
int
)
dim
.
y
;
s
=
samples
;
assert
(
w
>
0
&&
h
>
0
&&
s
>
0
);
glBindFramebuffer
(
GL_FRAMEBUFFER
,
framebuffer
);
w
=
(
int
)
dim
.
x
;
h
=
(
int
)
dim
.
y
;
s
=
samples
;
assert
(
w
>
0
&&
h
>
0
&&
s
>
0
);
GLenum
type
=
samples
==
1
?
GL_TEXTURE_2D
:
GL_TEXTURE_2D_MULTISAMPLE
;
glBindFramebuffer
(
GL_FRAMEBUFFER
,
framebuffer
)
;
std
::
vector
<
GLenum
>
draw_buffers
;
GLenum
type
=
samples
==
1
?
GL_TEXTURE_2D
:
GL_TEXTURE_2D_MULTISAMPLE
;
f
or
(
GLenum
i
=
0
;
i
<
output_textures
.
size
();
i
++
)
{
std
::
vect
or
<
GLenum
>
draw_buffers
;
glBindTexture
(
type
,
output_textures
[
i
]);
for
(
GLenum
i
=
0
;
i
<
output_textures
.
size
();
i
++
)
{
if
(
s
>
1
)
{
glBindTexture
(
type
,
output_textures
[
i
]);
glTexImage2DMultisample
(
type
,
s
,
GL_RGB8
,
w
,
h
,
GL_TRUE
);
}
else
{
glTexImage2D
(
type
,
0
,
GL_RGB8
,
w
,
h
,
0
,
GL_RGB
,
GL_UNSIGNED_BYTE
,
0
);
glTexParameteri
(
type
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
glTexParameteri
(
type
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
}
glFramebufferTexture2D
(
GL_FRAMEBUFFER
,
GL_COLOR_ATTACHMENT0
+
i
,
type
,
output_textures
[
i
],
0
);
if
(
s
>
1
)
{
glTexImage2DMultisample
(
type
,
s
,
GL_RGB8
,
w
,
h
,
GL_TRUE
);
}
else
{
glTexImage2D
(
type
,
0
,
GL_RGB8
,
w
,
h
,
0
,
GL_RGB
,
GL_UNSIGNED_BYTE
,
0
);
glTexParameteri
(
type
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
glTexParameteri
(
type
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
}
draw_buffers
.
push_back
(
GL_COLOR_ATTACHMENT0
+
i
);
glFramebufferTexture2D
(
GL_FRAMEBUFFER
,
GL_COLOR_ATTACHMENT0
+
i
,
type
,
output_textures
[
i
],
0
);
glBindTexture
(
type
,
0
);
draw_buffers
.
push_back
(
GL_COLOR_ATTACHMENT0
+
i
);
}
if
(
depth
)
{
glBindTexture
(
type
,
0
);
glBindTexture
(
type
,
depth_tex
);
}
if
(
s
>
1
)
{
glTexImage2DMultisample
(
type
,
s
,
GL_DEPTH_COMPONENT32F
,
w
,
h
,
GL_TRUE
);
}
else
{
glTexImage2D
(
type
,
0
,
GL_DEPTH_COMPONENT32F
,
w
,
h
,
0
,
GL_DEPTH_COMPONENT
,
GL_FLOAT
,
0
);
glTexParameteri
(
type
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
glTexParameteri
(
type
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
}
glFramebufferTexture2D
(
GL_FRAMEBUFFER
,
GL_DEPTH_ATTACHMENT
,
type
,
depth_tex
,
0
);
glBindTexture
(
type
,
0
);
}
glDrawBuffers
((
GLsizei
)
draw_buffers
.
size
(),
draw_buffers
.
data
());
if
(
depth
)
{
glBindTexture
(
type
,
depth_tex
);
if
(
s
>
1
)
{
glTexImage2DMultisample
(
type
,
s
,
GL_DEPTH_COMPONENT32F
,
w
,
h
,
GL_TRUE
);
}
else
{
glTexImage2D
(
type
,
0
,
GL_DEPTH_COMPONENT32F
,
w
,
h
,
0
,
GL_DEPTH_COMPONENT
,
GL_FLOAT
,
0
);
glTexParameteri
(
type
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
glTexParameteri
(
type
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
}
glFramebufferTexture2D
(
GL_FRAMEBUFFER
,
GL_DEPTH_ATTACHMENT
,
type
,
depth_tex
,
0
);
glBindTexture
(
type
,
0
);
}
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
glDrawBuffers
((
GLsizei
)
draw_buffers
.
size
(),
draw_buffers
.
data
());
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
}
}
void
Framebuffer
::
clear
(
int
buf
,
Vec4
col
)
const
{
void
Framebuffer
::
clear
(
int
buf
,
Vec4
col
)
const
{
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
bind
();
bind
();
glClearBufferfv
(
GL_COLOR
,
buf
,
col
.
data
);
glClearBufferfv
(
GL_COLOR
,
buf
,
col
.
data
);
}
}
void
Framebuffer
::
clear_d
()
const
{
void
Framebuffer
::
clear_d
()
const
{
bind
();
bind
();
glClear
(
GL_DEPTH_BUFFER_BIT
);
glClear
(
GL_DEPTH_BUFFER_BIT
);
}
}
void
Framebuffer
::
bind_screen
()
{
void
Framebuffer
::
bind_screen
()
{
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
}
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
}
void
Framebuffer
::
bind
()
const
{
void
Framebuffer
::
bind
()
const
{
glBindFramebuffer
(
GL_FRAMEBUFFER
,
framebuffer
);
}
glBindFramebuffer
(
GL_FRAMEBUFFER
,
framebuffer
);
}
GLuint
Framebuffer
::
get_output
(
int
buf
)
const
{
GLuint
Framebuffer
::
get_output
(
int
buf
)
const
{
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
return
output_textures
[
buf
];
return
output_textures
[
buf
];
}
}
int
Framebuffer
::
bytes
()
const
{
int
Framebuffer
::
bytes
()
const
{
return
w
*
h
*
4
;
}
return
w
*
h
*
4
;
}
int
Framebuffer
::
samples
()
const
{
int
Framebuffer
::
samples
()
const
{
return
s
;
}
return
s
;
}
void
Framebuffer
::
flush
()
const
{
void
Framebuffer
::
flush
()
const
{
glFlush
();
}
glFlush
();
}
GLuint
Framebuffer
::
get_depth
()
const
{
GLuint
Framebuffer
::
get_depth
()
const
{
assert
(
depth_tex
);
assert
(
depth_tex
);
return
depth_tex
;
return
depth_tex
;
}
}
bool
Framebuffer
::
can_read_at
()
const
{
bool
Framebuffer
::
can_read_at
()
const
{
return
is_gl45
&&
s
==
1
;
}
return
is_gl45
&&
s
==
1
;
}
void
Framebuffer
::
read_at
(
int
buf
,
int
x
,
int
y
,
GLubyte
*
data
)
const
{
void
Framebuffer
::
read_at
(
int
buf
,
int
x
,
int
y
,
GLubyte
*
data
)
const
{
assert
(
can_read_at
());
assert
(
can_read_at
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
glGetTextureSubImage
(
output_textures
[
buf
],
0
,
x
,
y
,
0
,
1
,
1
,
1
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
4
,
data
);
glGetTextureSubImage
(
output_textures
[
buf
],
0
,
x
,
y
,
0
,
1
,
1
,
1
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
4
,
data
);
}
}
void
Framebuffer
::
read
(
int
buf
,
GLubyte
*
data
)
const
{
void
Framebuffer
::
read
(
int
buf
,
GLubyte
*
data
)
const
{
assert
(
s
==
1
);
assert
(
s
==
1
);
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
glBindTexture
(
GL_TEXTURE_2D
,
output_textures
[
buf
]);
glBindTexture
(
GL_TEXTURE_2D
,
output_textures
[
buf
]);
glGetTexImage
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
data
);
glGetTexImage
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
data
);
}
}
void
Framebuffer
::
blit_to
(
int
buf
,
const
Framebuffer
&
fb
,
bool
avg
)
const
{
void
Framebuffer
::
blit_to
(
int
buf
,
const
Framebuffer
&
fb
,
bool
avg
)
const
{
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
if
(
s
>
1
)
{
if
(
s
>
1
)
{
Effects
::
resolve_to
(
buf
,
*
this
,
fb
,
avg
);
Effects
::
resolve_to
(
buf
,
*
this
,
fb
,
avg
);
return
;
return
;
}
}
glBindFramebuffer
(
GL_READ_FRAMEBUFFER
,
framebuffer
);
glBindFramebuffer
(
GL_READ_FRAMEBUFFER
,
framebuffer
);
glBindFramebuffer
(
GL_DRAW_FRAMEBUFFER
,
fb
.
framebuffer
);
glBindFramebuffer
(
GL_DRAW_FRAMEBUFFER
,
fb
.
framebuffer
);
glReadBuffer
(
GL_COLOR_ATTACHMENT0
+
buf
);
glReadBuffer
(
GL_COLOR_ATTACHMENT0
+
buf
);
glBlitFramebuffer
(
0
,
0
,
w
,
h
,
0
,
0
,
fb
.
w
,
fb
.
h
,
GL_COLOR_BUFFER_BIT
,
GL_NEAREST
);
glBlitFramebuffer
(
0
,
0
,
w
,
h
,
0
,
0
,
fb
.
w
,
fb
.
h
,
GL_COLOR_BUFFER_BIT
,
GL_NEAREST
);
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
}
}
void
Framebuffer
::
blit_to_screen
(
int
buf
,
Vec2
dim
)
const
{
void
Framebuffer
::
blit_to_screen
(
int
buf
,
Vec2
dim
)
const
{
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
assert
(
buf
>=
0
&&
buf
<
(
int
)
output_textures
.
size
());
if
(
s
>
1
)
{
if
(
s
>
1
)
{
Effects
::
resolve_to_screen
(
buf
,
*
this
);
Effects
::
resolve_to_screen
(
buf
,
*
this
);
return
;
return
;
}
}
glBindFramebuffer
(
GL_READ_FRAMEBUFFER
,
framebuffer
);
glBindFramebuffer
(
GL_READ_FRAMEBUFFER
,
framebuffer
);
glBindFramebuffer
(
GL_DRAW_FRAMEBUFFER
,
0
);
glBindFramebuffer
(
GL_DRAW_FRAMEBUFFER
,
0
);
glReadBuffer
(
GL_COLOR_ATTACHMENT0
+
buf
);
glReadBuffer
(
GL_COLOR_ATTACHMENT0
+
buf
);
glBlitFramebuffer
(
0
,
0
,
w
,
h
,
0
,
0
,
(
GLint
)
dim
.
x
,
(
GLint
)
dim
.
y
,
GL_COLOR_BUFFER_BIT
,
GL_NEAREST
);
glBlitFramebuffer
(
0
,
0
,
w
,
h
,
0
,
0
,
(
GLint
)
dim
.
x
,
(
GLint
)
dim
.
y
,
GL_COLOR_BUFFER_BIT
,
GL_NEAREST
);
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
glBindFramebuffer
(
GL_FRAMEBUFFER
,
0
);
}
}
bool
Framebuffer
::
is_multisampled
()
const
{
bool
Framebuffer
::
is_multisampled
()
const
{
return
s
>
1
;
}
return
s
>
1
;
}
void
Effects
::
init
()
{
void
Effects
::
init
()
{
// Hack to let stuff get created for headless mode
// Hack to let stuff get created for headless mode
if
(
!
glGenVertexArrays
)
return
;
if
(
!
glGenVertexArrays
)
return
;
glGenVertexArrays
(
1
,
&
vao
);
glGenVertexArrays
(
1
,
&
vao
);
resolve_shader
.
load
(
effects_v
,
resolve_f
);
resolve_shader
.
load
(
effects_v
,
resolve_f
);
outline_shader
.
load
(
effects_v
,
outline_f
);
outline_shader
.
load
(
effects_v
,
outline_f
);
outline_shader_ms
.
load
(
effects_v
,
is_gl45
||
is_gl41
?
outline_ms_f_4
:
outline_ms_f_33
);
outline_shader_ms
.
load
(
effects_v
,
is_gl45
||
is_gl41
?
outline_ms_f_4
:
outline_ms_f_33
);
}
}
void
Effects
::
destroy
()
{
void
Effects
::
destroy
()
{
// Hack to let stuff get destroyed for headless mode
// Hack to let stuff get destroyed for headless mode
if
(
!
glDeleteVertexArrays
)
return
;
if
(
!
glDeleteVertexArrays
)
return
;
glDeleteVertexArrays
(
1
,
&
vao
);
vao
=
0
;
glDeleteVertexArrays
(
1
,
&
vao
);
resolve_shader
.
~
Shader
();
vao
=
0
;
outline_shader
.
~
Shader
();
resolve_shader
.
~
Shader
();
outline_shader_ms
.
~
Shader
();
outline_shader
.
~
Shader
();
}
outline_shader_ms
.
~
Shader
();
}
void
Effects
::
outline
(
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
Vec3
color
,
Vec2
min
,
Vec2
max
)
{
void
Effects
::
outline
(
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
Vec3
color
,
Vec2
min
,
glFlush
();
Vec2
max
)
{
to
.
bind
();
glFlush
();
Vec2
quad
[]
=
{
to
.
bind
();
Vec2
{
min
.
x
,
max
.
y
},
min
,
Vec2
quad
[]
=
{
Vec2
{
min
.
x
,
max
.
y
},
min
,
max
,
Vec2
{
max
.
x
,
min
.
y
}};
max
,
Vec2
{
max
.
x
,
min
.
y
}
if
(
from
.
is_multisampled
())
{
};
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
from
.
get_depth
());
outline_shader_ms
.
bind
();
if
(
from
.
is_multisampled
())
{
outline_shader_ms
.
uniform
(
"depth"
,
0
);
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
from
.
get_depth
());
outline_shader_ms
.
uniform
(
"color"
,
color
);
outline_shader_ms
.
bind
();
outline_shader_ms
.
uniform
(
"bounds"
,
4
,
quad
);
outline_shader_ms
.
uniform
(
"depth"
,
0
);
}
else
{
outline_shader_ms
.
uniform
(
"color"
,
color
);
glBindTexture
(
GL_TEXTURE_2D
,
from
.
get_depth
());
outline_shader_ms
.
uniform
(
"bounds"
,
4
,
quad
);
outline_shader
.
bind
();
}
else
{
outline_shader
.
uniform
(
"depth"
,
0
);
glBindTexture
(
GL_TEXTURE_2D
,
from
.
get_depth
());
outline_shader
.
uniform
(
"color"
,
color
);
outline_shader
.
bind
();
outline_shader
.
uniform
(
"i_screen_size"
,
1.0
f
/
Vec2
(
from
.
w
,
from
.
h
));
outline_shader
.
uniform
(
"depth"
,
0
);
outline_shader
.
uniform
(
"bounds"
,
4
,
quad
);
outline_shader
.
uniform
(
"color"
,
color
);
}
outline_shader
.
uniform
(
"i_screen_size"
,
1.0
f
/
Vec2
(
from
.
w
,
from
.
h
));
outline_shader
.
uniform
(
"bounds"
,
4
,
quad
);
glBindVertexArray
(
vao
);
}
glDisable
(
GL_DEPTH_TEST
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
glBindVertexArray
(
vao
);
glEnable
(
GL_DEPTH_TEST
);
glDisable
(
GL_DEPTH_TEST
);
glBindVertexArray
(
0
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
glFlush
();
glEnable
(
GL_DEPTH_TEST
);
}
glBindVertexArray
(
0
);
glFlush
();
void
Effects
::
resolve_to_screen
(
int
buf
,
const
Framebuffer
&
framebuffer
)
{
}
Framebuffer
::
bind_screen
();
void
Effects
::
resolve_to_screen
(
int
buf
,
const
Framebuffer
&
framebuffer
)
{
resolve_shader
.
bind
();
Framebuffer
::
bind_screen
();
assert
(
buf
>=
0
&&
buf
<
(
int
)
framebuffer
.
output_textures
.
size
());
resolve_shader
.
bind
();
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
framebuffer
.
output_textures
[
buf
]);
assert
(
buf
>=
0
&&
buf
<
(
int
)
framebuffer
.
output_textures
.
size
());
resolve_shader
.
uniform
(
"tex"
,
0
);
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
framebuffer
.
output_textures
[
buf
]);
resolve_shader
.
uniform
(
"samples"
,
framebuffer
.
s
);
resolve_shader
.
uniform
(
"bounds"
,
4
,
screen_quad
);
resolve_shader
.
uniform
(
"tex"
,
0
);
resolve_shader
.
uniform
(
"samples"
,
framebuffer
.
s
);
glBindVertexArray
(
vao
);
resolve_shader
.
uniform
(
"bounds"
,
4
,
screen_quad
);
glDisable
(
GL_DEPTH_TEST
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
glBindVertexArray
(
vao
);
glEnable
(
GL_DEPTH_TEST
);
glDisable
(
GL_DEPTH_TEST
);
glBindVertexArray
(
0
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
}
glEnable
(
GL_DEPTH_TEST
);
glBindVertexArray
(
0
);
void
Effects
::
resolve_to
(
int
buf
,
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
bool
avg
)
{
}
to
.
bind
();
void
Effects
::
resolve_to
(
int
buf
,
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
bool
avg
)
{
resolve_shader
.
bind
();
to
.
bind
();
assert
(
buf
>=
0
&&
buf
<
(
int
)
from
.
output_textures
.
size
());
resolve_shader
.
bind
();
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
from
.
output_textures
[
buf
]);
assert
(
buf
>=
0
&&
buf
<
(
int
)
from
.
output_textures
.
size
());
resolve_shader
.
uniform
(
"tex"
,
0
);
glBindTexture
(
GL_TEXTURE_2D_MULTISAMPLE
,
from
.
output_textures
[
buf
]);
resolve_shader
.
uniform
(
"samples"
,
avg
?
from
.
s
:
1
);
resolve_shader
.
uniform
(
"bounds"
,
4
,
screen_quad
);
resolve_shader
.
uniform
(
"tex"
,
0
);
resolve_shader
.
uniform
(
"samples"
,
avg
?
from
.
s
:
1
);
glBindVertexArray
(
vao
);
resolve_shader
.
uniform
(
"bounds"
,
4
,
screen_quad
);
glDisable
(
GL_DEPTH_TEST
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
glBindVertexArray
(
vao
);
glEnable
(
GL_DEPTH_TEST
);
glDisable
(
GL_DEPTH_TEST
);
glBindVertexArray
(
0
);
glDrawArrays
(
GL_TRIANGLE_STRIP
,
0
,
4
);
}
glEnable
(
GL_DEPTH_TEST
);
glBindVertexArray
(
0
);
static
void
debug_proc
(
GLenum
glsource
,
GLenum
gltype
,
GLuint
,
GLenum
severity
,
GLsizei
,
}
const
GLchar
*
glmessage
,
const
void
*
)
{
static
void
debug_proc
(
GLenum
glsource
,
GLenum
gltype
,
GLuint
,
GLenum
severity
,
GLsizei
,
const
GLchar
*
glmessage
,
const
void
*
)
{
std
::
string
message
(
glmessage
);
std
::
string
source
,
type
;
std
::
string
message
(
glmessage
);
std
::
string
source
,
type
;
switch
(
glsource
)
{
case
GL_DEBUG_SOURCE_API
:
switch
(
glsource
)
{
source
=
"OpenGL API"
;
case
GL_DEBUG_SOURCE_API
:
break
;
source
=
"OpenGL API"
;
case
GL_DEBUG_SOURCE_WINDOW_SYSTEM
:
break
;
source
=
"Window System"
;
case
GL_DEBUG_SOURCE_WINDOW_SYSTEM
:
break
;
source
=
"Window System"
;
case
GL_DEBUG_SOURCE_SHADER_COMPILER
:
break
;
source
=
"Shader Compiler"
;
case
GL_DEBUG_SOURCE_SHADER_COMPILER
:
break
;
source
=
"Shader Compiler"
;
case
GL_DEBUG_SOURCE_THIRD_PARTY
:
break
;
source
=
"Third Party"
;
case
GL_DEBUG_SOURCE_THIRD_PARTY
:
break
;
source
=
"Third Party"
;
case
GL_DEBUG_SOURCE_APPLICATION
:
break
;
source
=
"Application"
;
case
GL_DEBUG_SOURCE_APPLICATION
:
break
;
source
=
"Application"
;
case
GL_DEBUG_SOURCE_OTHER
:
break
;
source
=
"Other"
;
case
GL_DEBUG_SOURCE_OTHER
:
break
;
source
=
"Other"
;
}
break
;
}
switch
(
gltype
)
{
case
GL_DEBUG_TYPE_ERROR
:
switch
(
gltype
)
{
type
=
"Error"
;
case
GL_DEBUG_TYPE_ERROR
:
break
;
type
=
"Error"
;
case
GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
:
break
;
type
=
"Deprecated"
;
case
GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
:
break
;
type
=
"Deprecated"
;
case
GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
:
break
;
type
=
"Undefined Behavior"
;
case
GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
:
break
;
type
=
"Undefined Behavior"
;
case
GL_DEBUG_TYPE_PORTABILITY
:
break
;
type
=
"Portability"
;
case
GL_DEBUG_TYPE_PORTABILITY
:
break
;
type
=
"Portability"
;
case
GL_DEBUG_TYPE_PERFORMANCE
:
break
;
type
=
"Performance"
;
case
GL_DEBUG_TYPE_PERFORMANCE
:
break
;
type
=
"Performance"
;
case
GL_DEBUG_TYPE_MARKER
:
break
;
type
=
"Marker"
;
case
GL_DEBUG_TYPE_MARKER
:
break
;
type
=
"Marker"
;
case
GL_DEBUG_TYPE_PUSH_GROUP
:
break
;
type
=
"Push Group"
;
case
GL_DEBUG_TYPE_PUSH_GROUP
:
break
;
type
=
"Push Group"
;
case
GL_DEBUG_TYPE_POP_GROUP
:
break
;
type
=
"Pop Group"
;
case
GL_DEBUG_TYPE_POP_GROUP
:
break
;
type
=
"Pop Group"
;
case
GL_DEBUG_TYPE_OTHER
:
break
;
type
=
"Other"
;
case
GL_DEBUG_TYPE_OTHER
:
break
;
type
=
"Other"
;
}
break
;
}
switch
(
severity
)
{
case
GL_DEBUG_SEVERITY_HIGH
:
switch
(
severity
)
{
case
GL_DEBUG_SEVERITY_MEDIUM
:
case
GL_DEBUG_SEVERITY_HIGH
:
warn
(
"OpenGL | source: %s type: %s message: %s"
,
source
.
c_str
(),
type
.
c_str
(),
case
GL_DEBUG_SEVERITY_MEDIUM
:
message
.
c_str
());
warn
(
"OpenGL | source: %s type: %s message: %s"
,
source
.
c_str
(),
type
.
c_str
(),
message
.
c_str
());
break
;
break
;
}
}
}
}
static
void
check_leaked_handles
()
{
static
void
check_leaked_handles
()
{
#define GL_CHECK(type) if(glIs##type && glIs##type(i) == GL_TRUE) { warn("Leaked OpenGL handle %u of type %s", i, #type); leaked = true;}
#define GL_CHECK(type) \
if (glIs##type && glIs##type(i) == GL_TRUE) { \
warn("Leaked OpenGL handle %u of type %s", i, #type); \
leaked = true; \
}
bool
leaked
=
false
;
bool
leaked
=
false
;
for
(
GLuint
i
=
0
;
i
<
10000
;
i
++
)
{
for
(
GLuint
i
=
0
;
i
<
10000
;
i
++
)
{
GL_CHECK
(
Texture
);
GL_CHECK
(
Texture
);
GL_CHECK
(
Buffer
);
GL_CHECK
(
Buffer
);
GL_CHECK
(
Framebuffer
);
GL_CHECK
(
Framebuffer
);
GL_CHECK
(
Renderbuffer
);
GL_CHECK
(
Renderbuffer
);
GL_CHECK
(
VertexArray
);
GL_CHECK
(
VertexArray
);
GL_CHECK
(
Program
);
GL_CHECK
(
Program
);
GL_CHECK
(
ProgramPipeline
);
GL_CHECK
(
ProgramPipeline
);
GL_CHECK
(
Query
);
GL_CHECK
(
Query
);
if
(
glIsShader
(
i
)
==
GL_TRUE
)
{
if
(
glIsShader
(
i
)
==
GL_TRUE
)
{
leaked
=
true
;
leaked
=
true
;
GLint
shader_len
=
0
;
GLint
shader_len
=
0
;
glGetShaderiv
(
i
,
GL_SHADER_SOURCE_LENGTH
,
&
shader_len
);
glGetShaderiv
(
i
,
GL_SHADER_SOURCE_LENGTH
,
&
shader_len
);
GLchar
*
shader
=
new
GLchar
[
shader_len
];
GLchar
*
shader
=
new
GLchar
[
shader_len
];
glGetShaderSource
(
i
,
shader_len
,
nullptr
,
shader
);
glGetShaderSource
(
i
,
shader_len
,
nullptr
,
shader
);
warn
(
"Leaked OpenGL shader %u. Source: %s"
,
i
,
shader
);
warn
(
"Leaked OpenGL shader %u. Source: %s"
,
i
,
shader
);
delete
[]
shader
;
delete
[]
shader
;
}
}
}
}
if
(
leaked
)
{
if
(
leaked
)
{
warn
(
"Leaked OpenGL objects!"
);
warn
(
"Leaked OpenGL objects!"
);
}
}
#undef GL_CHECK
#undef GL_CHECK
}
}
static
void
setup_debug_proc
()
{
static
void
setup_debug_proc
()
{
if
(
!
glDebugMessageCallback
||
!
glDebugMessageControl
)
return
;
if
(
!
glDebugMessageCallback
||
!
glDebugMessageControl
)
glEnable
(
GL_DEBUG_OUTPUT
);
return
;
glEnable
(
GL_DEBUG_OUTPUT_SYNCHRONOUS
);
glEnable
(
GL_DEBUG_OUTPUT
);
glDebugMessageCallback
(
debug_proc
,
nullptr
);
glEnable
(
GL_DEBUG_OUTPUT_SYNCHRONOUS
);
glDebugMessageControl
(
GL_DONT_CARE
,
GL_DONT_CARE
,
GL_DONT_CARE
,
0
,
nullptr
,
GL_TRUE
);
glDebugMessageCallback
(
debug_proc
,
nullptr
);
glDebugMessageControl
(
GL_DONT_CARE
,
GL_DONT_CARE
,
GL_DONT_CARE
,
0
,
nullptr
,
GL_TRUE
);
}
}
const
std
::
string
Effects
::
effects_v
=
R"(
const
std
::
string
Effects
::
effects_v
=
R"(
...
@@ -1095,7 +1099,7 @@ void main() {
...
@@ -1095,7 +1099,7 @@ void main() {
})"
;
})"
;
namespace
Shaders
{
namespace
Shaders
{
const
std
::
string
line_v
=
R"(
const
std
::
string
line_v
=
R"(
#version 330 core
#version 330 core
layout (location = 0) in vec3 v_pos;
layout (location = 0) in vec3 v_pos;
...
@@ -1108,7 +1112,7 @@ void main() {
...
@@ -1108,7 +1112,7 @@ void main() {
gl_Position = mvp * vec4(v_pos, 1.0f);
gl_Position = mvp * vec4(v_pos, 1.0f);
f_col = v_col;
f_col = v_col;
})"
;
})"
;
const
std
::
string
line_f
=
R"(
const
std
::
string
line_f
=
R"(
#version 330 core
#version 330 core
layout (location = 0) out vec4 out_col;
layout (location = 0) out vec4 out_col;
...
@@ -1120,8 +1124,8 @@ smooth in vec3 f_col;
...
@@ -1120,8 +1124,8 @@ smooth in vec3 f_col;
void main() {
void main() {
out_id = vec4(0.0f);
out_id = vec4(0.0f);
out_col = vec4(f_col, alpha);
out_col = vec4(f_col, alpha);
})"
;
})"
;
const
std
::
string
mesh_v
=
R"(
const
std
::
string
mesh_v
=
R"(
#version 330 core
#version 330 core
layout (location = 0) in vec3 v_pos;
layout (location = 0) in vec3 v_pos;
...
@@ -1138,7 +1142,7 @@ void main() {
...
@@ -1138,7 +1142,7 @@ void main() {
f_norm = (normal * vec4(v_norm, 0.0f)).xyz;
f_norm = (normal * vec4(v_norm, 0.0f)).xyz;
gl_Position = mvp * vec4(v_pos, 1.0f);
gl_Position = mvp * vec4(v_pos, 1.0f);
})"
;
})"
;
const
std
::
string
inst_v
=
R"(
const
std
::
string
inst_v
=
R"(
#version 330 core
#version 330 core
layout (location = 0) in vec3 v_pos;
layout (location = 0) in vec3 v_pos;
...
@@ -1161,7 +1165,7 @@ void main() {
...
@@ -1161,7 +1165,7 @@ void main() {
f_norm = (n * vec4(v_norm, 0.0f)).xyz;
f_norm = (n * vec4(v_norm, 0.0f)).xyz;
gl_Position = proj * mv * vec4(v_pos, 1.0f);
gl_Position = proj * mv * vec4(v_pos, 1.0f);
})"
;
})"
;
const
std
::
string
mesh_f
=
R"(
const
std
::
string
mesh_f
=
R"(
#version 330 core
#version 330 core
uniform bool solid, use_v_id;
uniform bool solid, use_v_id;
...
@@ -1193,7 +1197,7 @@ void main() {
...
@@ -1193,7 +1197,7 @@ void main() {
float light = clamp(0.3f + 0.6f * ndotl, 0.0f, alpha);
float light = clamp(0.3f + 0.6f * ndotl, 0.0f, alpha);
out_col = vec4(light * use_color, alpha);
out_col = vec4(light * use_color, alpha);
}
}
})"
;
})"
;
const
std
::
string
dome_v
=
R"(
const
std
::
string
dome_v
=
R"(
#version 330 core
#version 330 core
...
@@ -1237,6 +1241,7 @@ void main() {
...
@@ -1237,6 +1241,7 @@ void main() {
}
}
}
}
else discard;
else discard;
})"
;
})"
;
}
}
}
// namespace Shaders
}
// namespace GL
src/platform/gl.h
View file @
c2535f0f
...
@@ -2,11 +2,11 @@
...
@@ -2,11 +2,11 @@
#pragma once
#pragma once
#include <string>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_map>
#include <vector>
#include <glad/glad.h>
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
#include <glad/glad.h>
namespace
GL
{
namespace
GL
{
...
@@ -20,12 +20,7 @@ void clear_screen(Vec4 col);
...
@@ -20,12 +20,7 @@ void clear_screen(Vec4 col);
void
viewport
(
Vec2
dim
);
void
viewport
(
Vec2
dim
);
int
max_msaa
();
int
max_msaa
();
enum
class
Opt
{
enum
class
Opt
{
wireframe
,
offset
,
culling
,
depth_write
};
wireframe
,
offset
,
culling
,
depth_write
};
void
enable
(
Opt
opt
);
void
enable
(
Opt
opt
);
void
disable
(
Opt
opt
);
void
disable
(
Opt
opt
);
...
@@ -36,250 +31,248 @@ using TexID = GLuint;
...
@@ -36,250 +31,248 @@ using TexID = GLuint;
class
Tex2D
{
class
Tex2D
{
public:
public:
Tex2D
();
Tex2D
(
const
Tex2D
&
src
)
=
delete
;
Tex2D
(
Tex2D
&&
src
);
~
Tex2D
();
Tex2D
();
void
operator
=
(
const
Tex2D
&
src
)
=
delete
;
Tex2D
(
const
Tex2D
&
src
)
=
delete
;
void
operator
=
(
Tex2D
&&
src
);
Tex2D
(
Tex2D
&&
src
);
~
Tex2D
();
void
operator
=
(
const
Tex2D
&
src
)
=
delete
;
void
image
(
int
w
,
int
h
,
unsigned
char
*
img
);
void
operator
=
(
Tex2D
&&
src
);
TexID
get_id
()
const
;
void
bind
(
int
idx
=
0
)
const
;
void
image
(
int
w
,
int
h
,
unsigned
char
*
img
);
TexID
get_id
()
const
;
void
bind
(
int
idx
=
0
)
const
;
private:
private:
GLuint
id
;
GLuint
id
;
};
};
class
Mesh
{
class
Mesh
{
public:
public:
typedef
GLuint
Index
;
typedef
GLuint
Index
;
struct
Vert
{
struct
Vert
{
Vec3
pos
;
Vec3
pos
;
Vec3
norm
;
Vec3
norm
;
GLuint
id
;
GLuint
id
;
};
};
Mesh
();
Mesh
();
Mesh
(
std
::
vector
<
Vert
>&&
vertices
,
std
::
vector
<
Index
>&&
indices
);
Mesh
(
std
::
vector
<
Vert
>
&&
vertices
,
std
::
vector
<
Index
>
&&
indices
);
Mesh
(
const
Mesh
&
src
)
=
delete
;
Mesh
(
const
Mesh
&
src
)
=
delete
;
Mesh
(
Mesh
&&
src
);
Mesh
(
Mesh
&&
src
);
~
Mesh
();
~
Mesh
();
void
operator
=
(
const
Mesh
&
src
)
=
delete
;
void
operator
=
(
const
Mesh
&
src
)
=
delete
;
void
operator
=
(
Mesh
&&
src
);
void
operator
=
(
Mesh
&&
src
);
/// Assumes proper shader is already bound
/// Assumes proper shader is already bound
void
render
();
void
render
();
void
recreate
(
std
::
vector
<
Vert
>&&
vertices
,
std
::
vector
<
Index
>&&
indices
);
void
recreate
(
std
::
vector
<
Vert
>
&&
vertices
,
std
::
vector
<
Index
>
&&
indices
);
std
::
vector
<
Vert
>
&
edit_verts
();
std
::
vector
<
Vert
>
&
edit_verts
();
std
::
vector
<
Index
>
&
edit_indices
();
std
::
vector
<
Index
>
&
edit_indices
();
BBox
bbox
()
const
;
BBox
bbox
()
const
;
const
std
::
vector
<
Vert
>
&
verts
()
const
;
const
std
::
vector
<
Vert
>
&
verts
()
const
;
const
std
::
vector
<
Index
>
&
indices
()
const
;
const
std
::
vector
<
Index
>
&
indices
()
const
;
GLuint
tris
()
const
;
GLuint
tris
()
const
;
private:
private:
void
update
();
void
update
();
void
create
();
void
create
();
void
destroy
();
void
destroy
();
BBox
_bbox
;
BBox
_bbox
;
GLuint
vao
=
0
,
vbo
=
0
,
ebo
=
0
;
GLuint
vao
=
0
,
vbo
=
0
,
ebo
=
0
;
GLuint
n_elem
=
0
;
GLuint
n_elem
=
0
;
bool
dirty
=
true
;
bool
dirty
=
true
;
std
::
vector
<
Vert
>
_verts
;
std
::
vector
<
Vert
>
_verts
;
std
::
vector
<
Index
>
_idxs
;
std
::
vector
<
Index
>
_idxs
;
friend
class
Instances
;
friend
class
Instances
;
};
};
class
Instances
{
class
Instances
{
public:
public:
Instances
(
GL
::
Mesh
&&
mesh
);
Instances
(
GL
::
Mesh
&&
mesh
);
Instances
(
const
Instances
&
src
)
=
delete
;
Instances
(
const
Instances
&
src
)
=
delete
;
Instances
(
Instances
&&
src
);
Instances
(
Instances
&&
src
);
~
Instances
();
~
Instances
();
void
operator
=
(
const
Instances
&
src
)
=
delete
;
void
operator
=
(
const
Instances
&
src
)
=
delete
;
void
operator
=
(
Instances
&&
src
);
void
operator
=
(
Instances
&&
src
);
struct
Info
{
struct
Info
{
GLuint
id
;
GLuint
id
;
Mat4
transform
;
Mat4
transform
;
};
};
void
render
();
void
render
();
size_t
add
(
const
Mat4
&
transform
,
GLuint
id
=
0
);
size_t
add
(
const
Mat4
&
transform
,
GLuint
id
=
0
);
Info
&
get
(
size_t
idx
);
Info
&
get
(
size_t
idx
);
void
clear
();
void
clear
();
private:
private:
void
create
();
void
create
();
void
destroy
();
void
destroy
();
void
update
();
void
update
();
GLuint
vbo
=
0
;
GLuint
vbo
=
0
;
bool
dirty
=
false
;
bool
dirty
=
false
;
Mesh
mesh
;
Mesh
mesh
;
std
::
vector
<
Info
>
data
;
std
::
vector
<
Info
>
data
;
};
};
class
Lines
{
class
Lines
{
public:
public:
struct
Vert
{
struct
Vert
{
Vec3
pos
;
Vec3
pos
;
Vec3
color
;
Vec3
color
;
};
};
Lines
(
float
thickness
=
1.0
f
);
Lines
(
float
thickness
=
1.0
f
);
Lines
(
std
::
vector
<
Vert
>&&
verts
,
float
thickness
=
1.0
f
);
Lines
(
std
::
vector
<
Vert
>
&&
verts
,
float
thickness
=
1.0
f
);
Lines
(
const
Lines
&
src
)
=
delete
;
Lines
(
const
Lines
&
src
)
=
delete
;
Lines
(
Lines
&&
src
);
Lines
(
Lines
&&
src
);
~
Lines
();
~
Lines
();
void
operator
=
(
const
Lines
&
src
)
=
delete
;
void
operator
=
(
const
Lines
&
src
)
=
delete
;
void
operator
=
(
Lines
&&
src
);
void
operator
=
(
Lines
&&
src
);
/// Assumes proper shader is already bound
/// Assumes proper shader is already bound
void
render
(
bool
smooth
)
const
;
void
render
(
bool
smooth
)
const
;
void
add
(
Vec3
start
,
Vec3
end
,
Vec3
color
);
void
add
(
Vec3
start
,
Vec3
end
,
Vec3
color
);
void
pop
();
void
pop
();
void
clear
();
void
clear
();
private:
private:
void
create
();
void
create
();
void
destroy
();
void
destroy
();
void
update
()
const
;
void
update
()
const
;
mutable
bool
dirty
=
false
;
mutable
bool
dirty
=
false
;
float
thickness
=
0.0
f
;
float
thickness
=
0.0
f
;
GLuint
vao
=
0
,
vbo
=
0
;
GLuint
vao
=
0
,
vbo
=
0
;
std
::
vector
<
Vert
>
vertices
;
std
::
vector
<
Vert
>
vertices
;
};
};
class
Shader
{
class
Shader
{
public:
public:
Shader
();
Shader
();
Shader
(
std
::
string
vertex_file
,
std
::
string
fragment_file
);
Shader
(
std
::
string
vertex_file
,
std
::
string
fragment_file
);
Shader
(
const
Shader
&
src
)
=
delete
;
Shader
(
const
Shader
&
src
)
=
delete
;
Shader
(
Shader
&&
src
);
Shader
(
Shader
&&
src
);
~
Shader
();
~
Shader
();
void
operator
=
(
const
Shader
&
src
)
=
delete
;
void
operator
=
(
const
Shader
&
src
)
=
delete
;
void
operator
=
(
Shader
&&
src
);
void
operator
=
(
Shader
&&
src
);
void
bind
()
const
;
void
bind
()
const
;
void
load
(
std
::
string
vertex
,
std
::
string
fragment
);
void
load
(
std
::
string
vertex
,
std
::
string
fragment
);
void
uniform
(
std
::
string
name
,
const
Mat4
&
mat
)
const
;
void
uniform
(
std
::
string
name
,
const
Mat4
&
mat
)
const
;
void
uniform
(
std
::
string
name
,
Vec3
vec3
)
const
;
void
uniform
(
std
::
string
name
,
Vec3
vec3
)
const
;
void
uniform
(
std
::
string
name
,
Vec2
vec2
)
const
;
void
uniform
(
std
::
string
name
,
Vec2
vec2
)
const
;
void
uniform
(
std
::
string
name
,
GLint
i
)
const
;
void
uniform
(
std
::
string
name
,
GLint
i
)
const
;
void
uniform
(
std
::
string
name
,
GLuint
i
)
const
;
void
uniform
(
std
::
string
name
,
GLuint
i
)
const
;
void
uniform
(
std
::
string
name
,
GLfloat
f
)
const
;
void
uniform
(
std
::
string
name
,
GLfloat
f
)
const
;
void
uniform
(
std
::
string
name
,
bool
b
)
const
;
void
uniform
(
std
::
string
name
,
bool
b
)
const
;
void
uniform
(
std
::
string
name
,
int
count
,
const
Vec2
items
[])
const
;
void
uniform
(
std
::
string
name
,
int
count
,
const
Vec2
items
[])
const
;
void
uniform_block
(
std
::
string
name
,
GLuint
i
)
const
;
void
uniform_block
(
std
::
string
name
,
GLuint
i
)
const
;
private:
private:
GLuint
loc
(
std
::
string
name
)
const
;
GLuint
loc
(
std
::
string
name
)
const
;
static
bool
validate
(
GLuint
program
);
static
bool
validate
(
GLuint
program
);
GLuint
program
=
0
;
GLuint
program
=
0
;
GLuint
v
=
0
,
f
=
0
;
GLuint
v
=
0
,
f
=
0
;
void
destroy
();
void
destroy
();
};
};
/// this is very restrictive; it assumes a set number of gl_rgb8 output
/// this is very restrictive; it assumes a set number of gl_rgb8 output
/// textures and a floating point depth render buffer.
/// textures and a floating point depth render buffer.
class
Framebuffer
{
class
Framebuffer
{
public:
public:
Framebuffer
();
Framebuffer
();
Framebuffer
(
int
outputs
,
Vec2
dim
,
int
samples
=
1
,
bool
depth
=
true
);
Framebuffer
(
int
outputs
,
Vec2
dim
,
int
samples
=
1
,
bool
depth
=
true
);
Framebuffer
(
const
Framebuffer
&
src
)
=
delete
;
Framebuffer
(
const
Framebuffer
&
src
)
=
delete
;
Framebuffer
(
Framebuffer
&&
src
);
Framebuffer
(
Framebuffer
&&
src
);
~
Framebuffer
();
~
Framebuffer
();
void
operator
=
(
const
Framebuffer
&
src
)
=
delete
;
void
operator
=
(
const
Framebuffer
&
src
)
=
delete
;
void
operator
=
(
Framebuffer
&&
src
);
void
operator
=
(
Framebuffer
&&
src
);
static
void
bind_screen
();
static
void
bind_screen
();
void
setup
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
);
void
setup
(
int
outputs
,
Vec2
dim
,
int
samples
,
bool
d
);
void
resize
(
Vec2
dim
,
int
samples
=
1
);
void
resize
(
Vec2
dim
,
int
samples
=
1
);
void
bind
()
const
;
void
bind
()
const
;
bool
is_multisampled
()
const
;
bool
is_multisampled
()
const
;
GLuint
get_output
(
int
buf
)
const
;
GLuint
get_output
(
int
buf
)
const
;
GLuint
get_depth
()
const
;
GLuint
get_depth
()
const
;
void
flush
()
const
;
void
flush
()
const
;
int
samples
()
const
;
int
samples
()
const
;
int
bytes
()
const
;
int
bytes
()
const
;
bool
can_read_at
()
const
;
bool
can_read_at
()
const
;
void
read_at
(
int
buf
,
int
x
,
int
y
,
GLubyte
*
data
)
const
;
void
read_at
(
int
buf
,
int
x
,
int
y
,
GLubyte
*
data
)
const
;
void
read
(
int
buf
,
GLubyte
*
data
)
const
;
void
read
(
int
buf
,
GLubyte
*
data
)
const
;
void
blit_to_screen
(
int
buf
,
Vec2
dim
)
const
;
void
blit_to_screen
(
int
buf
,
Vec2
dim
)
const
;
void
blit_to
(
int
buf
,
const
Framebuffer
&
fb
,
bool
avg
=
true
)
const
;
void
blit_to
(
int
buf
,
const
Framebuffer
&
fb
,
bool
avg
=
true
)
const
;
void
clear
(
int
buf
,
Vec4
col
)
const
;
void
clear
(
int
buf
,
Vec4
col
)
const
;
void
clear_d
()
const
;
void
clear_d
()
const
;
private:
private:
void
create
();
void
create
();
void
destroy
();
void
destroy
();
std
::
vector
<
GLuint
>
output_textures
;
std
::
vector
<
GLuint
>
output_textures
;
GLuint
depth_tex
=
0
;
GLuint
depth_tex
=
0
;
GLuint
framebuffer
=
0
;
GLuint
framebuffer
=
0
;
int
w
=
0
,
h
=
0
,
s
=
0
;
int
w
=
0
,
h
=
0
,
s
=
0
;
bool
depth
=
true
;
bool
depth
=
true
;
friend
class
Effects
;
friend
class
Effects
;
};
};
class
Effects
{
class
Effects
{
public:
public:
static
void
resolve_to_screen
(
int
buf
,
const
Framebuffer
&
framebuffer
);
static
void
resolve_to_screen
(
int
buf
,
const
Framebuffer
&
framebuffer
);
static
void
resolve_to
(
int
buf
,
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
bool
avg
=
true
);
static
void
resolve_to
(
int
buf
,
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
bool
avg
=
true
);
static
void
outline
(
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
Vec3
color
,
Vec2
min
,
Vec2
max
);
static
void
outline
(
const
Framebuffer
&
from
,
const
Framebuffer
&
to
,
Vec3
color
,
Vec2
min
,
Vec2
max
);
private:
private:
static
void
init
();
static
void
init
();
static
void
destroy
();
static
void
destroy
();
static
inline
Shader
resolve_shader
,
outline_shader
,
outline_shader_ms
;
static
inline
Shader
resolve_shader
,
outline_shader
,
outline_shader_ms
;
static
inline
GLuint
vao
;
static
inline
GLuint
vao
;
static
inline
const
Vec2
screen_quad
[]
=
{
static
inline
const
Vec2
screen_quad
[]
=
{
Vec2
{
-
1.0
f
,
1.0
f
},
Vec2
{
-
1.0
f
,
-
1.0
f
},
Vec2
{
-
1.0
f
,
1.0
f
},
Vec2
{
1.0
f
,
1.0
f
},
Vec2
{
1.0
f
,
-
1.0
f
}};
Vec2
{
-
1.0
f
,
-
1.0
f
},
Vec2
{
1.0
f
,
1.0
f
},
friend
void
setup
();
Vec2
{
1.0
f
,
-
1.0
f
}
friend
void
shutdown
();
};
static
const
std
::
string
effects_v
;
friend
void
setup
();
static
const
std
::
string
outline_f
,
outline_ms_f_33
,
outline_ms_f_4
;
friend
void
shutdown
();
static
const
std
::
string
resolve_f
;
static
const
std
::
string
effects_v
;
static
const
std
::
string
outline_f
,
outline_ms_f_33
,
outline_ms_f_4
;
static
const
std
::
string
resolve_f
;
};
};
namespace
Shaders
{
namespace
Shaders
{
extern
const
std
::
string
line_v
,
line_f
;
extern
const
std
::
string
line_v
,
line_f
;
extern
const
std
::
string
mesh_v
,
mesh_f
;
extern
const
std
::
string
mesh_v
,
mesh_f
;
extern
const
std
::
string
inst_v
;
extern
const
std
::
string
inst_v
;
extern
const
std
::
string
dome_v
,
dome_f
;
extern
const
std
::
string
dome_v
,
dome_f
;
}
}
}
// namespace Shaders
}
// namespace GL
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