16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-23 00:29:19 +02:00

milek7/sim branch opengl 3.3 renderer import

This commit is contained in:
tmj-fstate
2019-10-26 15:17:09 +02:00
parent d24fccb4d7
commit 0fd23a53d9
90 changed files with 7629 additions and 549 deletions

View File

@@ -125,6 +125,7 @@ class TAnimAdvanced
class TAnimModel : public scene::basic_node {
friend opengl_renderer;
friend opengl33_renderer;
friend itemproperties_panel;
public:

View File

@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
// Ra: zestaw klas do robienia wskaźników, aby uporządkować nagłówki
//---------------------------------------------------------------------------
class opengl_renderer;
class opengl33_renderer;
class TTrack; // odcinek trajektorii
class basic_event;
class TTrain; // pojazd sterowany

View File

@@ -204,18 +204,18 @@ material_data::assign( std::string const &Replacableskin ) {
}
textures_alpha = (
GfxRenderer->Material( replacable_skins[ 1 ] ).has_alpha ?
GfxRenderer->Material( replacable_skins[ 1 ] ).is_translucent() ?
0x31310031 : // tekstura -1 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
0x30300030 ); // wszystkie tekstury nieprzezroczyste - nie renderować w cyklu przezroczystych
if( GfxRenderer->Material( replacable_skins[ 2 ] ).has_alpha ) {
if( GfxRenderer->Material( replacable_skins[ 2 ] ).is_translucent() ) {
// tekstura -2 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
textures_alpha |= 0x02020002;
}
if( GfxRenderer->Material( replacable_skins[ 3 ] ).has_alpha ) {
if( GfxRenderer->Material( replacable_skins[ 3 ] ).is_translucent() ) {
// tekstura -3 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
textures_alpha |= 0x04040004;
}
if( GfxRenderer->Material( replacable_skins[ 4 ] ).has_alpha ) {
if( GfxRenderer->Material( replacable_skins[ 4 ] ).is_translucent() ) {
// tekstura -4 z kanałem alfa - nie renderować w cyklu nieprzezroczystych
textures_alpha |= 0x08080008;
}
@@ -477,12 +477,9 @@ void TDynamicObject::SetPneumatic(bool front, bool red)
void TDynamicObject::UpdateAxle(TAnim *pAnim)
{ // animacja osi
pAnim->smAnimated->SetRotate(float3(1, 0, 0), *pAnim->dWheelAngle);
};
void TDynamicObject::UpdateBoogie(TAnim *pAnim)
{ // animacja wózka
pAnim->smAnimated->SetRotate(float3(1, 0, 0), *pAnim->dWheelAngle);
size_t wheel_id = pAnim->dWheelAngle;
pAnim->smAnimated->SetRotate(float3(1, 0, 0), dWheelAngle[wheel_id]);
pAnim->smAnimated->future_transform = glm::rotate((float)glm::radians(m_future_wheels_angle[wheel_id]), glm::vec3(1.0f, 0.0f, 0.0f));
};
// animacja drzwi - przesuw
@@ -3210,7 +3207,11 @@ bool TDynamicObject::Update(double dt, double dt1)
// TBD: place the meter on mover logic level?
simulation::Train->add_distance( dDOMoveLen );
}
glm::dvec3 old_pos = vPosition;
Move(dDOMoveLen);
m_future_movement = (glm::dvec3(vPosition) - old_pos) / dt1 * Timer::GetDeltaRenderTime();
if (!bEnabled) // usuwane pojazdy nie mają toru
{ // pojazd do usunięcia
bDynamicRemove = true; // sprawdzić
@@ -3316,17 +3317,19 @@ bool TDynamicObject::Update(double dt, double dt1)
if (MoverParameters->Vel != 0)
{ // McZapkie-050402: krecenie kolami:
glm::dvec3 old_wheels = glm::dvec3(dWheelAngle[0], dWheelAngle[1], dWheelAngle[2]);
dWheelAngle[0] += 114.59155902616464175359630962821 * MoverParameters->V * dt1 /
MoverParameters->WheelDiameterL; // przednie toczne
dWheelAngle[1] += MoverParameters->nrot * dt1 * 360.0; // napędne
dWheelAngle[2] += 114.59155902616464175359630962821 * MoverParameters->V * dt1 /
MoverParameters->WheelDiameterT; // tylne toczne
if (dWheelAngle[0] > 360.0)
dWheelAngle[0] -= 360.0; // a w drugą stronę jak się kręcą?
if (dWheelAngle[1] > 360.0)
dWheelAngle[1] -= 360.0;
if (dWheelAngle[2] > 360.0)
dWheelAngle[2] -= 360.0;
m_future_wheels_angle = (glm::dvec3(dWheelAngle[0], dWheelAngle[1], dWheelAngle[2]) - old_wheels) / dt1 * Timer::GetDeltaRenderTime();
dWheelAngle[0] = clamp_circular( dWheelAngle[0] );
dWheelAngle[1] = clamp_circular( dWheelAngle[1] );
dWheelAngle[2] = clamp_circular( dWheelAngle[2] );
}
if (pants) // pantograf może być w wagonie kuchennym albo pojeździe rewizyjnym (np. SR61)
{ // przeliczanie kątów dla pantografów
@@ -4530,7 +4533,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
}
// Ra: ustawianie indeksów osi
for (i = 0; i < iAnimType[ANIM_WHEELS]; ++i) // ilość osi (zabezpieczenie przed błędami w CHK)
pAnimations[i].dWheelAngle = dWheelAngle + 1; // domyślnie wskaźnik na napędzające
pAnimations[i].dWheelAngle = 1; // domyślnie wskaźnik na napędzające
i = 0;
j = 1;
k = 0;
@@ -4543,13 +4546,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
{ // wersja ze wskaźnikami jest bardziej elastyczna na nietypowe układy
if ((k >= 'A') && (k <= 'J')) // 10 chyba maksimum?
{
pAnimations[i++].dWheelAngle = dWheelAngle + 1; // obrót osi napędzających
pAnimations[i++].dWheelAngle = 1; // obrót osi napędzających
--k; // następna będzie albo taka sama, albo bierzemy kolejny znak
m = 2; // następujące toczne będą miały inną średnicę
}
else if ((k >= '1') && (k <= '9'))
{
pAnimations[i++].dWheelAngle = dWheelAngle + m; // obrót osi tocznych
pAnimations[i++].dWheelAngle = m; // obrót osi tocznych
--k; // następna będzie albo taka sama, albo bierzemy kolejny znak
}
else
@@ -6381,6 +6384,11 @@ void TDynamicObject::OverheadTrack(float o)
}
};
glm::dvec3 TDynamicObject::get_future_movement() const {
return m_future_movement;
}
// returns type of the nearest functional power source present in the trainset
TPowerSource
TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const {

View File

@@ -124,7 +124,7 @@ public:
union
{ // parametry animacji
TAnimValveGear *pValveGear; // współczynniki do animacji parowozu
double *dWheelAngle; // wskaźnik na kąt obrotu osi
int dWheelAngle; // wskaźnik na kąt obrotu osi
float *fParam; // różne parametry dla animacji
TAnimPant *fParamPants; // różne parametry dla animacji
};
@@ -162,6 +162,7 @@ struct material_data {
class TDynamicObject { // klasa pojazdu
friend opengl_renderer;
friend opengl33_renderer;
public:
static bool bDynamicRemove; // moved from ground
@@ -179,6 +180,8 @@ private: // położenie pojazdu w świecie oraz parametry ruchu
float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia
Math3D::vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
glm::dvec3 m_future_movement;
glm::dvec3 m_future_wheels_angle;
public:
// parametry położenia pojazdu dostępne publicznie
@@ -257,7 +260,6 @@ private:
void UpdateNone(TAnim *pAnim){}; // animacja pusta (funkcje ustawiania submodeli, gdy blisko kamery)
*/
void UpdateAxle(TAnim *pAnim); // animacja osi
void UpdateBoogie(TAnim *pAnim); // animacja wózka
void UpdateDoorTranslate(TAnim *pAnim); // animacja drzwi - przesuw
void UpdateDoorRotate(TAnim *pAnim); // animacja drzwi - obrót
void UpdateDoorFold(TAnim *pAnim); // animacja drzwi - składanie
@@ -655,6 +657,7 @@ private:
void DestinationSet(std::string to, std::string numer);
material_handle DestinationFind( std::string Destination );
void OverheadTrack(float o);
glm::dvec3 get_future_movement() const;
double MED[9][8]; // lista zmiennych do debugowania hamulca ED
static std::string const MED_labels[ 8 ];

View File

@@ -404,9 +404,9 @@ global_settings::ConfigParse(cParser &Parser) {
else if( token == "gfx.reflections.framerate" ) {
auto const updatespersecond { std::abs( Parser.getToken<double>() ) };
ReflectionUpdatesPerSecond = (
ReflectionUpdateInterval = (
updatespersecond > 0 ?
1000 / std::min( 30.0, updatespersecond ) :
1.0 / std::min( 30.0, updatespersecond ) :
0 );
}
else if (token == "timespeed")

View File

@@ -25,6 +25,7 @@ struct global_settings {
bool ctrlState{ false };
bool altState{ false };
std::mt19937 random_engine{ std::mt19937( static_cast<unsigned int>( std::time( NULL ) ) ) };
std::mt19937 local_random_engine{ std::mt19937( static_cast<unsigned int>( std::time( NULL ) ) ) };
TDynamicObject *changeDynObj{ nullptr };// info o zmianie pojazdu
TCamera pCamera; // parametry kamery
TCamera pDebugCamera;
@@ -91,7 +92,6 @@ struct global_settings {
// ui
int PythonScreenUpdateRate { 200 }; // delay between python-based screen updates, in milliseconds
int iTextMode{ 0 }; // tryb pracy wyświetlacza tekstowego
int iScreenMode[ 12 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // numer ekranu wyświetlacza tekstowego
glm::vec4 UITextColor { glm::vec4( 225.f / 255.f, 225.f / 255.f, 225.f / 255.f, 1.f ) }; // base color of UI text
float UIBgOpacity { 0.65f }; // opacity of ui windows
std::string asLang{ "pl" }; // domyślny język - http://tools.ietf.org/html/bcp47
@@ -99,6 +99,7 @@ struct global_settings {
int iWindowWidth{ 800 };
int iWindowHeight{ 600 };
float fDistanceFactor{ iWindowHeight / 768.f }; // baza do przeliczania odległości dla LoD
float targetfps { 0.0f };
bool bFullScreen{ false };
bool VSync{ false };
bool bWireFrame{ false };
@@ -115,7 +116,7 @@ struct global_settings {
float depth{ 250.f };
float distance{ 500.f }; // no longer used
} shadowtune;
int ReflectionUpdatesPerSecond{ static_cast<int>( 1000 / ( 1.0 / 300.0 ) ) };
double ReflectionUpdateInterval{ 300.0 };
bool bUseVBO{ true }; // czy jest VBO w karcie graficznej (czy użyć)
float AnisotropicFiltering{ 8.f }; // requested level of anisotropic filtering. TODO: move it to renderer object
float FieldOfView{ 45.f }; // vertical field of view for the camera. TODO: move it to the renderer
@@ -175,6 +176,21 @@ struct global_settings {
// other
std::string AppName{ "EU07" };
std::string asVersion{ "UNKNOWN" }; // z opisem
// TODO: move these to relevant areas
bool render_cab = true;
int gfx_framebuffer_width = -1;
int gfx_framebuffer_height = -1;
bool gfx_shadowmap_enabled = true;
bool gfx_envmap_enabled = true;
bool gfx_postfx_motionblur_enabled = true;
float gfx_postfx_motionblur_shutter = 0.01f;
GLenum gfx_postfx_motionblur_format = GL_RG16F;
GLenum gfx_format_color = GL_RGB16F;
GLenum gfx_format_depth = GL_DEPTH_COMPONENT32F;
bool gfx_skippipeline = false;
bool gfx_extraeffects = true;
bool gfx_shadergamma = false;
bool gfx_usegles = false;
// methods
void LoadIniFile( std::string asFileName );

6
Logs.h
View File

@@ -16,7 +16,11 @@ enum logtype : unsigned int {
generic = ( 1 << 0 ),
file = ( 1 << 1 ),
model = ( 1 << 2 ),
texture = ( 1 << 3 )
texture = ( 1 << 3 ),
// lua = ( 1 << 4 ),
material = ( 1 << 5 ),
shader = ( 1 << 6 ),
// net = ( 1 << 7 )
};
void WriteLog( const char *str, logtype const Type = logtype::generic );

View File

@@ -8953,8 +8953,8 @@ void TMoverParameters::LoadFIZ_Param( std::string const &line ) {
auto lookup = categories.find( category );
CategoryFlag = (
lookup != categories.end() ?
lookup->second :
0 );
lookup->second :
0 );
if( CategoryFlag == 0 ) {
ErrorLog( "Unknown vehicle category: \"" + category + "\"." );
}

View File

@@ -374,17 +374,34 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
m_material = GfxRenderer->Fetch_Material( material );
// renderowanie w cyklu przezroczystych tylko jeśli:
// 1. Opacity=0 (przejściowo <1, czy tam <100) oraz
// 2. tekstura ma przezroczystość
iFlags |=
( ( ( Opacity < 1.0 )
&& ( ( m_material != null_handle )
&& ( GfxRenderer->Material( m_material ).has_alpha ) ) ) ?
iFlags |= (
Opacity < 0.999f ?
0x20 :
0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta
0x10 ); // 0x20-przezroczysta, 0x10-nieprzezroczysta
};
}
else
else {
iFlags |= 0x10;
}
if (m_material > 0)
{
opengl_material const &mat = GfxRenderer->Material(m_material);
// if material have opacity set, replace submodel opacity with it
if (!std::isnan(mat.opacity))
{
iFlags &= ~0x30;
if (mat.opacity == 0.0f)
iFlags |= 0x20; // translucent
else
iFlags |= 0x10; // opaque
}
// and same thing with selfillum
if (!std::isnan(mat.selfillum))
fLight = mat.selfillum;
}
// visibility range
std::string discard;
@@ -974,73 +991,75 @@ TSubModel *TSubModel::GetFromName(std::string const &search, bool i)
// WORD hbIndices[18]={3,0,1,5,4,2,1,0,4,1,5,3,2,3,5,2,4,0};
void TSubModel::RaAnimation(TAnimType a)
{
glm::mat4 m = OpenGLMatrices.data(GL_MODELVIEW);
RaAnimation(m, a);
glLoadMatrixf(glm::value_ptr(m));
}
void TSubModel::RaAnimation(glm::mat4 &m, TAnimType a)
{ // wykonanie animacji niezależnie od renderowania
switch (a)
{ // korekcja położenia, jeśli submodel jest animowany
case TAnimType::at_Translate: // Ra: było "true"
if (iAnimOwner != iInstance)
break; // cudza animacja
glTranslatef(v_TransVector.x, v_TransVector.y, v_TransVector.z);
m = glm::translate(m, glm::vec3(v_TransVector.x, v_TransVector.y, v_TransVector.z));
break;
case TAnimType::at_Rotate: // Ra: było "true"
if (iAnimOwner != iInstance)
break; // cudza animacja
glRotatef(f_Angle, v_RotateAxis.x, v_RotateAxis.y, v_RotateAxis.z);
m = glm::rotate(m, glm::radians(f_Angle), glm::vec3(v_RotateAxis.x, v_RotateAxis.y, v_RotateAxis.z));
break;
case TAnimType::at_RotateXYZ:
if (iAnimOwner != iInstance)
break; // cudza animacja
glTranslatef(v_TransVector.x, v_TransVector.y, v_TransVector.z);
glRotatef(v_Angles.x, 1.0f, 0.0f, 0.0f);
glRotatef(v_Angles.y, 0.0f, 1.0f, 0.0f);
glRotatef(v_Angles.z, 0.0f, 0.0f, 1.0f);
m = glm::translate(m, glm::vec3(v_TransVector.x, v_TransVector.y, v_TransVector.z));
m = glm::rotate(m, glm::radians(v_Angles.x), glm::vec3(1.0f, 0.0f, 0.0f));
m = glm::rotate(m, glm::radians(v_Angles.y), glm::vec3(0.0f, 1.0f, 0.0f));
m = glm::rotate(m, glm::radians(v_Angles.z), glm::vec3(0.0f, 0.0f, 1.0f));
break;
case TAnimType::at_SecondsJump: // sekundy z przeskokiem
glRotatef(simulation::Time.data().wSecond * 6.0, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(simulation::Time.data().wSecond * 6.0f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_MinutesJump: // minuty z przeskokiem
glRotatef(simulation::Time.data().wMinute * 6.0, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(simulation::Time.data().wMinute * 6.0f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_HoursJump: // godziny skokowo 12h/360°
glRotatef(simulation::Time.data().wHour * 30.0 * 0.5, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(simulation::Time.data().wHour * 30.0f * 0.5f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Hours24Jump: // godziny skokowo 24h/360°
glRotatef(simulation::Time.data().wHour * 15.0 * 0.25, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(simulation::Time.data().wHour * 15.0f * 0.25f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Seconds: // sekundy płynnie
glRotatef(simulation::Time.second() * 6.0, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians((float)simulation::Time.second() * 6.0f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Minutes: // minuty płynnie
glRotatef(simulation::Time.data().wMinute * 6.0 + simulation::Time.second() * 0.1, 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(simulation::Time.data().wMinute * 6.0f + (float)simulation::Time.second() * 0.1f), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Hours: // godziny płynnie 12h/360°
glRotatef(2.0 * Global.fTimeAngleDeg, 0.0, 1.0, 0.0);
// glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0);
m = glm::rotate(m, glm::radians(2.0f * (float)Global.fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Hours24: // godziny płynnie 24h/360°
glRotatef(Global.fTimeAngleDeg, 0.0, 1.0, 0.0);
// glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0);
m = glm::rotate(m, glm::radians((float)Global.fTimeAngleDeg), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Billboard: // obrót w pionie do kamery
{
Math3D::matrix4x4 mat; mat.OpenGL_Matrix( OpenGLMatrices.data_array( GL_MODELVIEW ) );
float3 gdzie = float3(mat[3][0], mat[3][1], mat[3][2]); // początek układu współrzędnych submodelu względem kamery
glLoadIdentity(); // macierz jedynkowa
glTranslatef(gdzie.x, gdzie.y, gdzie.z); // początek układu zostaje bez
// zmian
glRotated(atan2(gdzie.x, gdzie.z) * 180.0 / M_PI, 0.0, 1.0,
0.0); // jedynie obracamy w pionie o kąt
m = glm::mat4(1.0f);
m = glm::translate(m, glm::vec3(gdzie.x, gdzie.y, gdzie.z)); // początek układu zostaje bez zmian
m = glm::rotate(m, (float)atan2(gdzie.x, gdzie.z), glm::vec3(0.0f, 1.0f, 0.0f)); // jedynie obracamy w pionie o kąt
}
break;
case TAnimType::at_Wind: // ruch pod wpływem wiatru (wiatr będziemy liczyć potem...)
glRotated(1.5 * std::sin(M_PI * simulation::Time.second() / 6.0), 0.0, 1.0, 0.0);
m = glm::rotate(m, glm::radians(1.5f * (float)sin(M_PI * simulation::Time.second() / 6.0)), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_Sky: // animacja nieba
glRotated(Global.fLatitudeDeg, 1.0, 0.0, 0.0); // ustawienie osi OY na północ
// glRotatef(Global.fTimeAngleDeg,0.0,1.0,0.0); //obrót dobowy osi OX
glRotated(-fmod(Global.fTimeAngleDeg, 360.0), 0.0, 1.0, 0.0); // obrót dobowy osi OX
break;
case TAnimType::at_IK11: // ostatni element animacji szkieletowej (podudzie, stopa)
glRotatef(v_Angles.z, 0.0f, 1.0f, 0.0f); // obrót względem osi pionowej (azymut)
glRotatef(v_Angles.x, 1.0f, 0.0f, 0.0f); // obrót względem poziomu (deklinacja)
m = glm::rotate(m, glm::radians((float)Global.fLatitudeDeg), glm::vec3(0.0f, 1.0f, 0.0f)); // ustawienie osi OY na północ
m = glm::rotate(m, glm::radians((float)-fmod(Global.fTimeAngleDeg, 360.0)), glm::vec3(0.0f, 1.0f, 0.0f));
break;
case TAnimType::at_DigiClk: // animacja zegara cyfrowego
{ // ustawienie animacji w submodelach potomnych
@@ -1063,8 +1082,8 @@ void TSubModel::RaAnimation(TAnimType a)
}
if (mAnimMatrix) // można by to dać np. do at_Translate
{
glMultMatrixf(mAnimMatrix->readArray());
mAnimMatrix = NULL; // jak animator będzie potrzebował, to ustawi ponownie
m *= glm::make_mat4(mAnimMatrix->e);
mAnimMatrix = nullptr; // jak animator będzie potrzebował, to ustawi ponownie
}
};
@@ -1783,13 +1802,31 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, std::vector<std::string> *t,
}
*/
m_material = GfxRenderer->Fetch_Material( m_materialname );
if( ( iFlags & 0x30 ) == 0 ) {
// texture-alpha based fallback if for some reason we don't have opacity flag set yet
iFlags |= (
( ( m_material != null_handle )
&& ( GfxRenderer->Material( m_material ).has_alpha ) ) ?
0x20 :
0x10 ); // 0x10-nieprzezroczysta, 0x20-przezroczysta
// if we don't have phase flags set for some reason, try to fix it
if (!(iFlags & 0x30) && m_material != null_handle)
{
opengl_material const &mat = GfxRenderer->Material(m_material);
float opacity = mat.opacity;
// if material don't have opacity set, try to guess it
if (std::isnan(opacity))
opacity = mat.get_or_guess_opacity();
// set phase flag based on material opacity
if (opacity == 0.0f)
iFlags |= 0x20; // translucent
else
iFlags |= 0x10; // opaque
}
if (m_material > 0)
{
opengl_material const &mat = GfxRenderer->Material(m_material);
// replace submodel selfillum with material one
if (!std::isnan(mat.selfillum))
fLight = mat.selfillum;
}
}
else {

View File

@@ -12,8 +12,9 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h"
#include "dumb3d.h"
#include "Float3d.h"
#include "openglgeometrybank.h"
#include "geometrybank.h"
#include "material.h"
#include "gl/query.h"
// Ra: specjalne typy submodeli, poza tym GL_TRIANGLES itp.
const int TP_ROTATOR = 256;
@@ -58,6 +59,7 @@ class TSubModel
//m7todo: zrobić normalną serializację
friend opengl_renderer;
friend opengl33_renderer;
friend TModel3d; // temporary workaround. TODO: clean up class content/hierarchy
friend TDynamicObject; // temporary etc
friend scene::shape_node; // temporary etc
@@ -151,7 +153,8 @@ public: // chwilowo
private:
int SeekFaceNormal( std::vector<unsigned int> const &Masks, int const Startface, unsigned int const Mask, glm::vec3 const &Position, gfx::vertex_array const &Vertices );
void RaAnimation(TAnimType a);
// returns true if the submodel is a smoke emitter attachment point, false otherwise
void RaAnimation(glm::mat4 &m, TAnimType a);
// returns true if the submodel is a smoke emitter attachment point, false otherwise
bool is_emitter() const;
public:
@@ -217,6 +220,8 @@ public:
return m_material; }
void ParentMatrix(float4x4 *m) const;
float MaxY( float4x4 const &m );
std::optional<gl::query> occlusion_query;
glm::mat4 future_transform;
void deserialize(std::istream&);
void serialize(std::ostream&,
@@ -231,6 +236,7 @@ public:
class TModel3d
{
friend opengl_renderer;
friend opengl33_renderer;
private:
TSubModel *Root; // drzewo submodeli

View File

@@ -40,7 +40,7 @@ void render_task::run() {
::glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
if( GLEW_EXT_texture_filter_anisotropic ) {
if( GL_EXT_texture_filter_anisotropic ) {
// anisotropic filtering
::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering );
}

View File

@@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/.
#include "Texture.h"
#include <ddraw.h>
#include "GL/glew.h"
#include "application.h"
#include "dictionary.h"
@@ -29,6 +28,9 @@ http://mozilla.org/MPL/2.0/.
#define EU07_DEFERRED_TEXTURE_UPLOAD
std::array<GLuint, gl::MAX_TEXTURES + 2> opengl_texture::units = { 0 };
GLint opengl_texture::m_activeunit = -1;
texture_manager::texture_manager() {
// since index 0 is used to indicate no texture, we put a blank entry in the first texture slot
@@ -545,16 +547,56 @@ opengl_texture::load_TGA() {
}
bool
opengl_texture::bind() {
opengl_texture::bind(size_t unit) {
if( ( false == is_ready )
&& ( false == create() ) ) {
return false;
}
::glBindTexture( GL_TEXTURE_2D, id );
if (units[unit] == id)
return true;
if (GLAD_GL_ARB_direct_state_access)
{
glBindTextureUnit(unit, id);
}
else
{
if (unit != m_activeunit)
{
glActiveTexture(GL_TEXTURE0 + unit);
m_activeunit = unit;
}
glBindTexture(target, id);
}
units[unit] = id;
return true;
}
void
opengl_texture::unbind(size_t unit)
{
if (GLAD_GL_ARB_direct_state_access)
{
glBindTextureUnit(unit, 0);
}
else
{
if (unit != m_activeunit)
{
glActiveTexture(GL_TEXTURE0 + unit);
m_activeunit = unit;
}
//todo: for other targets
glBindTexture(GL_TEXTURE_2D, 0);
}
units[unit] = 0;
}
bool
opengl_texture::create() {
@@ -697,6 +739,38 @@ opengl_texture::release() {
return;
}
void
opengl_texture::alloc_rendertarget( GLint format, GLint components, int width, int height, int s, GLint wrap ) {
data_width = width;
data_height = height;
data_format = format;
data_components = components;
data_mapcount = 1;
is_rendertarget = true;
wrap_mode_s = wrap;
wrap_mode_t = wrap;
samples = s;
if( samples > 1 )
target = GL_TEXTURE_2D_MULTISAMPLE;
create();
}
void
opengl_texture::set_components_hint( GLint hint ) {
components_hint = hint;
}
void
opengl_texture::reset_unit_cache() {
for( auto &unit : units ) {
unit = 0;
}
m_activeunit = -1;
}
void
opengl_texture::set_filtering() const {
@@ -704,7 +778,7 @@ opengl_texture::set_filtering() const {
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
::glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
if( GLEW_EXT_texture_filter_anisotropic ) {
if( GL_EXT_texture_filter_anisotropic ) {
// anisotropic filtering
::glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, Global.AnisotropicFiltering );
}
@@ -793,7 +867,7 @@ texture_manager::unit( GLint const Textureunit ) {
// ustalenie numeru tekstury, wczytanie jeśli jeszcze takiej nie było
texture_handle
texture_manager::create( std::string Filename, bool const Loadnow ) {
texture_manager::create( std::string Filename, bool const Loadnow, GLint Formathint ) {
if( Filename.find( '|' ) != std::string::npos )
Filename.erase( Filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury
@@ -866,6 +940,7 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
texture->name = locator.first;
texture->type = locator.second;
texture->traits = traits;
texture->components_hint = Formathint;
auto const textureindex = (texture_handle)m_textures.size();
m_textures.emplace_back( texture, std::chrono::steady_clock::time_point() );
m_texturemappings.emplace( locator.first, textureindex );
@@ -888,40 +963,18 @@ texture_manager::create( std::string Filename, bool const Loadnow ) {
void
texture_manager::bind( std::size_t const Unit, texture_handle const Texture ) {
m_textures[ Texture ].second = m_garbagecollector.timestamp();
if( m_units[ Unit ].unit == 0 ) {
// no texture unit, nothing to bind the texture to
return;
}
// even if we may skip texture binding make sure the relevant texture unit is activated
unit( m_units[ Unit ].unit );
if( Texture == m_units[ Unit ].texture ) {
// don't bind again what's already active
return;
}
// TBD, TODO: do binding in texture object, add support for other types than 2d
if( Texture != null_handle ) {
#ifndef EU07_DEFERRED_TEXTURE_UPLOAD
// NOTE: we could bind dedicated 'error' texture here if the id isn't valid
::glBindTexture( GL_TEXTURE_2D, texture(Texture).id );
m_units[ Unit ].texture = Texture;
#else
if( true == texture( Texture ).bind() ) {
m_units[ Unit ].texture = Texture;
}
else {
// TODO: bind a special 'error' texture on failure
::glBindTexture( GL_TEXTURE_2D, 0 );
m_units[ Unit ].texture = 0;
}
#endif
}
else {
::glBindTexture( GL_TEXTURE_2D, 0 );
m_units[ Unit ].texture = 0;
}
// all done
return;
if (Texture != null_handle)
mark_as_used(Texture).bind(Unit);
else
opengl_texture::unbind(Unit);
}
opengl_texture &
texture_manager::mark_as_used(const texture_handle Texture) {
auto &pair = m_textures[ Texture ];
pair.second = m_garbagecollector.timestamp();
return *pair.first;
}
void

View File

@@ -12,8 +12,8 @@ http://mozilla.org/MPL/2.0/.
#include <istream>
#include <ddraw.h>
#include <string>
#include "GL/glew.h"
#include "ResourceManager.h"
#include "gl/ubo.h"
struct opengl_texture {
static DDSURFACEDESC2 deserialize_ddsd(std::istream&);
@@ -27,12 +27,20 @@ struct opengl_texture {
void
load();
bool
bind();
bind( size_t unit );
static void
unbind( size_t unit );
bool
create();
// releases resources allocated on the opengl end, storing local copy if requested
void
release();
void
alloc_rendertarget( GLint format, GLint components, int width, int height, int samples = 1, GLint wrap = GL_CLAMP_TO_BORDER );
void
set_components_hint( GLint hint );
static void
reset_unit_cache();
inline
int
width() const {
@@ -49,6 +57,10 @@ struct opengl_texture {
std::string name; // name of the texture source file
std::string type; // type of the texture source file
std::size_t size{ 0 }; // size of the texture data, in kb
GLint components_hint = 0; // components that material wants
GLenum target = GL_TEXTURE_2D;
static std::array<GLuint, gl::MAX_TEXTURES + 2> units;
private:
// methods
@@ -63,6 +75,8 @@ private:
void flip_vertical();
// members
bool is_rendertarget = false; // is used as postfx rendertarget, without loaded data
int samples = 1;
std::vector<char> data; // texture data (stored GL-style, bottom-left origin)
resource_state data_state{ resource_state::none }; // current state of texture data
int data_width{ 0 },
@@ -70,10 +84,18 @@ private:
data_mapcount{ 0 };
GLint data_format{ 0 },
data_components{ 0 };
GLint data_type = GL_UNSIGNED_BYTE;
GLint wrap_mode_s = GL_REPEAT;
GLint wrap_mode_t = GL_REPEAT;
/*
std::atomic<bool> is_loaded{ false }; // indicates the texture data was loaded and can be processed
std::atomic<bool> is_good{ false }; // indicates the texture data was retrieved without errors
*/
static std::unordered_map<GLint, int> precompressed_formats;
static std::unordered_map<GLint, GLint> drivercompressed_formats;
static std::unordered_map<GLint, std::unordered_map<GLint, GLint>> mapping;
static GLint m_activeunit;
};
typedef int texture_handle;
@@ -91,10 +113,12 @@ public:
unit( GLint const Textureunit );
// creates texture object out of data stored in specified file
texture_handle
create( std::string Filename, bool const Loadnow = true );
create( std::string Filename, bool const Loadnow = true, GLint Formathint = GL_SRGB_ALPHA );
// binds specified texture to specified texture unit
void
bind( std::size_t const Unit, texture_handle const Texture );
opengl_texture &
mark_as_used( texture_handle const Texture );
// provides direct access to specified texture object
opengl_texture &
texture( texture_handle const Texture ) const { return *(m_textures[ Texture ].first); }

View File

@@ -54,10 +54,12 @@ struct subsystem_stopwatches {
stopwatch gfx_shadows;
stopwatch gfx_reflections;
stopwatch gfx_swap;
stopwatch gfx_gui;
stopwatch sim_total;
stopwatch sim_dynamics;
stopwatch sim_events;
stopwatch sim_ai;
stopwatch mainloop_total;
};
extern subsystem_stopwatches subsystem;

View File

@@ -585,11 +585,11 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
else if (iCategoryFlag & 2)
if (m_material1 && fTexLength)
{ // dla drogi trzeba ustalić proporcje boków nawierzchni
auto const &texture1 { GfxRenderer->Texture( GfxRenderer->Material( m_material1 ).texture1 ) };
auto const &texture1 { GfxRenderer->Texture( GfxRenderer->Material( m_material1 ).textures[0] ) };
if( texture1.height() > 0 ) {
fTexRatio1 = static_cast<float>( texture1.width() ) / static_cast<float>( texture1.height() ); // proporcja boków
}
auto const &texture2 { GfxRenderer->Texture( GfxRenderer->Material( m_material2 ).texture1 ) };
auto const &texture2 { GfxRenderer->Texture( GfxRenderer->Material( m_material2 ).textures[0] ) };
if( texture2.height() > 0 ) {
fTexRatio2 = static_cast<float>( texture2.width() ) / static_cast<float>( texture2.height() ); // proporcja boków
}

View File

@@ -144,6 +144,7 @@ private:
class TTrack : public scene::basic_node {
friend opengl_renderer;
friend opengl33_renderer;
// NOTE: temporary arrangement
friend itemproperties_panel;

View File

@@ -21,6 +21,7 @@ class TTractionPowerSource;
class TTraction : public scene::basic_node {
friend opengl_renderer;
friend opengl33_renderer;
public: // na razie
TTractionPowerSource *psPower[ 2 ] { nullptr, nullptr }; // najbliższe zasilacze z obu kierunków

View File

@@ -7558,7 +7558,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
( substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
DynamicObject->asBaseDir + renderername :
renderername ),
GfxRenderer->Material( material ).texture1 );
GfxRenderer->Material( material ).textures[0] );
}
// btLampkaUnknown.Init("unknown",mdKabina,false);
} while (token != "");

View File

@@ -25,14 +25,12 @@ http://mozilla.org/MPL/2.0/.
#ifdef EU07_BUILD_STATIC
#pragma comment( lib, "glfw3.lib" )
#pragma comment( lib, "glew32s.lib" )
#else
#ifdef _WIN32
#pragma comment( lib, "glfw3dll.lib" )
#else
#pragma comment( lib, "glfw3.lib" )
#endif
#pragma comment( lib, "glew32.lib" )
#endif // build_static
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )
@@ -125,10 +123,10 @@ eu07_application::init( int Argc, char *Argv[] ) {
if( ( result = init_glfw() ) != 0 ) {
return result;
}
init_callbacks();
if( ( result = init_gfx() ) != 0 ) {
return result;
}
init_callbacks();
if( ( result = init_audio() ) != 0 ) {
return result;
}
@@ -255,6 +253,16 @@ eu07_application::set_cursor_pos( double const Horizontal, double const Vertical
glfwSetCursorPos( m_windows.front(), Horizontal, Vertical );
}
glm::dvec2
eu07_application::get_cursor_pos() const {
glm::dvec2 pos;
if( !m_windows.empty() ) {
glfwGetCursorPos( m_windows.front(), &pos.x, &pos.y );
}
return pos;
}
void
eu07_application::get_cursor_pos( double &Horizontal, double &Vertical ) const {
@@ -320,10 +328,12 @@ eu07_application::init_debug() {
// memory leaks
_CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_LEAK_CHECK_DF );
// floating point operation errors
/*
auto state { _clearfp() };
state = _control87( 0, 0 );
// this will turn on FPE for #IND and zerodiv
state = _control87( state & ~( _EM_ZERODIVIDE | _EM_INVALID ), _MCW_EM );
*/
#endif
#ifdef _WIN32
::SetUnhandledExceptionFilter( unhandled_handler );
@@ -507,18 +517,38 @@ eu07_application::init_callbacks() {
int
eu07_application::init_gfx() {
if( glewInit() != GLEW_OK ) {
ErrorLog( "Bad init: failed to initialize glew" );
return -1;
if (Global.gfx_usegles)
{
if( 0 == gladLoadGLES2Loader( (GLADloadproc)glfwGetProcAddress ) ) {
ErrorLog( "Bad init: failed to initialize glad" );
return -1;
}
}
else
{
if( 0 == gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress ) ) {
ErrorLog( "Bad init: failed to initialize glad" );
return -1;
}
}
GfxRenderer = std::make_unique<opengl_renderer>();
if( ( false == GfxRenderer->Init( m_windows.front() ) )
|| ( false == ui_layer::init( m_windows.front() ) ) ) {
return -1;
{
// legacy render path
GfxRenderer = std::make_unique<opengl_renderer>();
Global.DisabledLogTypes |= logtype::material;
}
if( false == GfxRenderer->Init( m_windows.front() ) ) {
return -1;
}
if( false == ui_layer::init( m_windows.front() ) ) {
return -1;
}
/*
for (const global_settings::extraviewport_config &conf : Global.extra_viewports)
if (!GfxRenderer.AddViewport(conf))
return -1;
*/
return 0;
}

View File

@@ -56,6 +56,8 @@ public:
set_cursor( int const Mode );
void
set_cursor_pos( double const Horizontal, double const Vertical );
glm::dvec2
get_cursor_pos() const;
void
get_cursor_pos( double &Horizontal, double &Vertical ) const;
// input handlers

View File

@@ -245,9 +245,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
Mousex,
Mousey,
GLFW_PRESS,
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
0 );
0 );
}
else {
// control picking mode
@@ -258,8 +256,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
m_slider.value(),
0,
GLFW_PRESS,
// TODO: pass correct entity id once the missing systems are in place
0 );
0 );
}
if( false == m_pickmodepanning ) {
@@ -275,9 +272,7 @@ drivermouse_input::move( double Mousex, double Mousey ) {
viewoffset.x,
viewoffset.y,
GLFW_PRESS,
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
0 );
0 );
m_cursorposition = cursorposition;
}
}
@@ -287,7 +282,7 @@ drivermouse_input::scroll( double const Xoffset, double const Yoffset ) {
if( Global.ctrlState ) {
// ctrl + scroll wheel adjusts fov
Global.FieldOfView = clamp( static_cast<float>( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.gfx_total.average() ), 15.0f, 75.0f );
Global.FieldOfView = clamp( static_cast<float>( Global.FieldOfView - Yoffset * 20.0 / Timer::subsystem.mainloop_total.average() ), 15.0f, 75.0f );
}
else {
// scroll adjusts master controller
@@ -323,12 +318,12 @@ drivermouse_input::button( int const Button, int const Action ) {
// left mouse button launches on_click event associated with to the node
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
if( Action == GLFW_PRESS ) {
auto const *node { GfxRenderer->Update_Pick_Node() };
if( ( node == nullptr )
|| ( typeid( *node ) != typeid( TAnimModel ) ) ) {
return;
}
simulation::Region->on_click( static_cast<TAnimModel const *>( node ) );
GfxRenderer->Pick_Node(
[this](scene::basic_node *node) {
if( ( node == nullptr )
|| ( typeid( *node ) != typeid( TAnimModel ) ) )
return;
simulation::Region->on_click( static_cast<TAnimModel const *>( node ) ); } );
}
}
// right button controls panning
@@ -349,10 +344,11 @@ drivermouse_input::button( int const Button, int const Action ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( mousecommand, 0, 0, Action, 0 );
m_relay.post( mousecommand, 0, 0, Action, 0 );
mousecommand = user_command::none;
}
else {
m_pickwaiting = false;
if( Button == GLFW_MOUSE_BUTTON_LEFT ) {
if( m_slider.command() != user_command::none ) {
m_relay.post( m_slider.command(), 0, 0, Action, 0 );
@@ -369,68 +365,77 @@ drivermouse_input::button( int const Button, int const Action ) {
}
else {
// if not release then it's press
auto const lookup = m_buttonbindings.find( simulation::Train->GetLabel( GfxRenderer->Update_Pick_Control() ) );
if( lookup != m_buttonbindings.end() ) {
// if the recognized element under the cursor has a command associated with the pressed button, notify the recipient
mousecommand = (
Button == GLFW_MOUSE_BUTTON_LEFT ?
lookup->second.left :
lookup->second.right
);
if( mousecommand == user_command::none ) { return; }
// check manually for commands which have 'fast' variants launched with shift modifier
if( Global.shiftState ) {
switch( mousecommand ) {
case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; }
case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; }
case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; }
case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; }
case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; }
case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; }
default: { break; }
}
}
m_pickwaiting = true;
GfxRenderer->Pick_Control(
[this, Button, Action, &mousecommand](TSubModel const *control) {
switch( mousecommand ) {
case user_command::mastercontrollerincrease:
case user_command::mastercontrollerdecrease:
case user_command::secondcontrollerincrease:
case user_command::secondcontrollerdecrease:
case user_command::trainbrakeincrease:
case user_command::trainbrakedecrease:
case user_command::independentbrakeincrease:
case user_command::independentbrakedecrease: {
// these commands trigger varying repeat rate mode,
// which scales the rate based on the distance of the cursor from its point when the command was first issued
m_varyingpollrateorigin = m_cursorposition;
m_varyingpollrate = true;
break;
}
case user_command::jointcontrollerset:
case user_command::mastercontrollerset:
case user_command::secondcontrollerset:
case user_command::trainbrakeset:
case user_command::independentbrakeset: {
m_slider.bind( mousecommand );
mousecommand = user_command::none;
return;
}
default: {
break;
}
}
// NOTE: basic keyboard controls don't have any parameters
// NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( mousecommand, 0, 0, Action, 0 );
m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one
}
else {
// if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
m_pickmodepanning = true;
}
}
bool pickwaiting = m_pickwaiting;
m_pickwaiting = false;
auto const lookup = m_buttonbindings.find( simulation::Train->GetLabel( control ) );
if( lookup != m_buttonbindings.end() ) {
// if the recognized element under the cursor has a command associated with the pressed button, notify the recipient
mousecommand = (
Button == GLFW_MOUSE_BUTTON_LEFT ?
lookup->second.left :
lookup->second.right
);
if( mousecommand == user_command::none ) { return; }
// check manually for commands which have 'fast' variants launched with shift modifier
if( Global.shiftState ) {
switch( mousecommand ) {
case user_command::mastercontrollerincrease: { mousecommand = user_command::mastercontrollerincreasefast; break; }
case user_command::mastercontrollerdecrease: { mousecommand = user_command::mastercontrollerdecreasefast; break; }
case user_command::secondcontrollerincrease: { mousecommand = user_command::secondcontrollerincreasefast; break; }
case user_command::secondcontrollerdecrease: { mousecommand = user_command::secondcontrollerdecreasefast; break; }
case user_command::independentbrakeincrease: { mousecommand = user_command::independentbrakeincreasefast; break; }
case user_command::independentbrakedecrease: { mousecommand = user_command::independentbrakedecreasefast; break; }
default: { break; }
}
}
switch( mousecommand ) {
case user_command::mastercontrollerincrease:
case user_command::mastercontrollerdecrease:
case user_command::secondcontrollerincrease:
case user_command::secondcontrollerdecrease:
case user_command::trainbrakeincrease:
case user_command::trainbrakedecrease:
case user_command::independentbrakeincrease:
case user_command::independentbrakedecrease: {
// these commands trigger varying repeat rate mode,
// which scales the rate based on the distance of the cursor from its point when the command was first issued
m_varyingpollrateorigin = m_cursorposition;
m_varyingpollrate = true;
break;
}
case user_command::jointcontrollerset:
case user_command::mastercontrollerset:
case user_command::secondcontrollerset:
case user_command::trainbrakeset:
case user_command::independentbrakeset: {
m_slider.bind( mousecommand );
mousecommand = user_command::none;
return;
}
default: {
break;
}
}
// NOTE: basic keyboard controls don't have any parameters
// NOTE: as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( mousecommand, 0, 0, Action, 0 );
if (!pickwaiting) // already depressed
m_relay.post( mousecommand, 0, 0, GLFW_RELEASE, 0 );
m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one
}
else {
// if we don't have any recognized element under the cursor and the right button was pressed, enter view panning mode
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
m_pickmodepanning = true;
} } } );
}
}
}
@@ -457,13 +462,13 @@ drivermouse_input::poll() {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 );
m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 );
}
if( m_mousecommandright != user_command::none ) {
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 );
m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 );
}
m_updateaccumulator -= updaterate;
}

View File

@@ -105,6 +105,7 @@ private:
bool m_varyingpollrate { false }; // indicates rate of command repeats is affected by the cursor position
glm::dvec2 m_varyingpollrateorigin; // helper, cursor position when the command was initiated
std::array<int, GLFW_MOUSE_BUTTON_LAST> m_buttons;
bool m_pickwaiting;
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

View File

@@ -229,11 +229,14 @@ editor_mode::on_mouse_button( int const Button, int const Action, int const Mods
if( Action == GLFW_PRESS ) {
// left button press
m_node = GfxRenderer->Update_Pick_Node();
if( m_node ) {
Application.set_cursor( GLFW_CURSOR_DISABLED );
}
dynamic_cast<editor_ui*>( m_userinterface.get() )->set_node( m_node );
m_node = nullptr;
GfxRenderer->Pick_Node(
[ this ]( scene::basic_node *node ) {
m_node = node;
if( m_node ) {
Application.set_cursor( GLFW_CURSOR_DISABLED );
}
dynamic_cast<editor_ui*>( m_userinterface.get() )->set_node( m_node ); } );
}
else {
// left button release

View File

@@ -11,7 +11,21 @@ http://mozilla.org/MPL/2.0/.
#include "uilayer.h"
#include "Classes.h"
/*
// helper, associated bool is set when the primary value was changed and expects processing at the observer's leisure
template<typename Type_>
using changeable = std::pair<Type_, bool>;
// helper, holds a set of changeable properties for a scene node
struct item_properties {
scene::basic_node const *node { nullptr }; // properties' owner
changeable<std::string> name {};
changeable<glm::dvec3> location {};
changeable<glm::vec3> rotation {};
};
*/
class itemproperties_panel : public ui_panel {
public:

View File

@@ -47,6 +47,113 @@ basic_vertex::deserialize( std::istream &s ) {
texture.y = sn_utils::ld_float32( s );
}
// based on
// Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”.
// Terathon Software, 2001. http://terathon.com/code/tangent.html
void calculate_tangent(vertex_array &vertices, int type)
{
size_t vertex_count = vertices.size();
if (!vertex_count || vertices[0].tangent.w != 0.0f)
return;
size_t triangle_count;
if (type == GL_TRIANGLES)
triangle_count = vertex_count / 3;
else if (type == GL_TRIANGLE_STRIP)
triangle_count = vertex_count - 2;
else if (type == GL_TRIANGLE_FAN)
triangle_count = vertex_count - 2;
else
return;
std::vector<glm::vec3> tan(vertex_count * 2);
for (size_t a = 0; a < triangle_count; a++)
{
size_t i1, i2, i3;
if (type == GL_TRIANGLES)
{
i1 = a * 3;
i2 = a * 3 + 1;
i3 = a * 3 + 2;
}
else if (type == GL_TRIANGLE_STRIP)
{
if (a % 2 == 0)
{
i1 = a;
i2 = a + 1;
}
else
{
i1 = a + 1;
i2 = a;
}
i3 = a + 2;
}
else if (type == GL_TRIANGLE_FAN)
{
i1 = 0;
i2 = a + 1;
i3 = a + 2;
}
const glm::vec3 &v1 = vertices[i1].position;
const glm::vec3 &v2 = vertices[i2].position;
const glm::vec3 &v3 = vertices[i3].position;
const glm::vec2 &w1 = vertices[i1].texture;
const glm::vec2 &w2 = vertices[i2].texture;
const glm::vec2 &w3 = vertices[i3].texture;
float x1 = v2.x - v1.x;
float x2 = v3.x - v1.x;
float y1 = v2.y - v1.y;
float y2 = v3.y - v1.y;
float z1 = v2.z - v1.z;
float z2 = v3.z - v1.z;
float s1 = w2.x - w1.x;
float s2 = w3.x - w1.x;
float t1 = w2.y - w1.y;
float t2 = w3.y - w1.y;
float ri = (s1 * t2 - s2 * t1);
if (ri == 0.0f) {
//ErrorLog("Bad model: failed to generate tangent vectors for vertices: " +
// std::to_string(i1) + ", " + std::to_string(i2) + ", " + std::to_string(i3));
// useless error, as we don't have name of problematic model here
// why does it happen?
ri = 1.0f;
}
float r = 1.0f / ri;
glm::vec3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r);
glm::vec3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r);
tan[i1] += sdir;
tan[i2] += sdir;
tan[i3] += sdir;
tan[vertex_count + i1] += tdir;
tan[vertex_count + i2] += tdir;
tan[vertex_count + i3] += tdir;
}
for (size_t a = 0; a < vertex_count; a++)
{
const glm::vec3 &n = vertices[a].normal;
const glm::vec3 &t = tan[a];
const glm::vec3 &t2 = tan[vertex_count + a];
vertices[a].tangent = glm::vec4(glm::normalize((t - n * glm::dot(n, t))),
(glm::dot(glm::cross(n, t), t2) < 0.0F) ? -1.0F : 1.0F);
}
}
// generic geometry bank class, allows storage, update and drawing of geometry chunks
// creates a new geometry chunk of specified type from supplied vertex data. returns: handle to the chunk

View File

@@ -9,13 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "GL/glew.h"
#ifdef _WIN32
#include "GL/wglew.h"
#endif
#include "ResourceManager.h"
namespace gfx {
@@ -25,6 +18,7 @@ struct basic_vertex {
glm::vec3 position; // 3d space
glm::vec3 normal; // 3d space
glm::vec2 texture; // uv space
glm::vec4 tangent; // xyz - tangent, w - handedness
basic_vertex() = default;
basic_vertex( glm::vec3 Position, glm::vec3 Normal, glm::vec2 Texture ) :
@@ -53,6 +47,8 @@ struct stream_units {
using vertex_array = std::vector<basic_vertex>;
void calculate_tangent( vertex_array &vertices, int type );
// generic geometry bank class, allows storage, update and drawing of geometry chunks
struct geometry_handle {

27
gl/bindable.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
namespace gl
{
template <typename T>
class bindable
{
protected:
thread_local static bindable<T>* active;
public:
void bind()
{
if (active == this)
return;
active = this;
T::bind(*static_cast<T*>(active));
}
static void unbind()
{
active = nullptr;
T::bind(0);
}
};
template <typename T> thread_local bindable<T>* bindable<T>::active;
}

89
gl/buffer.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include "stdafx.h"
#include "buffer.h"
GLenum gl::buffer::glenum_target(gl::buffer::targets target)
{
static GLenum mapping[13] =
{
GL_ARRAY_BUFFER,
GL_ATOMIC_COUNTER_BUFFER,
GL_COPY_READ_BUFFER,
GL_COPY_WRITE_BUFFER,
GL_DISPATCH_INDIRECT_BUFFER,
GL_DRAW_INDIRECT_BUFFER,
GL_ELEMENT_ARRAY_BUFFER,
GL_PIXEL_PACK_BUFFER,
GL_PIXEL_UNPACK_BUFFER,
GL_SHADER_STORAGE_BUFFER,
GL_TEXTURE_BUFFER,
GL_TRANSFORM_FEEDBACK_BUFFER,
GL_UNIFORM_BUFFER
};
return mapping[target];
}
void gl::buffer::bind(targets target)
{
if (binding_points[target] == *this)
return;
glBindBuffer(glenum_target(target), *this);
binding_points[target] = *this;
}
void gl::buffer::bind_base(targets target, GLuint index)
{
glBindBufferBase(glenum_target(target), index, *this);
binding_points[target] = *this;
}
void gl::buffer::unbind(targets target)
{
glBindBuffer(glenum_target(target), 0);
binding_points[target] = 0;
}
void gl::buffer::unbind()
{
for (size_t i = 0; i < sizeof(binding_points) / sizeof(GLuint); i++)
unbind((targets)i);
}
gl::buffer::buffer()
{
glGenBuffers(1, *this);
}
gl::buffer::~buffer()
{
glDeleteBuffers(1, *this);
}
void gl::buffer::allocate(targets target, int size, GLenum hint)
{
bind(target);
glBufferData(glenum_target(target), size, nullptr, hint);
}
void gl::buffer::upload(targets target, const void *data, int offset, int size)
{
bind(target);
glBufferSubData(glenum_target(target), offset, size, data);
}
void gl::buffer::download(targets target, void *data, int offset, int size)
{
bind(target);
if (GLAD_GL_VERSION_3_3)
{
glGetBufferSubData(glenum_target(target), offset, size, data);
}
else
{
void *glbuf = glMapBufferRange(glenum_target(target), offset, size, GL_MAP_READ_BIT);
memcpy(data, glbuf, size);
glUnmapBuffer(glenum_target(target));
}
}
thread_local GLuint gl::buffer::binding_points[13];

46
gl/buffer.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
#include "object.h"
#include "bindable.h"
namespace gl
{
class buffer : public object
{
thread_local static GLuint binding_points[13];
public:
enum targets
{
ARRAY_BUFFER = 0,
ATOMIC_COUNTER_BUFFER,
COPY_READ_BUFFER,
COPY_WRITE_BUFFER,
DISPATCH_INDIRECT_BUFFER,
DRAW_INDIRECT_BUFFER,
ELEMENT_ARRAY_BUFFER,
PIXEL_PACK_BUFFER,
PIXEL_UNPACK_BUFFER,
SHADER_STORAGE_BUFFER,
TEXTURE_BUFFER,
TRANSFORM_FEEDBACK_BUFFER,
UNIFORM_BUFFER
};
protected:
static GLenum glenum_target(targets target);
public:
buffer();
~buffer();
void bind(targets target);
void bind_base(targets target, GLuint index);
static void unbind(targets target);
static void unbind();
void allocate(targets target, int size, GLenum hint);
void upload(targets target, const void *data, int offset, int size);
void download(targets target, void *data, int offset, int size);
};
}

38
gl/cubemap.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "stdafx.h"
#include "cubemap.h"
gl::cubemap::cubemap()
{
glGenTextures(1, *this);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
gl::cubemap::~cubemap()
{
glDeleteTextures(1, *this);
}
void gl::cubemap::alloc(GLint format, int width, int height, GLenum components, GLenum type)
{
glBindTexture(GL_TEXTURE_CUBE_MAP, *this);
for (GLuint tgt = GL_TEXTURE_CUBE_MAP_POSITIVE_X; tgt <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; tgt++)
glTexImage2D(tgt, 0, format, width, height, 0, components, type, nullptr);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
void gl::cubemap::bind(int unit)
{
glActiveTexture(unit);
glBindTexture(GL_TEXTURE_CUBE_MAP, *this);
}
void gl::cubemap::generate_mipmaps()
{
glBindTexture(GL_TEXTURE_CUBE_MAP, *this);
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

19
gl/cubemap.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "object.h"
namespace gl
{
// cubemap texture rendertarget
// todo: integrate with texture system
class cubemap : public object
{
public:
cubemap();
~cubemap();
void alloc(GLint format, int width, int height, GLenum components, GLenum type);
void bind(int unit);
void generate_mipmaps();
};
}

20
gl/fence.cpp Normal file
View File

@@ -0,0 +1,20 @@
#include "stdafx.h"
#include "fence.h"
gl::fence::fence()
{
sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
gl::fence::~fence()
{
glDeleteSync(sync);
}
bool gl::fence::is_signalled()
{
GLsizei len = 0;
GLint val;
glGetSynciv(sync, GL_SYNC_STATUS, 1, &len, &val);
return len == 1 && val == GL_SIGNALED;
}

20
gl/fence.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "object.h"
namespace gl
{
class fence
{
GLsync sync;
public:
fence();
~fence();
bool is_signalled();
fence(const fence&) = delete;
fence& operator=(const fence&) = delete;
};
}

103
gl/framebuffer.cpp Normal file
View File

@@ -0,0 +1,103 @@
#include "stdafx.h"
#include "framebuffer.h"
gl::framebuffer::framebuffer()
{
glGenFramebuffers(1, *this);
}
gl::framebuffer::~framebuffer()
{
glDeleteFramebuffers(1, *this);
}
void gl::framebuffer::bind(GLuint id)
{
glBindFramebuffer(GL_FRAMEBUFFER, id);
}
void gl::framebuffer::attach(const opengl_texture &tex, GLenum location)
{
bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, location, tex.target, tex.id, 0);
}
void gl::framebuffer::attach(const cubemap &tex, int face, GLenum location)
{
bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, location, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, *tex, 0);
}
void gl::framebuffer::attach(const renderbuffer &rb, GLenum location)
{
bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER, *rb);
}
void gl::framebuffer::detach(GLenum location)
{
bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, location, GL_RENDERBUFFER, 0);
}
bool gl::framebuffer::is_complete()
{
bind();
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
return status == GL_FRAMEBUFFER_COMPLETE;
}
void gl::framebuffer::clear(GLbitfield mask)
{
bind();
if (mask & GL_DEPTH_BUFFER_BIT)
glDepthMask(GL_TRUE);
glClear(mask);
}
void gl::framebuffer::blit_to(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment)
{
blit(this, other, 0, 0, w, h, mask, attachment);
}
void gl::framebuffer::blit_from(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment)
{
blit(other, this, 0, 0, w, h, mask, attachment);
}
void gl::framebuffer::blit(framebuffer *src, framebuffer *dst, int sx, int sy, int w, int h, GLbitfield mask, GLenum attachment)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, src ? *src : 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst ? *dst : 0);
if (mask & GL_COLOR_BUFFER_BIT)
{
int attachment_n = attachment - GL_COLOR_ATTACHMENT0;
GLenum outputs[8] = { GL_NONE };
outputs[attachment_n] = attachment;
glReadBuffer(attachment);
glDrawBuffers(attachment_n + 1, outputs);
}
glBlitFramebuffer(sx, sy, sx + w, sy + h, 0, 0, w, h, mask, GL_NEAREST);
unbind();
}
void gl::framebuffer::setup_drawing(int attachments)
{
bind();
GLenum a[8] =
{
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT7
};
glDrawBuffers(std::min(attachments, 8), &a[0]);
}

33
gl/framebuffer.h Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include "object.h"
#include "bindable.h"
#include "renderbuffer.h"
#include "Texture.h"
#include "cubemap.h"
namespace gl
{
class framebuffer : public object, public bindable<framebuffer>
{
public:
framebuffer();
~framebuffer();
void attach(const opengl_texture &tex, GLenum location);
void attach(const cubemap &tex, int face, GLenum location);
void attach(const renderbuffer &rb, GLenum location);
void setup_drawing(int attachments);
void detach(GLenum location);
void clear(GLbitfield mask);
bool is_complete();
void blit_to(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment);
void blit_from(framebuffer *other, int w, int h, GLbitfield mask, GLenum attachment);
static void blit(framebuffer *src, framebuffer *dst, int sx, int sy, int w, int h, GLbitfield mask, GLenum attachment);
using bindable::bind;
static void bind(GLuint id);
};
}

72
gl/glsl_common.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "stdafx.h"
#include "glsl_common.h"
std::string gl::glsl_common;
void gl::glsl_common_setup()
{
glsl_common =
"#define SHADOWMAP_ENABLED " + std::to_string((int)Global.gfx_shadowmap_enabled) + "\n" +
"#define ENVMAP_ENABLED " + std::to_string((int)Global.gfx_envmap_enabled) + "\n" +
"#define MOTIONBLUR_ENABLED " + std::to_string((int)Global.gfx_postfx_motionblur_enabled) + "\n" +
"#define POSTFX_ENABLED " + std::to_string((int)!Global.gfx_skippipeline) + "\n" +
"#define EXTRAEFFECTS_ENABLED " + std::to_string((int)Global.gfx_extraeffects) + "\n" +
"#define USE_GLES " + std::to_string((int)Global.gfx_usegles) + "\n" +
"const uint MAX_LIGHTS = " + std::to_string(MAX_LIGHTS) + "U;\n" +
"const uint MAX_PARAMS = " + std::to_string(MAX_PARAMS) + "U;\n" +
R"STRING(
const uint LIGHT_SPOT = 0U;
const uint LIGHT_POINT = 1U;
const uint LIGHT_DIR = 2U;
struct light_s
{
vec3 pos;
uint type;
vec3 dir;
float in_cutoff;
vec3 color;
float out_cutoff;
float linear;
float quadratic;
float intensity;
float ambient;
};
layout(std140) uniform light_ubo
{
vec3 ambient;
vec3 fog_color;
uint lights_count;
light_s lights[MAX_LIGHTS];
};
layout (std140) uniform model_ubo
{
mat4 modelview;
mat3 modelviewnormal;
vec4 param[MAX_PARAMS];
mat4 future;
float opacity;
float emission;
float fog_density;
float alpha_mult;
};
layout (std140) uniform scene_ubo
{
mat4 projection;
mat4 lightview;
vec3 scene_extra;
float time;
};
)STRING";
}

10
gl/glsl_common.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "ubo.h"
#include "Globals.h"
namespace gl
{
extern std::string glsl_common;
void glsl_common_setup();
}

32
gl/object.h Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include <glad/glad.h>
namespace gl
{
class object
{
private:
GLuint id = 0;
public:
inline operator GLuint() const
{
return id;
}
inline operator GLuint* const()
{
return &id;
}
inline operator const GLuint* const() const
{
return &id;
}
object() = default;
object(const object&) = delete;
object& operator=(const object&) = delete;
};
}

65
gl/pbo.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "stdafx.h"
#include "pbo.h"
void gl::pbo::request_read(int x, int y, int lx, int ly, int pixsize, GLenum format, GLenum type)
{
int s = lx * ly * pixsize;
if (s != size)
allocate(PIXEL_PACK_BUFFER, s, GL_STREAM_DRAW);
size = s;
data_ready = false;
sync.reset();
bind(PIXEL_PACK_BUFFER);
glReadPixels(x, y, lx, ly, format, type, 0);
unbind(PIXEL_PACK_BUFFER);
sync.emplace();
}
bool gl::pbo::read_data(int lx, int ly, void *data, int pixsize)
{
is_busy();
if (!data_ready)
return false;
int s = lx * ly * pixsize;
if (s != size)
return false;
download(PIXEL_PACK_BUFFER, data, 0, s);
unbind(PIXEL_PACK_BUFFER);
data_ready = false;
return true;
}
bool gl::pbo::is_busy()
{
if (!sync)
return false;
if (sync->is_signalled())
{
data_ready = true;
sync.reset();
return false;
}
return true;
}
void* gl::pbo::map(GLuint mode, targets target)
{
bind(target);
return glMapBuffer(buffer::glenum_target(target), mode);
}
void gl::pbo::unmap(targets target)
{
bind(target);
glUnmapBuffer(buffer::glenum_target(target));
sync.emplace();
}

22
gl/pbo.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "buffer.h"
#include "fence.h"
#include <optional>
namespace gl {
class pbo : public buffer
{
std::optional<fence> sync;
int size = 0;
bool data_ready;
public:
void request_read(int x, int y, int lx, int ly, int pixsize = 4, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE);
bool read_data(int lx, int ly, void *data, int pixsize = 4);
bool is_busy();
void* map(GLuint mode, targets target = PIXEL_UNPACK_BUFFER);
void unmap(targets target = PIXEL_UNPACK_BUFFER);
};
}

49
gl/postfx.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "stdafx.h"
#include "postfx.h"
std::shared_ptr<gl::shader> gl::postfx::vertex;
std::shared_ptr<gl::vao> gl::postfx::vao;
gl::postfx::postfx(const std::string &s) : postfx(shader("postfx_" + s + ".frag"))
{
}
gl::postfx::postfx(const shader &s)
{
if (!vertex)
vertex = std::make_shared<gl::shader>("quad.vert");
if (!vao)
vao = std::make_shared<gl::vao>();
program.attach(*vertex);
program.attach(s);
program.link();
}
void gl::postfx::apply(opengl_texture &src, framebuffer *dst)
{
apply({&src}, dst);
}
void gl::postfx::apply(std::vector<opengl_texture *> src, framebuffer *dst)
{
if (dst)
{
dst->clear(GL_COLOR_BUFFER_BIT);
dst->bind();
}
else
framebuffer::unbind();
program.bind();
vao->bind();
size_t unit = 0;
for (opengl_texture *tex : src)
tex->bind(unit++);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

25
gl/postfx.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include "shader.h"
#include "vao.h"
#include "framebuffer.h"
#include "Texture.h"
namespace gl
{
class postfx
{
private:
gl::program program;
static std::shared_ptr<gl::shader> vertex;
static std::shared_ptr<gl::vao> vao;
public:
postfx(const std::string &s);
postfx(const shader &s);
void attach();
void apply(opengl_texture &src, framebuffer *dst);
void apply(std::vector<opengl_texture*> src, framebuffer *dst);
};
}

65
gl/query.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "stdafx.h"
#include "query.h"
#include "Globals.h"
gl::query::query(targets target)
: target(target)
{
glGenQueries(1, *this);
}
gl::query::~query()
{
end();
glDeleteQueries(1, *this);
}
void gl::query::begin()
{
if (active_queries[target])
active_queries[target]->end();
glBeginQuery(glenum_target(target), *this);
active_queries[target] = this;
}
void gl::query::end()
{
if (active_queries[target] != this)
return;
glEndQuery(glenum_target(target));
active_queries[target] = nullptr;
}
std::optional<int64_t> gl::query::result()
{
GLuint ready;
glGetQueryObjectuiv(*this, GL_QUERY_RESULT_AVAILABLE, &ready);
int64_t value = 0;
if (ready) {
if (!Global.gfx_usegles)
glGetQueryObjecti64v(*this, GL_QUERY_RESULT, &value);
else
glGetQueryObjectuiv(*this, GL_QUERY_RESULT, reinterpret_cast<GLuint*>(&value));
return std::optional<int64_t>(value);
}
return std::nullopt;
}
GLenum gl::query::glenum_target(targets target)
{
static GLenum mapping[6] =
{
GL_SAMPLES_PASSED,
GL_ANY_SAMPLES_PASSED,
GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
GL_PRIMITIVES_GENERATED,
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
GL_TIME_ELAPSED
};
return mapping[target];
}
thread_local gl::query* gl::query::active_queries[6];

36
gl/query.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#include "object.h"
namespace gl
{
class query : public object
{
public:
enum targets
{
SAMPLES_PASSED = 0,
ANY_SAMPLES_PASSED,
ANY_SAMPLES_PASSED_CONSERVATIVE,
PRIMITIVES_GENERATED,
TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
TIME_ELAPSED
};
private:
targets target;
thread_local static query* active_queries[6];
protected:
GLenum glenum_target(targets target);
public:
query(targets target);
~query();
void begin();
void end();
std::optional<int64_t> result();
};
}

27
gl/renderbuffer.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include "stdafx.h"
#include "renderbuffer.h"
gl::renderbuffer::renderbuffer()
{
glGenRenderbuffers(1, *this);
}
gl::renderbuffer::~renderbuffer()
{
glDeleteRenderbuffers(1, *this);
}
void gl::renderbuffer::bind(GLuint id)
{
glBindRenderbuffer(GL_RENDERBUFFER, id);
}
void gl::renderbuffer::alloc(GLuint format, int width, int height, int samples)
{
bind();
if (samples == 1)
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
else
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
}

19
gl/renderbuffer.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "object.h"
#include "bindable.h"
namespace gl
{
class renderbuffer : public object, public bindable<renderbuffer>
{
public:
renderbuffer();
~renderbuffer();
void alloc(GLuint format, int width, int height, int samples = 1);
static void bind(GLuint id);
using bindable::bind;
};
}

334
gl/shader.cpp Normal file
View File

@@ -0,0 +1,334 @@
#include "stdafx.h"
#include <fstream>
#include <sstream>
#include "shader.h"
#include "glsl_common.h"
#include "Logs.h"
inline bool strcend(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
std::string gl::shader::read_file(const std::string &filename)
{
std::stringstream stream;
std::ifstream f;
f.exceptions(std::ifstream::badbit);
f.open("shaders/" + filename);
stream << f.rdbuf();
f.close();
std::string str = stream.str();
return str;
}
void gl::shader::expand_includes(std::string &str)
{
size_t start_pos = 0;
std::string magic = "#include";
while ((start_pos = str.find(magic, start_pos)) != str.npos)
{
size_t fp = str.find('<', start_pos);
size_t fe = str.find('>', start_pos);
if (fp == str.npos || fe == str.npos)
return;
std::string filename = str.substr(fp + 1, fe - fp - 1);
std::string content;
if (filename != "common")
content = read_file(filename);
else
content = glsl_common;
str.replace(start_pos, fe - start_pos + 1, content);
}
}
std::unordered_map<std::string, gl::shader::components_e> gl::shader::components_mapping =
{
{ "R", components_e::R },
{ "RG", components_e::RG },
{ "RGB", components_e::RGB },
{ "RGBA", components_e::RGBA },
{ "sRGB", components_e::sRGB },
{ "sRGB_A", components_e::sRGB_A }
};
std::unordered_map<std::string, gl::shader::defaultparam_e> gl::shader::defaultparams_mapping =
{
{ "required", defaultparam_e::required },
{ "nan", defaultparam_e::nan },
{ "zero", defaultparam_e::zero },
{ "one", defaultparam_e::one },
{ "ambient", defaultparam_e::ambient },
{ "diffuse", defaultparam_e::diffuse },
{ "specular", defaultparam_e::specular }
};
void gl::shader::process_source(std::string &str)
{
expand_includes(str);
parse_texture_entries(str);
parse_param_entries(str);
}
void gl::shader::parse_texture_entries(std::string &str)
{
size_t start_pos = 0;
std::string magic = "#texture";
while ((start_pos = str.find(magic, start_pos)) != str.npos)
{
size_t fp = str.find('(', start_pos);
size_t fe = str.find(')', start_pos);
if (fp == str.npos || fe == str.npos)
return;
std::istringstream ss(str.substr(fp + 1, fe - fp - 1));
std::string token;
std::string name;
texture_entry conf;
size_t arg = 0;
while (std::getline(ss, token, ','))
{
std::istringstream token_ss(token);
if (arg == 0)
token_ss >> name;
else if (arg == 1)
token_ss >> conf.id;
else if (arg == 2)
{
std::string comp;
token_ss >> comp;
if (components_mapping.find(comp) == components_mapping.end())
log_error("unknown components: " + comp);
else
conf.components = components_mapping[comp];
}
arg++;
}
if (arg == 3)
{
if (name.empty())
log_error("empty name");
else if (conf.id >= gl::MAX_TEXTURES)
log_error("invalid texture binding: " + std::to_string(conf.id));
else
texture_conf.emplace(std::make_pair(name, conf));
}
else
log_error("invalid argument count to #texture");
str.erase(start_pos, fe - start_pos + 1);
}
}
void gl::shader::parse_param_entries(std::string &str)
{
size_t start_pos = 0;
std::string magic = "#param";
while ((start_pos = str.find(magic, start_pos)) != str.npos)
{
size_t fp = str.find('(', start_pos);
size_t fe = str.find(')', start_pos);
if (fp == str.npos || fe == str.npos)
return;
std::istringstream ss(str.substr(fp + 1, fe - fp - 1));
std::string token;
std::string name;
param_entry conf;
size_t arg = 0;
while (std::getline(ss, token, ','))
{
std::istringstream token_ss(token);
if (arg == 0)
token_ss >> name;
else if (arg == 1)
token_ss >> conf.location;
else if (arg == 2)
token_ss >> conf.offset;
else if (arg == 3)
token_ss >> conf.size;
else if (arg == 4)
{
std::string tok;
token_ss >> tok;
if (defaultparams_mapping.find(tok) == defaultparams_mapping.end())
log_error("unknown param default: " + tok);
conf.defaultparam = defaultparams_mapping[tok];
}
arg++;
}
if (arg == 5)
{
if (name.empty())
log_error("empty name");
else if (conf.location >= gl::MAX_PARAMS)
log_error("invalid param binding: " + std::to_string(conf.location));
else if (conf.offset > 3)
log_error("invalid offset: " + std::to_string(conf.offset));
else if (conf.offset + conf.size > 4)
log_error("invalid size: " + std::to_string(conf.size));
else
param_conf.emplace(std::make_pair(name, conf));
}
else
log_error("invalid argument count to #param");
str.erase(start_pos, fe - start_pos + 1);
}
}
void gl::shader::log_error(const std::string &str)
{
ErrorLog("bad shader: " + name + ": " + str, logtype::shader);
}
gl::shader::shader(const std::string &filename)
{
name = filename;
GLuint type;
if (strcend(filename, ".vert"))
type = GL_VERTEX_SHADER;
else if (strcend(filename, ".frag"))
type = GL_FRAGMENT_SHADER;
else if (strcend(filename, ".geom"))
type = GL_GEOMETRY_SHADER;
else
throw shader_exception("unknown shader " + filename);
std::string str;
if (!Global.gfx_usegles)
{
str += "#version 330 core\n";
}
else
{
if (GLAD_GL_ES_VERSION_3_1) {
str += "#version 310 es\n";
if (type == GL_GEOMETRY_SHADER)
str += "#extension GL_EXT_geometry_shader : require\n";
} else {
str += "#version 300 es\n";
}
str += "precision highp float;\n";
str += "precision highp sampler2DShadow;\n";
}
str += "vec4 FBOUT(vec4 x) { return " + (Global.gfx_shadergamma ? std::string("vec4(pow(x.rgb, vec3(1.0 / 2.2)), x.a)") : std::string("x")) + "; }\n";
str += read_file(filename);
process_source(str);
const GLchar *cstr = str.c_str();
if (!cstr[0])
throw shader_exception("cannot read shader: " + filename);
**this = glCreateShader(type);
glShaderSource(*this, 1, &cstr, 0);
glCompileShader(*this);
GLint status;
glGetShaderiv(*this, GL_COMPILE_STATUS, &status);
if (!status)
{
GLchar info[512];
glGetShaderInfoLog(*this, 512, 0, info);
std::cerr << std::string(info) << std::endl;
throw shader_exception("failed to compile " + filename + ": " + std::string(info));
}
}
gl::shader::~shader()
{
glDeleteShader(*this);
}
void gl::program::init()
{
bind();
for (auto it : texture_conf)
{
shader::texture_entry &e = it.second;
GLuint loc = glGetUniformLocation(*this, it.first.c_str());
glUniform1i(loc, e.id);
}
glUniform1i(glGetUniformLocation(*this, "shadowmap"), MAX_TEXTURES + 0);
glUniform1i(glGetUniformLocation(*this, "envmap"), MAX_TEXTURES + 1);
GLuint index;
if ((index = glGetUniformBlockIndex(*this, "scene_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, 0, index);
if ((index = glGetUniformBlockIndex(*this, "model_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, 1, index);
if ((index = glGetUniformBlockIndex(*this, "light_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, 2, index);
}
gl::program::program()
{
**this = glCreateProgram();
}
gl::program::program(std::vector<std::reference_wrapper<const gl::shader>> shaders) : program()
{
for (const gl::shader &s : shaders)
attach(s);
link();
}
void gl::program::attach(const gl::shader &s)
{
for (auto it : s.texture_conf)
texture_conf.emplace(std::make_pair(it.first, std::move(it.second)));
for (auto it : s.param_conf)
param_conf.emplace(std::make_pair(it.first, std::move(it.second)));
glAttachShader(*this, *s);
}
void gl::program::link()
{
glLinkProgram(*this);
GLint status;
glGetProgramiv(*this, GL_LINK_STATUS, &status);
if (!status)
{
GLchar info[512];
glGetProgramInfoLog(*this, 512, 0, info);
throw shader_exception("failed to link program: " + std::string(info));
}
init();
}
gl::program::~program()
{
glDeleteProgram(*this);
}
void gl::program::bind(GLuint i)
{
glUseProgram(i);
}

96
gl/shader.h Normal file
View File

@@ -0,0 +1,96 @@
#pragma once
#include <string>
#include <vector>
#include <functional>
#include "object.h"
#include "bindable.h"
namespace gl
{
class shader_exception : public std::runtime_error
{
using runtime_error::runtime_error;
};
class shader : public object
{
public:
shader(const std::string &filename);
~shader();
enum class components_e
{
R = GL_RED,
RG = GL_RG,
RGB = GL_RGB,
RGBA = GL_RGBA,
sRGB = GL_SRGB,
sRGB_A = GL_SRGB_ALPHA
};
struct texture_entry
{
size_t id;
components_e components;
};
enum class defaultparam_e
{
required,
nan,
zero,
one,
ambient,
diffuse,
specular
};
struct param_entry
{
size_t location;
size_t offset;
size_t size;
defaultparam_e defaultparam;
};
std::unordered_map<std::string, texture_entry> texture_conf;
std::unordered_map<std::string, param_entry> param_conf;
std::string name;
private:
void process_source(std::string &str);
void expand_includes(std::string &str);
void parse_texture_entries(std::string &str);
void parse_param_entries(std::string &str);
std::string read_file(const std::string &filename);
static std::unordered_map<std::string, components_e> components_mapping;
static std::unordered_map<std::string, defaultparam_e> defaultparams_mapping;
void log_error(const std::string &str);
};
class program : public object, public bindable<program>
{
public:
program();
program(std::vector<std::reference_wrapper<const gl::shader>>);
~program();
using bindable::bind;
static void bind(GLuint i);
void attach(const shader &);
void link();
std::unordered_map<std::string, shader::texture_entry> texture_conf;
std::unordered_map<std::string, shader::param_entry> param_conf;
private:
void init();
};
}

19
gl/ubo.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "stdafx.h"
#include "ubo.h"
gl::ubo::ubo(int size, int idx, GLenum hint)
{
allocate(buffer::UNIFORM_BUFFER, size, hint);
index = idx;
bind_uniform();
}
void gl::ubo::bind_uniform()
{
bind_base(buffer::UNIFORM_BUFFER, index);
}
void gl::ubo::update(const uint8_t *data, int offset, int size)
{
upload(buffer::UNIFORM_BUFFER, data, offset, size);
}

113
gl/ubo.h Normal file
View File

@@ -0,0 +1,113 @@
#pragma once
#include "object.h"
#include "bindable.h"
#include "buffer.h"
#define UBS_PAD(x) uint8_t PAD[x]
namespace gl
{
class ubo : public buffer
{
int index;
public:
ubo(int size, int index, GLenum hint = GL_DYNAMIC_DRAW);
void bind_uniform();
void update(const uint8_t *data, int offset, int size);
template <typename T> void update(const T &data, size_t offset = 0)
{
update(reinterpret_cast<const uint8_t*>(&data), offset, sizeof(data));
}
};
// layout std140
// structs must match with GLSL
// ordered to minimize padding
#pragma pack(push, 1)
const size_t MAX_TEXTURES = 8;
const size_t ENVMAP_SIZE = 1024;
struct scene_ubs
{
glm::mat4 projection;
glm::mat4 lightview;
glm::vec3 scene_extra;
float time;
};
static_assert(sizeof(scene_ubs) == 144, "bad size of ubs");
const size_t MAX_PARAMS = 3;
struct model_ubs
{
glm::mat4 modelview;
glm::mat3x4 modelviewnormal;
glm::vec4 param[MAX_PARAMS];
glm::mat4 future;
float opacity;
float emission;
float fog_density;
float alpha_mult;
UBS_PAD(4);
void set_modelview(const glm::mat4 &mv)
{
modelview = mv;
modelviewnormal = glm::mat3x4(glm::mat3(glm::transpose(glm::inverse(mv))));
}
};
static_assert(sizeof(model_ubs) == 196 + 16 * MAX_PARAMS, "bad size of ubs");
struct light_element_ubs
{
enum type_e
{
SPOT = 0,
POINT,
DIR
};
glm::vec3 pos;
type_e type;
glm::vec3 dir;
float in_cutoff;
glm::vec3 color;
float out_cutoff;
float linear;
float quadratic;
float intensity;
float ambient;
};
static_assert(sizeof(light_element_ubs) == 64, "bad size of ubs");
const size_t MAX_LIGHTS = 8;
struct light_ubs
{
glm::vec3 ambient;
UBS_PAD(4);
glm::vec3 fog_color;
uint32_t lights_count;
light_element_ubs lights[MAX_LIGHTS];
};
static_assert(sizeof(light_ubs) == 32 + sizeof(light_element_ubs) * MAX_LIGHTS, "bad size of ubs");
#pragma pack(pop)
}

85
gl/vao.cpp Normal file
View File

@@ -0,0 +1,85 @@
#include "stdafx.h"
#include "vao.h"
bool gl::vao::use_vao = true;
gl::vao::vao()
{
if (!use_vao)
return;
glGenVertexArrays(1, *this);
}
gl::vao::~vao()
{
if (!use_vao)
return;
unbind();
glDeleteVertexArrays(1, *this);
}
void gl::vao::setup_attrib(gl::buffer &buffer, int attrib, int size, int type, int stride, int offset)
{
if (use_vao) {
bind();
buffer.bind(buffer::ARRAY_BUFFER);
glVertexAttribPointer(attrib, size, type, GL_FALSE, stride, reinterpret_cast<void*>(offset));
glEnableVertexAttribArray(attrib);
}
else {
params.push_back({buffer, attrib, size, type, stride, offset});
active = nullptr;
}
}
void gl::vao::setup_ebo(buffer &e)
{
if (use_vao) {
bind();
e.bind(buffer::ELEMENT_ARRAY_BUFFER);
}
else {
ebo = &e;
active = nullptr;
}
}
void gl::vao::bind()
{
if (active == this)
return;
active = this;
if (use_vao) {
glBindVertexArray(*this);
}
else {
for (attrib_params &param : params) {
param.buffer.bind(gl::buffer::ARRAY_BUFFER);
glVertexAttribPointer(param.attrib, param.size, param.type, GL_FALSE, param.stride, reinterpret_cast<void*>(param.offset));
glEnableVertexAttribArray(param.attrib);
}
for (size_t i = params.size(); i < 4; i++)
glDisableVertexAttribArray(i);
if (ebo)
ebo->bind(gl::buffer::ELEMENT_ARRAY_BUFFER);
else
gl::buffer::unbind(gl::buffer::ELEMENT_ARRAY_BUFFER);
}
}
void gl::vao::unbind()
{
active = nullptr;
if (use_vao) {
glBindVertexArray(0);
}
else {
for (size_t i = 0; i < 4; i++)
glDisableVertexAttribArray(i);
}
}

37
gl/vao.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#include "object.h"
#include "bindable.h"
#include "buffer.h"
namespace gl
{
class vao : object, public bindable<vao>
{
struct attrib_params {
// TBD: should be shared_ptr? (when buffer is destroyed by owner VAO could still potentially exist)
gl::buffer &buffer;
int attrib;
int size;
int type;
int stride;
int offset;
};
buffer *ebo = nullptr;
std::vector<attrib_params> params;
public:
vao();
~vao();
void setup_attrib(buffer &buffer, int attrib, int size, int type, int stride, int offset);
void setup_ebo(buffer &ebo);
void bind();
static void unbind();
static bool use_vao;
};
}

View File

@@ -58,14 +58,23 @@
<Filter Include="Header Files\math">
<UniqueIdentifier>{77356e25-abc5-4f1c-9caf-6cf554a65770}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\gfx\gl">
<UniqueIdentifier>{4fcccdfc-d0d4-45a9-9603-b13d8dfe345c}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\gfx">
<UniqueIdentifier>{8b47594a-f06a-4c9b-9aef-70f6ec24a288}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\gfx\gl">
<UniqueIdentifier>{b8dcf22f-cddb-4d1f-a2fa-8c54e5da4a39}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\math">
<UniqueIdentifier>{dd00198e-a316-4bcc-a4d3-916c8dcfe08f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AirCoupler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AnimModel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Button.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -78,9 +87,6 @@
<ClCompile Include="Driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dumb3d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DynObj.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -90,9 +96,6 @@
<ClCompile Include="EvLaunch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Float3d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Gauge.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -102,15 +105,9 @@
<ClCompile Include="Logs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MdlMngr.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MemCell.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Model3d.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mtable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -126,15 +123,9 @@
<ClCompile Include="Segment.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="sky.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Spring.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -174,15 +165,9 @@
<ClCompile Include="sun.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="renderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="skydome.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stars.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="lightarray.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -192,30 +177,18 @@
<ClCompile Include="sn_utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="frustum.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="uilayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="openglmatrixstack.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="moon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="command.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="openglgeometrybank.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="translation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="material.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="scene.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -336,9 +309,6 @@
<ClCompile Include="precipitation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="openglcolor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ref\imgui\examples\imgui_impl_opengl2.cpp">
<Filter>Source Files\imgui</Filter>
</ClCompile>
@@ -351,23 +321,119 @@
<ClCompile Include="particles.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gl\buffer.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\cubemap.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\fence.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\framebuffer.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\glsl_common.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\pbo.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\postfx.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\query.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\renderbuffer.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\shader.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\ubo.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="gl\vao.cpp">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="dumb3d.cpp">
<Filter>Source Files\math</Filter>
</ClCompile>
<ClCompile Include="Float3d.cpp">
<Filter>Source Files\math</Filter>
</ClCompile>
<ClCompile Include="frustum.cpp">
<Filter>Source Files\math</Filter>
</ClCompile>
<ClCompile Include="AnimModel.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="geometrybank.cpp">
<Filter>Source Files</Filter>
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglrenderer.cpp">
<Filter>Source Files</Filter>
<ClCompile Include="material.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="opengllight.cpp">
<Filter>Source Files</Filter>
<ClCompile Include="Model3d.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="MdlMngr.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglcamera.cpp">
<Filter>Source Files</Filter>
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglcolor.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglgeometrybank.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="opengllight.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglmatrixstack.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglparticles.cpp">
<Filter>Source Files</Filter>
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglrenderer.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglskydome.cpp">
<Filter>Source Files</Filter>
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="renderer.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="sky.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="stars.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="Texture.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="ref\glad\src\glad.c">
<Filter>Source Files\gfx\gl</Filter>
</ClCompile>
<ClCompile Include="opengl33renderer.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="opengl33particles.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="opengl33light.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="openglprecipitation.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
<ClCompile Include="opengl33precipitation.cpp">
<Filter>Source Files\gfx</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@@ -638,9 +704,6 @@
<ClInclude Include="stars.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="precipitation.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="AnimModel.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
@@ -677,6 +740,66 @@
<ClInclude Include="skydome.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gl\bindable.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\buffer.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\cubemap.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\fence.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\framebuffer.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\glsl_common.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\object.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\pbo.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\postfx.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\query.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\renderbuffer.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\shader.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\ubo.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="gl\vao.h">
<Filter>Header Files\gfx\gl</Filter>
</ClInclude>
<ClInclude Include="opengl33renderer.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="opengl33particles.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="opengl33light.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="precipitation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="openglprecipitation.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
<ClInclude Include="opengl33precipitation.h">
<Filter>Header Files\gfx</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="maszyna.rc">

View File

@@ -15,28 +15,172 @@ http://mozilla.org/MPL/2.0/.
#include "utilities.h"
#include "sn_utils.h"
#include "Globals.h"
#include "Logs.h"
opengl_material::opengl_material()
{
for (size_t i = 0; i < params.size(); i++)
params[i] = glm::vec4(std::numeric_limits<float>::quiet_NaN());
}
bool
opengl_material::deserialize( cParser &Input, bool const Loadnow ) {
parse_info = std::make_unique<parse_info_s>();
bool result { false };
while( true == deserialize_mapping( Input, 0, Loadnow ) ) {
result = true; // once would suffice but, eh
}
has_alpha = (
texture1 != null_handle ?
GfxRenderer->Texture( texture1 ).has_alpha :
false );
return result;
}
void opengl_material::log_error(const std::string &str)
{
ErrorLog("bad material: " + name + ": " + str, logtype::material);
}
std::map<std::string, int> texture_bindings {
{ "diffuse", 0 },
{ "normal", 1 }
};
void opengl_material::finalize(bool Loadnow)
{
if (parse_info)
{
for (auto it : parse_info->tex_mapping)
{
std::string key = it.first;
std::string value = it.second.name;
if (key.size() > 0 && key[0] != '_')
{
size_t num = std::stoi(key) - 1;
if (num < gl::MAX_TEXTURES)
textures[num] = GfxRenderer->Fetch_Texture(value, Loadnow);
else
log_error("invalid texture binding: " + std::to_string(num));
}
else if (key.size() > 2)
{
key.erase(0, 1);
key.pop_back();
std::map<std::string, int>::iterator lookup;
if( shader && shader->texture_conf.find( key ) != shader->texture_conf.end() ) {
textures[ shader->texture_conf[ key ].id ] = GfxRenderer->Fetch_Texture( value, Loadnow );
}
else if( ( shader == nullptr )
&& ( lookup = texture_bindings.find( key ) ) != texture_bindings.end() ) {
textures[ lookup->second ] = GfxRenderer->Fetch_Texture( value, Loadnow );
}
else {
log_error( "unknown texture binding: " + key );
}
}
else
log_error("unrecognized texture binding: " + key);
}
if (!shader)
{
if (textures[0] == null_handle)
{
log_error("shader not specified, assuming \"default_0\"");
shader = GfxRenderer->Fetch_Shader("default_0");
}
else if (textures[1] == null_handle)
{
log_error("shader not specified, assuming \"default_1\"");
shader = GfxRenderer->Fetch_Shader("default_1");
}
else if (textures[2] == null_handle)
{
log_error("shader not specified, assuming \"default_2\"");
shader = GfxRenderer->Fetch_Shader("default_2");
}
}
if (!shader)
return;
for (auto it : parse_info->param_mapping)
{
std::string key = it.first;
glm::vec4 value = it.second.data;
if (key.size() > 1 && key[0] != '_')
{
size_t num = std::stoi(key) - 1;
if (num < gl::MAX_PARAMS)
params[num] = value;
else
log_error("invalid param binding: " + std::to_string(num));
}
else if (key.size() > 2)
{
key.erase(0, 1);
key.pop_back();
if (shader->param_conf.find(key) != shader->param_conf.end())
{
gl::shader::param_entry entry = shader->param_conf[key];
for (size_t i = 0; i < entry.size; i++)
params[entry.location][entry.offset + i] = value[i];
}
else
log_error("unknown param binding: " + key);
}
else
log_error("unrecognized param binding: " + key);
}
parse_info.reset();
}
if (!shader)
return;
for (auto it : shader->param_conf)
{
gl::shader::param_entry entry = it.second;
if (std::isnan(params[entry.location][entry.offset]))
{
float value = std::numeric_limits<float>::quiet_NaN();
if (entry.defaultparam == gl::shader::defaultparam_e::one)
value = 1.0f;
else if (entry.defaultparam == gl::shader::defaultparam_e::zero)
value = 0.0f;
else if (entry.defaultparam == gl::shader::defaultparam_e::required)
log_error("unspecified required param: " + it.first);
else if (entry.defaultparam != gl::shader::defaultparam_e::nan)
{
params_state.push_back(entry);
continue;
}
for (size_t i = 0; i < entry.size; i++)
params[entry.location][entry.offset + i] = value;
}
}
for (auto it : shader->texture_conf)
{
gl::shader::texture_entry &entry = it.second;
texture_handle handle = textures[entry.id];
if (handle)
GfxRenderer->Texture(handle).set_components_hint((GLint)entry.components);
else
log_error("missing texture: " + it.first);
}
}
// imports member data pair from the config file
bool
opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow ) {
// NOTE: comma can be part of legacy file names, so we don't treat it as a separator here
std::string const key { Input.getToken<std::string>( true, "\n\r\t ;[]" ) };
auto key { Input.getToken<std::string>( true, "\n\r\t ;[]" ) };
// key can be an actual key or block end
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
@@ -59,24 +203,69 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
; // all work is done in the header
}
}
else if( ( key == "texture1:" )
|| ( key == "texture_diffuse:" ) ) {
auto const value { deserialize_random_set( Input ) };
if( ( texture1 == null_handle )
|| ( Priority > priority1 ) ) {
texture1 = GfxRenderer->Fetch_Texture( value, Loadnow );
priority1 = Priority;
else if (key.compare(0, 7, "texture") == 0) {
key.erase(0, 7);
auto value { deserialize_random_set( Input ) };
replace_slashes( value );
auto it = parse_info->tex_mapping.find(key);
if (it == parse_info->tex_mapping.end())
parse_info->tex_mapping.emplace(std::make_pair(key, parse_info_s::tex_def({ value, Priority })));
else if (Priority > it->second.priority)
{
parse_info->tex_mapping.erase(it);
parse_info->tex_mapping.emplace(std::make_pair(key, parse_info_s::tex_def({ value, Priority })));
}
}
else if( ( key == "texture2:" )
|| ( key == "texture_normalmap:" ) ) {
auto const value { deserialize_random_set( Input ) };
if( ( texture2 == null_handle )
|| ( Priority > priority2 ) ) {
texture2 = GfxRenderer->Fetch_Texture( value, Loadnow );
priority2 = Priority;
else if (key.compare(0, 5, "param") == 0) {
key.erase(0, 5);
std::string value = Input.getToken<std::string>( true, "\n\r\t;" );
std::istringstream stream(value);
glm::vec4 data;
stream >> data.r;
stream >> data.g;
stream >> data.b;
stream >> data.a;
auto it = parse_info->param_mapping.find(key);
if (it == parse_info->param_mapping.end())
parse_info->param_mapping.emplace(std::make_pair(key, parse_info_s::param_def({ data, Priority })));
else if (Priority > it->second.priority)
{
parse_info->param_mapping.erase(it);
parse_info->param_mapping.emplace(std::make_pair(key, parse_info_s::param_def({ data, Priority })));
}
}
else if (key == "shader:" &&
(!shader || Priority > m_shader_priority))
{
try
{
std::string value = deserialize_random_set( Input );
shader = GfxRenderer->Fetch_Shader(value);
m_shader_priority = Priority;
}
catch (gl::shader_exception const &e)
{
log_error("invalid shader: " + std::string(e.what()));
}
}
else if (key == "opacity:" &&
Priority > m_opacity_priority)
{
std::string value = deserialize_random_set( Input );
opacity = std::stof(value); //m7t: handle exception
m_opacity_priority = Priority;
}
else if (key == "selfillum:" &&
Priority > m_selfillum_priority)
{
std::string value = deserialize_random_set( Input );
selfillum = std::stof(value); //m7t: handle exception
m_selfillum_priority = Priority;
}
else if( key == "size:" ) {
Input.getTokens( 2 );
Input
@@ -109,6 +298,22 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
}
float opengl_material::get_or_guess_opacity() const {
if (!std::isnan(opacity))
return opacity;
if (textures[0] != null_handle)
{
auto const &tex = GfxRenderer->Texture(textures[0]);
if (tex.has_alpha)
return 0.0f;
else
return 0.5f;
}
return 0.0f;
}
// create material object from data stored in specified file.
// NOTE: the deferred load parameter is passed to textures defined by material, the material itself is always loaded immediately
@@ -169,19 +374,35 @@ material_manager::create( std::string const &Filename, bool const Loadnow ) {
// if there's no .mat file, this can be either autogenerated texture,
// or legacy method of referring just to diffuse texture directly.
// wrap basic material around it in either case
material.texture1 = GfxRenderer->Fetch_Texture( Filename, Loadnow );
if( material.texture1 != null_handle ) {
// use texture path and name to tell the newly created materials apart
material.name = GfxRenderer->Texture( material.texture1 ).name;
material.has_alpha = GfxRenderer->Texture( material.texture1 ).has_alpha;
material.textures[0] = GfxRenderer->Fetch_Texture( Filename, Loadnow );
if( material.textures[0] != null_handle )
{
// use texture path and name to tell the newly created materials apart
material.name = GfxRenderer->Texture( material.textures[0] ).name;
// material would attach default shader anyway, but it would spit to error log
try
{
material.shader = GfxRenderer->Fetch_Shader("default_1");
}
catch (gl::shader_exception const &e)
{
ErrorLog("invalid shader: " + std::string(e.what()));
}
}
}
if( false == material.name.empty() ) {
// if we have material name it means resource was processed succesfully
materialhandle = m_materials.size();
m_materials.emplace_back( material );
m_materialmappings.emplace( material.name, materialhandle );
if( false == material.name.empty() ) {
// if we have material name and shader it means resource was processed succesfully
try {
material.finalize(Loadnow);
materialhandle = m_materials.size();
m_materialmappings.emplace( material.name, materialhandle );
m_materials.emplace_back( std::move(material) );
} catch (gl::shader_exception const &e) {
ErrorLog("invalid shader: " + std::string(e.what()));
m_materialmappings.emplace( filename, materialhandle );
}
}
else {
// otherwise record our failure to process the resource, to speed up subsequent attempts
@@ -222,4 +443,4 @@ material_manager::find_on_disk( std::string const &Materialname ) const {
{ ".mat" } ) );
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

View File

@@ -11,40 +11,69 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h"
#include "Texture.h"
#include "gl/shader.h"
#include "gl/ubo.h"
typedef int material_handle;
// a collection of parameters for the rendering setup.
// for modern opengl this translates to set of attributes for the active shaders,
// for legacy opengl this is basically just texture(s) assigned to geometry
// for modern opengl this translates to set of attributes for shaders
struct opengl_material {
std::array<texture_handle, gl::MAX_TEXTURES> textures = { null_handle };
std::array<glm::vec4, gl::MAX_PARAMS> params;
std::vector<gl::shader::param_entry> params_state;
texture_handle texture1 { null_handle }; // primary texture, typically diffuse+apha
texture_handle texture2 { null_handle }; // secondary texture, typically normal+reflection
std::shared_ptr<gl::program> shader;
float opacity = std::numeric_limits<float>::quiet_NaN();
float selfillum = std::numeric_limits<float>::quiet_NaN();
bool has_alpha { false }; // alpha state, calculated from presence of alpha in texture1
std::string name;
glm::vec2 size { -1.f, -1.f }; // 'physical' size of bound texture, in meters
// constructors
opengl_material() = default;
opengl_material();
// methods
bool
deserialize( cParser &Input, bool const Loadnow );
void finalize(bool Loadnow);
float get_or_guess_opacity() const;
inline bool
is_translucent() const {
return ( get_or_guess_opacity() == 0.0f ); }
private:
// methods
// imports member data pair from the config file, overriding existing parameter values of lower priority
// imports member data pair from the config file
bool
deserialize_mapping( cParser &Input, int const Priority, bool const Loadnow );
void log_error(const std::string &str);
// extracts name of the sound file from provided data stream
std::string
deserialize_filename( cParser &Input );
// members
int priority1 { -1 }; // priority of last loaded primary texture
int priority2 { -1 }; // priority of last loaded secondary texture
// priorities for textures, shader, opacity
int m_shader_priority = -1;
int m_opacity_priority = -1;
int m_selfillum_priority = -1;
struct parse_info_s
{
struct tex_def
{
std::string name;
int priority;
};
struct param_def
{
glm::vec4 data;
int priority;
};
std::unordered_map<std::string, tex_def> tex_mapping;
std::unordered_map<std::string, param_def> param_mapping;
};
std::unique_ptr<parse_info_s> parse_info;
};
class material_manager {
@@ -56,6 +85,8 @@ public:
create( std::string const &Filename, bool const Loadnow );
opengl_material const &
material( material_handle const Material ) const { return m_materials[ Material ]; }
opengl_material &
material( material_handle const Material ) { return m_materials[ Material ]; }
private:
// types
@@ -71,7 +102,6 @@ private:
// members:
material_sequence m_materials;
index_map m_materialmappings;
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

2
moon.h
View File

@@ -1,8 +1,6 @@
#pragma once
#include "windows.h"
#include "GL/glew.h"
#include "GL/wglew.h"
// TODO: sun and moon share code as celestial bodies, we could make a base class out of it

22
opengl33light.cpp Normal file
View File

@@ -0,0 +1,22 @@
/*
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 "opengl33light.h"
void opengl33_light::apply_intensity(float const Factor) {
factor = Factor;
}
void opengl33_light::apply_angle() {}
//---------------------------------------------------------------------------

28
opengl33light.h Normal file
View File

@@ -0,0 +1,28 @@
/*
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 "light.h"
struct opengl33_light : public basic_light {
GLuint id{(GLuint)-1};
float factor;
void apply_intensity(float const Factor = 1.0f);
void apply_angle();
opengl33_light &operator=(basic_light const &Right) {
basic_light::operator=(Right);
return *this; }
};
//---------------------------------------------------------------------------

138
opengl33particles.cpp Normal file
View File

@@ -0,0 +1,138 @@
/*
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 "opengl33particles.h"
#include "particles.h"
#include "openglcamera.h"
#include "simulation.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, 0.f } },
{ { 0.5f, 0.5f, 0.f }, { 1.f, 1.f } },
{ { -0.5f, 0.5f, 0.f }, { 0.f, 1.f } },
};
void
opengl33_particles::update( opengl_camera const &Camera ) {
if (!Global.Smoke)
return;
m_particlevertices.clear();
// 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 &source : sources ) {
auto const particlecolor {
glm::clamp(
source.second.color()
* ( glm::vec3 { Global.DayLight.ambient } + 0.35f * glm::vec3{ Global.DayLight.diffuse } ),
glm::vec3{ 0.f }, glm::vec3{ 1.f } ) };
auto const &particles { source.second.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(
sizestep * std::ceil( m_particlevertices.size() + ( particles.size() * billboard_vertices.size() ) / sizestep ) );
for( auto const &particle : particles ) {
// TODO: particle color support
vertex.color[ 0 ] = particlecolor.r;
vertex.color[ 1 ] = particlecolor.g;
vertex.color[ 2 ] = particlecolor.b;
vertex.color.a = std::clamp(particle.opacity, 0.0f, 1.0f);
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 &billboardvertex : billboard_vertices ) {
vertex.position = offset + ( rotation * billboardvertex.first * particle.size ) * camerarotation;
vertex.texture = billboardvertex.second;
m_particlevertices.emplace_back( vertex );
}
}
}
// ship the billboard data to the gpu:
// make sure we have enough room...
if( m_buffercapacity < m_particlevertices.size() ) {
m_buffercapacity = m_particlevertices.size();
if (!m_buffer)
m_buffer.emplace();
m_buffer->allocate(gl::buffer::ARRAY_BUFFER,
m_buffercapacity * sizeof(particle_vertex), GL_STREAM_DRAW);
}
if (m_buffer) {
// ...send the data...
m_buffer->upload(gl::buffer::ARRAY_BUFFER,
m_particlevertices.data(), 0, m_particlevertices.size() * sizeof(particle_vertex));
}
}
void
opengl33_particles::render() {
if (!Global.Smoke)
return;
if( m_buffercapacity == 0 ) { return; }
if( m_particlevertices.empty() ) { return; }
if (!m_vao) {
m_vao.emplace();
m_vao->setup_attrib(*m_buffer, 0, 3, GL_FLOAT, sizeof(particle_vertex), 0);
m_vao->setup_attrib(*m_buffer, 1, 4, GL_FLOAT, sizeof(particle_vertex), 12);
m_vao->setup_attrib(*m_buffer, 2, 2, GL_FLOAT, sizeof(particle_vertex), 28);
m_buffer->unbind(gl::buffer::ARRAY_BUFFER);
m_vao->unbind();
}
if (!m_shader) {
gl::shader vert("smoke.vert");
gl::shader frag("smoke.frag");
gl::program *prog = new gl::program({vert, frag});
m_shader = std::unique_ptr<gl::program>(prog);
}
m_buffer->bind(gl::buffer::ARRAY_BUFFER);
m_shader->bind();
m_vao->bind();
glDrawArrays(GL_TRIANGLES, 0, m_particlevertices.size());
m_shader->unbind();
m_vao->unbind();
m_buffer->unbind(gl::buffer::ARRAY_BUFFER);
}
//---------------------------------------------------------------------------

54
opengl33particles.h Normal file
View File

@@ -0,0 +1,54 @@
/*
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 "gl/buffer.h"
#include "gl/vao.h"
#include "gl/shader.h"
class opengl_camera;
// particle data visualizer
class opengl33_particles {
public:
// constructors
opengl33_particles() = default;
// methods
void
update( opengl_camera const &Camera );
void
render( );
private:
// types
struct particle_vertex {
glm::vec3 position; // 3d space
glm::vec4 color; // rgba, unsigned byte format
glm::vec2 texture; // uv space
};
/*
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
std::optional<gl::buffer> m_buffer;
std::optional<gl::vao> m_vao;
std::unique_ptr<gl::program> m_shader;
std::size_t m_buffercapacity{ 0 }; // total capacity of the last established buffer
};
//---------------------------------------------------------------------------

159
opengl33precipitation.cpp Normal file
View File

@@ -0,0 +1,159 @@
/*
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 "opengl33precipitation.h"
#include "Globals.h"
#include "renderer.h"
#include "simulationenvironment.h"
opengl33_precipitation::~opengl33_precipitation() {
// TODO: release allocated resources
}
void
opengl33_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<float> 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
opengl33_precipitation::update() {
if (!m_shader)
{
gl::shader vert("precipitation.vert");
gl::shader frag("precipitation.frag");
m_shader.emplace(std::vector<std::reference_wrapper<const gl::shader>>({vert, frag}));
}
if (!m_vertexbuffer) {
m_vao.emplace();
m_vao->bind();
if( m_vertices.empty() ) {
// create visualization mesh
create( 18 );
}
// build the buffers
m_vertexbuffer.emplace();
m_vertexbuffer->allocate(gl::buffer::ARRAY_BUFFER, m_vertices.size() * sizeof( glm::vec3 ), GL_STATIC_DRAW);
m_vertexbuffer->upload(gl::buffer::ARRAY_BUFFER, m_vertices.data(), 0, m_vertices.size() * sizeof( glm::vec3 ));
m_vao->setup_attrib(*m_vertexbuffer, 0, 3, GL_FLOAT, sizeof(glm::vec3), 0);
m_uvbuffer.emplace();
m_uvbuffer->allocate(gl::buffer::ARRAY_BUFFER, m_uvs.size() * sizeof( glm::vec2 ), GL_STATIC_DRAW);
m_uvbuffer->upload(gl::buffer::ARRAY_BUFFER, m_uvs.data(), 0, m_uvs.size() * sizeof( glm::vec2 ));
m_vao->setup_attrib(*m_uvbuffer, 1, 2, GL_FLOAT, sizeof(glm::vec2), 0);
m_indexbuffer.emplace();
m_indexbuffer->allocate(gl::buffer::ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof( unsigned short ), GL_STATIC_DRAW);
m_indexbuffer->upload(gl::buffer::ELEMENT_ARRAY_BUFFER, m_indices.data(), 0, m_indices.size() * sizeof( unsigned short ));
m_vao->setup_ebo(*m_indexbuffer);
m_vao->unbind();
// NOTE: vertex and index source data is superfluous past this point, but, eh
}
// 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
opengl33_precipitation::render() {
if( !m_shader ) { return; }
if( !m_vao ) { return; }
GfxRenderer->Bind_Texture( 0, m_texture );
m_shader->bind();
m_vao->bind();
::glDrawElements( GL_TRIANGLES, static_cast<GLsizei>( m_indices.size() ), GL_UNSIGNED_SHORT, reinterpret_cast<void const*>( 0 ) );
m_vao->unbind();
}

43
opengl33precipitation.h Normal file
View File

@@ -0,0 +1,43 @@
/*
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 "Texture.h"
#include "gl/vao.h"
#include "gl/shader.h"
class opengl33_precipitation {
public:
// constructors
opengl33_precipitation() = default;
// destructor
~opengl33_precipitation();
// methods
void
update();
void
render();
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;
texture_handle m_texture { -1 };
float m_overcast { -1.f }; // cached overcast level, difference from current state triggers texture update
std::optional<gl::buffer> m_vertexbuffer;
std::optional<gl::buffer> m_uvbuffer;
std::optional<gl::buffer> m_indexbuffer;
std::optional<gl::program> m_shader;
std::optional<gl::vao> m_vao;
};

3904
opengl33renderer.cpp Normal file

File diff suppressed because it is too large Load Diff

377
opengl33renderer.h Normal file
View File

@@ -0,0 +1,377 @@
/*
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 "renderer.h"
#include "openglcamera.h"
#include "opengl33light.h"
#include "opengl33particles.h"
#include "openglskydome.h"
#include "opengl33precipitation.h"
#include "simulationenvironment.h"
#include "scene.h"
#include "MemCell.h"
#include "lightarray.h"
#include "gl/ubo.h"
#include "gl/framebuffer.h"
#include "gl/renderbuffer.h"
#include "gl/postfx.h"
#include "gl/shader.h"
#include "gl/cubemap.h"
#include "gl/glsl_common.h"
#include "gl/pbo.h"
#include "gl/query.h"
// bare-bones render controller, in lack of anything better yet
class opengl33_renderer : public gfx_renderer {
public:
// types
/// Renderer runtime settings
struct Settings
{
bool traction_debug { false };
} settings;
// methods
bool Init(GLFWwindow *Window);
/*
bool AddViewport(const global_settings::extraviewport_config &conf);
*/
// main draw call. returns false on error
bool Render();
void SwapBuffers();
inline float Framerate()
{
return m_framerate;
}
// 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();
// creates a new geometry chunk of specified type from supplied vertex data, in specified bank. returns: handle to the chunk or NULL
gfx::geometry_handle Insert(gfx::vertex_array &Vertices, gfx::geometrybank_handle const &Geometry, int const Type);
// replaces data of specified chunk with the supplied vertex data, starting from specified offset
bool Replace(gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type, std::size_t const Offset = 0);
// adds supplied vertex data at the end of specified chunk
bool Append(gfx::vertex_array &Vertices, gfx::geometry_handle const &Geometry, int const Type);
// draws supplied geometry handles
void Draw_Geometry(std::vector<gfx::geometrybank_handle>::iterator begin, std::vector<gfx::geometrybank_handle>::iterator end);
void Draw_Geometry(const gfx::geometrybank_handle &handle);
// provides direct access to vertex data of specfied chunk
gfx::vertex_array const &Vertices(gfx::geometry_handle const &Geometry) const;
// material methods
material_handle Fetch_Material(std::string const &Filename, bool const Loadnow = true);
void Bind_Material(material_handle const Material, TSubModel *sm = nullptr);
void Bind_Material_Shadow(material_handle const Material);
// shader methods
std::shared_ptr<gl::program> Fetch_Shader( std::string const &name ) override;
opengl_material const &Material(material_handle const Material) const;
opengl_material &Material(material_handle const Material);
// 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;
opengl_texture &
Texture( texture_handle const Texture ) override;
opengl_texture const &
Texture( texture_handle const Texture ) const override;
// utility methods
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; }
void Update_AnimModel(TAnimModel *model);
// maintenance methods
void Update(double const Deltatime);
void Update_Pick_Control();
void Update_Pick_Node();
glm::dvec3 get_mouse_depth();
// debug methods
std::string const &info_times() const;
std::string const &info_stats() const;
void pick_control(std::function<void(TSubModel const *)> callback);
void pick_node(std::function<void(scene::basic_node *)> callback);
// members
GLenum static const sunlight{0};
std::size_t m_drawcount{0};
bool debug_ui_active = false;
private:
// types
enum class rendermode
{
none,
color,
shadows,
cabshadows,
reflections,
pickcontrols,
pickscenery
};
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 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 pass_camera;
opengl_camera viewport_camera;
rendermode draw_mode{rendermode::none};
float draw_range{0.0f};
};
struct viewport_config {
int width;
int height;
float draw_range;
bool main = false;
GLFWwindow *window = nullptr;
glm::mat4 camera_transform;
std::unique_ptr<gl::framebuffer> msaa_fb;
std::unique_ptr<gl::renderbuffer> msaa_rbc;
std::unique_ptr<gl::renderbuffer> msaa_rbv;
std::unique_ptr<gl::renderbuffer> msaa_rbd;
std::unique_ptr<gl::framebuffer> main_fb;
std::unique_ptr<opengl_texture> main_texv;
std::unique_ptr<opengl_texture> main_tex;
std::unique_ptr<gl::framebuffer> main2_fb;
std::unique_ptr<opengl_texture> main2_tex;
};
viewport_config *m_current_viewport = nullptr;
typedef std::vector<opengl33_light> opengllight_array;
// methods
std::unique_ptr<gl::program> make_shader(std::string v, std::string f);
bool Init_caps();
void setup_pass(viewport_config &Viewport, 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_shadow_map(opengl_texture *tex, renderpass_config conf);
void setup_env_map(gl::cubemap *tex);
void setup_environment_light(TEnvironmentType const Environment = e_flat);
// runs jobs needed to generate graphics for specified render pass
void Render_pass(viewport_config &vp, rendermode const Mode);
// creates dynamic environment cubemap
bool Render_reflections(viewport_config &vp);
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, Math3D::vector3 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);
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, Math3D::vector3 const &Position, glm::vec3 const &Angle);
bool Render_Alpha(TModel3d *Model, material_data const *Material, float const Squaredistance);
void Render_Alpha(TSubModel *Submodel);
void Update_Lights(light_array &Lights);
glm::vec3 pick_color(std::size_t const Index);
std::size_t pick_index(glm::ivec3 const &Color);
bool init_viewport(viewport_config &vp);
void draw(const gfx::geometry_handle &handle);
void draw(std::vector<gfx::geometrybank_handle>::iterator begin, std::vector<gfx::geometrybank_handle>::iterator end);
void draw_debug_ui();
// members
GLFWwindow *m_window{nullptr}; // main window
gfx::geometrybank_manager m_geometry;
material_manager m_materials;
texture_manager m_textures;
opengl33_light m_sunlight;
opengllight_array m_lights;
/*
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_smoketexture{-1};
// main shadowmap resources
int m_shadowbuffersize{2048};
glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space
glm::mat4 m_cabshadowtexturematrix; // conversion from cab-centric world space to light-centric clip space
int m_environmentcubetextureface{0}; // helper, currently processed cube map face
double m_environmentupdatetime{0}; // time of the most recent environment map update
glm::dvec3 m_environmentupdatelocation; // coordinates of most recent environment map update
opengl_skydome m_skydomerenderer;
opengl33_precipitation m_precipitationrenderer;
opengl33_particles m_particlerenderer; // particle visualization subsystem
unsigned int m_framestamp; // id of currently rendered gfx frame
float m_framerate;
double m_updateaccumulator{0.0};
std::string m_debugtimestext;
std::string m_pickdebuginfo;
debug_stats m_debugstats;
std::string m_debugstatstext;
glm::vec4 m_baseambient{0.0f, 0.0f, 0.0f, 1.0f};
glm::vec4 m_shadowcolor{colors::shadow};
// TEnvironmentType m_environment { e_flat };
float m_specularopaquescalefactor{1.f};
float m_speculartranslucentscalefactor{1.f};
float m_fogrange = 2000.0f;
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 const *> m_pickcontrolsitems;
TSubModel const *m_pickcontrolitem{nullptr};
std::vector<scene::basic_node *> m_picksceneryitems;
scene::basic_node *m_picksceneryitem{nullptr};
glm::vec3 m_worldmousecoordinates { 0.f };
#ifdef EU07_USE_DEBUG_CAMERA
renderpass_config m_worldcamera; // debug item
#endif
std::optional<gl::query> m_timequery;
GLuint64 m_gllasttime = 0;
double m_precipitationrotation;
glm::mat4 perspective_projection(float fov, float aspect, float z_near, float z_far);
glm::mat4 perpsective_frustumtest_projection(float fov, float aspect, float z_near, float z_far);
glm::mat4 ortho_projection(float left, float right, float bottom, float top, float z_near, float z_far);
glm::mat4 ortho_frustumtest_projection(float left, float right, float bottom, float top, float z_near, float z_far);
std::vector<std::function<void(TSubModel const *)>> m_control_pick_requests;
std::vector<std::function<void(scene::basic_node *)>> m_node_pick_requests;
std::unique_ptr<gl::shader> m_vertex_shader;
std::unique_ptr<gl::ubo> scene_ubo;
std::unique_ptr<gl::ubo> model_ubo;
std::unique_ptr<gl::ubo> light_ubo;
gl::scene_ubs scene_ubs;
gl::model_ubs model_ubs;
gl::light_ubs light_ubs;
std::unordered_map<std::string, std::shared_ptr<gl::program>> m_shaders;
std::unique_ptr<gl::program> m_line_shader;
std::unique_ptr<gl::program> m_freespot_shader;
std::unique_ptr<gl::program> m_billboard_shader;
std::unique_ptr<gl::program> m_celestial_shader;
std::unique_ptr<gl::vao> m_empty_vao;
std::vector<std::unique_ptr<viewport_config>> m_viewports;
std::unique_ptr<gl::postfx> m_pfx_motionblur;
std::unique_ptr<gl::postfx> m_pfx_tonemapping;
std::unique_ptr<gl::program> m_shadow_shader;
std::unique_ptr<gl::program> m_alpha_shadow_shader;
std::unique_ptr<gl::framebuffer> m_pick_fb;
std::unique_ptr<opengl_texture> m_pick_tex;
std::unique_ptr<gl::renderbuffer> m_pick_rb;
std::unique_ptr<gl::program> m_pick_shader;
std::unique_ptr<gl::cubemap> m_empty_cubemap;
std::unique_ptr<gl::framebuffer> m_cabshadows_fb;
std::unique_ptr<opengl_texture> m_cabshadows_tex;
std::unique_ptr<gl::framebuffer> m_env_fb;
std::unique_ptr<gl::renderbuffer> m_env_rb;
std::unique_ptr<gl::cubemap> m_env_tex;
std::unique_ptr<gl::framebuffer> m_shadow_fb;
std::unique_ptr<opengl_texture> m_shadow_tex;
std::unique_ptr<gl::pbo> m_picking_pbo;
std::unique_ptr<gl::pbo> m_picking_node_pbo;
std::unique_ptr<gl::pbo> m_depth_pointer_pbo;
std::unique_ptr<gl::framebuffer> m_depth_pointer_fb;
std::unique_ptr<gl::framebuffer> m_depth_pointer_fb2;
std::unique_ptr<gl::renderbuffer> m_depth_pointer_rb;
std::unique_ptr<opengl_texture> m_depth_pointer_tex;
std::unique_ptr<gl::program> m_depth_pointer_shader;
material_handle m_invalid_material;
bool m_blendingenabled;
bool m_widelines_supported;
struct headlight_config_s
{
float in_cutoff = 1.005f;
float out_cutoff = 0.993f;
float falloff_linear = 0.069f;
float falloff_quadratic = 0.03f;
float intensity = 1.0f;
float ambient = 0.184f;
};
headlight_config_s headlight_config;
};
//---------------------------------------------------------------------------

View File

@@ -9,7 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "GL/glew.h"
#include "frustum.h"
#include "scene.h"
@@ -23,6 +22,10 @@ public:
inline
void
update_frustum() { update_frustum( m_projection, m_modelview ); }
inline
void
update_frustum(glm::mat4 frustumtest_proj) {
update_frustum(frustumtest_proj, m_modelview); }
void
update_frustum( glm::mat4 const &Projection, glm::mat4 const &Modelview );
bool

View File

@@ -162,14 +162,14 @@ opengl_vbogeometrybank::bind_streams( gfx::stream_units const &Units, unsigned i
}
// 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 *>( sizeof( float ) * 3 ) );
::glNormalPointer( GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( 12 ) );
::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 *>( sizeof( float ) * 3 ) );
::glColorPointer( 3, GL_FLOAT, sizeof( gfx::basic_vertex ), reinterpret_cast<void const *>( 12 ) );
::glEnableClientState( GL_COLOR_ARRAY );
}
else {

View File

@@ -9,7 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "GL/glew.h"
#include "light.h"
struct opengl_light : public basic_light {

View File

@@ -14,10 +14,6 @@ http://mozilla.org/MPL/2.0/.
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "GL/glew.h"
#ifdef _WIN32
#include "GL/wglew.h"
#endif
// encapsulation of the fixed pipeline opengl matrix stack
class opengl_matrices {

View File

@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "GL/glew.h"
class opengl_camera;
// particle data visualizer

171
openglprecipitation.cpp Normal file
View File

@@ -0,0 +1,171 @@
/*
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 "openglprecipitation.h"
#include "Globals.h"
#include "renderer.h"
#include "simulationenvironment.h"
opengl_precipitation::~opengl_precipitation() {
if( m_vertexbuffer != 0 ) { ::glDeleteBuffers( 1, &m_vertexbuffer ); }
if( m_indexbuffer != 0 ) { ::glDeleteBuffers( 1, &m_indexbuffer ); }
if( m_uvbuffer != 0 ) { ::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<float> 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() {
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( m_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 );
}

44
openglprecipitation.h Normal file
View File

@@ -0,0 +1,44 @@
/*
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 "Texture.h"
class opengl_precipitation {
public:
// constructors
opengl_precipitation() = default;
// destructor
~opengl_precipitation();
// methods
inline
void
set_unit( GLint const Textureunit ) {
m_textureunit = Textureunit; }
void
update();
void
render();
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 };
GLint m_textureunit { 0 };
texture_handle m_texture { -1 };
float m_overcast { -1.f }; // cached overcast level, difference from current state triggers texture update
};

View File

@@ -51,7 +51,7 @@ opengl_renderer::Init( GLFWwindow *Window ) {
std::vector<GLint>{ m_normaltextureunit, m_diffusetextureunit } );
m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit
ui_layer::set_unit( m_diffusetextureunit );
simulation::Environment.m_precipitation.set_unit( m_diffusetextureunit );
m_precipitationrenderer.set_unit( m_diffusetextureunit );
select_unit( m_diffusetextureunit );
::glDepthFunc( GL_LEQUAL );
@@ -548,7 +548,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glPolygonOffset( 1.f, 1.f );
// main shadowmap
::glBindFramebufferEXT( GL_FRAMEBUFFER, m_shadowframebuffer );
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_shadowframebuffer );
::glViewport( 0, 0, m_shadowbuffersize, m_shadowbuffersize );
#ifdef EU07_USE_DEBUG_SHADOWMAP
@@ -589,7 +589,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glEnable( GL_POLYGON_OFFSET_FILL ); // alleviate depth-fighting
::glPolygonOffset( 1.f, 1.f );
::glBindFramebufferEXT( GL_FRAMEBUFFER, m_cabshadowframebuffer );
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_cabshadowframebuffer );
::glViewport( 0, 0, m_shadowbuffersize / 2, m_shadowbuffersize / 2 );
#ifdef EU07_USE_DEBUG_CABSHADOWMAP
@@ -719,10 +719,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
bool
opengl_renderer::Render_reflections() {
if( Global.ReflectionUpdatesPerSecond == 0 ) { return false; }
if( Global.ReflectionUpdateInterval == 0 ) { return false; }
auto const timestamp { static_cast<int>( Timer::GetTime() * 1000 ) };
if( ( timestamp - m_environmentupdatetime < Global.ReflectionUpdatesPerSecond )
auto const timestamp { Timer::GetTime() };
if( ( timestamp - m_environmentupdatetime < Global.ReflectionUpdateInterval )
&& ( glm::length( m_renderpass.camera.position() - m_environmentupdatelocation ) < 1000.0 ) ) {
// run update every 5+ mins of simulation time, or at least 1km from the last location
return false;
@@ -736,7 +736,7 @@ opengl_renderer::Render_reflections() {
m_environmentcubetextureface < GL_TEXTURE_CUBE_MAP_POSITIVE_X + 6;
++m_environmentcubetextureface ) {
::glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, m_environmentcubetextureface, m_environmentcubetexture, 0 );
::glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_environmentcubetextureface, m_environmentcubetexture, 0 );
Render_pass( rendermode::reflections );
}
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
@@ -1567,9 +1567,9 @@ opengl_renderer::Bind_Material( material_handle const Material ) {
auto const &material = m_materials.material( Material );
if( false == Global.BasicRenderer ) {
m_textures.bind( textureunit::normals, material.texture2 );
m_textures.bind( textureunit::normals, material.textures[1] );
}
m_textures.bind( textureunit::diffuse, material.texture1 );
m_textures.bind( textureunit::diffuse, material.textures[0] );
}
opengl_material const &
@@ -1578,6 +1578,13 @@ opengl_renderer::Material( material_handle const Material ) const {
return m_materials.material( Material );
}
// shader methods
std::shared_ptr<gl::program>
opengl_renderer::Fetch_Shader( std::string const &name ) {
return std::shared_ptr<gl::program>();
}
// texture methods
void
opengl_renderer::select_unit( GLint const Textureunit ) {
@@ -1586,7 +1593,7 @@ opengl_renderer::select_unit( GLint const Textureunit ) {
}
texture_handle
opengl_renderer::Fetch_Texture( std::string const &Filename, bool const Loadnow ) {
opengl_renderer::Fetch_Texture( std::string const &Filename, bool const Loadnow, GLint format_hint ) {
return m_textures.create( Filename, Loadnow );
}
@@ -1597,12 +1604,36 @@ opengl_renderer::Bind_Texture( texture_handle const Texture ) {
m_textures.bind( textureunit::diffuse, Texture );
}
void
opengl_renderer::Bind_Texture( std::size_t const Unit, texture_handle const Texture ) {
m_textures.bind( Unit, Texture );
}
opengl_texture &
opengl_renderer::Texture( texture_handle const Texture ) {
return m_textures.texture( Texture );
}
opengl_texture const &
opengl_renderer::Texture( texture_handle const Texture ) const {
return m_textures.texture( Texture );
}
void
opengl_renderer::Pick_Control( std::function<void( TSubModel const * )> Callback ) {
m_control_pick_requests.emplace_back( Callback );
}
void
opengl_renderer::Pick_Node( std::function<void( scene::basic_node * )> Callback ) {
m_node_pick_requests.emplace_back( Callback );
}
void
opengl_renderer::Render( scene::basic_region *Region ) {
@@ -3012,7 +3043,7 @@ opengl_renderer::Render_precipitation() {
// momentarily disable depth write, to allow vehicle cab drawn afterwards to mask it instead of leaving it 'inside'
::glDepthMask( GL_FALSE );
simulation::Environment.m_precipitation.render();
m_precipitationrenderer.render();
if( Global.bUseVBO ) {
gfx::opengl_vbogeometrybank::reset();
}
@@ -3646,7 +3677,7 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
// utility methods
TSubModel *
void
opengl_renderer::Update_Pick_Control() {
#ifdef EU07_USE_PICKING_FRAMEBUFFER
@@ -3690,10 +3721,14 @@ opengl_renderer::Update_Pick_Control() {
}
#endif
m_pickcontrolitem = control;
return control;
// return control;
for( auto callback : m_control_pick_requests ) {
callback( m_pickcontrolitem );
}
m_control_pick_requests.clear();
}
scene::basic_node *
void
opengl_renderer::Update_Pick_Node() {
#ifdef EU07_USE_PICKING_FRAMEBUFFER
@@ -3739,7 +3774,11 @@ opengl_renderer::Update_Pick_Node() {
}
#endif
m_picksceneryitem = node;
return node;
// return node;
for( auto callback : m_node_pick_requests ) {
callback( m_picksceneryitem );
}
m_node_pick_requests.clear();
}
// converts provided screen coordinates to world coordinates of most recent color pass
@@ -3775,6 +3814,7 @@ opengl_renderer::Update( double const Deltatime ) {
renderpass_config renderpass;
setup_pass( renderpass, rendermode::color );
m_skydomerenderer.update();
m_precipitationrenderer.update();
m_particlerenderer.update( renderpass.camera );
}
@@ -3806,6 +3846,30 @@ opengl_renderer::Update( double const Deltatime ) {
*/
m_updateaccumulator += Deltatime;
if( ( true == Global.ControlPicking )
&& ( false == FreeFlyModeFlag ) ) {
if( ( false == m_control_pick_requests.empty() )
|| ( m_updateaccumulator >= 1.0 ) ) {
Update_Pick_Control();
}
}
else {
m_pickcontrolitem = nullptr;
}
// temporary conditions for testing. eventually will be coupled with editor mode
if( ( true == Global.ControlPicking )
&& ( true == FreeFlyModeFlag )
&& ( ( true == DebugModeFlag )
|| ( true == EditorModeFlag ) ) ) {
if( ( false == m_control_pick_requests.empty() )
|| ( m_updateaccumulator >= 1.0 ) ) {
Update_Pick_Node();
}
}
else {
m_picksceneryitem = nullptr;
}
if( m_updateaccumulator < 1.0 ) {
// too early for any work
return;
@@ -3856,22 +3920,6 @@ opengl_renderer::Update( double const Deltatime ) {
m_debugtimestext += m_textures.info();
}
if( ( true == Global.ControlPicking )
&& ( false == FreeFlyModeFlag ) ) {
Update_Pick_Control();
}
else {
m_pickcontrolitem = nullptr;
}
// temporary conditions for testing. eventually will be coupled with editor mode
if( ( true == Global.ControlPicking )
&& ( true == DebugModeFlag )
&& ( true == FreeFlyModeFlag ) ) {
Update_Pick_Node();
}
else {
m_picksceneryitem = nullptr;
}
// dump last opengl error, if any
auto const glerror = ::glGetError();
if( glerror != GL_NO_ERROR ) {
@@ -3984,12 +4032,12 @@ opengl_renderer::Init_caps() {
+ " OpenGL Version: " + oglversion );
#ifdef EU07_USEIMGUIIMPLOPENGL2
if( !GLEW_VERSION_1_5 ) {
if( !GLAD_GL_VERSION_1_5 ) {
ErrorLog( "Requires openGL >= 1.5" );
return false;
}
#else
if( !GLEW_VERSION_3_0 ) {
if( !GLAD_GL_VERSION_3_0 ) {
ErrorLog( "Requires openGL >= 3.0" );
return false;
}
@@ -3998,7 +4046,7 @@ opengl_renderer::Init_caps() {
WriteLog( "Supported extensions: " + std::string((char *)glGetString( GL_EXTENSIONS )) );
WriteLog( std::string("Render path: ") + ( Global.bUseVBO ? "VBO" : "Display lists" ) );
if( GLEW_EXT_framebuffer_object ) {
if( GL_EXT_framebuffer_object ) {
m_framebuffersupport = true;
WriteLog( "Framebuffer objects enabled" );
}

View File

@@ -9,12 +9,12 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "GL/glew.h"
#include "renderer.h"
#include "opengllight.h"
#include "openglcamera.h"
#include "openglparticles.h"
#include "openglskydome.h"
#include "openglprecipitation.h"
#include "lightarray.h"
#include "scene.h"
#include "simulationenvironment.h"
@@ -70,14 +70,24 @@ public:
Bind_Material( material_handle const Material ) override;
opengl_material 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 ) override;
Fetch_Texture( std::string const &Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA ) override;
void
Bind_Texture( texture_handle const Texture );
Bind_Texture( texture_handle const Texture ) override;
void
Bind_Texture( std::size_t const Unit, texture_handle const Texture ) override;
opengl_texture &
Texture( texture_handle const Texture ) override;
opengl_texture const &
Texture( texture_handle const Texture ) const override;
// utility methods
void
Pick_Control( std::function<void( TSubModel const * )> Callback ) override;
void
Pick_Node( std::function<void( scene::basic_node * )> Callback ) override;
TSubModel const *
Pick_Control() const override { return m_pickcontrolitem; }
scene::basic_node const *
@@ -87,9 +97,9 @@ public:
// maintenance methods
void
Update( double const Deltatime ) override;
TSubModel *
void
Update_Pick_Control() override;
scene::basic_node *
void
Update_Pick_Node() override;
glm::dvec3
Update_Mouse_Position() override;
@@ -249,6 +259,7 @@ private:
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
@@ -288,7 +299,7 @@ private:
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
int m_environmentupdatetime { 0 }; // time of the most recent environment map update
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 { GL_TEXTURE0 };
@@ -325,6 +336,8 @@ private:
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 * )>> 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

View File

@@ -27,7 +27,7 @@ void opengl_skydome::update() {
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
// setup gpu data buffers:
// ...static data...
if( m_indexbuffer == -1 ) {
if( m_indexbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_indexbuffer );
if( ( m_indexbuffer > 0 ) && ( m_indexbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indexbuffer );
@@ -36,7 +36,7 @@ void opengl_skydome::update() {
m_indexcount = indices.size();
}
}
if( m_vertexbuffer == -1 ) {
if( m_vertexbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_vertexbuffer );
if( ( m_vertexbuffer > 0 ) && ( m_vertexbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ARRAY_BUFFER, m_vertexbuffer );
@@ -45,7 +45,7 @@ void opengl_skydome::update() {
}
}
// ...and dynamic data
if( m_coloursbuffer == -1 ) {
if( m_coloursbuffer == (GLuint)-1 ) {
::glGenBuffers( 1, &m_coloursbuffer );
if( ( m_coloursbuffer > 0 ) && ( m_coloursbuffer != (GLuint)-1 ) ) {
::glBindBuffer( GL_ARRAY_BUFFER, m_coloursbuffer );

View File

@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "GL/glew.h"
class opengl_skydome {
public:
@@ -19,7 +17,7 @@ public:
// destructor
~opengl_skydome();
// methods
// updates data stores on the opengl end. NOTE: unbinds
// updates data stores on the opengl end. NOTE: unbinds buffers
void update();
// draws the skydome
void render();

View File

@@ -11,8 +11,6 @@ http://mozilla.org/MPL/2.0/.
#include "precipitation.h"
#include "Globals.h"
#include "openglmatrixstack.h"
#include "renderer.h"
#include "Timer.h"
#include "simulation.h"
#include "Train.h"
@@ -21,89 +19,11 @@ basic_precipitation::~basic_precipitation() {
// TODO: release allocated resources
}
void
basic_precipitation::create( int const Tesselation ) {
auto const heightfactor { 10.f }; // height-to-radius factor
m_moverate *= heightfactor;
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<float> 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
}
bool
basic_precipitation::init() {
create( 18 );
// TODO: select texture based on current overcast level
// TODO: when the overcast level dynamic change is in check the current level during render and pick the appropriate texture on the fly
std::string const densitysuffix { (
Global.Overcast < 1.35 ?
"_light" :
"_medium" ) };
if( Global.Weather == "rain:" ) {
m_moverateweathertypefactor = 2.f;
m_texture = GfxRenderer->Fetch_Texture( "fx/rain" + densitysuffix );
}
else if( Global.Weather == "snow:" ) {
m_moverateweathertypefactor = 1.25f;
m_texture = GfxRenderer->Fetch_Texture( "fx/snow" + densitysuffix );
}
auto const heightfactor { 10.f }; // height-to-radius factor
m_moverate *= heightfactor;
return true;
}
@@ -160,49 +80,8 @@ basic_precipitation::update() {
if( std::abs( m_cameramove.z ) < 0.001 ) { m_cameramove.z = 0.0; }
}
void
basic_precipitation::render() {
float
basic_precipitation::get_textureoffset() const {
GfxRenderer->Bind_Texture( m_texture );
// cache entry state
::glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
if( m_vertexbuffer == -1 ) {
// 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
}
// 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( m_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, m_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 );
return m_textureoffset;
}

View File

@@ -9,8 +9,6 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include "Texture.h"
// based on "Rendering Falling Rain and Snow"
// by Niniane Wang, Bretton Wade
@@ -22,32 +20,17 @@ public:
// destructor
~basic_precipitation();
// methods
inline
void
set_unit( GLint const Textureunit ) {
m_textureunit = Textureunit; }
bool
init();
void
update();
void
render();
float
get_textureoffset() const;
glm::dvec3 m_cameramove{ 0.0 };
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 };
GLint m_textureunit { 0 };
texture_handle m_texture { -1 };
float m_textureoffset { 0.f };
float m_moverate { 30 * 0.001f };
float m_moverateweathertypefactor { 1.f }; // medium-dependent; 1.0 for snow, faster for rain

View File

@@ -27,7 +27,7 @@
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
#include "stdafx.h"
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#include "imgui.h"
#include "imgui_impl_opengl2.h"

View File

@@ -48,7 +48,7 @@
//----------------------------------------
#include "stdafx.h"
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS

View File

@@ -40,18 +40,25 @@ public:
virtual auto Fetch_Material( std::string const &Filename, bool const Loadnow = true ) -> material_handle = 0;
virtual void Bind_Material( material_handle const Material ) = 0;
virtual auto Material( material_handle const Material ) const -> opengl_material const & = 0;
// shader methods
virtual auto Fetch_Shader( std::string const &name ) -> std::shared_ptr<gl::program> = 0;
// texture methods
virtual auto Fetch_Texture( std::string const &Filename, bool const Loadnow = true ) -> texture_handle = 0;
virtual auto Fetch_Texture( std::string const &Filename, bool const Loadnow = true, GLint format_hint = GL_SRGB_ALPHA ) -> texture_handle = 0;
virtual void Bind_Texture( texture_handle const Texture ) = 0;
virtual void Bind_Texture( std::size_t const Unit, texture_handle const Texture ) = 0;
virtual auto Texture( texture_handle const Texture ) -> opengl_texture & = 0;
virtual auto Texture( texture_handle const Texture ) const -> opengl_texture const & = 0;
// utility methods
virtual void Pick_Control( std::function<void( TSubModel const * )> Callback ) = 0;
virtual void Pick_Node( std::function<void( scene::basic_node * )> Callback ) = 0;
virtual auto Pick_Control() const -> TSubModel const * = 0;
virtual auto Pick_Node() const -> scene::basic_node const * = 0;
virtual auto Mouse_Position() const -> glm::dvec3 = 0;
// maintenance methods
virtual void Update( double const Deltatime ) = 0;
virtual auto Update_Pick_Control() -> TSubModel * = 0;
virtual auto Update_Pick_Node() -> scene::basic_node * = 0;
virtual void Update_Pick_Control() = 0;
virtual void Update_Pick_Node() = 0;
virtual auto Update_Mouse_Position() -> glm::dvec3 = 0;
// debug methods
virtual auto info_times() const -> std::string const & = 0;

View File

@@ -22,6 +22,9 @@ http://mozilla.org/MPL/2.0/.
#include "Traction.h"
#include "sound.h"
class opengl_renderer;
class opengl33_renderer;
namespace scene {
int const EU07_CELLSIZE = 250;
@@ -63,6 +66,7 @@ struct scratch_data {
class basic_cell {
friend opengl_renderer;
friend opengl33_renderer;
public:
// constructors
@@ -200,6 +204,7 @@ private:
class basic_section {
friend opengl_renderer;
friend opengl33_renderer;
public:
// constructors
@@ -304,6 +309,7 @@ private:
class basic_region {
friend opengl_renderer;
friend opengl33_renderer;
public:
// constructors

View File

@@ -200,7 +200,7 @@ shape_node::import( cParser &Input, scene::node_data const &Nodedata ) {
// TBT, TODO: add methods to material manager to access these simpler
auto const texturehandle = (
m_data.material != null_handle ?
GfxRenderer->Material( m_data.material ).texture1 :
GfxRenderer->Material( m_data.material ).textures[0] :
null_handle );
auto const &texture = (
texturehandle ?
@@ -346,7 +346,7 @@ shape_node::convert( TSubModel const *Submodel ) {
m_data.lighting.diffuse = Submodel->f4Diffuse;
m_data.lighting.specular = Submodel->f4Specular;
m_data.material = Submodel->m_material;
m_data.translucent = ( true == GfxRenderer->Material( m_data.material ).has_alpha );
m_data.translucent = ( true == GfxRenderer->Material( m_data.material ).is_translucent() );
// NOTE: we set unlimited view range typical for terrain, because we don't expect to convert any other 3d models
m_data.rangesquared_max = std::numeric_limits<double>::max();

View File

@@ -18,11 +18,13 @@ http://mozilla.org/MPL/2.0/.
#include "sound.h"
class opengl_renderer;
class opengl33_renderer;
// wrapper for environment elements -- sky, sun, stars, clouds etc
class world_environment {
friend opengl_renderer;
friend opengl33_renderer;
public:
// methods
@@ -43,6 +45,9 @@ public:
inline auto &
skydome() {
return m_skydome; }
inline auto const &
precipitation() const {
return m_precipitation; }
inline auto const &
wind() const {
return m_wind.vector; }

1
sky.h
View File

@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
class TSky {
friend opengl_renderer;
friend opengl33_renderer;
public:
TSky() = default;

View File

@@ -9,6 +9,7 @@
class cStars {
friend opengl_renderer;
friend opengl33_renderer;
public:
// types:

View File

@@ -66,31 +66,27 @@
#include <mutex>
#include <condition_variable>
#include <typeinfo>
#include <bitset>
#include <chrono>
#include <optional>
#include <filesystem>
#ifdef NDEBUG
#define EU07_BUILD_STATIC
#endif
#ifdef EU07_BUILD_STATIC
#define GLEW_STATIC
#else
#ifdef _WIN32
#define GLFW_DLL
#endif // _windows
#endif // build_static
#ifndef __ANDROID__
#include "GL/glew.h"
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
#ifdef _WIN32
#include "GL/wglew.h"
#endif
#define GLFW_INCLUDE_GLU
//m7todo: jest tu bo nie chcia³o mi siê wpychaæ do wszystkich plików
#ifndef __ANDROID__
#include "glad/glad.h"
#include "GL/glu.h"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#ifndef GLFW_TRUE
#define GLFW_FALSE 0
#define GLFW_TRUE 1
#define glfwGetKeyName(a, b) ("")
#define glfwFocusWindow(w)
#endif
#define GLM_ENABLE_EXPERIMENTAL
@@ -102,10 +98,14 @@
#include <glm/gtc/epsilon.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/string_cast.hpp>
int const null_handle = 0;
#include "openglmatrixstack.h"
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define glDebug(x) if (GLAD_GL_GREMEDY_string_marker) glStringMarkerGREMEDY(0, __FILE__ ":" STRINGIZE(__LINE__) ": " x);
#include "openglcolor.h"
// imgui.h comes with its own operator new which gets wrecked by dbg_new, so we temporarily disable the latter

2
sun.h
View File

@@ -1,8 +1,6 @@
#pragma once
#include "windows.h"
#include "GL/glew.h"
#include "GL/wglew.h"
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -110,6 +110,12 @@ double Random(double a, double b)
return dis(Global.random_engine);
}
double LocalRandom(double a, double b)
{
uint32_t val = Global.local_random_engine();
return interpolate(a, b, (double)val / Global.random_engine.max());
}
bool FuzzyLogic(double Test, double Threshold, double Probability)
{
if ((Test > Threshold) && (!DebugModeFlag))

View File

@@ -56,6 +56,7 @@ inline long Round(double const f)
}
double Random(double a, double b);
double LocalRandom( double a, double b );
inline double Random()
{
@@ -67,6 +68,16 @@ inline double Random(double b)
return Random(0.0, b);
}
inline double LocalRandom()
{
return LocalRandom( 0.0, 1.0 );
}
inline double LocalRandom( double b )
{
return LocalRandom( 0.0, b );
}
inline double BorlandTime()
{
auto timesinceepoch = std::time( nullptr );

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 19
#define VERSION_MINOR 1014
#define VERSION_MINOR 1026
#define VERSION_REVISION 0