17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 05:09:20 +02:00

Remove legacy OpenGL 2.1 renderer

This commit is contained in:
2026-10-15 00:06:31 +02:00
parent 05ffb9058c
commit 3d3eef2e1c
35 changed files with 29 additions and 6760 deletions

View File

@@ -1,14 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/openglcolor.h"
opengl_color OpenGLColor;

View File

@@ -1,77 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "utilities/Globals.h"
// encapsulation of the fixed pipeline opengl color
class opengl_color {
public:
// constructors:
opengl_color() = default;
// methods:
inline
void
color3( glm::vec3 const &Color ) {
return color4( glm::vec4{ Color, 1.f } ); }
inline
void
color3( float const Red, float const Green, float const Blue ) {
return color3( glm::vec3 { Red, Green, Blue } ); }
inline
void
color3( float const *Value ) {
return color3( glm::make_vec3( Value ) ); }
inline
void
color4( glm::vec4 const &Color ) {
if( ( Color != m_color ) || ( false == Global.bUseVBO ) ) {
m_color = Color;
::glColor4fv( glm::value_ptr( m_color ) ); } }
inline
void
color4( float const Red, float const Green, float const Blue, float const Alpha ) {
return color4( glm::vec4{ Red, Green, Blue, Alpha } ); }
inline
void
color4( float const *Value ) {
return color4( glm::make_vec4( Value ) );
}
inline
glm::vec4 const &
data() const {
return m_color; }
inline
float const *
data_array() const {
return glm::value_ptr( m_color ); }
private:
// members:
glm::vec4 m_color { -1 };
};
extern opengl_color OpenGLColor;
// NOTE: standard opengl calls re-definitions
#undef glColor3f
#undef glColor3fv
#undef glColor4f
#undef glColor4fv
#define glColor3f OpenGLColor.color3
#define glColor3fv OpenGLColor.color3
#define glColor4f OpenGLColor.color4
#define glColor4fv OpenGLColor.color4
//---------------------------------------------------------------------------

View File

