Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
GameDevWeek
Dependencies
Cpp
mirrage
Commits
b10a8d6d
Commit
b10a8d6d
authored
Jul 11, 2018
by
Florian Oetke
Browse files
frustum culling and renderer refactoring (implements #27)
parent
267a0b94
Changes
55
Hide whitespace changes
Inline
Side-by-side
assets/core_assets/assets_core_shader.map
View file @
b10a8d6d
...
...
@@ -12,6 +12,7 @@ frag_shader:shadow_model = shader/bin/shadow_model.frag.spv
vert_shader:model = shader/bin/model.vert.spv
frag_shader:model = shader/bin/model.frag.spv
frag_shader:model_emissive = shader/bin/model_emissive.frag.spv
frag_shader:model_alphatest = shader/bin/model_alphatest.frag.spv
vert_shader:ui = shader/bin/ui.vert.spv
frag_shader:ui = shader/bin/ui.frag.spv
...
...
assets/core_assets/shader/bin/model.frag.spv
View file @
b10a8d6d
No preview for this file type
assets/core_assets/shader/bin/model_alphatest.frag.spv
0 → 100644
View file @
b10a8d6d
File added
assets/core_assets/shader/bin/model_emissive.frag.spv
View file @
b10a8d6d
No preview for this file type
assets/core_assets/shader/model.frag
View file @
b10a8d6d
...
...
@@ -5,6 +5,8 @@
#include
"global_uniforms.glsl"
#include
"normal_encoding.glsl"
layout
(
early_fragment_tests
)
in
;
layout
(
location
=
0
)
in
vec3
world_pos
;
layout
(
location
=
1
)
in
vec3
view_pos
;
layout
(
location
=
2
)
in
vec3
normal
;
...
...
@@ -33,9 +35,6 @@ vec3 tangent_space_to_world(vec3 N);
void
main
()
{
vec4
albedo
=
texture
(
albedo_sampler
,
tex_coords
);
if
(
albedo
.
a
<
0
.
1
)
discard
;
vec4
mat_data
=
texture
(
mat_data_sampler
,
tex_coords
);
vec3
normal
=
tangent_space_to_world
(
decode_tangent_normal
(
mat_data
.
rg
));
...
...
assets/core_assets/shader/model_alphatest.frag
0 → 100644
View file @
b10a8d6d
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#include
"global_uniforms.glsl"
#include
"normal_encoding.glsl"
layout
(
location
=
0
)
in
vec3
world_pos
;
layout
(
location
=
1
)
in
vec3
view_pos
;
layout
(
location
=
2
)
in
vec3
normal
;
layout
(
location
=
3
)
in
vec2
tex_coords
;
layout
(
location
=
0
)
out
vec4
depth_out
;
layout
(
location
=
1
)
out
vec4
albedo_mat_id_out
;
layout
(
location
=
2
)
out
vec4
mat_data_out
;
layout
(
set
=
1
,
binding
=
0
)
uniform
sampler2D
albedo_sampler
;
layout
(
set
=
1
,
binding
=
1
)
uniform
sampler2D
mat_data_sampler
;
layout
(
push_constant
)
uniform
Per_model_uniforms
{
mat4
model
;
vec4
light_color
;
vec4
options
;
}
model_uniforms
;
const
float
PI
=
3
.
14159265359
;
vec3
decode_tangent_normal
(
vec2
tn
);
vec3
tangent_space_to_world
(
vec3
N
);
void
main
()
{
vec4
albedo
=
texture
(
albedo_sampler
,
tex_coords
);
if
(
albedo
.
a
<
0
.
1
)
discard
;
vec4
mat_data
=
texture
(
mat_data_sampler
,
tex_coords
);
vec3
normal
=
tangent_space_to_world
(
decode_tangent_normal
(
mat_data
.
rg
));
float
roughness
=
mat_data
.
b
;
float
metallic
=
mat_data
.
a
;
roughness
=
mix
(
0
.
01
,
0
.
99
,
roughness
*
roughness
);
depth_out
=
vec4
(
-
view_pos
.
z
/
global_uniforms
.
proj_planes
.
y
,
0
,
0
,
1
);
albedo_mat_id_out
=
vec4
(
albedo
.
rgb
,
0
.
0
);
mat_data_out
=
vec4
(
encode_normal
(
normal
),
roughness
,
metallic
);
float
disect
=
model_uniforms
.
options
.
x
;
if
(
disect
>
0
&&
world_pos
.
z
>=
disect
)
discard
;
}
vec3
decode_tangent_normal
(
vec2
tn
)
{
if
(
dot
(
tn
,
tn
)
<
0
.
00001
)
return
vec3
(
0
,
0
,
1
);
vec3
N
=
vec3
(
tn
*
2
-
1
,
0
);
N
.
z
=
sqrt
(
1
-
dot
(
N
.
xy
,
N
.
xy
));
return
N
;
}
vec3
tangent_space_to_world
(
vec3
N
)
{
vec3
VN
=
normalize
(
normal
);
// calculate tangent
vec3
p_dx
=
dFdx
(
view_pos
);
vec3
p_dy
=
dFdy
(
view_pos
);
vec2
tc_dx
=
dFdx
(
tex_coords
);
vec2
tc_dy
=
dFdy
(
tex_coords
);
vec3
p_dy_N
=
cross
(
p_dy
,
VN
);
vec3
p_dx_N
=
cross
(
VN
,
p_dx
);
vec3
T
=
p_dy_N
*
tc_dx
.
x
+
p_dx_N
*
tc_dy
.
x
;
vec3
B
=
p_dy_N
*
tc_dx
.
y
+
p_dx_N
*
tc_dy
.
y
;
float
inv_max
=
inversesqrt
(
max
(
dot
(
T
,
T
),
dot
(
B
,
B
)));
mat3
TBN
=
mat3
(
T
*
inv_max
,
B
*
inv_max
,
VN
);
return
normalize
(
TBN
*
N
);
}
assets/core_assets/shader/model_emissive.frag
View file @
b10a8d6d
...
...
@@ -5,6 +5,8 @@
#include
"global_uniforms.glsl"
#include
"normal_encoding.glsl"
layout
(
early_fragment_tests
)
in
;
layout
(
location
=
0
)
in
vec3
world_pos
;
layout
(
location
=
1
)
in
vec3
view_pos
;
layout
(
location
=
2
)
in
vec3
normal
;
...
...
@@ -28,9 +30,6 @@ layout(push_constant) uniform Per_model_uniforms {
void
main
()
{
vec4
albedo
=
texture
(
albedo_sampler
,
tex_coords
);
if
(
albedo
.
a
<
0
.
1
)
discard
;
depth_out
=
vec4
(
-
view_pos
.
z
/
global_uniforms
.
proj_planes
.
y
,
0
,
0
,
1
);
albedo_mat_id
=
vec4
(
albedo
.
rgb
,
1
.
0
);
mat_data
=
vec4
(
encode_normal
(
normalize
(
normal
)),
0
.
0
,
0
.
0
);
...
...
assets/demo_assets/models/cube.mmf
View file @
b10a8d6d
No preview for this file type
dependencies/CMakeLists.txt
View file @
b10a8d6d
...
...
@@ -24,8 +24,11 @@ add_subdirectory(sf2)
if
(
MIRRAGE_BUILD_MESH_CONVERTER
)
add_subdirectory
(
assimp
)
set_property
(
TARGET assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/assimp/include"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/assimp/include"
)
find_package
(
assimp 4.1
)
if
(
NOT assimp_FOUND
)
add_subdirectory
(
assimp
)
set_property
(
TARGET assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/assimp/include"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/assimp/include"
)
endif
()
add_subdirectory
(
stb_image
)
endif
()
src/demo/src/game_engine.cpp
View file @
b10a8d6d
...
...
@@ -4,6 +4,7 @@
#include
<mirrage/renderer/pass/blit_pass.hpp>
#include
<mirrage/renderer/pass/bloom_pass.hpp>
#include
<mirrage/renderer/pass/deferred_pass.hpp>
#include
<mirrage/renderer/pass/frustum_culling_pass.hpp>
#include
<mirrage/renderer/pass/gen_mipmap_pass.hpp>
#include
<mirrage/renderer/pass/gi_pass.hpp>
#include
<mirrage/renderer/pass/gui_pass.hpp>
...
...
@@ -25,10 +26,10 @@ namespace mirrage {
char
**
env
)
:
Engine
(
org
,
title
,
version_major
,
version_minor
,
debug
,
false
,
argc
,
argv
,
env
)
,
_renderer_factory
(
std
::
make_unique
<
renderer
::
Deferred_renderer_factory
>
(
graphics_context
()
,
*
this
,
window
(),
assets
(),
util
::
make_vector
(
renderer
::
make_pass_factory
<
renderer
::
Shadowmapping_pass_factory
>
(),
util
::
make_vector
(
renderer
::
make_pass_factory
<
renderer
::
Frustum_culling_pass_factory
>
(),
renderer
::
make_pass_factory
<
renderer
::
Shadowmapping_pass_factory
>
(),
renderer
::
make_pass_factory
<
renderer
::
Deferred_pass_factory
>
(),
renderer
::
make_pass_factory
<
renderer
::
Gen_mipmap_pass_factory
>
(),
renderer
::
make_pass_factory
<
renderer
::
Ssao_pass_factory
>
(),
...
...
src/demo/src/meta_system.cpp
View file @
b10a8d6d
...
...
@@ -11,7 +11,7 @@ namespace mirrage {
Meta_system
::
Meta_system
(
Game_engine
&
engine
)
:
_entities
(
engine
.
assets
(),
this
)
,
_renderer
(
engine
.
renderer_factory
().
create_renderer
(
_entities
,
*
this
))
,
_renderer
(
engine
.
renderer_factory
().
create_renderer
(
_entities
))
,
_model_loading
(
std
::
make_unique
<
renderer
::
Loading_system
>
(
_entities
,
engine
.
assets
()))
,
_nims
(
std
::
make_unique
<
systems
::
Nim_system
>
(
_entities
))
{
...
...
src/demo/src/test_screen.cpp
View file @
b10a8d6d
...
...
@@ -64,10 +64,7 @@ namespace mirrage {
:
Screen
(
engine
)
,
_mailbox
(
engine
.
bus
())
,
_meta_system
(
static_cast
<
Game_engine
&>
(
engine
))
,
_gui
(
engine
.
window
().
viewport
(),
engine
.
assets
(),
engine
.
input
(),
_meta_system
.
renderer
().
find_pass
<
gui
::
Gui_renderer
>
())
,
_gui
(
engine
.
gui
())
,
_performance_log
(
util
::
nothing
)
,
_window_width
(
engine
.
window
().
width
())
,
_window_height
(
engine
.
window
().
height
())
...
...
@@ -320,8 +317,6 @@ namespace mirrage {
void
Test_screen
::
_draw
()
{
_gui
.
start_frame
();
if
(
_show_ui
)
{
_draw_settings_window
();
_draw_histogram_window
();
...
...
src/demo/src/test_screen.hpp
View file @
b10a8d6d
...
...
@@ -40,7 +40,7 @@ namespace mirrage {
Meta_system
_meta_system
;
gui
::
Gui
_gui
;
gui
::
Gui
&
_gui
;
ecs
::
Entity_facet
_camera
;
ecs
::
Entity_facet
_sun
;
...
...
src/mesh_converter/model_parser.cpp
View file @
b10a8d6d
...
...
@@ -11,6 +11,7 @@
#include
<assimp/scene.h>
// Output data structure
#include
<assimp/Importer.hpp>
// C++ importer interface
#include
<glm/gtx/norm.hpp>
#include
<gsl/gsl>
#include
<fstream>
...
...
@@ -70,6 +71,35 @@ namespace mirrage {
out
.
write
(
reinterpret_cast
<
const
char
*>
(
value
.
data
()),
value
.
size
()
*
sizeof
(
T
));
}
struct
Bounding_sphere_calculator
{
bool
first_point
=
true
;
glm
::
vec3
min_vertex_pos
;
glm
::
vec3
max_vertex_pos
;
glm
::
vec3
center
;
float
radius_2
=
0.0
f
;
void
add_point
(
glm
::
vec3
p
)
{
if
(
first_point
)
{
first_point
=
false
;
min_vertex_pos
=
p
;
max_vertex_pos
=
p
;
return
;
}
min_vertex_pos
.
x
=
std
::
min
(
min_vertex_pos
.
x
,
p
.
x
);
min_vertex_pos
.
y
=
std
::
min
(
min_vertex_pos
.
y
,
p
.
y
);
min_vertex_pos
.
z
=
std
::
min
(
min_vertex_pos
.
z
,
p
.
z
);
max_vertex_pos
.
x
=
std
::
max
(
max_vertex_pos
.
x
,
p
.
x
);
max_vertex_pos
.
y
=
std
::
max
(
max_vertex_pos
.
y
,
p
.
y
);
max_vertex_pos
.
z
=
std
::
max
(
max_vertex_pos
.
z
,
p
.
z
);
}
void
start_process
()
{
center
=
min_vertex_pos
+
(
max_vertex_pos
-
min_vertex_pos
)
/
2.
f
;
}
void
process_point
(
glm
::
vec3
p
)
{
radius_2
=
std
::
max
(
radius_2
,
glm
::
distance2
(
p
,
center
));
}
};
}
// namespace
...
...
@@ -124,6 +154,8 @@ namespace mirrage {
vertex_count
+=
mesh
->
mNumVertices
;
}
auto
rigged
=
false
;
// TODO
// load meshes
auto
indices
=
std
::
vector
<
std
::
uint32_t
>
();
auto
vertices
=
std
::
vector
<
renderer
::
Model_vertex
>
();
...
...
@@ -167,9 +199,30 @@ namespace mirrage {
"Unable to open output file
\"
"
<<
model_out_filename
<<
"
\"
!"
);
auto
header
=
renderer
::
Model_file_header
();
header
.
vertex_
count
=
gsl
::
narrow
<
std
::
uint32_t
>
(
vertices
.
size
()
*
sizeof
(
renderer
::
Model_vertex
));
header
.
index_
count
=
gsl
::
narrow
<
std
::
uint32_t
>
(
indices
.
size
()
*
sizeof
(
std
::
uint32_t
));
header
.
vertex_
size
=
gsl
::
narrow
<
std
::
uint32_t
>
(
vertices
.
size
()
*
sizeof
(
renderer
::
Model_vertex
));
header
.
index_
size
=
gsl
::
narrow
<
std
::
uint32_t
>
(
indices
.
size
()
*
sizeof
(
std
::
uint32_t
));
header
.
submesh_count
=
gsl
::
narrow
<
std
::
uint32_t
>
(
sub_meshes
.
size
());
header
.
flags
=
rigged
?
1
:
0
;
// calculate bounding sphere
auto
bounding_sphere
=
Bounding_sphere_calculator
{};
for
(
auto
&
v
:
vertices
)
{
bounding_sphere
.
add_point
(
v
.
position
);
}
bounding_sphere
.
start_process
();
for
(
auto
&
v
:
vertices
)
{
bounding_sphere
.
process_point
(
v
.
position
);
}
header
.
bounding_sphere_radius
=
std
::
sqrt
(
bounding_sphere
.
radius_2
);
header
.
bounding_sphere_offset_x
=
bounding_sphere
.
center
.
x
;
header
.
bounding_sphere_offset_y
=
bounding_sphere
.
center
.
y
;
header
.
bounding_sphere_offset_z
=
bounding_sphere
.
center
.
z
;
LOG
(
plog
::
debug
)
<<
"Bounds: "
<<
header
.
bounding_sphere_radius
<<
" at "
<<
header
.
bounding_sphere_offset_x
<<
"/"
<<
header
.
bounding_sphere_offset_y
<<
"/"
<<
header
.
bounding_sphere_offset_z
;
// write header
write
(
model_out_file
,
header
);
...
...
@@ -179,6 +232,28 @@ namespace mirrage {
write
(
model_out_file
,
sub_mesh
.
index_offset
);
write
(
model_out_file
,
sub_mesh
.
index_count
);
// calculate bounding sphere
auto
bounding_sphere
=
Bounding_sphere_calculator
{};
for
(
auto
i
=
0u
;
i
<
sub_mesh
.
index_count
;
i
++
)
{
auto
idx
=
indices
.
at
(
i
+
sub_mesh
.
index_offset
);
bounding_sphere
.
add_point
(
vertices
.
at
(
idx
).
position
);
}
bounding_sphere
.
start_process
();
for
(
auto
i
=
0u
;
i
<
sub_mesh
.
index_count
;
i
++
)
{
auto
idx
=
indices
.
at
(
i
+
sub_mesh
.
index_offset
);
bounding_sphere
.
process_point
(
vertices
.
at
(
idx
).
position
);
}
write
(
model_out_file
,
std
::
sqrt
(
bounding_sphere
.
radius_2
));
write
(
model_out_file
,
bounding_sphere
.
center
.
x
);
write
(
model_out_file
,
bounding_sphere
.
center
.
y
);
write
(
model_out_file
,
bounding_sphere
.
center
.
z
);
LOG
(
plog
::
debug
)
<<
"Sub-Bounds: "
<<
std
::
sqrt
(
bounding_sphere
.
radius_2
)
<<
" at "
<<
bounding_sphere
.
center
.
x
<<
"/"
<<
bounding_sphere
.
center
.
y
<<
"/"
<<
bounding_sphere
.
center
.
z
;
auto
material_id_length
=
gsl
::
narrow
<
std
::
uint32_t
>
(
sub_mesh
.
material_id
.
size
());
write
(
model_out_file
,
material_id_length
);
model_out_file
.
write
(
sub_mesh
.
material_id
.
data
(),
material_id_length
);
...
...
src/mirrage/core/include/mirrage/engine.hpp
View file @
b10a8d6d
...
...
@@ -74,6 +74,7 @@ namespace mirrage {
auto
&
screens
()
noexcept
{
return
_screens
;
}
auto
&
translator
()
noexcept
{
return
*
_translator
;
}
auto
&
net
()
noexcept
{
return
*
_net_manager
;
}
auto
&
gui
()
noexcept
{
return
*
_gui
;
}
protected:
virtual
void
_on_pre_frame
(
util
::
Time
)
{}
...
...
@@ -96,6 +97,7 @@ namespace mirrage {
std
::
unique_ptr
<
input
::
Input_manager
>
_input_manager
;
std
::
unique_ptr
<
Engine_event_filter
>
_event_filter
;
std
::
unique_ptr
<
net
::
Net_manager
>
_net_manager
;
std
::
unique_ptr
<
gui
::
Gui
>
_gui
;
double
_current_time
=
0
;
double
_last_time
=
0
;
...
...
src/mirrage/core/src/engine.cpp
View file @
b10a8d6d
...
...
@@ -3,6 +3,7 @@
#include
<mirrage/asset/asset_manager.hpp>
#include
<mirrage/graphic/context.hpp>
#include
<mirrage/graphic/window.hpp>
#include
<mirrage/gui/gui.hpp>
#include
<mirrage/input/input_manager.hpp>
#include
<mirrage/net/net_manager.hpp>
#include
<mirrage/translations.hpp>
...
...
@@ -116,6 +117,8 @@ namespace mirrage {
_graphics_main_window
.
process
([
&
](
auto
&
window
)
{
_input_manager
->
viewport
({
0
,
0
,
window
.
width
(),
window
.
height
()});
_input_manager
->
window
(
window
.
window_handle
());
_gui
=
std
::
make_unique
<
gui
::
Gui
>
(
window
.
viewport
(),
*
_asset_manager
,
*
_input_manager
);
});
if
(
headless
)
{
...
...
@@ -199,6 +202,9 @@ namespace mirrage {
_on_pre_frame
(
delta_time_smoothed
*
second
);
if
(
_gui
)
_gui
->
start_frame
();
_screens
.
on_frame
(
delta_time_smoothed
*
second
);
_on_post_frame
(
delta_time_smoothed
*
second
);
...
...
src/mirrage/ecs/include/mirrage/ecs/components/transform_comp.hpp
View file @
b10a8d6d
...
...
@@ -24,6 +24,7 @@ namespace mirrage::ecs::components {
void
rotate_local
(
float
yaw
,
float
pitch
);
auto
to_mat4
()
const
noexcept
->
glm
::
mat4
;
auto
to_mat3
()
const
noexcept
->
glm
::
mat3
;
glm
::
vec3
position
{
0
,
0
,
0
};
glm
::
quat
orientation
{
1
,
0
,
0
,
0
};
...
...
src/mirrage/ecs/include/mirrage/ecs/entity_manager.hpp
View file @
b10a8d6d
...
...
@@ -46,7 +46,7 @@ namespace mirrage::ecs {
// user interface; thread-safe
auto
emplace
()
noexcept
->
Entity_facet
;
auto
emplace
(
const
std
::
string
&
blueprint
)
->
Entity_facet
;
auto
emplace
(
const
std
::
string
&
blueprint
)
->
Entity_facet
;
// TODO/FIXME: currently NOT thread-safe
auto
get
(
Entity_handle
entity
)
->
util
::
maybe
<
Entity_facet
>
;
auto
get_handle
(
Entity_id
id
)
const
->
Entity_handle
{
return
_handles
.
get
(
id
);
}
auto
validate
(
Entity_handle
entity
)
->
bool
{
return
_handles
.
valid
(
entity
);
}
...
...
src/mirrage/ecs/src/components/transform_comp.cpp
View file @
b10a8d6d
...
...
@@ -38,4 +38,13 @@ namespace mirrage::ecs::components {
model
[
3
]
=
glm
::
vec4
(
position
,
1.
f
);
return
model
;
}
auto
Transform_comp
::
to_mat3
()
const
noexcept
->
glm
::
mat3
{
// clang-format off
return
glm
::
toMat3
(
orientation
)
*
glm
::
mat3
(
scale
.
x
,
0
,
0
,
0
,
scale
.
y
,
0
,
0
,
0
,
scale
.
z
);
// clang-format on
}
}
// namespace mirrage::ecs::components
src/mirrage/gui/include/mirrage/gui/gui.hpp
View file @
b10a8d6d
...
...
@@ -58,7 +58,8 @@ namespace mirrage::gui {
class
Gui_renderer
{
public:
virtual
~
Gui_renderer
()
=
default
;
Gui_renderer
(
Gui
&
gui
);
virtual
~
Gui_renderer
();
void
draw_gui
();
...
...
@@ -81,7 +82,7 @@ namespace mirrage::gui {
virtual
void
finalize_draw
()
=
0
;
private:
Gui
*
_gui
=
nullptr
;
Gui
*
_gui
;
};
// TODO: gamepad input: https://gist.github.com/vurtun/519801825b4ccfad6767
...
...
@@ -90,17 +91,13 @@ namespace mirrage::gui {
// https://github.com/vurtun/nuklear/blob/master/example/skinning.c
class
Gui
{
public:
Gui
(
glm
::
vec4
viewport
,
asset
::
Asset_manager
&
assets
,
input
::
Input_manager
&
input
,
util
::
tracking_ptr
<
Gui_renderer
>
renderer
);
Gui
(
glm
::
vec4
viewport
,
asset
::
Asset_manager
&
assets
,
input
::
Input_manager
&
input
);
~
Gui
();
void
draw
();
void
start_frame
();
auto
ctx
()
->
nk_context
*
;
auto
renderer
()
noexcept
->
auto
&
{
return
_renderer
;
}
void
viewport
(
glm
::
vec4
new_viewport
);
...
...
@@ -108,16 +105,19 @@ namespace mirrage::gui {
auto
centered_left
(
int
width
,
int
height
)
->
struct
nk_rect
;
auto
centered_right
(
int
width
,
int
height
)
->
struct
nk_rect
;
auto
ready
()
const
noexcept
{
return
bool
(
_impl
);
}
private:
friend
class
Gui_renderer
;
struct
PImpl
;
glm
::
vec4
_viewport
;
asset
::
Asset_manager
&
_assets
;
input
::
Input_manager
&
_input
;
util
::
tracking_ptr
<
Gui_renderer
>
_rendere
r
;
Gui_renderer
*
_last_renderer
;
std
::
unique_ptr
<
PImpl
>
_impl
;
glm
::
vec4
_viewport
;
asset
::
Asset_manager
&
_assets
;
input
::
Input_manager
&
_input
;
Gui_renderer
*
_renderer
=
nullpt
r
;
Gui_renderer
*
_last_renderer
=
nullptr
;
std
::
unique_ptr
<
PImpl
>
_impl
;
void
_init
();
};
...
...
Prev
1
2
3
Next
Write
Preview
Supports
Markdown
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