dynamically assigned render lights

This commit is contained in:
tmj-fstate
2017-02-27 02:58:38 +01:00
parent 0752024d47
commit 80b8da6749
16 changed files with 344 additions and 158 deletions

View File

@@ -3760,12 +3760,14 @@ void TDynamicObject::Render()
// double ObjDist= SquareMagnitude(Global::pCameraPosition-pos);
if (this == Global::pUserDynamic)
{ // specjalne ustawienie, aby nie trzęsło
#ifdef EU07_USE_OLD_LIGHTING_MODEL
if (Global::bSmudge)
{ // jak jest widoczna smuga, to pojazd renderować po
// wyrenderowaniu smugi
glPopMatrix(); // a to trzeba zebrać przed wyjściem
return;
}
#endif
// if (Global::pWorld->) //tu trzeba by ustawić animacje na modelu
// zewnętrznym
glLoadIdentity(); // zacząć od macierzy jedynkowej

View File

@@ -420,7 +420,7 @@ public: // modele składowe pojazdu
void Render();
void RenderAlpha();
void RenderSounds();
inline vector3 GetPosition()
inline vector3 GetPosition() const
{
return vPosition;
};
@@ -436,7 +436,7 @@ public: // modele składowe pojazdu
{
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition;
};
inline vector3 VectorFront()
inline vector3 VectorFront() const
{
return vFront;
};
@@ -456,7 +456,7 @@ public: // modele składowe pojazdu
{
return MoverParameters->Vel;
};
inline double GetLength()
inline double GetLength() const
{
return MoverParameters->Dim.L;
};

View File

@@ -718,6 +718,9 @@ int WINAPI WinMain(HINSTANCE hInstance, // instance
fullscreen))
return 0; // quit if window was not created
SetForegroundWindow(hWnd);
GfxRenderer.Init();
// McZapkie: proba przeplukania klawiatury
Console *pConsole = new Console(); // Ra: nie wiem, czy ma to sens, ale jakoś zainicjowac trzeba
while (Console::Pressed(VK_F10))

View File