@@ -1,375 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/openglgeometrybank.h"
#include "rendering/openglcolor.h"
#include "utilities/Logs.h"
namespace gfx {
// opengl vbo-based variant of the geometry bank
GLuint opengl_vbogeometrybank::m_activevertexbuffer { 0 }; // buffer bound currently on the opengl end, if any
unsigned int opengl_vbogeometrybank::m_activestreams { gfx::stream::none }; // currently enabled data type pointers
std::vector<GLint> opengl_vbogeometrybank::m_activetexturearrays; // currently enabled texture coord arrays
// create() subclass details
void
opengl_vbogeometrybank::create_( gfx::geometry_handle const &Geometry ) {
// adding a chunk means we'll be (re)building the buffer, which will fill the chunk records, amongst other things.
// thus we don't need to initialize the values here
m_chunkrecords.emplace_back( chunk_record() );
// kiss the existing buffer goodbye, new overall data size means we'll be making a new one
delete_buffer();
}
// replace() subclass details
void
opengl_vbogeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
chunkrecord.is_good = false;
// if the overall length of the chunk didn't change we can get away with reusing the old buffer...
if( geometry_bank::chunk( Geometry ).vertices.size() != chunkrecord.vertex_count ) {
// ...but otherwise we'll need to allocate a new one
// TBD: we could keep and reuse the old buffer also if the new chunk is smaller than the old one,
// but it'd require some extra tracking and work to keep all chunks up to date; also wasting vram; may be not worth it?
delete_buffer();
}
}
// draw() subclass details
std::size_t
opengl_vbogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
setup_buffer();
auto &chunkrecord { m_chunkrecords[ Geometry.chunk - 1 ] };
// sanity check; shouldn't be needed but, eh
if( chunkrecord.vertex_count == 0 ) { return 0; }
// setup...
if( m_activevertexbuffer != m_vertexbuffer ) {
bind_buffer();
}
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
if( false == chunkrecord.is_good ) {
// we may potentially need to upload new buffer data before we can draw it
if( chunkrecord.index_count > 0 ) {
::glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER,
chunkrecord.index_offset * sizeof( gfx::basic_index ),
chunkrecord.index_count * sizeof( gfx::basic_index ),
chunk.indices.data() );
}
::glBufferSubData(
GL_ARRAY_BUFFER,
chunkrecord.vertex_offset * sizeof( gfx::basic_vertex ),
chunkrecord.vertex_count * sizeof( gfx::basic_vertex ),
chunk.vertices.data() );
chunkrecord.is_good = true;
}
// ...render...
if( chunkrecord.index_count > 0 ) {
/*
::glDrawElementsBaseVertex(
chunk.type,
chunkrecord.index_count, GL_UNSIGNED_INT, reinterpret_cast<void const *>( chunkrecord.index_offset * sizeof( gfx::basic_index ) ),
chunkrecord.vertex_offset );
*/
if (glDrawRangeElementsBaseVertex) {
if( m_activestreams != Streams ) {
bind_streams( Units, Streams );
}
::glDrawRangeElementsBaseVertex(
chunk.type,
0, static_cast<GLuint>(chunkrecord.vertex_count),
static_cast<GLsizei>(chunkrecord.index_count), GL_UNSIGNED_INT, reinterpret_cast<void const *>( chunkrecord.index_offset * sizeof( gfx::basic_index ) ),
static_cast<GLint>(chunkrecord.vertex_offset) );
}
else {
bind_streams( Units, Streams, chunkrecord.vertex_offset );
::glDrawRangeElements(
chunk.type,
0, static_cast<GLuint>(chunkrecord.vertex_count),
static_cast<GLsizei>(chunkrecord.index_count), GL_UNSIGNED_INT, reinterpret_cast<void const *>( chunkrecord.index_offset * sizeof( gfx::basic_index ) ) );
}
}
else {
if( m_activestreams != Streams ) {
bind_streams( Units, Streams );
}
::glDrawArrays( chunk.type, static_cast<GLint>(chunkrecord.vertex_offset), static_cast<GLsizei>(chunkrecord.vertex_count) );
}
// ...post-render cleanup
/*
::glDisableClientState( GL_VERTEX_ARRAY );
::glDisableClientState( GL_NORMAL_ARRAY );
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
::glBindBuffer( GL_ARRAY_BUFFER, 0 ); m_activebuffer = 0;
*/
auto const vertexcount { ( chunkrecord.index_count > 0 ? chunkrecord.index_count : chunkrecord.vertex_count ) };
switch( chunk.type ) {
case GL_TRIANGLES: { return vertexcount / 3; }
case GL_TRIANGLE_STRIP: { return vertexcount - 2; }
default: { return 0; }
}
}
// release () subclass details
void
opengl_vbogeometrybank::release_() {
delete_buffer();
}
void
opengl_vbogeometrybank::setup_buffer() {
if( m_vertexbuffer != 0 ) { return; }
// if there's no buffer, we'll have to make one
// NOTE: this isn't exactly optimal in terms of ensuring the gfx card doesn't stall waiting for the data
// may be better to initiate upload earlier (during update phase) and trust this effort won't go to waste
if( true == m_chunks.empty() ) { return; }
std::size_t vertexcount{ 0 };
std::size_t indexcount{ 0 };
auto chunkiterator = m_chunks.cbegin();
for( auto &chunkrecord : m_chunkrecords ) {
// fill records for all chunks, based on the chunk data
chunkrecord.is_good = false; // if we're re-creating buffer, chunks might've been uploaded in the old one
chunkrecord.vertex_offset = vertexcount;
chunkrecord.vertex_count = chunkiterator->vertices.size();
vertexcount += chunkrecord.vertex_count;
chunkrecord.index_offset = indexcount;
chunkrecord.index_count = chunkiterator->indices.size();
indexcount += chunkrecord.index_count;
++chunkiterator;
}
// the odds for all created chunks to get replaced with empty ones are quite low, but the possibility does exist
if( vertexcount == 0 ) { return; }
// try to set up the buffers we need
if( ( indexcount > 0 ) && ( m_indexbuffer == 0 ) ) {
::glGenBuffers( 1, &m_indexbuffer );
if( m_indexbuffer == 0 ) { return; } // if we didn't get a buffer we'll try again during the next draw call
}
if( m_vertexbuffer == 0 ) {
::glGenBuffers( 1, &m_vertexbuffer );
if( m_vertexbuffer == 0 ) { return; } // if we didn't get a buffer we'll try again during the next draw call
}
bind_buffer();
// NOTE: we're using static_draw since it's generally true for all we have implemented at the moment
// TODO: allow to specify usage hint at the object creation, and pass it here
if( indexcount > 0 ) {
::glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
indexcount * sizeof( gfx::basic_index ),
nullptr,
GL_STATIC_DRAW );
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
// TBD: throw a bad_alloc?
ErrorLog( "openGL error: out of memory; failed to create a geometry index buffer" );
delete_buffer();
return;
}
}
::glBufferData(
GL_ARRAY_BUFFER,
vertexcount * sizeof( gfx::basic_vertex ),
nullptr,
GL_STATIC_DRAW );
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
// TBD: throw a bad_alloc?
ErrorLog( "openGL error: out of memory; failed to create a geometry buffer" );
delete_buffer();
return;
}
}
void
opengl_vbogeometrybank::bind_buffer() const {
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
m_activevertexbuffer = m_vertexbuffer;
m_activestreams = gfx::stream::none;
}
void
opengl_vbogeometrybank::delete_buffer() {
if( m_indexbuffer != 0 ) {
::glDeleteBuffers( 1, &m_indexbuffer );
m_indexbuffer = 0;
}
if( m_vertexbuffer != 0 ) {
::glDeleteBuffers( 1, &m_vertexbuffer );
if( m_activevertexbuffer == m_vertexbuffer ) {
m_activevertexbuffer = 0;
release_streams();
}
m_vertexbuffer = 0;
// NOTE: since we've deleted the buffer all chunks it held were rendered invalid as well
// instead of clearing their state here we're delaying it until new buffer is created to avoid looping through chunk records twice
}
}
void
opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned int const Streams, size_t offset ) {
if( Streams & gfx::stream::position ) {
::glVertexPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( offsetof(gfx::basic_vertex, position) + sizeof( gfx::basic_vertex ) * offset ) );
::glEnableClientState( GL_VERTEX_ARRAY );
}
else {
::glDisableClientState( GL_VERTEX_ARRAY );
}
// NOTE: normal and color streams share the data, making them effectively mutually exclusive
if( Streams & gfx::stream::normal ) {
::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) );
::glEnableClientState( GL_NORMAL_ARRAY );
}
else {
::glDisableClientState( GL_NORMAL_ARRAY );
}
if( Streams & gfx::stream::color ) {
::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( offsetof(gfx::basic_vertex, normal) + sizeof( gfx::basic_vertex ) * offset ) );
::glEnableClientState( GL_COLOR_ARRAY );
}
else {
::glDisableClientState( GL_COLOR_ARRAY );
}
if( Streams & gfx::stream::texture ) {
for( auto unit : Units.texture ) {
::glClientActiveTexture( GL_TEXTURE0 + unit );
::glTexCoordPointer( 2, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( offsetof(gfx::basic_vertex, texture) + sizeof( gfx::basic_vertex ) * offset ) );
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
}
m_activetexturearrays = Units.texture;
}
else {
for( auto unit : Units.texture ) {
::glClientActiveTexture( GL_TEXTURE0 + unit );
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}
m_activetexturearrays.clear(); // NOTE: we're simplifying here, since we always toggle the same texture coord sets
}
m_activestreams = Streams;
}
void
opengl_vbogeometrybank::release_streams() {
::glDisableClientState( GL_VERTEX_ARRAY );
::glDisableClientState( GL_NORMAL_ARRAY );
::glDisableClientState( GL_COLOR_ARRAY );
for( auto unit : m_activetexturearrays ) {
::glClientActiveTexture( GL_TEXTURE0 + unit );
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}
m_activestreams = gfx::stream::none;
m_activetexturearrays.clear();
}
// opengl display list based variant of the geometry bank
// create() subclass details
void
opengl_dlgeometrybank::create_( gfx::geometry_handle const &Geometry ) {
m_chunkrecords.emplace_back( chunk_record() );
}
// replace() subclass details
void
opengl_dlgeometrybank::replace_( gfx::geometry_handle const &Geometry ) {
delete_list( Geometry );
}
// draw() subclass details
std::size_t
opengl_dlgeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) {
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
if( chunkrecord.streams != Streams ) {
delete_list( Geometry );
chunkrecord.primitive_count = 0;
}
if( chunkrecord.list == 0 ) {
// we don't have a list ready, so compile one
chunkrecord.streams = Streams;
chunkrecord.list = ::glGenLists( 1 );
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
::glNewList( chunkrecord.list, GL_COMPILE );
::glBegin( chunk.type );
if( chunk.indices.size() > 0 ) {
// indexed geometry
for( auto const &index : chunk.indices ) {
auto const &vertex { chunk.vertices[ index ] };
if( Streams & gfx::stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); }
else if( Streams & gfx::stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); }
if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } }
if( Streams & gfx::stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); }
}
}
else {
// raw geometry
for( auto const &vertex : chunk.vertices ) {
if( Streams & gfx::stream::normal ) { ::glNormal3fv( glm::value_ptr( vertex.normal ) ); }
else if( Streams & gfx::stream::color ) { ::glColor3fv( glm::value_ptr( vertex.normal ) ); }
if( Streams & gfx::stream::texture ) { for( auto unit : Units.texture ) { ::glMultiTexCoord2fv( unit, glm::value_ptr( vertex.texture ) ); } }
if( Streams & gfx::stream::position ) { ::glVertex3fv( glm::value_ptr( vertex.position ) ); }
}
}
::glEnd();
::glEndList();
auto const vertexcount { ( chunk.indices.empty() ? chunk.vertices.size() : chunk.indices.size() ) };
switch( chunk.type ) {
case GL_TRIANGLES: { chunkrecord.primitive_count += vertexcount / 3; break; }
case GL_TRIANGLE_STRIP: { chunkrecord.primitive_count += vertexcount - 2; break; }
default: { break; }
}
}
// with the list done we can just play it
::glCallList( chunkrecord.list );
return chunkrecord.primitive_count;
}
// release () subclass details
void
opengl_dlgeometrybank::release_() {
for( auto &chunkrecord : m_chunkrecords ) {
if( chunkrecord.list != 0 ) {
::glDeleteLists( chunkrecord.list, 1 );
chunkrecord.list = 0;
}
chunkrecord.streams = gfx::stream::none;
}
}
void
opengl_dlgeometrybank::delete_list( gfx::geometry_handle const &Geometry ) {
// NOTE: given it's our own internal method we trust it to be called with valid parameters
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
if( chunkrecord.list != 0 ) {
::glDeleteLists( chunkrecord.list, 1 );
chunkrecord.list = 0;
}
chunkrecord.streams = gfx::stream::none;
}
} // namespace gfx

