1 | // Copyright (C) 2016-2016 ChaosForge Ltd
|
---|
2 | // http://chaosforge.org/
|
---|
3 | //
|
---|
4 | // This file is part of Nova libraries.
|
---|
5 | // For conditions of distribution and use, see copying.txt file in root folder.
|
---|
6 |
|
---|
7 | #include "nv/engine/renderer.hh"
|
---|
8 |
|
---|
9 | #include "nv/core/profiler.hh"
|
---|
10 |
|
---|
11 | using namespace nv;
|
---|
12 |
|
---|
13 | renderer::renderer( context* ctx )
|
---|
14 | : m_context( ctx )
|
---|
15 | {
|
---|
16 | for ( auto& i : m_statistics ) i = 0;
|
---|
17 |
|
---|
18 | struct qvtx
|
---|
19 | {
|
---|
20 | nv::vec2 position;
|
---|
21 | nv::vec2 texcoord;
|
---|
22 | };
|
---|
23 |
|
---|
24 | qvtx quad[] = {
|
---|
25 | qvtx{ vec2( -1.0f,-1.0f ), vec2( 0.0f, 0.0f ) },
|
---|
26 | qvtx{ vec2( 1.0f,-1.0f ), vec2( 1.0f, 0.0f ) },
|
---|
27 | qvtx{ vec2( 1.0f,1.0f ), vec2( 1.0f, 1.0f ) },
|
---|
28 | qvtx{ vec2( 1.0f,1.0f ), vec2( 1.0f, 1.0f ) },
|
---|
29 | qvtx{ vec2( -1.0f,1.0f ), vec2( 0.0f, 1.0f ) },
|
---|
30 | qvtx{ vec2( -1.0f,-1.0f ), vec2( 0.0f, 0.0f ) },
|
---|
31 | };
|
---|
32 | m_quad = m_context->create_vertex_array( quad, 6, STATIC_DRAW );
|
---|
33 | }
|
---|
34 |
|
---|
35 | void renderer::sort()
|
---|
36 | {
|
---|
37 | stable_sort( m_elements.begin(), m_elements.end(), renderer_element_compare() );
|
---|
38 | }
|
---|
39 |
|
---|
40 |
|
---|
41 | void renderer::render( const scene_state& s, const render_pass& pass )
|
---|
42 | {
|
---|
43 | scene_state ss( s );
|
---|
44 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
45 | m_context->set_draw_buffers( pass.output_count, pass.output );
|
---|
46 | m_context->set_viewport( ss.get_viewport() );
|
---|
47 |
|
---|
48 | if ( pass.cstate.buffers != buffer_mask::NO_BUFFER )
|
---|
49 | m_context->clear( pass.cstate );
|
---|
50 |
|
---|
51 | for ( uint32 i = 0; i < size( pass.binds ); ++i )
|
---|
52 | if ( pass.binds[i] )
|
---|
53 | m_context->bind( pass.binds[i], texture_slot( i ) );
|
---|
54 |
|
---|
55 | resource_id current_mat;
|
---|
56 | mat4 model = ss.get_model();
|
---|
57 | for ( const renderer_element& element : m_elements )
|
---|
58 | if ( match( element.flags, pass ) )
|
---|
59 | {
|
---|
60 | ss.set_model( model * element.model.extract() );
|
---|
61 | if ( auto mesh = element.mesh.lock() )
|
---|
62 | if ( mesh->count > 0 )
|
---|
63 | if ( auto program = pass.programs[mesh->shader].lock() )
|
---|
64 | {
|
---|
65 | if ( element.mat.id() != current_mat )
|
---|
66 | {
|
---|
67 | if ( auto mat = element.mat.lock() )
|
---|
68 | {
|
---|
69 | for ( uint32 i = 0; i < 8; ++i )
|
---|
70 | if ( mat->textures[i] && !pass.binds[i] )
|
---|
71 | m_context->bind( mat->textures[i], nv::texture_slot( i ) );
|
---|
72 | current_mat = element.mat.id();
|
---|
73 | }
|
---|
74 | }
|
---|
75 |
|
---|
76 | m_context->get_device()->set_opt_uniform( *program, "nv_bone_offset", element.bone_offset );
|
---|
77 | m_context->get_device()->set_opt_uniform( *program, "nv_flags", unsigned( *element.flags.data() ) );
|
---|
78 |
|
---|
79 | m_context->apply_engine_uniforms( *program, ss );
|
---|
80 | m_context->draw( TRIANGLES, pass.rstate, *program, mesh->va, mesh->count );
|
---|
81 |
|
---|
82 | m_statistics[TRIANGLE_COUNT] += mesh->count / 3;
|
---|
83 | m_statistics[DRAW_CALL]++;
|
---|
84 | }
|
---|
85 | }
|
---|
86 |
|
---|
87 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
88 | }
|
---|
89 |
|
---|
90 | void renderer::render( const scene_state& ss, const render_pass& pass, vertex_array va, uint32 va_count, uint32 program_idx )
|
---|
91 | {
|
---|
92 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
93 | m_context->set_draw_buffers( pass.output_count, pass.output );
|
---|
94 | m_context->set_viewport( ss.get_viewport() );
|
---|
95 |
|
---|
96 | if ( pass.cstate.buffers != buffer_mask::NO_BUFFER )
|
---|
97 | m_context->clear( pass.cstate );
|
---|
98 |
|
---|
99 | for ( uint32 i = 0; i < size( pass.binds ); ++i )
|
---|
100 | if ( pass.binds[i] )
|
---|
101 | m_context->bind( pass.binds[i], texture_slot(i) );
|
---|
102 |
|
---|
103 | if ( auto program = pass.programs[program_idx].lock() )
|
---|
104 | {
|
---|
105 | m_context->apply_engine_uniforms( *program, ss );
|
---|
106 | m_context->draw( TRIANGLES, pass.rstate, *program, va, va_count );
|
---|
107 | m_statistics[ TRIANGLE_COUNT ] += 2;
|
---|
108 | m_statistics[ DRAW_CALL ]++;
|
---|
109 | }
|
---|
110 |
|
---|
111 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
112 | }
|
---|
113 |
|
---|
114 | void nv::renderer::render_direct( const scene_state& s, const render_pass& pass, const nv::array_view< renderer_direct_element >& elements, uint32 program_idx )
|
---|
115 | {
|
---|
116 | if ( m_elements.size() == 0 ) return;
|
---|
117 |
|
---|
118 | scene_state ss( s );
|
---|
119 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
120 | m_context->set_draw_buffers( pass.output_count, pass.output );
|
---|
121 | m_context->set_viewport( ss.get_viewport() );
|
---|
122 |
|
---|
123 | if ( pass.cstate.buffers != buffer_mask::NO_BUFFER )
|
---|
124 | m_context->clear( pass.cstate );
|
---|
125 |
|
---|
126 | for ( uint32 i = 0; i < size( pass.binds ); ++i )
|
---|
127 | if ( pass.binds[i] )
|
---|
128 | m_context->bind( pass.binds[i], texture_slot( i ) );
|
---|
129 |
|
---|
130 | resource_id current_mat;
|
---|
131 | resource_id current_prog;
|
---|
132 |
|
---|
133 | mat4 model = ss.get_model();
|
---|
134 | for ( uint32 index = 0; index < elements.size(); ++index )
|
---|
135 | {
|
---|
136 | const renderer_direct_element& element = elements[index];
|
---|
137 | if ( match( element.flags, pass ) )
|
---|
138 | {
|
---|
139 | ss.set_model( model * element.model.extract() );
|
---|
140 | if ( element.count > 0 )
|
---|
141 | {
|
---|
142 | if ( auto program = element.programs[program_idx].lock() )
|
---|
143 | {
|
---|
144 | if ( element.material.id() != current_mat )
|
---|
145 | {
|
---|
146 | if ( auto mat = element.material.lock() )
|
---|
147 | {
|
---|
148 | for ( uint32 i = 0; i < 8; ++i )
|
---|
149 | if ( mat->textures[i] && !pass.binds[i] )
|
---|
150 | m_context->bind( mat->textures[i], nv::texture_slot( i ) );
|
---|
151 | current_mat = element.material.id();
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | m_context->get_device()->set_opt_uniform( *program, "nv_flags", unsigned( *element.flags.data() ) );
|
---|
156 | m_context->get_device()->set_opt_uniform( *program, "nv_index", unsigned( index ) );
|
---|
157 | m_context->apply_engine_uniforms( *program, ss );
|
---|
158 |
|
---|
159 | if ( element.instances > 0 )
|
---|
160 | m_context->draw_instanced( TRIANGLES, pass.rstate, *program, element.instances, element.va, element.count, element.first );
|
---|
161 | else
|
---|
162 | m_context->draw( TRIANGLES, pass.rstate, *program, element.va, element.count, element.first );
|
---|
163 |
|
---|
164 | m_statistics[TRIANGLE_COUNT] += ( element.count / 3 ) * max< uint32 >( element.instances, 1 );
|
---|
165 | m_statistics[DRAW_CALL]++;
|
---|
166 | }
|
---|
167 | }
|
---|
168 | }
|
---|
169 | }
|
---|
170 | m_context->bind( pass.fbuffer, FRAMEBUFFER );
|
---|
171 | }
|
---|