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