View File

@@ -1,124 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "rendering/geometrybank.h"
namespace gfx {
// opengl vbo-based variant of the geometry bank
class opengl_vbogeometrybank : public geometry_bank {
public:
// constructors:
opengl_vbogeometrybank() = default;
// destructor
~opengl_vbogeometrybank() {
delete_buffer(); }
// methods:
static
void
reset() {
m_activevertexbuffer = 0;
m_activestreams = gfx::stream::none; }
private:
// types:
struct chunk_record {
std::size_t vertex_offset{ 0 }; // beginning of the chunk vertex data as offset from the beginning of the last established buffer
std::size_t vertex_count{ 0 }; // size of the chunk in the last established buffer
std::size_t index_offset{ 0 };
std::size_t index_count{ 0 };
bool is_good{ false }; // true if local content of the chunk matches the data on the opengl end
};
using chunkrecord_sequence = std::vector<chunk_record>;
// methods:
// create() subclass details
void
create_( gfx::geometry_handle const &Geometry ) override;
// replace() subclass details
void
replace_( gfx::geometry_handle const &Geometry ) override;
// draw() subclass details
auto
draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) -> std::size_t override;
// release() subclass details
void
release_() override;
void
setup_buffer();
void
bind_buffer() const;
void
delete_buffer();
static
void
bind_streams(gfx::stream_units const &Units, unsigned int const Streams , size_t offset = 0);
static
void
release_streams();
// members:
static GLuint m_activevertexbuffer; // buffer bound currently on the opengl end, if any
static unsigned int m_activestreams;
static std::vector<GLint> m_activetexturearrays;
GLuint m_vertexbuffer { 0 }; // id of the buffer holding vertex data on the opengl end
GLuint m_indexbuffer { 0 }; // id of the buffer holding index data on the opengl end
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
};
// opengl display list based variant of the geometry bank
class opengl_dlgeometrybank : public geometry_bank {
public:
// constructors:
opengl_dlgeometrybank() = default;
// destructor:
~opengl_dlgeometrybank() {
for( auto const &chunkrecord : m_chunkrecords ) {
::glDeleteLists( chunkrecord.list, 1 ); } }
private:
// types:
struct chunk_record {
GLuint list { 0 }; // display list associated with the chunk
unsigned int streams { 0 }; // stream combination used to generate the display list
std::size_t primitive_count { 0 };
};
using chunkrecord_sequence = std::vector<chunk_record>;
// methods:
// create() subclass details
void
create_( gfx::geometry_handle const &Geometry ) override;
// replace() subclass details
void
replace_( gfx::geometry_handle const &Geometry ) override;
// draw() subclass details
auto
draw_( gfx::geometry_handle const &Geometry, gfx::stream_units const &Units, unsigned int const Streams ) -> std::size_t override;
// release () subclass details
void
release_() override;
void
delete_list( gfx::geometry_handle const &Geometry );
// members:
chunkrecord_sequence m_chunkrecords; // helper data for all stored geometry chunks, in matching order
};
} // namespace gfx

View File

@@ -1,44 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/opengllight.h"
void
opengl_light::apply_intensity( float const Factor ) {
if( Factor == 1.f ) {
::glLightfv( id, GL_AMBIENT, glm::value_ptr( ambient ) );
::glLightfv( id, GL_DIFFUSE, glm::value_ptr( diffuse ) );
::glLightfv( id, GL_SPECULAR, glm::value_ptr( specular ) );
}
else {
auto const factor{ std::clamp( Factor, 0.05f, 1.f ) };
// temporary light scaling mechanics (ultimately this work will be left to the shaders
glm::vec4 scaledambient( ambient.r * factor, ambient.g * factor, ambient.b * factor, ambient.a );
glm::vec4 scaleddiffuse( diffuse.r * factor, diffuse.g * factor, diffuse.b * factor, diffuse.a );
glm::vec4 scaledspecular( specular.r * factor, specular.g * factor, specular.b * factor, specular.a );
glLightfv( id, GL_AMBIENT, glm::value_ptr( scaledambient ) );
glLightfv( id, GL_DIFFUSE, glm::value_ptr( scaleddiffuse ) );
glLightfv( id, GL_SPECULAR, glm::value_ptr( scaledspecular ) );
}
}
void
opengl_light::apply_angle() {
::glLightfv( id, GL_POSITION, glm::value_ptr( glm::vec4{ position, ( is_directional ? 0.f : 1.f ) } ) );
if( false == is_directional ) {
::glLightfv( id, GL_SPOT_DIRECTION, glm::value_ptr( direction ) );
}
}
//---------------------------------------------------------------------------

