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:
@@ -125,6 +125,7 @@ class TAnimAdvanced
|
||||
class TAnimModel : public scene::basic_node {
|
||||
|
||||
friend opengl_renderer;
|
||||
friend opengl33_renderer;
|
||||
friend itemproperties_panel;
|
||||
|
||||
public:
|
||||
|
||||
@@ -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
|
||||
|
||||
46
DynObj.cpp
46
DynObj.cpp
@@ -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 {
|
||||
|
||||
7
DynObj.h
7
DynObj.h
@@ -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 ];
|
||||
|
||||
@@ -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")
|
||||
|
||||
20
Globals.h
20
Globals.h
@@ -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
6
Logs.h
@@ -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 );
|
||||
|
||||
@@ -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 + "\"." );
|
||||
}
|
||||
|
||||
123
Model3d.cpp
123
Model3d.cpp
@@ -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 {
|
||||
|
||||
10
Model3d.h
10
Model3d.h
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
131
Texture.cpp
131
Texture.cpp
@@ -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
|
||||
|
||||
30
Texture.h
30
Texture.h
@@ -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); }
|
||||
|
||||
2
Timer.h
2
Timer.h
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
1
Track.h
1
Track.h
@@ -144,6 +144,7 @@ private:
|
||||
class TTrack : public scene::basic_node {
|
||||
|
||||
friend opengl_renderer;
|
||||
friend opengl33_renderer;
|
||||
// NOTE: temporary arrangement
|
||||
friend itemproperties_panel;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 != "");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
107
geometrybank.cpp
107
geometrybank.cpp
@@ -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
|
||||
|
||||
@@ -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
27
gl/bindable.h
Normal 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
89
gl/buffer.cpp
Normal 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
46
gl/buffer.h
Normal 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
38
gl/cubemap.cpp
Normal 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
19
gl/cubemap.h
Normal 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
20
gl/fence.cpp
Normal 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
20
gl/fence.h
Normal 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
103
gl/framebuffer.cpp
Normal 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
33
gl/framebuffer.h
Normal 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
72
gl/glsl_common.cpp
Normal 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
10
gl/glsl_common.h
Normal 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
32
gl/object.h
Normal 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
65
gl/pbo.cpp
Normal 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
22
gl/pbo.h
Normal 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
49
gl/postfx.cpp
Normal 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
25
gl/postfx.h
Normal 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
65
gl/query.cpp
Normal 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
36
gl/query.h
Normal 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
27
gl/renderbuffer.cpp
Normal 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
19
gl/renderbuffer.h
Normal 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
334
gl/shader.cpp
Normal 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
96
gl/shader.h
Normal 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
19
gl/ubo.cpp
Normal 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
113
gl/ubo.h
Normal 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
85
gl/vao.cpp
Normal 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 ¶m : 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
37
gl/vao.h
Normal 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;
|
||||
};
|
||||
}
|
||||
@@ -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">
|
||||
|
||||
283
material.cpp
283
material.cpp
@@ -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" } ) );
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
52
material.h
52
material.h
@@ -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
2
moon.h
@@ -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
22
opengl33light.cpp
Normal 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
28
opengl33light.h
Normal 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
138
opengl33particles.cpp
Normal 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
54
opengl33particles.h
Normal 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
159
opengl33precipitation.cpp
Normal 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
43
opengl33precipitation.h
Normal 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
3904
opengl33renderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
377
opengl33renderer.h
Normal file
377
opengl33renderer.h
Normal 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;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
171
openglprecipitation.cpp
Normal 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
44
openglprecipitation.h
Normal 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
|
||||
};
|
||||
@@ -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" );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
13
renderer.h
13
renderer.h
@@ -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;
|
||||
|
||||
6
scene.h
6
scene.h
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
1
sky.h
@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
class TSky {
|
||||
|
||||
friend opengl_renderer;
|
||||
friend opengl33_renderer;
|
||||
|
||||
public:
|
||||
TSky() = default;
|
||||
|
||||
1
stars.h
1
stars.h
@@ -9,6 +9,7 @@
|
||||
class cStars {
|
||||
|
||||
friend opengl_renderer;
|
||||
friend opengl33_renderer;
|
||||
|
||||
public:
|
||||
// types:
|
||||
|
||||
38
stdafx.h
38
stdafx.h
@@ -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
2
sun.h
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "windows.h"
|
||||
#include "GL/glew.h"
|
||||
#include "GL/wglew.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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))
|
||||
|
||||
11
utilities.h
11
utilities.h
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user