@@ -104,8 +104,7 @@ GLfloat Global::diffuseLight[] = {0.85f, 0.85f, 0.80f, 1.0f};
GLfloat Global::specularLight[] = {0.95f, 0.94f, 0.90f, 1.0f};
#else
opengl_light Global::DayLight;
opengl_light Global::VehicleLight;
opengl_light Global::VehicleLightRear;
int Global::DynamicLightCount{ 3 };
#endif
GLfloat Global::whiteLight[] = {1.00f, 1.00f, 1.00f, 1.0f};
GLfloat Global::noLight[] = {0.00f, 0.00f, 0.00f, 1.0f};
@@ -577,7 +576,14 @@ void Global::ConfigParse(cParser &Parser)
std::tm *localtime = std::localtime(&timenow);
Global::fMoveLight = localtime->tm_yday + 1; // numer bieżącego dnia w roku
}
// TODO: calculate lights single time here for static setup. or get rid of static setup
}
else if( token == "dynamiclights" ) {
// number of dynamic lights in the scene
Parser.getTokens( 1, false );
Parser >> Global::DynamicLightCount;
// clamp the light number
Global::DynamicLightCount = std::min( 7, Global::DynamicLightCount ); // max 8 lights per opengl specs, and one used for sun
Global::DynamicLightCount = std::max( 1, Global::DynamicLightCount ); // at least one light for controlled vehicle
}
else if (token == "smoothtraction")
{

View File

@@ -233,9 +233,7 @@ class Global
#else
// TODO: put these things in the renderer
static opengl_light DayLight;
// TODO: possibly create a pool of few lights which can be attached to nearby vehicles
static opengl_light VehicleLight;
static opengl_light VehicleLightRear;
static int DynamicLightCount;
#endif
static GLfloat whiteLight[];
static GLfloat noLight[];

View File

@@ -1841,29 +1841,20 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
case TP_DYNAMIC:
tmp->DynamicObject = new TDynamicObject();
// tmp->DynamicObject->Load(Parser);
parser->getTokens();
*parser >> token;
str1 = token; // katalog
// McZapkie: doszedl parametr ze zmienialna skora
parser->getTokens();
*parser >> token;
Skin = token; // tekstura wymienna
parser->getTokens();
*parser >> token;
str3 = token; // McZapkie-131102: model w MMD
parser->getTokens(3);
*parser
>> str1 // katalog
>> Skin // tekstura wymienna
>> str3; // McZapkie-131102: model w MMD
if (bTrainSet)
{ // jeśli pojazd jest umieszczony w składzie
str = asTrainSetTrack;
parser->getTokens();
*parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie, normalnie w składzie 0
parser->getTokens();
*parser >> token;
DriverType = token; // McZapkie:010303 - w przyszlosci rozne
// konfiguracje mechanik/pomocnik itp
parser->getTokens(3);
*parser
>> tf1 // Ra: -1 oznacza odwrotne wstawienie, normalnie w składzie 0
>> DriverType // McZapkie:010303 - w przyszlosci rozne konfiguracje mechanik/pomocnik itp
>> str4;
tf3 = fTrainSetVel; // prędkość
parser->getTokens();
*parser >> token;
str4 = token;
int2 = str4.find("."); // yB: wykorzystuje tutaj zmienna, ktora potem bedzie ladunkiem
if (int2 != string::npos) // yB: jesli znalazl kropke, to ja przetwarza jako parametry
{
@@ -1892,17 +1883,12 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
fTrainSetDist = 0; // zerowanie dodatkowego przesunięcia
asTrainName = ""; // puste oznacza jazdę pojedynczego bez rozkładu, "none" jest dla
// składu (trainset)
parser->getTokens();
*parser >> token;
str = token; // track
parser->getTokens();
*parser >> tf1; // Ra: -1 oznacza odwrotne wstawienie
parser->getTokens();
*parser >> token;
DriverType = token; // McZapkie:010303: obsada
parser->getTokens();
*parser >>
tf3; // prędkość, niektórzy wpisują tu "3" jako sprzęg, żeby nie było tabliczki
parser->getTokens(4);
*parser
>> str // track
>> tf1 // Ra: -1 oznacza odwrotne wstawienie
>> DriverType // McZapkie:010303: obsada
>> tf3; // prędkość, niektórzy wpisują tu "3" jako sprzęg, żeby nie było tabliczki
iTrainSetWehicleNumber = 0;
TempConnectionType[iTrainSetWehicleNumber] = 3; // likwidacja tabliczki na końcu?
}
@@ -1911,8 +1897,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
if (int2 > 0)
{ // jeżeli ładunku jest więcej niż 0, to rozpoznajemy jego typ
parser->getTokens();
*parser >> token;
str2 = token; // LoadType
*parser >> str2; // LoadType
if (str2 == "enddynamic") // idiotoodporność: ładunek bez podanego typu
{
str2 = "";
@@ -1986,6 +1971,16 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
}
if (token.compare("enddynamic") != 0)
Error("enddynamic statement missing");
/*
if( tmp->DynamicObject->MoverParameters->LightPowerSource.SourceType != TPowerSource::NotDefined ) {
// if the vehicle has defined light source, it can (potentially) emit light, so add it to the light array
*/
if( tmp->DynamicObject->MoverParameters->SecuritySystem.SystemType != 0 ) {
// we check for presence of security system, as a way to determine whether the vehicle is a controllable engine
// NOTE: this isn't 100% precise, e.g. middle EZT module comes with security system, while it has no lights
m_lights.insert( tmp->DynamicObject );
}
break;
case TP_MODEL:
if (rmin < 0)
@@ -4558,6 +4553,25 @@ bool TGround::Update(double dt, int iter)
return true;
};
// updates scene lights array
void
TGround::Update_Lights() {
m_lights.update();
// arrange the light array from closest to farthest from current position of the camera
auto const camera = Global::pCameraPosition;
std::sort(
m_lights.data.begin(),
m_lights.data.end(),
[&]( light_array::light_record const &Left, light_array::light_record const &Right ) {
// move lights which are off at the end...
if( Left.intensity == 0.0f ) { return false; }
if( Right.intensity == 0.0f ) { return true; }
// ...otherwise prefer closer and/or brigher light sources
return ((camera - Left.position).LengthSquared() * (1.0f - Left.intensity)) < ((camera - Right.position).LengthSquared() * (1.0f - Right.intensity));
} );
}
// Winger 170204 - szukanie trakcji nad pantografami
bool TGround::GetTraction(TDynamicObject *model)
{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie
@@ -4808,6 +4822,27 @@ bool TGround::GetTraction(TDynamicObject *model)
return true;
};
bool
TGround::Render( Math3D::vector3 const &Camera ) {
GfxRenderer.Update_Lights( m_lights );
if( Global::bUseVBO ) { // renderowanie przez VBO
if( !RenderVBO( Camera ) )
return false;
if( !RenderAlphaVBO( Camera ) )
return false;
}
else { // renderowanie przez Display List
if( !RenderDL( Camera ) )
return false;
if( !RenderAlphaDL( Camera ) )
return false;
}
return true;
}
bool TGround::RenderDL(vector3 pPosition)
{ // renderowanie scenerii z Display List - faza nieprzezroczystych
glDisable(GL_BLEND);
@@ -5339,6 +5374,8 @@ void TGround::DynamicRemove(TDynamicObject *dyn)
node = (*n); // zapamiętanie węzła, aby go usunąć
(*n) = node->nNext; // pominięcie na liście
Global::TrainDelete(d);
// remove potential entries in the light array
m_lights.remove( d );
d = d->Next(); // przejście do kolejnego pojazdu, póki jeszcze jest
delete node; // usuwanie fizyczne z pamięci
}

View File

@@ -16,7 +16,9 @@ http://mozilla.org/MPL/2.0/.
#include "ResourceManager.h"
#include "Texture.h"
#include "dumb3d.h"
#include "Float3d.h"
#include "Names.h"
#include "lightarray.h"
using namespace Math3D;
@@ -303,11 +305,11 @@ class TGround
TNames *sTracks = nullptr; // posortowane nazwy torów i eventów
#else
typedef std::unordered_map<std::string, TEvent *> event_map;
// typedef std::unordered_map<std::string, TGroundNode *> groundnode_map;
event_map m_eventmap;
// groundnode_map m_memcellmap, m_modelmap, m_trackmap;
TNames<TGroundNode *> m_trackmap;
#endif
light_array m_lights; // collection of dynamic light sources present in the scene
private: // metody prywatne
bool EventConditon(TEvent *e);
@@ -350,8 +352,10 @@ class TGround
void MoveGroundNode(vector3 pPosition);
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
void Update_Lights(); // updates scene lights array
bool AddToQuery(TEvent *Event, TDynamicObject *Node);
bool GetTraction(TDynamicObject *model);
bool Render( Math3D::vector3 const &Camera );
bool RenderDL(vector3 pPosition);
bool RenderAlphaDL(vector3 pPosition);
bool RenderVBO(vector3 pPosition);

110
World.cpp
View File

@@ -512,25 +512,6 @@ bool TWorld::Init(HWND NhWnd, HDC hDC)
Global::DayLight.diffuse[ 0 ] = 255.0 / 255.0;
Global::DayLight.diffuse[ 1 ] = 242.0 / 255.0;
Global::DayLight.diffuse[ 2 ] = 231.0 / 255.0;
Global::VehicleLight.id = opengl_renderer::vehiclelight;
// directional light
Global::VehicleLight.position[ 3 ] = 1.0f;
::glLightf( opengl_renderer::vehiclelight, GL_SPOT_CUTOFF, 20.0f );
::glLightf( opengl_renderer::vehiclelight, GL_SPOT_EXPONENT, 10.0f );
::glLightf( opengl_renderer::vehiclelight, GL_CONSTANT_ATTENUATION, 0.0f );
::glLightf( opengl_renderer::vehiclelight, GL_LINEAR_ATTENUATION, 0.035f );
// halogen light. TODO: allow light type definition
Global::VehicleLight.diffuse[ 0 ] = 255.0 / 255.0;
Global::VehicleLight.diffuse[ 1 ] = 241.0 / 255.0;
Global::VehicleLight.diffuse[ 2 ] = 224.0 / 255.0;
// rear light
Global::VehicleLightRear = Global::VehicleLight;
Global::VehicleLightRear.id = opengl_renderer::vehiclelightrear;
::glLightf( opengl_renderer::vehiclelightrear, GL_SPOT_CUTOFF, 20.0f );
::glLightf( opengl_renderer::vehiclelightrear, GL_SPOT_EXPONENT, 10.0f );
::glLightf( opengl_renderer::vehiclelightrear, GL_CONSTANT_ATTENUATION, 0.0f );
::glLightf( opengl_renderer::vehiclelightrear, GL_LINEAR_ATTENUATION, 0.035f );
#endif
Ground.Init(Global::SceneryFile, hDC);
@@ -1256,6 +1237,8 @@ bool TWorld::Update()
Ground.CheckQuery();
Ground.Update_Lights();
if( Train != nullptr ) {
TSubModel::iInstance = reinterpret_cast<int>( Train->Dynamic() );
Train->Update( dt );
@@ -1275,13 +1258,6 @@ bool TWorld::Update()
( Train->Dynamic()->fShade <= 0.0 ?
( Global::fLuminance <= 0.5 ) :
( Train->Dynamic()->fShade * Global::fLuminance <= 0.5 ) ) );
// match the vehicle light position with new position of the vehicle
Global::VehicleLight.set_position( Train->Dynamic()->GetPosition() + ( Train->Dynamic()->VectorFront() * Train->Dynamic()->GetLength() * 0.45 ) );
Global::VehicleLight.direction = Train->Dynamic()->VectorFront();
Global::VehicleLightRear.set_position( Train->Dynamic()->GetPosition() - ( Train->Dynamic()->VectorFront() * Train->Dynamic()->GetLength() * 0.45 ) );
Global::VehicleLightRear.direction = Train->Dynamic()->VectorFront();
Global::VehicleLightRear.direction.RotateY( M_PI );
}
m_init = true;
@@ -1556,78 +1532,11 @@ bool TWorld::Render()
Environment.render();
}
// enable vehicle light, if it's present and on
if( nullptr != Train ) {
if( false == Ground.Render( Camera.Pos ) ) { return false; }
auto const &frontlights = Train->Controlled()->iLights[ 0 ];
int const frontlightcount = 0 +
( ( frontlights & 1 ) ? 1 : 0 ) +
( ( frontlights & 4 ) ? 1 : 0 ) +
( ( frontlights & 16 ) ? 1 : 0 );
if( ( true == Train->Controlled()->Battery )
&& ( frontlightcount > 0 ) ) {
// halogen light. TODO: allow light type definition
Global::VehicleLight.ambient[ 0 ] = 0.15f * 255.0 * frontlightcount / 255.0;
Global::VehicleLight.ambient[ 1 ] = 0.15f * 241.0 * frontlightcount / 255.0;
Global::VehicleLight.ambient[ 2 ] = 0.15f * 224.0 * frontlightcount / 255.0;
::glLightf( opengl_renderer::vehiclelight, GL_LINEAR_ATTENUATION, 0.3f / pow(frontlightcount, 2) );
glEnable( GfxRenderer.vehiclelight );
Global::VehicleLight.apply_intensity();
Global::VehicleLight.apply_angle();
}
else {
glDisable( GfxRenderer.vehiclelight );
}
auto const &rearlights = Train->Controlled()->iLights[ 1 ];
int const rearlightcount = 0 +
( ( rearlights & 1 ) ? 1 : 0 ) +
( ( rearlights & 4 ) ? 1 : 0 ) +
( ( rearlights & 16 ) ? 1 : 0 );
if( ( true == Train->Controlled()->Battery )
&& ( rearlightcount > 0 ) ) {
// halogen light. TODO: allow light type definition
Global::VehicleLightRear.ambient[ 0 ] = 0.15f * 255.0 * rearlightcount / 255.0;
Global::VehicleLightRear.ambient[ 1 ] = 0.15f * 241.0 * rearlightcount / 255.0;
Global::VehicleLightRear.ambient[ 2 ] = 0.15f * 224.0 * rearlightcount / 255.0;
::glLightf( opengl_renderer::vehiclelightrear, GL_LINEAR_ATTENUATION, 0.3f / pow( rearlightcount, 2 ) );
glEnable( GfxRenderer.vehiclelightrear );
Global::VehicleLightRear.apply_intensity();
Global::VehicleLightRear.apply_angle();
}
else {
glDisable( GfxRenderer.vehiclelightrear );
}
}
if (Global::bUseVBO)
{ // renderowanie przez VBO
if (!Ground.RenderVBO(Camera.Pos))
return false;
if (!Ground.RenderAlphaVBO(Camera.Pos))
return false;
}
else
{ // renderowanie przez Display List
if (!Ground.RenderDL(Camera.Pos))
return false;
if (!Ground.RenderAlphaDL(Camera.Pos))
return false;
}
/*
TSubModel::iInstance = (int)(Train ? Train->Dynamic() : 0); //żeby nie robić cudzych animacji
// if (Camera.Type==tp_Follow)
if (Train)
Train->Update();
*/
Render_Cab();
Render_UI();
// glFlush();
// Global::bReCompile=false; //Ra: już zrobiona rekompilacja
ResourceManager::Sweep( Timer::GetSimulationTime() );
return true;
@@ -1652,6 +1561,7 @@ TWorld::Render_Cab() {
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
return;
}
/*
// ABu: Rendering kabiny jako ostatniej, zeby bylo widac przez szyby, tylko w widoku ze srodka
if( ( Train->Dynamic()->mdKabina != Train->Dynamic()->mdModel ) &&
@@ -1777,18 +1687,18 @@ TWorld::Render_Cab() {
glEnable( GL_FOG );
}
}
*/
glEnable( GL_LIGHTING ); // po renderowaniu smugi jest to wyłączone
// Ra: pojazd użytkownika należało by renderować po smudze, aby go nie rozświetlała
Global::bSmudge = false; // aby model użytkownika się teraz wyrenderował
dynamic->Render();
dynamic->RenderAlpha(); // przezroczyste fragmenty pojazdów na torach
/*
} // yB: moje smuuugi 1 - koniec
else
glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit
*/
*/ glEnable( GL_LIGHTING ); // po renderowaniu drutów może być to wyłączone. TODO: have the wires render take care of its own shit
if( dynamic->mdKabina ) // bo mogła zniknąć przy przechodzeniu do innego pojazdu
{
#ifdef EU07_USE_OLD_LIGHTING_MODEL
@@ -1874,10 +1784,6 @@ TWorld::Render_Cab() {
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseCabLight );
glLightfv( GL_LIGHT0, GL_SPECULAR, specularCabLight );
#else
// cab shouldn't get affected by the vehicle light, so we disable it here
::glDisable( GfxRenderer.vehiclelight );
::glDisable( GfxRenderer.vehiclelightrear );
if( dynamic->InteriorLightLevel > 0.0f ) {
// crude way to light the cabin, until we have something more complete in place

View File

@@ -83,7 +83,8 @@ class vector3
void inline Normalize();
void inline SafeNormalize();
double inline Length();
double inline Length() const;
double inline LengthSquared() const;
void inline Zero()
{
x = y = z = 0.0;
@@ -435,11 +436,16 @@ void inline vector3::Normalize()
z *= il;
}
double inline vector3::Length()
double inline vector3::Length() const
{
return SQRT_FUNCTION(x * x + y * y + z * z);
}
double inline vector3::LengthSquared() const {
return ( x * x + y * y + z * z );
}
inline bool operator==(const matrix4x4 &m1, const matrix4x4 &m2)
{
for (int x = 0; x < 4; ++x)

75
lightarray.cpp Normal file
View File

@@ -0,0 +1,75 @@
/*
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/.
*/
/*
MaSzyna EU07 locomotive simulator
Copyright (C) 2001-2004 Marcin Wozniak and others
*/
#include "stdafx.h"
#include "lightarray.h"
#include "dynobj.h"
void
light_array::insert( TDynamicObject const *Owner ) {
// we're only storing lights for locos, which have two sets of lights, front and rear
// for a more generic role this function would have to be tweaked to add vehicle type-specific light combinations
data.emplace_back( Owner, 0 );
data.emplace_back( Owner, 1 );
}
void
light_array::remove( TDynamicObject const *Owner ) {
data.erase(
std::remove_if(
data.begin(),
data.end(),
[=]( light_record const &light ){ return light.owner == Owner; } ),
data.end() );
}
// updates records in the collection
void
light_array::update() {
for( auto &light : data ) {
// update light parameters to match current data of the owner
if( light.index == 0 ) {
// front light set
light.position = light.owner->GetPosition() + ( light.owner->VectorFront() * light.owner->GetLength() * 0.45 );
light.direction = light.owner->VectorFront();
}
else {
// rear light set
light.position = light.owner->GetPosition() - ( light.owner->VectorFront() * light.owner->GetLength() * 0.45 );
light.direction = light.owner->VectorFront();
light.direction.x = -light.direction.x;
light.direction.z = -light.direction.z;
}
// determine intensity of this light set
if( true == light.owner->MoverParameters->Battery ) {
// with battery on, the intensity depends on the state of activated switches
auto const &lightbits = light.owner->iLights[ light.index ];
light.count = 0 +
( ( lightbits & 1 ) ? 1 : 0 ) +
( ( lightbits & 4 ) ? 1 : 0 ) +
( ( lightbits & 16 ) ? 1 : 0 );
light.intensity = 0.15f * light.count; // TODO: intensity can be affected further by dim switch or other factors
}
else {
// with battery off the lights are off
light.intensity = 0.0f;
light.count = 0;
}
}
}

45
lightarray.h Normal file
View File

@@ -0,0 +1,45 @@
#pragma once
#include <vector>
#include "dumb3d.h"
#include "float3d.h"
#include "dynobj.h"
// collection of virtual light sources present in the scene
// used by the renderer to determine most suitable placement for actual light sources during render
struct light_array {
public:
// types
struct light_record {
light_record( TDynamicObject const *Owner, int const Lightindex) :
owner(Owner), index(Lightindex)
{};
TDynamicObject const *owner; // the object in world which 'carries' the light
int index{ -1 }; // 0: front lights, 1: rear lights
Math3D::vector3 position; // position of the light in 3d scene
Math3D::vector3 direction; // direction of the light in 3d scene
float3 color{ 255.0f / 255.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light
float intensity{ 0.0f }; // (combined) intensity of the light(s)
int count{ 0 }; // number (or pattern) of active light(s)
};
// methods
// adds records for lights of specified owner to the collection
void
insert( TDynamicObject const *Owner );
// removes records for lights of specified owner from the collection
void
remove( TDynamicObject const *Owner );
// updates records in the collection
void
update();
// types
typedef std::vector<light_record> lightrecord_array;
// members
lightrecord_array data;
};

View File

@@ -104,6 +104,7 @@
<ClCompile Include="Gauge.cpp" />
<ClCompile Include="Globals.cpp" />
<ClCompile Include="Ground.cpp" />
<ClCompile Include="lightarray.cpp" />
<ClCompile Include="Logs.cpp" />
<ClCompile Include="mczapkie\friction.cpp" />
<ClCompile Include="mczapkie\hamulce.cpp" />
@@ -166,6 +167,7 @@
<ClInclude Include="Gauge.h" />
<ClInclude Include="Globals.h" />
<ClInclude Include="Ground.h" />
<ClInclude Include="lightarray.h" />
<ClInclude Include="Logs.h" />
<ClInclude Include="McZapkie\friction.h" />
<ClInclude Include="McZapkie\hamulce.h" />
@@ -222,4 +224,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -201,6 +201,9 @@
<ClCompile Include="stars.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="lightarray.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="opengl\glew.h">
@@ -392,6 +395,9 @@
<ClInclude Include="stars.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="lightarray.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="maszyna.rc">

View File

@@ -9,7 +9,85 @@ http://mozilla.org/MPL/2.0/.
#include "stdafx.h"
#include "renderer.h"
#include "globals.h"
opengl_renderer GfxRenderer;
void
opengl_renderer::Init() {
// create dynamic light pool
for( int idx = 0; idx < Global::DynamicLightCount; ++idx ) {
opengl_light light;
light.id = GL_LIGHT1 + idx;
light.position[ 3 ] = 1.0f;
::glLightf( light.id, GL_SPOT_CUTOFF, 20.0f );
::glLightf( light.id, GL_SPOT_EXPONENT, 10.0f );
::glLightf( light.id, GL_CONSTANT_ATTENUATION, 0.0f );
::glLightf( light.id, GL_LINEAR_ATTENUATION, 0.035f );
m_lights.emplace_back( light );
}
}
void
opengl_renderer::Update_Lights( light_array const &Lights ) {
int const count = std::min( m_lights.size(), Lights.data.size() );
if( count == 0 ) { return; }
auto renderlight = m_lights.begin();
for( auto const &scenelight : Lights.data ) {
if( renderlight == m_lights.end() ) {
// we ran out of lights to assign
break;
}
if( scenelight.intensity == 0.0f ) {
// all lights past this one are bound to be off
break;
}
if( ( Global::pCameraPosition - scenelight.position ).Length() > 1000.0f ) {
// we don't care about lights past arbitrary limit of 1 km.
// but there could still be weaker lights which are closer, so keep looking
continue;
}
// if the light passed tests so far, it's good enough
renderlight->set_position( scenelight.position );
renderlight->direction = scenelight.direction;
renderlight->diffuse[ 0 ] = scenelight.color.x;
renderlight->diffuse[ 1 ] = scenelight.color.y;
renderlight->diffuse[ 2 ] = scenelight.color.z;
renderlight->ambient[ 0 ] = scenelight.color.x * scenelight.intensity;
renderlight->ambient[ 1 ] = scenelight.color.y * scenelight.intensity;
renderlight->ambient[ 2 ] = scenelight.color.z * scenelight.intensity;
::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, 0.3f / std::pow( scenelight.count, 2 ) );
::glEnable( renderlight->id );
renderlight->apply_intensity();
renderlight->apply_angle();
++renderlight;
}
while( renderlight != m_lights.end() ) {
// if we went through all scene lights and there's still opengl lights remaining, kill these
::glDisable( renderlight->id );
++renderlight;
}
}
void
opengl_renderer::Disable_Lights() {
for( int idx = 0; idx < m_lights.size() + 1; ++idx ) {
::glDisable( GL_LIGHT0 + idx );
}
}
//---------------------------------------------------------------------------

View File

@@ -11,6 +11,7 @@ http://mozilla.org/MPL/2.0/.
#include "opengl/glew.h"
#include "texture.h"
#include "lightarray.h"
#include "dumb3d.h"
struct opengl_light {
@@ -23,10 +24,10 @@ struct opengl_light {
GLfloat specular[ 4 ];
opengl_light() {
position[ 0 ] = position[ 1 ] = position[ 2 ] = 0.0f; position[ 3 ] = 1.0f;
ambient[ 0 ] = ambient[ 1 ] = ambient[ 2 ] = 0.0f; ambient[ 3 ] = 1.0f;
diffuse[ 0 ] = diffuse[ 1 ] = diffuse[ 2 ] = diffuse[ 3 ] = 1.0f;
specular[ 0 ] = specular[ 1 ] = specular[ 2 ] = specular[ 3 ] = 1.0f;
position[ 0 ] = position[ 1 ] = position[ 2 ] = 0.0f; position[ 3 ] = 1.0f; // 0,0,0,1
ambient[ 0 ] = ambient[ 1 ] = ambient[ 2 ] = 0.0f; ambient[ 3 ] = 1.0f; // 0,0,0,1
diffuse[ 0 ] = diffuse[ 1 ] = diffuse[ 2 ] = diffuse[ 3 ] = 1.0f; // 1,1,1,1
specular[ 0 ] = specular[ 1 ] = specular[ 2 ] = specular[ 3 ] = 1.0f; // 1,1,1,1
}
inline
@@ -72,33 +73,50 @@ struct opengl_material {
class opengl_renderer {
public:
GLenum static const sunlight{ GL_LIGHT0 };
GLenum static const vehiclelight{ GL_LIGHT1 };
GLenum static const vehiclelightrear{ GL_LIGHT2 };
// types
// methods
void
Init();
void
Update_Lights( light_array const &Lights );
void
Disable_Lights();
texture_manager::size_type
GetTextureId( std::string Filename, std::string const &Dir, int const Filter = -1, bool const Loadnow = true ) {
return m_textures.GetTextureId( Filename, Dir, Filter, Loadnow );
}
void
Bind( texture_manager::size_type const Id ) {
// temporary until we separate the renderer
m_textures.Bind( Id );
}
opengl_texture &
Texture( texture_manager::size_type const Id ) {
return m_textures.Texture( Id );
}
// members
GLenum static const sunlight{ GL_LIGHT0 };
private:
// types
enum class rendermode {
color
};
typedef std::vector<opengl_light> opengllight_array;
// members
rendermode renderpass{ rendermode::color };
opengllight_array m_lights;
texture_manager m_textures;
};

View File

@@ -36,7 +36,7 @@ void TSky::Render( float3 const &Tint )
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
#else
::glEnable( GL_LIGHTING );
::glDisable( GL_LIGHT0 );
GfxRenderer.Disable_Lights();
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, &Tint.x );
#endif
if (Global::bUseVBO)
@@ -56,7 +56,7 @@ void TSky::Render( float3 const &Tint )
#else
GLfloat noambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
::glLightModelfv( GL_LIGHT_MODEL_AMBIENT, noambient );
::glEnable( GL_LIGHT0 );
::glEnable( GL_LIGHT0 ); // other lights will be enabled during lights update
::glDisable( GL_LIGHTING );
#endif
}