View File

@@ -1,29 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "rendering/light.h"
struct opengl_light : public basic_light {
GLuint id { (GLuint)-1 };
void
apply_intensity( float const Factor = 1.0f );
void
apply_angle();
opengl_light &
operator=( basic_light const &Right ) {
basic_light::operator=( Right );
return *this; }
};
//---------------------------------------------------------------------------

View File

@@ -1,158 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/openglparticles.h"
#include "rendering/particles.h"
#include "rendering/openglcamera.h"
#include "simulation/simulation.h"
#include "utilities/Logs.h"
std::vector<std::pair<glm::vec3, glm::vec2>> const billboard_vertices {
{ { -0.5f, -0.5f, 0.f }, { 0.f, 0.f } },
{ { 0.5f, -0.5f, 0.f }, { 1.f, 0.f } },
{ { 0.5f, 0.5f, 0.f }, { 1.f, 1.f } },
{ { -0.5f, 0.5f, 0.f }, { 0.f, 1.f } }
};
void
opengl_particles::update( opengl_camera const &Camera ) {
m_particlevertices.clear();
if( false == Global.Smoke ) { return; }
// build a list of visible smoke sources
// NOTE: arranged by distance to camera, if we ever need sorting and/or total amount cap-based culling
std::multimap<float, smoke_source const &> sources;
for( auto const &source : simulation::Particles.sequence() ) {
if( false == Camera.visible( source.area() ) ) { continue; }
// NOTE: the distance is negative when the camera is inside the source's bounding area
sources.emplace(
static_cast<float>( glm::length( Camera.position() - source.area().center ) - source.area().radius ),
source );
}
if( true == sources.empty() ) { return; }
// build billboard data for particles from visible sources
auto const camerarotation { glm::mat3( Camera.modelview() ) };
particle_vertex vertex;
for( auto const &[sourcekey, sourcedata] : sources ) {
auto const particlecolor {
glm::clamp(
sourcedata.color()
* ( glm::vec3 { Global.DayLight.ambient } + 0.35f * glm::vec3{ Global.DayLight.diffuse } )
* 255.f,
glm::vec3{ 0.f }, glm::vec3{ 255.f } ) };
auto const &particles { sourcedata.sequence() };
// TODO: put sanity cap on the overall amount of particles that can be drawn
auto const sizestep { 256.0 * billboard_vertices.size() };
m_particlevertices.reserve(
static_cast<std::size_t>( sizestep * std::ceil( static_cast<double>(m_particlevertices.size()) + ( static_cast<double>(particles.size() * billboard_vertices.size()) ) / sizestep ) ) );
for( auto const &particle : particles ) {
// TODO: particle color support
vertex.color[ 0 ] = static_cast<std::uint_fast8_t>( particlecolor.r );
vertex.color[ 1 ] = static_cast<std::uint_fast8_t>( particlecolor.g );
vertex.color[ 2 ] = static_cast<std::uint_fast8_t>( particlecolor.b );
vertex.color[ 3 ] = static_cast<std::uint_fast8_t>( std::clamp( particle.opacity * 255, 0.f, 255.f ) );
auto const offset { glm::vec3{ particle.position - Camera.position() } };
auto const rotation { glm::angleAxis( particle.rotation, glm::vec3{ 0.f, 0.f, 1.f } ) };
for( auto const &[billboardoffset, billboardtexture] : billboard_vertices ) {
vertex.position = offset + ( rotation * billboardoffset * particle.size ) * camerarotation;
vertex.texture = billboardtexture;
m_particlevertices.emplace_back( vertex );
}
}
}
// ship the billboard data to the gpu:
// setup...
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// ...make sure we have enough room...
if( m_buffercapacity < m_particlevertices.size() ) {
// allocate gpu side buffer big enough to hold the data
m_buffercapacity = 0;
if( m_buffer != (GLuint)-1 ) {
// get rid of the old buffer
::glDeleteBuffers( 1, &m_buffer );
m_buffer = (GLuint)-1;
}
::glGenBuffers( 1, &m_buffer );
if( ( m_buffer > 0 ) && ( m_buffer != (GLuint)-1 ) ) {
// if we didn't get a buffer we'll try again during the next draw call
// NOTE: we match capacity instead of current size to reduce number of re-allocations
auto const particlecount { m_particlevertices.capacity() };
::glBindBuffer( GL_ARRAY_BUFFER, m_buffer );
::glBufferData(
GL_ARRAY_BUFFER,
particlecount * sizeof( particle_vertex ),
nullptr,
GL_DYNAMIC_DRAW );
if( ::glGetError() == GL_OUT_OF_MEMORY ) {
// TBD: throw a bad_alloc?
ErrorLog( "openGL error: out of memory; failed to create a geometry buffer" );
::glDeleteBuffers( 1, &m_buffer );
m_buffer = (GLuint)-1;
}
else {
m_buffercapacity = particlecount;
}
}
}
// ...send the data...
if( ( m_buffer > 0 ) && ( m_buffer != (GLuint)-1 ) ) {
// if the buffer exists at this point it's guaranteed to be big enough to hold our data
::glBindBuffer( GL_ARRAY_BUFFER, m_buffer );
::glBufferSubData(
GL_ARRAY_BUFFER,
0,
m_particlevertices.size() * sizeof( particle_vertex ),
m_particlevertices.data() );
}
// ...and cleanup
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
}
std::size_t
opengl_particles::render( GLint const Textureunit ) {
if( false == Global.Smoke ) { return 0; }
if( m_buffercapacity == 0 ) { return 0; }
if( m_particlevertices.empty() ) { return 0; }
if( ( m_buffer == 0 ) || ( m_buffer == (GLuint)-1 ) ) { return 0; }
// setup...
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
::glBindBuffer( GL_ARRAY_BUFFER, m_buffer );
::glVertexPointer( 3, GL_FLOAT, sizeof( particle_vertex ), static_cast<char *>( nullptr ) );
::glEnableClientState( GL_VERTEX_ARRAY );
::glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( particle_vertex ), reinterpret_cast<void const *>( sizeof( float ) * 3 ) );
::glEnableClientState( GL_COLOR_ARRAY );
::glClientActiveTexture( GL_TEXTURE0 + Textureunit );
::glTexCoordPointer( 2, GL_FLOAT, sizeof( particle_vertex ), reinterpret_cast<void const *>( sizeof( float ) * 3 + sizeof( std::uint8_t ) * 4 ) );
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
// ...draw...
::glDrawArrays( GL_QUADS, 0, static_cast<GLsizei>(m_particlevertices.size()) );
// ...and cleanup
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
return m_particlevertices.size() / 4;
}
//---------------------------------------------------------------------------

