[507] | 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"
|
---|
[508] | 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 | }
|
---|