View File

@@ -1,51 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
class opengl_camera;
// particle data visualizer
class opengl_particles {
public:
// constructors
opengl_particles() = default;
// destructor
~opengl_particles() {
if( m_buffer != -1 ) {
::glDeleteBuffers( 1, &m_buffer ); } }
// methods
void
update( opengl_camera const &Camera );
std::size_t
render( GLint const Textureunit );
private:
// types
struct particle_vertex {
glm::vec3 position; // 3d space
std::uint8_t color[ 4 ]; // rgba, unsigned byte format
glm::vec2 texture; // uv space
float padding[ 2 ]; // experimental, some gfx hardware allegedly works better with 32-bit aligned data blocks
};
/*
using sourcedistance_pair = std::pair<smoke_source *, float>;
using source_sequence = std::vector<sourcedistance_pair>;
*/
using particlevertex_sequence = std::vector<particle_vertex>;
// methods
// members
/*
source_sequence m_sources; // list of particle sources visible in current render pass, with their respective distances to the camera
*/
particlevertex_sequence m_particlevertices; // geometry data of visible particles, generated on the cpu end
GLuint m_buffer{ (GLuint)-1 }; // id of the buffer holding geometry data on the opengl end
std::size_t m_buffercapacity{ 0 }; // total capacity of the last established buffer
};
//---------------------------------------------------------------------------

View File

@@ -1,173 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/openglprecipitation.h"
#include "utilities/Globals.h"
#include "rendering/renderer.h"
#include "simulation/simulationenvironment.h"
opengl_precipitation::~opengl_precipitation() {
if( m_vertexbuffer != -1 ) { ::glDeleteBuffers( 1, &m_vertexbuffer ); }
if( m_indexbuffer != -1 ) { ::glDeleteBuffers( 1, &m_indexbuffer ); }
if( m_uvbuffer != -1 ) { ::glDeleteBuffers( 1, &m_uvbuffer ); }
}
void
opengl_precipitation::create( int const Tesselation ) {
m_vertices.clear();
m_uvs.clear();
m_indices.clear();
auto const heightfactor { 10.f }; // height-to-radius factor
auto const verticaltexturestretchfactor { 1.5f }; // crude motion blur
// create geometry chunk
auto const latitudes { 3 }; // just a cylinder with end cones
auto const longitudes { Tesselation };
auto const longitudehalfstep { 0.5f * static_cast<float>( 2.0 * M_PI * 1.f / longitudes ) }; // for crude uv correction
std::uint16_t index = 0;
// auto const radius { 25.f }; // cylinder radius
std::vector radii { 25.f, 10.f, 5.f, 1.f };
for( auto radius : radii ) {
for( int i = 0; i <= latitudes; ++i ) {
auto const latitude{ static_cast<float>( M_PI * ( -0.5f + (float)( i ) / latitudes ) ) };
auto const z{ std::sin( latitude ) };
auto const zr{ std::cos( latitude ) };
for( int j = 0; j <= longitudes; ++j ) {
// NOTE: for the first and last row half of the points we create end up unused but, eh
auto const longitude{ static_cast<float>( 2.0 * M_PI * (float)( j ) / longitudes ) };
auto const x{ std::cos( longitude ) };
auto const y{ std::sin( longitude ) };
// NOTE: cartesian to opengl swap would be: -x, -z, -y
m_vertices.emplace_back( glm::vec3( -x * zr, -z * heightfactor, -y * zr ) * radius );
// uvs
// NOTE: first and last row receives modified u values to deal with limitation of mapping onto triangles
auto u = (
i == 0 ? longitude + longitudehalfstep :
i == latitudes ? longitude - longitudehalfstep :
longitude );
m_uvs.emplace_back(
u / ( 2.0 * M_PI ) * radius,
1.f - (float)( i ) / latitudes * radius * heightfactor * 0.5f / verticaltexturestretchfactor );
if( ( i == 0 ) || ( j == 0 ) ) {
// initial edge of the dome, don't start indices yet
++index;
}
else {
// the end cones are built from one triangle of each quad, the middle rows use both
if( i < latitudes ) {
m_indices.emplace_back( index - 1 - ( longitudes + 1 ) );
m_indices.emplace_back( index - 1 );
m_indices.emplace_back( index );
}
if( i > 1 ) {
m_indices.emplace_back( index );
m_indices.emplace_back( index - ( longitudes + 1 ) );
m_indices.emplace_back( index - 1 - ( longitudes + 1 ) );
}
++index;
}
} // longitude
} // latitude
} // radius
}
void
opengl_precipitation::update() {
// NOTE: we should really be checking state of each buffer as theoretically allocation could go wrong mid-way, but, eh
if( m_vertexbuffer == (GLuint)-1 ) {
if( m_vertices.empty() ) {
// create visualization mesh
create( 18 );
}
// cache entry state
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// build the buffers
::glGenBuffers( 1, &m_vertexbuffer );
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
::glBufferData( GL_ARRAY_BUFFER, m_vertices.size() * sizeof( glm::vec3 ), m_vertices.data(), GL_STATIC_DRAW );
::glGenBuffers( 1, &m_uvbuffer );
::glBindBuffer( GL_ARRAY_BUFFER, m_uvbuffer );
::glBufferData( GL_ARRAY_BUFFER, m_uvs.size() * sizeof( glm::vec2 ), m_uvs.data(), GL_STATIC_DRAW );
::glGenBuffers( 1, &m_indexbuffer );
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
::glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof( unsigned short ), m_indices.data(), GL_STATIC_DRAW );
// NOTE: vertex and index source data is superfluous past this point, but, eh
// cleanup
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
// TODO: include weather type check in the entry conditions
if( m_overcast == Global.Overcast ) { return; }
m_overcast = Global.Overcast;
std::string const densitysuffix { (
m_overcast < 1.35 ?
"_light" :
"_medium" ) };
if( Global.Weather == "rain:" ) {
m_texture = GfxRenderer->Fetch_Texture( "fx/rain" + densitysuffix );
}
else if( Global.Weather == "snow:" ) {
m_texture = GfxRenderer->Fetch_Texture( "fx/snow" + densitysuffix );
}
}
void
opengl_precipitation::render( GLint const Textureunit ) {
if( m_texture == null_handle ) { return; }
GfxRenderer->Bind_Texture( m_texture );
// cache entry state
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// positions
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
::glVertexPointer( 3, GL_FLOAT, sizeof( glm::vec3 ), reinterpret_cast<void const*>( 0 ) );
::glEnableClientState( GL_VERTEX_ARRAY );
// uvs
::glBindBuffer( GL_ARRAY_BUFFER, m_uvbuffer );
::glClientActiveTexture( GL_TEXTURE0 + Textureunit );
::glTexCoordPointer( 2, GL_FLOAT, sizeof( glm::vec2 ), reinterpret_cast<void const*>( 0 ) );
::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
// uv transformation matrix
::glMatrixMode( GL_TEXTURE );
::glLoadIdentity();
::glTranslatef( 0.f, simulation::Environment.precipitation().get_textureoffset(), 0.f );
// indices
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
::glDrawElements( GL_TRIANGLES, static_cast<GLsizei>( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast<void const*>( 0 ) );
// cleanup
::glLoadIdentity();
::glMatrixMode( GL_MODELVIEW );
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}

View File

@@ -1,39 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "model/Texture.h"
class opengl_precipitation {
public:
// constructors
opengl_precipitation() = default;
// destructor
~opengl_precipitation();
// methods
void
update();
void
render( GLint const Textureunit );
private:
// methods
void create( int const Tesselation );
// members
std::vector<glm::vec3> m_vertices;
std::vector<glm::vec2> m_uvs;
std::vector<std::uint16_t> m_indices;
GLuint m_vertexbuffer { (GLuint)-1 };
GLuint m_uvbuffer { (GLuint)-1 };
GLuint m_indexbuffer { (GLuint)-1 };
texture_handle m_texture { null_handle };
float m_overcast { -1.f }; // cached overcast level, difference from current state triggers texture update
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,398 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "rendering/renderer.h"
#include "rendering/opengllight.h"
#include "rendering/openglcamera.h"
#include "rendering/openglparticles.h"
#include "rendering/openglskydome.h"
#include "rendering/openglprecipitation.h"
#include "rendering/lightarray.h"
#include "scene/scene.h"
#include "simulation/simulationenvironment.h"
#include "world/MemCell.h"
#define EU07_USE_PICKING_FRAMEBUFFER
//#define EU07_USE_DEBUG_SHADOWMAP
//#define EU07_USE_DEBUG_CABSHADOWMAP
//#define EU07_USE_DEBUG_CAMERA
//#define EU07_USE_DEBUG_SOUNDEMITTERS
//#define EU07_DISABLECABREFLECTIONS
// bare-bones render controller, in lack of anything better yet
class opengl_renderer : public gfx_renderer {
public:
// types
// constructors
opengl_renderer() = default;
// destructor
~opengl_renderer() { }
// methods
bool
Init( GLFWwindow *Window ) override;
// main draw call. returns false on error
bool
Render() override;
void
SwapBuffers() override;
inline
float
Framerate() override { return m_framerate; }
bool AddViewport(const global_settings::extraviewport_config &conf) override { return false; }
bool Debug_Ui_State(std::optional<bool>) override { return false; }
void Shutdown() override {}
// geometry methods
// NOTE: hands-on geometry management is exposed as a temporary measure; ultimately all visualization data should be generated/handled automatically by the renderer itself
// creates a new geometry bank. returns: handle to the bank or NULL
gfx::geometrybank_handle
Create_Bank() override;
// creates a new indexed geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL
gfx::geometry_handle Insert(gfx::index_array &Indices, gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override;
// creates a new geometry chunk of specified type from supplied data, in specified bank. returns: handle to the chunk or NULL
gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometrybank_handle const &Geometry, int const Type) override;
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool Replace(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type, const std::size_t Offset = 0) override;
// adds supplied vertex data at the end of specified chunk
bool Append(gfx::vertex_array &Vertices, gfx::userdata_array &Userdata, gfx::geometry_handle const &Geometry, int const Type) override;
// provides direct access to index data of specfied chunk
gfx::index_array const &
Indices( gfx::geometry_handle const &Geometry ) const override;
// provides direct access to vertex data of specfied chunk
gfx::vertex_array const &
Vertices( gfx::geometry_handle const &Geometry ) const override;
// provides direct access to vertex data of specfied chunk
gfx::userdata_array const &
UserData( gfx::geometry_handle const &Geometry ) const override;
// material methods
material_handle
Fetch_Material( std::string const &Filename, bool const Loadnow = true ) override;
void
Bind_Material( material_handle const Material, TSubModel const *sm = nullptr, lighting_data const *lighting = nullptr ) override;
IMaterial const *
Material( material_handle const Material ) const override;
// shader methods
auto Fetch_Shader( std::string const &name ) -> std::shared_ptr<gl::program> override;
// texture methods
texture_handle
Fetch_Texture( std::string const &Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA ) override;
void
Bind_Texture( texture_handle const Texture ) override;
void
Bind_Texture( std::size_t const Unit, texture_handle const Texture ) override;
ITexture &
Texture( texture_handle const Texture ) override;
ITexture const &
Texture( texture_handle const Texture ) const override;
// utility methods
void
Pick_Control_Callback( std::function<void( TSubModel const *, const glm::vec2 )> Callback ) override;
void
Pick_Node_Callback( std::function<void( scene::basic_node * )> Callback ) override;
TSubModel const *
Pick_Control() const override { return m_pickcontrolitem; }
scene::basic_node const *
Pick_Node() const override { return m_picksceneryitem; }
glm::dvec3
Mouse_Position() const override { return m_worldmousecoordinates; }
glm::mat4
Camera_View_Matrix() const override { return glm::mat4( glm::mat3( m_colorpass.camera.modelview() ) ); }
glm::mat4
Camera_Projection_Matrix() const override { return m_colorpass.camera.projection(); }
glm::dvec3
Camera_Position() const override { return m_colorpass.camera.position(); }
// maintenance methods
void
Update( double const Deltatime ) override;
void
Update_Pick_Control() override;
void
Update_Pick_Node() override;
glm::dvec3
Update_Mouse_Position() override;
// debug methods
std::string const &
info_times() const override;
std::string const &
info_stats() const override;
void MakeScreenshot() override;
opengl_material const & Material( TSubModel const * Submodel ) const;
// members
GLenum static const sunlight { GL_LIGHT0 };
static std::unique_ptr<gfx_renderer> create_func();
private:
// types
enum class rendermode {
none,
color,
shadows,
cabshadows,
reflections,
pickcontrols,
pickscenery
};
enum textureunit {
helper = 0,
shadows,
normals,
diffuse
};
struct debug_stats {
int dynamics { 0 };
int models { 0 };
int submodels { 0 };
int paths { 0 };
int traction { 0 };
int shapes { 0 };
int lines { 0 };
int particles { 0 };
int drawcalls { 0 };
};
using section_sequence = std::vector<scene::basic_section *>;
using distancecell_pair = std::pair<double, scene::basic_cell *>;
using cell_sequence = std::vector<distancecell_pair>;
struct renderpass_config {
opengl_camera camera;
rendermode draw_mode { rendermode::none };
float draw_range { 0.0f };
debug_stats draw_stats;
};
struct units_state {
bool diffuse { false };
bool shadows { false };
bool reflections { false };
};
typedef std::vector<opengl_light> opengllight_array;
// methods
void
Disable_Lights();
void
setup_pass( renderpass_config &Config, rendermode const Mode, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false );
void
setup_matrices();
void
setup_drawing( bool const Alpha = false );
void
setup_units( bool const Diffuse, bool const Shadows, bool const Reflections );
void
setup_shadow_map( GLuint const Texture, glm::mat4 const &Transformation );
void
setup_shadow_color( glm::vec4 const &Shadowcolor );
void
setup_environment_light( TEnvironmentType const Environment = e_flat );
void
switch_units( bool const Diffuse, bool const Shadows, bool const Reflections );
// helper, texture manager method; activates specified texture unit
void
select_unit( GLint const Textureunit );
// runs jobs needed to generate graphics for specified render pass
void
Render_pass( rendermode const Mode );
// creates dynamic environment cubemap
bool
Render_reflections();
bool
Render( world_environment *Environment );
void
Render( scene::basic_region *Region );
void
Render( section_sequence::iterator First, section_sequence::iterator Last );
void
Render( cell_sequence::iterator First, cell_sequence::iterator Last );
void
Render( scene::shape_node const &Shape, bool const Ignorerange );
void
Render( TAnimModel *Instance );
bool
Render( TDynamicObject *Dynamic );
bool
Render( TModel3d *Model, material_data const *Material, float const Squaredistance, glm::dvec3 const &Position, glm::vec3 const &Angle );
bool
Render( TModel3d *Model, material_data const *Material, float const Squaredistance );
void
Render( TSubModel *Submodel );
void
Render( TTrack *Track );
void
Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last );
bool
Render_cab( TDynamicObject const *Dynamic, float const Lightlevel, bool const Alpha = false );
bool
Render_interior( bool const Alpha = false );
bool
Render_lowpoly( TDynamicObject *Dynamic, float const Squaredistance, bool const Setup, bool const Alpha = false );
bool
Render_coupler_adapter( TDynamicObject *Dynamic, float const Squaredistance, int const End, bool const Alpha = false );
void
Render( TMemCell *Memcell );
void
Render_particles();
void
Render_precipitation();
void
Render_Alpha( scene::basic_region *Region );
void
Render_Alpha( cell_sequence::reverse_iterator First, cell_sequence::reverse_iterator Last );
void
Render_Alpha( TAnimModel *Instance );
void
Render_Alpha( TTraction *Traction );
void
Render_Alpha( scene::lines_node const &Lines );
bool
Render_Alpha( TDynamicObject *Dynamic );
bool
Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance, glm::dvec3 const &Position, glm::vec3 const &Angle );
bool
Render_Alpha( TModel3d *Model, material_data const *Material, float const Squaredistance );
void
Render_Alpha( TSubModel *Submodel );
// characters of a text display
void
Render_Alpha_text( TSubModel *Submodel );
void
Update_Lights( light_array &Lights );
bool
Init_caps();
glm::vec3
pick_color( std::size_t const Index );
std::size_t
pick_index( glm::ivec3 const &Color );
// members
GLFWwindow *m_window { nullptr };
gfx::geometrybank_manager m_geometry;
material_manager m_materials;
texture_manager m_textures;
opengl_light m_sunlight;
opengllight_array m_lights;
opengl_skydome m_skydomerenderer;
opengl_precipitation m_precipitationrenderer;
opengl_particles m_particlerenderer; // particle visualization subsystem
/*
float m_sunandviewangle; // cached dot product of sunlight and camera vectors
*/
gfx::geometry_handle m_billboardgeometry { 0, 0 };
texture_handle m_glaretexture { -1 };
texture_handle m_suntexture { -1 };
texture_handle m_moontexture { -1 };
texture_handle m_reflectiontexture { -1 };
texture_handle m_smoketexture { -1 };
material_handle m_invalid_material;
// TODO: refactor framebuffer stuff into an object
bool m_framebuffersupport { false };
#ifdef EU07_USE_PICKING_FRAMEBUFFER
GLuint m_pickframebuffer { 0 };
GLuint m_picktexture { 0 };
GLuint m_pickdepthbuffer { 0 };
#endif
// main shadowmap resources
int m_shadowbuffersize { 2048 };
GLuint m_shadowframebuffer { 0 };
GLuint m_shadowtexture { 0 };
#ifdef EU07_USE_DEBUG_SHADOWMAP
GLuint m_shadowdebugtexture{ 0 };
#endif
#ifdef EU07_USE_DEBUG_CABSHADOWMAP
GLuint m_cabshadowdebugtexture{ 0 };
#endif
glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space
// cab shadowmap resources
GLuint m_cabshadowframebuffer { 0 };
GLuint m_cabshadowtexture { 0 };
glm::mat4 m_cabshadowtexturematrix; // conversion from cab-centric world space to light-centric clip space
// environment map resources
GLuint m_environmentframebuffer { 0 };
GLuint m_environmentcubetexture { 0 };
GLuint m_environmentdepthbuffer { 0 };
bool m_environmentcubetexturesupport { false }; // indicates whether we can use the dynamic environment cube map
int m_environmentcubetextureface { 0 }; // helper, currently processed cube map face
double m_environmentupdatetime { 0.0 }; // time of the most recent environment map update
glm::dvec3 m_environmentupdatelocation; // coordinates of most recent environment map update
int m_helpertextureunit { 0 };
int m_shadowtextureunit { 1 };
int m_normaltextureunit { 2 };
int m_diffusetextureunit{ 3 };
units_state m_unitstate;
unsigned int m_framestamp; // id of currently rendered gfx frame
float m_framerate;
double m_updateaccumulator { 0.0 };
// double m_pickupdateaccumulator { 0.0 };
std::string m_debugtimestext;
std::string m_pickdebuginfo;
std::string m_debugstatstext;
struct simulation_state {
std::string weather;
std::string season;
} m_simulationstate;
glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f };
glm::vec4 m_shadowcolor { colors::shadow };
float m_fogrange { 2000.f };
// TEnvironmentType m_environment { e_flat };
float m_specularopaquescalefactor { 1.f };
float m_speculartranslucentscalefactor { 1.f };
bool m_renderspecular{ false }; // controls whether to include specular component in the calculations
renderpass_config m_renderpass; // parameters for current render pass
section_sequence m_sectionqueue; // list of sections in current render pass
cell_sequence m_cellqueue;
renderpass_config m_colorpass; // parametrs of most recent color pass
renderpass_config m_shadowpass; // parametrs of most recent shadowmap pass
renderpass_config m_cabshadowpass; // parameters of most recent cab shadowmap pass
std::vector<TSubModel *> m_pickcontrolsitems;
TSubModel *m_pickcontrolitem { nullptr };
std::vector<scene::basic_node *> m_picksceneryitems;
scene::basic_node *m_picksceneryitem { nullptr };
glm::vec3 m_worldmousecoordinates { 0.f };
std::vector<std::function<void( TSubModel const *, const glm::vec2 )>> m_control_pick_requests;
std::vector<std::function<void( scene::basic_node * )>> m_node_pick_requests;
#ifdef EU07_USE_DEBUG_CAMERA
renderpass_config m_worldcamera; // debug item
#endif
bool m_isATI;
static bool renderer_register;
class opengl_imgui_renderer : public imgui_renderer
{
virtual bool Init() override;
virtual void Shutdown() override;
virtual void BeginFrame() override;
virtual void Render() override;
virtual std::uint64_t Create_Image(std::uint8_t const *Rgba, int const Width, int const Height) override;
virtual void Release_Image(std::uint64_t const Image) override;
} m_imgui_renderer;
virtual imgui_renderer *GetImguiRenderer() override
{
return &m_imgui_renderer;
}
};
//---------------------------------------------------------------------------

View File

@@ -1,103 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/openglskydome.h"
#include "simulation/simulationenvironment.h"
opengl_skydome::~opengl_skydome() {
if( m_vertexbuffer != -1 ) { ::glDeleteBuffers( 1, &m_vertexbuffer ); }
if( m_indexbuffer != -1 ) { ::glDeleteBuffers( 1, &m_indexbuffer ); }
if( m_coloursbuffer != -1 ) { ::glDeleteBuffers( 1, &m_coloursbuffer ); }
}
void opengl_skydome::update() {
auto &skydome { simulation::Environment.skydome() };
// cache entry state
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// setup gpu data buffers:
// ...static data...
if( m_indexbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_indexbuffer );
if( ( m_indexbuffer > 0 ) && ( m_indexbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
auto const &indices { skydome.indices() };
::glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof( unsigned short ), indices.data(), GL_STATIC_DRAW );
m_indexcount = indices.size();
}
}
if( m_vertexbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_vertexbuffer );
if( ( m_vertexbuffer > 0 ) && ( m_vertexbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
auto const &vertices { skydome.vertices() };
::glBufferData( GL_ARRAY_BUFFER, vertices.size() * sizeof( glm::vec3 ), vertices.data(), GL_STATIC_DRAW );
}
}
// ...and dynamic data
if( m_coloursbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_coloursbuffer );
if( ( m_coloursbuffer > 0 ) && ( m_coloursbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ARRAY_BUFFER, m_coloursbuffer );
auto const &colors { skydome.colors() };
::glBufferData( GL_ARRAY_BUFFER, colors.size() * sizeof( glm::vec3 ), colors.data(), GL_DYNAMIC_DRAW );
}
}
// ship the current dynamic data to the gpu
// TODO: ship the data if it changed since the last update
if (true == skydome.is_dirty() && ( m_coloursbuffer > 0 ) && ( m_coloursbuffer != (GLuint)-1 )) {
::glBindBuffer( GL_ARRAY_BUFFER, m_coloursbuffer );
auto &colors{ skydome.colors() };
/*
float twilightfactor = std::clamp( -simulation::Environment.sun().getAngle(), 0.0f, 18.0f ) / 18.0f;
auto gamma = std::lerp( glm::vec3( 0.45f ), glm::vec3( 1.0f ), twilightfactor );
for( auto & color : colors ) {
color = glm::pow( color, gamma );
}
*/
::glBufferSubData( GL_ARRAY_BUFFER, 0, colors.size() * sizeof( glm::vec3 ), colors.data() );
skydome.is_dirty() = false;
}
// cleanup
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}
// render skydome to screen
void opengl_skydome::render() {
if( ( m_indexbuffer == (GLuint)-1 )
|| ( m_vertexbuffer == (GLuint)-1 )
|| ( m_coloursbuffer == (GLuint)-1 ) ) {
return;
}
// setup:
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// ...positions...
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
::glVertexPointer( 3, GL_FLOAT, sizeof( glm::vec3 ), reinterpret_cast<void const*>( 0 ) );
::glEnableClientState( GL_VERTEX_ARRAY );
// ...colours...
::glBindBuffer( GL_ARRAY_BUFFER, m_coloursbuffer );
::glColorPointer( 3, GL_FLOAT, sizeof( glm::vec3 ), reinterpret_cast<void const*>( 0 ) );
::glEnableClientState( GL_COLOR_ARRAY );
// ...indices
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
// draw
::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
::glDrawElements( GL_TRIANGLES, static_cast<GLsizei>( m_indexcount ), GL_UNSIGNED_SHORT, reinterpret_cast<void const*>( 0 ) );
// cleanup
::glPopClientAttrib();
::glBindBuffer( GL_ARRAY_BUFFER, 0 );
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
}

View File

@@ -1,31 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
class opengl_skydome {
public:
// constructors
opengl_skydome() = default;
// destructor
~opengl_skydome();
// methods
// updates data stores on the opengl end. NOTE: unbinds buffers
void update();
// draws the skydome
void render();
private:
// members
GLuint m_indexbuffer{ (GLuint)-1 }; // id of the buffer holding index data on the opengl end
std::size_t m_indexcount { 0 };
GLuint m_vertexbuffer{ (GLuint)-1 }; // id of the buffer holding vertex data on the opengl end
GLuint m_coloursbuffer{ (GLuint)-1 }; // id of the buffer holding colour data on the opengl end
};

View File

@@ -164,8 +164,6 @@ private:
// holds all particle emitters defined in the scene and updates their state
class particle_manager {
friend opengl_renderer;
public:
// types
using source_sequence = std::vector<smoke_source>;