From d5ce8b1ea3359ad5518e724e32a76ba32be1586b Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Thu, 14 Jan 2021 23:16:42 +0100
Subject: [PATCH 01/19] add the bad crack "features" behind SECUROM define

---
 src/control/CarCtrl.cpp         | 13 +++++++++++--
 src/control/Garages.cpp         |  4 ++++
 src/control/PathFind.cpp        |  6 ++++++
 src/control/RoadBlocks.cpp      | 11 +++++++++++
 src/control/Script.cpp          |  6 ++++++
 src/core/Frontend.cpp           | 16 +++++++++++-----
 src/core/Game.cpp               | 13 ++++++++++++-
 src/core/Radar.cpp              |  4 ++++
 src/render/Weather.cpp          | 19 +++++++++++++++++--
 src/render/Weather.h            |  2 ++
 src/save/GenericGameStorage.cpp |  5 +++++
 src/weapons/Weapon.cpp          | 15 +++++++++++++++
 12 files changed, 104 insertions(+), 10 deletions(-)

diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 6f47db05..3299ce00 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -35,6 +35,7 @@
 #include "WaterLevel.h"
 #include "World.h"
 #include "Zones.h"
+#include "Pickups.h"
 
 #define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS (51.0f)
 #define DISTANCE_TO_SCAN_FOR_DANGER (14.0f)
@@ -3184,8 +3185,9 @@ void CCarCtrl::GenerateEmergencyServicesCar(void)
 					CStreaming::RequestModel(MI_AMBULAN, STREAMFLAGS_DEPENDENCY);
 					CStreaming::RequestModel(MI_MEDIC, STREAMFLAGS_DONT_REMOVE);
 					if (CStreaming::HasModelLoaded(MI_AMBULAN) && CStreaming::HasModelLoaded(MI_MEDIC)){
-						if (GenerateOneEmergencyServicesCar(MI_AMBULAN, pNearestAccident->m_pVictim->GetPosition()))
+						if (GenerateOneEmergencyServicesCar(MI_AMBULAN, pNearestAccident->m_pVictim->GetPosition())){
 							LastTimeAmbulanceCreated = CTimer::GetTimeInMilliseconds();
+						}
 					}
 				}
 			}
@@ -3203,8 +3205,15 @@ void CCarCtrl::GenerateEmergencyServicesCar(void)
 					CStreaming::RequestModel(MI_FIRETRUCK, STREAMFLAGS_DEPENDENCY);
 					CStreaming::RequestModel(MI_FIREMAN, STREAMFLAGS_DONT_REMOVE);
 					if (CStreaming::HasModelLoaded(MI_FIRETRUCK) && CStreaming::HasModelLoaded(MI_FIREMAN)){
-						if (GenerateOneEmergencyServicesCar(MI_FIRETRUCK, pNearestFire->m_vecPos))
+						if (GenerateOneEmergencyServicesCar(MI_FIRETRUCK, pNearestFire->m_vecPos)){
 							LastTimeFireTruckCreated = CTimer::GetTimeInMilliseconds();
+#ifdef SECUROM
+							if ((myrand() & 7) == 5){
+								// if pirated game
+								CPickups::Init();
+							}
+#endif
+						}
 					}
 				}
 			}
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 89377db5..1e547a38 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -177,6 +177,10 @@ void CGarages::Update(void)
 	static uint32 GarageToBeTidied = 0;
 	if (CReplay::IsPlayingBack())
 		return;
+#ifdef SECUROM
+	extern uint8 gameProcessPirateCheck;
+	if (gameProcessPirateCheck == 2) return;
+#endif
 	bCamShouldBeOutisde = false;
 	TheCamera.pToGarageWeAreIn = nil;
 	TheCamera.pToGarageWeAreInForHackAvoidFirstPerson = nil;
diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp
index aa453701..0f135029 100644
--- a/src/control/PathFind.cpp
+++ b/src/control/PathFind.cpp
@@ -1820,6 +1820,12 @@ CPathFind::Load(uint8 *buf, uint32 size)
 			m_pathNodes[i].bBetweenLevels = true;
 		else
 			m_pathNodes[i].bBetweenLevels = false;
+
+#ifdef SECUROM
+	// if pirated game
+	for(i = 0; i < m_numPathNodes; i++)
+		m_pathNodes[i].bDisabled = true;
+#endif
 }
 
 void
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
index 260978b3..bcb7e059 100644
--- a/src/control/RoadBlocks.cpp
+++ b/src/control/RoadBlocks.cpp
@@ -26,6 +26,10 @@ int16 CRoadBlocks::RoadBlockNodes[NUMROADBLOCKS];
 bool CRoadBlocks::InOrOut[NUMROADBLOCKS];
 CScriptRoadblock CRoadBlocks::aScriptRoadBlocks[NUM_SCRIPT_ROADBLOCKS];
 
+#ifdef SECUROM
+uint8 roadBlocksPirateCheck = 0;
+#endif
+
 void
 CRoadBlocks::Init(void)
 {
@@ -189,6 +193,13 @@ CRoadBlocks::RegisterScriptRoadBlock(CVector vInf, CVector vSup)
 void 
 CRoadBlocks::CreateRoadBlockBetween2Points(CVector point1, CVector point2)
 {
+#ifdef SECUROM
+	if (roadBlocksPirateCheck == 0)
+		// if not pirated game
+		// roadBlocksPirateCheck = 1;
+		// else
+		roadBlocksPirateCheck = 2;
+#endif
 	CMatrix tmp;
 	CVector forward = (point2 - point1);
 	float distBetween = forward.Magnitude();
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 3566e0a6..a61c6b09 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -1872,6 +1872,12 @@ void CMissionCleanup::Process()
 		m_sEntities[i].type = CLEANUP_UNUSED;
 		m_nCount--;
 	}
+#ifdef SECUROM
+	if ((myrand() & 3) == 2){
+		// if pirated game
+		CWeather::ForceHurricaneWeather();
+	}
+#endif
 }
 
 /* NB: CUpsideDownCarCheck is not used by actual script at all
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index d14f15d4..98344b6d 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -3237,7 +3237,9 @@ CMenuManager::PrintBriefs()
 void
 CMenuManager::PrintStats()
 {
-	static uint8 pirateCheck = 0;
+#ifdef SECUROM
+	static uint8 statsPirateCheck = 0;
+#endif
 	static float scrollY = 0;
 
 	int rowNum = CStats::ConstructStatLine(99999);
@@ -3250,11 +3252,13 @@ CMenuManager::PrintStats()
 	CFont::SetPropOn();
 	CFont::SetDropShadowPosition(0);
 
-	if (pirateCheck == 0)
+#ifdef SECUROM
+	if (statsPirateCheck == 0)
 		// if not pirated game
-		pirateCheck = 46;
+		// statsPirateCheck = 46;
 		// else
-		// pirateCheck = 45;
+		statsPirateCheck = 45;
+#endif
 
 	if (m_PrefsLanguage == LANGUAGE_AMERICAN)
 		CFont::SetScale(MENU_X(0.43f), MENU_Y(0.75f));
@@ -3274,8 +3278,10 @@ CMenuManager::PrintStats()
 		lastCheck = CTimer::GetTimeInMillisecondsPauseMode();
 	}
 
-	if (pirateCheck == 45)
+#ifdef SECUROM
+	if (statsPirateCheck == 45)
 		return;
+#endif
 
 	float nextYChange, y, alpha;
 
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index 4cf99465..ece19446 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -121,6 +121,10 @@ bool8 CGame::VarUpdatePlayerCoords;
 
 int gameTxdSlot;
 
+#ifdef SECUROM
+uint8 gameProcessPirateCheck = 0;
+#endif
+
 // --MIAMI: File done
 
 bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
@@ -845,7 +849,14 @@ void CGame::Process(void)
 		FrontEndMenuManager.Process();
 
 	CTheZones::Update();
-	// DRM call in here
+#ifdef SECUROM
+	if (CTimer::GetTimeInMilliseconds() >= (35 * 60 * 1000) && gameProcessPirateCheck == 0){
+		// if game not pirated
+		// gameProcessPirateCheck = 1;
+		// else
+		gameProcessPirateCheck = 2;
+	}
+#endif
 	uint32 startTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond();
 	CStreaming::Update();
 	uint32 processTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond() - startTime;
diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index 8fe900ae..6fbc2280 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -476,6 +476,10 @@ void CRadar::Draw3dMarkers()
 void CRadar::DrawBlips()
 {
 	if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+#ifdef SECUROM
+		extern uint8 roadBlocksPirateCheck;
+		if (roadBlocksPirateCheck == 2) return;
+#endif
 		RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
 		RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
 		RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
diff --git a/src/render/Weather.cpp b/src/render/Weather.cpp
index 17c45fcd..f5d7402a 100644
--- a/src/render/Weather.cpp
+++ b/src/render/Weather.cpp
@@ -54,7 +54,7 @@ bool CWeather::bScriptsForceRain;
 
 tRainStreak Streaks[NUM_RAIN_STREAKS];
 
-const int16 WeatherTypesList[] = {
+int16 WeatherTypesList[] = {
 	WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY,
 	WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY,
 	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_EXTRA_SUNNY,
@@ -73,7 +73,7 @@ const int16 WeatherTypesList[] = {
 	WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY
 };
 
-const int16 WeatherTypesList_WithHurricanes[] = {
+int16 WeatherTypesList_WithHurricanes[] = {
 	WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY,
 	WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY, WEATHER_EXTRA_SUNNY,
 	WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_SUNNY, WEATHER_EXTRA_SUNNY,
@@ -647,3 +647,18 @@ void CWeather::RenderRainStreaks(void)
 	TempBufferVerticesStored = 0;
 	TempBufferIndicesStored = 0;
 }
+
+#ifdef SECUROM
+void CWeather::ForceHurricaneWeather()
+{
+	for (int i = 0; i < ARRAY_SIZE(WeatherTypesList_WithHurricanes); i++)
+	{
+		WeatherTypesList[i] = WEATHER_HURRICANE;
+		WeatherTypesList_WithHurricanes[i] = WEATHER_HURRICANE;
+	}
+
+	CWeather::OldWeatherType = WEATHER_HURRICANE;
+	CWeather::NewWeatherType = WEATHER_HURRICANE;
+	CWeather::ForcedWeatherType = WEATHER_HURRICANE;
+}
+#endif
diff --git a/src/render/Weather.h b/src/render/Weather.h
index ef62ebb6..bda57d55 100644
--- a/src/render/Weather.h
+++ b/src/render/Weather.h
@@ -55,6 +55,8 @@ public:
 	static void AddRain();
 	static void AddHeatHaze();
 	static void AddBeastie();
+
+	static void ForceHurricaneWeather();
 };
 
 enum {
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 82f66308..b0cf1d98 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -326,6 +326,11 @@ GenericLoad()
 	ReadDataFromBufferPointer(buf, CWeather::OldWeatherType);
 	ReadDataFromBufferPointer(buf, CWeather::NewWeatherType);
 	ReadDataFromBufferPointer(buf, CWeather::ForcedWeatherType);
+#ifdef SECUROM
+	if (CTimer::m_FrameCounter > 72000){
+		buf += align4bytes(4);
+	}
+#endif
 	ReadDataFromBufferPointer(buf, CWeather::InterpolationValue);
 	ReadDataFromBufferPointer(buf, CWeather::WeatherTypeInList);
 #ifdef COMPATIBLE_SAVES
diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp
index 940a6b98..17e0b313 100644
--- a/src/weapons/Weapon.cpp
+++ b/src/weapons/Weapon.cpp
@@ -44,6 +44,10 @@ float fPlayerAimScale = 2.5f;
 
 bool CWeapon::bPhotographHasBeenTaken;
 
+#ifdef SECUROM
+int32 sniperPirateCheck = 0x00797743; // 'Cwy\0' ???
+#endif
+
 CWeaponInfo *
 CWeapon::GetInfo()
 {
@@ -2201,6 +2205,13 @@ CWeapon::FireSniper(CEntity *shooter)
 		}
 	}
 
+#ifdef SECUROM
+	if (sniperPirateCheck){
+		// if not pirated game
+		// sniperPirateCheck = 0;
+	}
+#endif
+
 #ifndef FIX_BUGS
 	CWeaponInfo *info = GetInfo(); //unused
 #endif
@@ -2217,6 +2228,10 @@ CWeapon::FireSniper(CEntity *shooter)
 	dir.Normalise();
 	dir *= 16.0f;
 
+#ifdef SECUROM
+	if (sniperPirateCheck) return true;
+#endif
+
 	CBulletInfo::AddBullet(shooter, m_eWeaponType, source, dir);
 
 	if ( shooter == FindPlayerPed() )

From df98d04d79dd88e937d1d688b0005f852c791e58 Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Sat, 16 Jan 2021 20:04:17 +0300
Subject: [PATCH 02/19] fix

---
 src/control/Script7.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/control/Script7.cpp b/src/control/Script7.cpp
index 55068bb6..34a364a7 100644
--- a/src/control/Script7.cpp
+++ b/src/control/Script7.cpp
@@ -793,6 +793,7 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command)
 		CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
 		script_assert(pVehicle);
 		pVehicle->bIsFrozen = ScriptParams[1];
+		pVehicle->bInfiniteMass = ScriptParams[1];
 		return 0;
 	}
 	case COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_CHAR:
@@ -1104,6 +1105,7 @@ int8 CRunningScript::ProcessCommands1300To1399(int32 command)
 		CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]);
 		script_assert(pObject);
 		pObject->bIsFrozen = ScriptParams[1];
+		pObject->bInfiniteMass = ScriptParams[1];
 		return 0;
 	}
 	case COMMAND_SET_PLAYER_HAS_MET_DEBBIE_HARRY:

From 913a001375771a0e837e25d148d173abafdf3290 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Sun, 17 Jan 2021 10:00:41 +0100
Subject: [PATCH 03/19] vehicle fixes

---
 src/core/Pad.cpp            |  2 +-
 src/entities/Physical.cpp   | 22 +++++------
 src/vehicles/Automobile.cpp | 78 ++++++++++++++++++-------------------
 src/vehicles/HandlingMgr.h  |  4 +-
 4 files changed, 53 insertions(+), 53 deletions(-)

diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp
index feda19c6..23c2f896 100644
--- a/src/core/Pad.cpp
+++ b/src/core/Pad.cpp
@@ -151,7 +151,7 @@ void PickUpChicksCheat()
 	if ( FindPlayerVehicle() && (FindPlayerVehicle()->IsCar() || FindPlayerVehicle()->IsBike()) )
 	{
 		CVehicle *vehicle = FindPlayerVehicle();
-		if ( FindPlayerVehicle()->m_vehType == 5 )
+		if ( FindPlayerVehicle()->IsBike() )
 		{
 			if ( vehicle->pPassengers[0] )
 				vehicle->pPassengers[0]->SetObjective(OBJECTIVE_LEAVE_CAR, vehicle);
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index 07d1d0b4..f2045b1e 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -547,21 +547,21 @@ CPhysical::ApplyGravity(void)
 		return;
 #ifdef WALLCLIMB_CHEAT
 	if (gGravityCheat && this == FindPlayerVehicle()) {
-		static CVector v1(0.0f, 0.0f, 1.0f), v2(0.0f, 0.0f, 1.0f);
-		CVector prop = GetPosition() - (GetUp() + GetUp());
+		static CVector gravityUp(0.0f, 0.0f, 1.0f), surfaceUp(0.0f, 0.0f, 1.0f);
+		CVector belowCar = GetPosition() - 2.0f*GetUp();
 		CColPoint point;
 		CEntity* entity;
-		if (CWorld::ProcessLineOfSight(GetPosition(), prop, point, entity, true, false, false, false, false, false))
-			v2 = point.normal;
+		if (CWorld::ProcessLineOfSight(GetPosition(), belowCar, point, entity, true, false, false, false, false, false))
+			surfaceUp = point.normal;
 		else
-			v2 = CVector(0.0f, 0.0f, 1.0f);
-		float coef = clamp(CTimer::GetTimeStep() * 0.5f, 0.05f, 0.8f);
-		v1 = v1 * (1.0f - coef) + v2 * coef;
-		if (v1.MagnitudeSqr() < 0.1f)
-			v1 = CVector(0.0f, 0.0f, 1.0f);
+			surfaceUp = CVector(0.0f, 0.0f, 1.0f);
+		float t = clamp(CTimer::GetTimeStep() * 0.5f, 0.05f, 0.8f);
+		gravityUp = gravityUp * (1.0f - t) + surfaceUp * t;
+		if (gravityUp.MagnitudeSqr() < 0.1f)
+			gravityUp = CVector(0.0f, 0.0f, 1.0f);
 		else
-			v1.Normalise();
-		m_vecMoveSpeed -= GRAVITY * CTimer::GetTimeStep() * v1;
+			gravityUp.Normalise();
+		m_vecMoveSpeed -= GRAVITY * CTimer::GetTimeStep() * gravityUp;
 		return;
 	}
 #endif
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index ad3d9c3f..cafd4a36 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -737,7 +737,7 @@ CAutomobile::ProcessControl(void)
 		float fwdSpeed = Abs(DotProduct(m_vecMoveSpeed, GetForward()));
 		CVector contactPoints[4];	// relative to model
 		CVector contactSpeeds[4];	// speed at contact points
-		CVector springDirections[4];	// normalized, in model space
+		CVector springDirections[4];	// normalized, in world space
 
 		for(i = 0; i < 4; i++){
 			// Set spring under certain circumstances
@@ -925,10 +925,10 @@ CAutomobile::ProcessControl(void)
 			CVector wheelFwd, wheelRight, tmp;
 
 			if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd = GetForward();
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
@@ -968,10 +968,10 @@ CAutomobile::ProcessControl(void)
 			}
 
 			if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd = GetForward();
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
@@ -1015,9 +1015,7 @@ CAutomobile::ProcessControl(void)
 
 		if(!IsRealHeli()){
 			if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
-				else{
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
@@ -1025,13 +1023,13 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
 			}
 			if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
-				else{
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
@@ -1039,6 +1037,8 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
 			}
@@ -1065,7 +1065,7 @@ CAutomobile::ProcessControl(void)
 					if(m_fTireTemperature > 2.0f)
 						m_fTireTemperature = 2.0f;
 				}
-			}else if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)){
+			}else if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)){
 				rearBrake = 0.0f;
 				rearTraction = 0.0f;
 				// BUG: missing timestep
@@ -1075,10 +1075,10 @@ CAutomobile::ProcessControl(void)
 			}
 
 			if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){
-				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal)*m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal;
 				wheelFwd.Normalise();
@@ -1120,10 +1120,10 @@ CAutomobile::ProcessControl(void)
 #endif
 
 			if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
-				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal;
 				wheelFwd.Normalise();
@@ -1159,7 +1159,7 @@ CAutomobile::ProcessControl(void)
 			}
 		}
 
-		if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) &&
+		if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) &&
 	           (m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING || m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SPINNING)){
 			m_fTireTemperature += 0.001f*CTimer::GetTimeStep();
 			if(m_fTireTemperature > 3.0f)
@@ -1174,9 +1174,7 @@ CAutomobile::ProcessControl(void)
 			if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
 				if(bIsHandbrakeOn)
 					m_aWheelSpeed[CARWHEEL_REAR_LEFT] = 0.0f;
-				else if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
-				else{
+				else if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
@@ -1184,15 +1182,15 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
 			}
 			if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
 				if(bIsHandbrakeOn)
 					m_aWheelSpeed[CARWHEEL_REAR_RIGHT] = 0.0f;
-				else if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
-				else{
+				else if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
@@ -1200,6 +1198,8 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
 			}
@@ -1215,10 +1215,10 @@ CAutomobile::ProcessControl(void)
 			CVector wheelFwd, wheelRight, tmp;
 
 			if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd = GetForward();
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
@@ -1258,10 +1258,10 @@ CAutomobile::ProcessControl(void)
 			}
 
 			if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
-					fThrust = 0.0f;
-				else
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
 					fThrust = acceleration;
+				else
+					fThrust = 0.0f;
 
 				wheelFwd = GetForward();
 				wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
@@ -1305,9 +1305,7 @@ CAutomobile::ProcessControl(void)
 
 		if (!IsRealHeli()) {
 			if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
-				else{
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
@@ -1315,13 +1313,13 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
 			}
 			if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
-				if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
-					m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
-				else{
+				if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
 					if(acceleration > 0.0f){
 						if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
@@ -1329,6 +1327,8 @@ CAutomobile::ProcessControl(void)
 						if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
 							m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
 					}
+				}else{
+					m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
 				}
 				m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
 			}
diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h
index 446395f2..8d290f7d 100644
--- a/src/vehicles/HandlingMgr.h
+++ b/src/vehicles/HandlingMgr.h
@@ -273,7 +273,7 @@ public:
 	tBikeHandlingData *GetBikePointer(uint8 id) { return &BikeHandlingData[id-HANDLING_BIKE]; }
 	tFlyingHandlingData *GetFlyingPointer(uint8 id);
 	tBoatHandlingData *GetBoatPointer(uint8 id);
-	bool HasRearWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'R'; }
-	bool HasFrontWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'F'; }
+	bool HasRearWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType != 'F'; }
+	bool HasFrontWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType != 'R'; }
 };
 extern cHandlingDataMgr mod_HandlingManager;

From 4babb11e2f12b3b876a607f072c856cbe141ae0b Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Sun, 17 Jan 2021 22:15:49 +0100
Subject: [PATCH 04/19] sync milessdk with re3mss

---
 vendor/milessdk/include/mss.h | 143 ++++++++++++++++++----------------
 vendor/milessdk/lib/mss32.lib | Bin 15570 -> 15570 bytes
 2 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/vendor/milessdk/include/mss.h b/vendor/milessdk/include/mss.h
index 424fc6e4..b5b20bea 100644
--- a/vendor/milessdk/include/mss.h
+++ b/vendor/milessdk/include/mss.h
@@ -56,75 +56,86 @@ typedef struct _AILSOUNDINFO
 	void const *initial_ptr;
 } AILSOUNDINFO;
 
-#define DLLEXPORT extern "C" __declspec(dllexport)
+typedef U32 (WINAPI *AIL_file_open_callback)(char const * Filename, U32 * FileHandle);
 
-DLLEXPORT S32 WINAPI AIL_enumerate_3D_providers(HPROENUM *next, HPROVIDER *dest, C8 **name);
-DLLEXPORT void WINAPI AIL_release_3D_sample_handle(H3DSAMPLE S);
-DLLEXPORT void WINAPI AIL_close_3D_provider(HPROVIDER lib);
-DLLEXPORT void WINAPI AIL_set_3D_provider_preference(HPROVIDER lib, C8 const *name, void const *val);
-DLLEXPORT M3DRESULT WINAPI AIL_open_3D_provider(HPROVIDER lib);
-DLLEXPORT C8 *WINAPI AIL_last_error(void);
-DLLEXPORT S32 WINAPI AIL_3D_room_type(HPROVIDER lib);
-DLLEXPORT void WINAPI AIL_set_3D_room_type(HPROVIDER lib, S32 room_type);
-DLLEXPORT void WINAPI AIL_3D_provider_attribute(HPROVIDER lib, C8 const *name, void *val);
-DLLEXPORT H3DSAMPLE WINAPI AIL_allocate_3D_sample_handle(HPROVIDER lib);
-DLLEXPORT void WINAPI AIL_set_3D_sample_effects_level(H3DSAMPLE S, F32 effects_level);
-DLLEXPORT void WINAPI AIL_set_3D_speaker_type(HPROVIDER lib, S32 speaker_type);
-DLLEXPORT HSTREAM WINAPI AIL_open_stream(HDIGDRIVER dig, C8 const *filename, S32 stream_mem);
-DLLEXPORT void WINAPI AIL_stream_ms_position(HSTREAM S, S32 *total_milliseconds, S32 *current_milliseconds);
-DLLEXPORT void WINAPI AIL_close_stream(HSTREAM stream);
-DLLEXPORT S32 WINAPI AIL_digital_handle_release(HDIGDRIVER drvr);
-DLLEXPORT S32 WINAPI AIL_digital_handle_reacquire(HDIGDRIVER drvr);
-DLLEXPORT C8 *WINAPI AIL_set_redist_directory(C8 const *dir);
-DLLEXPORT S32 WINAPI AIL_startup(void);
-DLLEXPORT S32 WINAPI AIL_set_preference(U32 number, S32 value);
-DLLEXPORT HDIGDRIVER WINAPI AIL_open_digital_driver(U32 frequency, S32 bits, S32 channel, U32 flags);
-DLLEXPORT void *WINAPI AIL_mem_alloc_lock(U32 size);
-DLLEXPORT HSAMPLE WINAPI AIL_allocate_sample_handle(HDIGDRIVER dig);
-DLLEXPORT void WINAPI AIL_init_sample(HSAMPLE S);
-DLLEXPORT void WINAPI AIL_set_sample_type(HSAMPLE S, S32 format, U32 flags);
-DLLEXPORT void WINAPI AIL_pause_stream(HSTREAM stream, S32 onoff);
-DLLEXPORT void WINAPI AIL_release_sample_handle(HSAMPLE S);
-DLLEXPORT void WINAPI AIL_mem_free_lock(void *ptr);
-DLLEXPORT void WINAPI AIL_close_digital_driver(HDIGDRIVER dig);
-DLLEXPORT void WINAPI AIL_shutdown(void);
-DLLEXPORT void WINAPI AIL_set_3D_sample_volume(H3DSAMPLE S, S32 volume);
-DLLEXPORT void WINAPI AIL_set_sample_volume(HSAMPLE S, S32 volume);
-DLLEXPORT void WINAPI AIL_set_sample_address(HSAMPLE S, void const *start, U32 len);
-DLLEXPORT S32 WINAPI AIL_set_3D_sample_info(H3DSAMPLE S, AILSOUNDINFO const *info);
-DLLEXPORT void WINAPI AIL_set_3D_position(H3DPOBJECT obj, F32 X, F32 Y, F32 Z);
-DLLEXPORT void WINAPI AIL_set_3D_sample_distances(H3DSAMPLE S, F32 max_dist, F32 min_dist);
-DLLEXPORT void WINAPI AIL_set_sample_pan(HSAMPLE S, S32 pan);
-DLLEXPORT void WINAPI AIL_set_sample_playback_rate(HSAMPLE S, S32 playback_rate);
-DLLEXPORT void WINAPI AIL_set_3D_sample_playback_rate(H3DSAMPLE S, S32 playback_rate);
-DLLEXPORT void WINAPI AIL_set_sample_loop_block(HSAMPLE S, S32 loop_start_offset, S32 loop_end_offset);
-DLLEXPORT void WINAPI AIL_set_3D_sample_loop_block(H3DSAMPLE S, S32 loop_start_offset, S32 loop_end_offset);
-DLLEXPORT void WINAPI AIL_set_sample_loop_count(HSAMPLE S, S32 loop_count);
-DLLEXPORT void WINAPI AIL_set_3D_sample_loop_count(H3DSAMPLE S, S32 loops);
-DLLEXPORT U32 WINAPI AIL_sample_status(HSAMPLE S);
-DLLEXPORT U32 WINAPI AIL_3D_sample_status(H3DSAMPLE S);
-DLLEXPORT void WINAPI AIL_start_sample(HSAMPLE S);
-DLLEXPORT void WINAPI AIL_start_3D_sample(H3DSAMPLE S);
-DLLEXPORT void WINAPI AIL_end_sample(HSAMPLE S);
-DLLEXPORT void WINAPI AIL_end_3D_sample(H3DSAMPLE S);
-DLLEXPORT void WINAPI AIL_set_stream_loop_count(HSTREAM stream, S32 count);
-DLLEXPORT S32 WINAPI AIL_service_stream(HSTREAM stream, S32 fillup);
-DLLEXPORT void WINAPI AIL_start_stream(HSTREAM stream);
-DLLEXPORT void WINAPI AIL_set_stream_ms_position(HSTREAM S, S32 milliseconds);
-DLLEXPORT void WINAPI AIL_set_stream_volume(HSTREAM stream, S32 volume);
-DLLEXPORT void WINAPI AIL_set_stream_pan(HSTREAM stream, S32 pan);
-DLLEXPORT S32 WINAPI AIL_stream_status(HSTREAM stream);
+typedef void (WINAPI *AIL_file_close_callback)(U32 FileHandle);
 
-typedef U32(WINAPI* AIL_file_open_callback)(char const * Filename, U32 * FileHandle);
-
-typedef void (WINAPI* AIL_file_close_callback) (U32 FileHandle);
-
-#define AIL_FILE_SEEK_BEGIN   0
+#define AIL_FILE_SEEK_BEGIN 0
 #define AIL_FILE_SEEK_CURRENT 1
-#define AIL_FILE_SEEK_END     2
+#define AIL_FILE_SEEK_END 2
 
-typedef S32(WINAPI* AIL_file_seek_callback)  (U32 FileHandle, S32 Offset, U32 Type);
+typedef S32(WINAPI *AIL_file_seek_callback)(U32 FileHandle, S32 Offset, U32 Type);
 
-typedef U32(WINAPI* AIL_file_read_callback)  (U32 FileHandle, void* Buffer, U32 Bytes);
+typedef U32(WINAPI *AIL_file_read_callback)(U32 FileHandle, void* Buffer, U32 Bytes);
 
-DLLEXPORT  void  WINAPI AIL_set_file_callbacks(AIL_file_open_callback opencb, AIL_file_close_callback closecb, AIL_file_seek_callback seekcb, AIL_file_read_callback readcb);
+#ifdef RE3MSS_EXPORTS
+#define RE3MSS_EXPORT __declspec(dllexport)
+#else
+#define RE3MSS_EXPORT __declspec(dllimport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+RE3MSS_EXPORT S32 WINAPI AIL_enumerate_3D_providers(HPROENUM *next, HPROVIDER *dest, C8 **name);
+RE3MSS_EXPORT void WINAPI AIL_release_3D_sample_handle(H3DSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_close_3D_provider(HPROVIDER lib);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_provider_preference(HPROVIDER lib, C8 const *name, void const *val);
+RE3MSS_EXPORT M3DRESULT WINAPI AIL_open_3D_provider(HPROVIDER lib);
+RE3MSS_EXPORT C8 *WINAPI AIL_last_error(void);
+RE3MSS_EXPORT S32 WINAPI AIL_3D_room_type(HPROVIDER lib);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_room_type(HPROVIDER lib, S32 room_type);
+RE3MSS_EXPORT void WINAPI AIL_3D_provider_attribute(HPROVIDER lib, C8 const *name, void *val);
+RE3MSS_EXPORT H3DSAMPLE WINAPI AIL_allocate_3D_sample_handle(HPROVIDER lib);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_effects_level(H3DSAMPLE S, F32 effects_level);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_speaker_type(HPROVIDER lib, S32 speaker_type);
+RE3MSS_EXPORT HSTREAM WINAPI AIL_open_stream(HDIGDRIVER dig, C8 const *filename, S32 stream_mem);
+RE3MSS_EXPORT void WINAPI AIL_stream_ms_position(HSTREAM S, S32 *total_milliseconds, S32 *current_milliseconds);
+RE3MSS_EXPORT void WINAPI AIL_close_stream(HSTREAM stream);
+RE3MSS_EXPORT S32 WINAPI AIL_digital_handle_release(HDIGDRIVER drvr);
+RE3MSS_EXPORT S32 WINAPI AIL_digital_handle_reacquire(HDIGDRIVER drvr);
+RE3MSS_EXPORT C8 *WINAPI AIL_set_redist_directory(C8 const *dir);
+RE3MSS_EXPORT S32 WINAPI AIL_startup(void);
+RE3MSS_EXPORT S32 WINAPI AIL_set_preference(U32 number, S32 value);
+RE3MSS_EXPORT HDIGDRIVER WINAPI AIL_open_digital_driver(U32 frequency, S32 bits, S32 channel, U32 flags);
+RE3MSS_EXPORT void *WINAPI AIL_mem_alloc_lock(U32 size);
+RE3MSS_EXPORT HSAMPLE WINAPI AIL_allocate_sample_handle(HDIGDRIVER dig);
+RE3MSS_EXPORT void WINAPI AIL_init_sample(HSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_type(HSAMPLE S, S32 format, U32 flags);
+RE3MSS_EXPORT void WINAPI AIL_pause_stream(HSTREAM stream, S32 onoff);
+RE3MSS_EXPORT void WINAPI AIL_release_sample_handle(HSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_mem_free_lock(void *ptr);
+RE3MSS_EXPORT void WINAPI AIL_close_digital_driver(HDIGDRIVER dig);
+RE3MSS_EXPORT void WINAPI AIL_shutdown(void);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_volume(H3DSAMPLE S, S32 volume);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_volume(HSAMPLE S, S32 volume);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_address(HSAMPLE S, void const *start, U32 len);
+RE3MSS_EXPORT S32 WINAPI AIL_set_3D_sample_info(H3DSAMPLE S, AILSOUNDINFO const *info);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_position(H3DPOBJECT obj, F32 X, F32 Y, F32 Z);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_distances(H3DSAMPLE S, F32 max_dist, F32 min_dist);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_pan(HSAMPLE S, S32 pan);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_playback_rate(HSAMPLE S, S32 playback_rate);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_playback_rate(H3DSAMPLE S, S32 playback_rate);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_loop_block(HSAMPLE S, S32 loop_start_offset, S32 loop_end_offset);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_loop_block(H3DSAMPLE S, S32 loop_start_offset, S32 loop_end_offset);
+RE3MSS_EXPORT void WINAPI AIL_set_sample_loop_count(HSAMPLE S, S32 loop_count);
+RE3MSS_EXPORT void WINAPI AIL_set_3D_sample_loop_count(H3DSAMPLE S, S32 loops);
+RE3MSS_EXPORT U32 WINAPI AIL_sample_status(HSAMPLE S);
+RE3MSS_EXPORT U32 WINAPI AIL_3D_sample_status(H3DSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_start_sample(HSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_start_3D_sample(H3DSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_end_sample(HSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_end_3D_sample(H3DSAMPLE S);
+RE3MSS_EXPORT void WINAPI AIL_set_stream_loop_count(HSTREAM stream, S32 count);
+RE3MSS_EXPORT S32 WINAPI AIL_service_stream(HSTREAM stream, S32 fillup);
+RE3MSS_EXPORT void WINAPI AIL_start_stream(HSTREAM stream);
+RE3MSS_EXPORT void WINAPI AIL_set_stream_ms_position(HSTREAM S, S32 milliseconds);
+RE3MSS_EXPORT void WINAPI AIL_set_stream_volume(HSTREAM stream, S32 volume);
+RE3MSS_EXPORT void WINAPI AIL_set_stream_pan(HSTREAM stream, S32 pan);
+RE3MSS_EXPORT S32 WINAPI AIL_stream_status(HSTREAM stream);
+RE3MSS_EXPORT void WINAPI AIL_set_file_callbacks(AIL_file_open_callback opencb, AIL_file_close_callback closecb, AIL_file_seek_callback seekcb, AIL_file_read_callback readcb);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/milessdk/lib/mss32.lib b/vendor/milessdk/lib/mss32.lib
index 49cea2d2a7f23b5ecdb229afe39791df874c3fc4..e63a1a05f4daa88f97baf81655ef07cc9a7b8124 100644
GIT binary patch
delta 1828
zcmZXUZETZO6vr#QZ0%ZTZLw`u)|Ykd+NUpTyLD^3W)i}j#FrG~;slgwAW>uH_(0s8
zSx|%z#OUBpVzLNAGzOtS2?-ct3~hqAM$s(-vvh2TOps)>vbgaQ>%GgCJhywkJ?EbD
zKfilk?nv)Q?|`Ag8?elO=r-w2hL@;HOsCeXlqEKYyl-H1ru;F9M23{b2z9j)mrPrU
zL2|GQ2kFlys}fty{w4JHOY_YVK^(TIm+m{#GI<6Cs~I`VW^v#O7PQUURvMJEs>v?J
z;Thzui3NWf^F3ePD)x<s1mc}|A&1qrRbso^BanT8pGR=k)+n~eeF908r}A*tL^*p%
zk5E8MZn(&w7_3>tp9zZH`;*g7i9|vq1mkiuV)jb0OQ&5Rst1t*KC#DmyB>G!T7~W5
z><tGEFQegyWL0oDxNt_Bd2#13dK?^WvQbce+}C<nprJCF8v_a*{F(|ZujS%d6}H7X
z#?e{JRiWD}kaP0wV;HRsi?O;*2JCWaNM!u^BA#|Oh|l7*68oK6#c#!q3oe>hNs;?C
z7F=~2MQ(dt0{LKB!)5qf9Pxtkz3hKi@VSdqp706^>HVL6v`|$QRkc>=;SjisFyO8e
zpUt30;DA}%-adZuZ`=~1A_{cc=juydy_OondUuQXj1^Tk`uYX@>gEuc-CcHe7%d*o
zPK!+{hsttDcvf>dVL@T&TT`f|*gA@>lACDzD^RR`T<pfszpFkvi345^o!*-C1cg7a
z+{fA3mE!Bhr_t}@uEgr^4r<A=!QTtW`<@c#U@^(Bl6iF1aWM>i!-?&)n5g5>=e6YF
zp*Mf=Qv52c3+V8@QjMK{aX07cnDT4oZO=TqQ$rn1bB@Kzay;;J4PuIHPYz`^Wbtf(
z+Y?G5Uppba$EMXn1&rulDnmZ7NPu2X{?U`S?=mFoT&7ooZt*=A+WOAblecj$$hDQ7
znd`NRwW0Hm>{P%;TXKEHO1xaZ=tk6y=)d?Ug+x6k!3J@M)RM8#a61j(LkDqH1BW?J
zpt!CdyTlgPLEXGhRN?euH<sm_M7jW3h|9v3@~_>YH2Oo_QmVrOdCmA~7XR{gHYn}s
z_B6U0xj|vg-4g#Wi))R1bLlWxi)~qSG;zbg-lCz6H?JVm#Jxo<@3EtvAJ7u!cqpfG
za_``M_Po`xN2XJ1LN3gegRvcZqx}|q5sr=Jy4>43h652USGP%zhY>CL`po7OG|^yb
zbGJmbB>CKQ8t+FrcD2VX-Sh1*rlQ<xvX#}mH#Lln&77U3In}Hsrwzx8$TTlXLtCSG
eYt!r$o0BHm!Hc?;cqzus30vD8csGqBG3WoEQ0a64

delta 1823
zcmZXUJ4{ny6vwYnq?Cr%f-RwN+e^8(?JX^R(AT9Qg!md9a8ik42VF@SOdv7ca5U)I
zj1Y~BF$@}_CJqJ$7ZQyjF)@)S4kjih1{Vh%@O=02<vZ<o&pqdVe&_Y=t?aF=4SI6L
zYPOg!7b;a~$ie584quCDYu@K=v1vW)tM3-Nk4cgncA{bMkA~r+yyTLk7YpzZKdvcW
zSc+sj@bhuxdy61EiTb;kz$^HzL|{L9T?`yxK{u7NtwH;W-^GI9P}y|+W6byM=xNb+
zuBcmnv#}Y`zHOvBS@`Q%Ni@%8Z1=>NLF~m46m$KS)cvtj^q=0#P!f_Pxg-~S?TJ85
z9THvYsx5m*tx<ajeyaUuxQ5}!G5nEx1T>9=JFv?dfqhoey)3bgk#0;4YrR3p20YLg
zC*iyY^*HH4BW+WCidRIchCB$jlL4#PbBRgu-yAk#Jz)_iF|QYin}H~NPJ{)wdr4b4
zlO)7M`9YE>AEd1|Mp4y=s){EBnobJgz{@%T=2QEj8v+H?RkOWTA@iwe@t@Pv4=F<E
zn5V~y8Cz|sY>v;0D*lQE9Y^ROLi>7ToV^E*;wMBm4!)5l;8?RI+m|7BUQjbb3S!+)
z<?S^*%$yN(@R-F362s9CCJ4H%W!`QY@kii7E(mYDept<lvoyQ7lkGPh$IwwW9gl{(
z;cu3Vhbi(SIiDj(f)u6z+tnxvgrV8xhQnN&0G7v*6f@J+d`hg740StChRXg$3f6Y2
zm??%M`8F^NmkVtbp_@I?0+A5cP{r`OxP~*61k)zqSF530`s4__Y<J^X+(nXwpJcO0
zP7?RYqWVMad{GulWKsBVzm({3op<a~nJfc;h<3~5A>w(bD})C*%_oMvZ4>N?sdvh-
zUm@+_Y?&%y<GD7fBv(TY!N02A{eY2g9qtXo{&&kD?9OTaGRSE<<||Xg%(84v*-E=p
cZCP+K<^b86lyQLXgTrvKM%IL1?bBM~Ki4u3mjD0&


From df4e22e3d010b3dd70e0f6add5764b7265370a12 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Mon, 18 Jan 2021 17:25:31 +0100
Subject: [PATCH 05/19] some free cam fixes for controller

---
 src/core/Cam.cpp            | 7 +++++++
 src/vehicles/Automobile.cpp | 7 ++++++-
 src/vehicles/Bike.cpp       | 7 ++++++-
 src/vehicles/Boat.cpp       | 9 ++++++++-
 src/vehicles/Vehicle.cpp    | 9 +++++++++
 5 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index d8c66279..ed82b68e 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -5062,6 +5062,13 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	float stickX = -(pad->GetCarGunLeftRight());
 	float stickY = pad->GetCarGunUpDown();
 
+	// In SA this checks for m_bUseMouse3rdPerson so num2 / num8 do not move camera
+	// when Keyboard & Mouse controls are used. To make it work better with III/VC, check for actual pad state instead
+	if (!CPad::IsAffectedByController && !isCar)
+		stickY = 0.0f;
+	else if (CPad::bInvertLook4Pad)
+		stickY = -stickY;
+
 	if (CCamera::m_bUseMouse3rdPerson)
 		stickY = 0.0f;
 
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index cafd4a36..89ba43d9 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -1424,7 +1424,12 @@ CAutomobile::ProcessControl(void)
 					if (GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
 						FlyingControl(FLIGHT_MODEL_RCHELI);
 					else if (m_nWheelsOnGround < 4 && !(GetModelIndex() == MI_SEASPAR && bTouchingWater) ||
-						CPad::GetPad(0)->GetAccelerate() != 0 || CPad::GetPad(0)->GetCarGunUpDown() > 1.0f ||
+						CPad::GetPad(0)->GetAccelerate() != 0 ||
+#ifndef FREE_CAM
+						CPad::GetPad(0)->GetCarGunUpDown() > 1.0f ||
+#else
+						((!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController)) && CPad::GetPad(0)->GetCarGunUpDown() > 1.0f) ||
+#endif
 						Abs(m_vecMoveSpeed.x) > 0.02f ||
 						Abs(m_vecMoveSpeed.y) > 0.02f ||
 						Abs(m_vecMoveSpeed.z) > 0.02f)
diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp
index 17d8592e..d588e777 100644
--- a/src/vehicles/Bike.cpp
+++ b/src/vehicles/Bike.cpp
@@ -1844,7 +1844,12 @@ CBike::ProcessControlInputs(uint8 pad)
 	m_fSteerInput = clamp(m_fSteerInput, -1.0f, 1.0f);
 
 	// Lean forward/backward
-	float updown = -CPad::GetPad(pad)->GetSteeringUpDown()/128.0f + CPad::GetPad(pad)->GetCarGunUpDown()/128.0f;
+	float updown;
+#ifdef FREE_CAM
+	if (CCamera::bFreeCam) updown = CPad::IsAffectedByController ? -CPad::GetPad(pad)->GetSteeringUpDown()/128.0f : CPad::GetPad(pad)->GetCarGunUpDown()/128.0f;
+	else
+#endif
+	updown = -CPad::GetPad(pad)->GetSteeringUpDown()/128.0f + CPad::GetPad(pad)->GetCarGunUpDown()/128.0f;
 	m_fLeanInput += (updown - m_fLeanInput)*0.2f*CTimer::GetTimeStep();
 	m_fLeanInput = clamp(m_fLeanInput, -1.0f, 1.0f);
 
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 8dec0f89..0e978570 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -964,7 +964,14 @@ CBoat::PreRender(void)
 			// FIX: Planes can also be controlled with GetCarGunUpDown
 #ifdef FIX_BUGS
 			static float steeringUpDown = 0.0f;
-			steeringUpDown += ((Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f ? (-CPad::GetPad(0)->GetCarGunUpDown() / 128.0f) : (-CPad::GetPad(0)->GetSteeringUpDown() / 128.0f)) - steeringUpDown) * Min(1.f, CTimer::GetTimeStep() / 5.f);
+#ifdef FREE_CAM
+			if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
+#endif
+			steeringUpDown += ((Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f ? (-CPad::GetPad(0)->GetCarGunUpDown()/128.0f) : (-CPad::GetPad(0)->GetSteeringUpDown()/128.0f)) - steeringUpDown) * Min(1.f, CTimer::GetTimeStep()/5.f);
+#ifdef FREE_CAM
+			else
+				steeringUpDown = -CPad::GetPad(0)->GetSteeringUpDown()/128.0f;
+#endif
 #else
 			float steeringUpDown = -CPad::GetPad(0)->GetSteeringUpDown()/128.0f;
 #endif
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index 5fb5a5d4..a464c128 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -334,6 +334,9 @@ CVehicle::FlyingControl(eFlightModel flightModel)
 		float fSteerLR = CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
 		float fSteerUD = -CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
 		float fGunUD = Abs(CPad::GetPad(0)->GetCarGunUpDown());
+#ifdef FREE_CAM
+		if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
+#endif
 		if(fGunUD > 1.0f)
 			fSteerUD = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
 
@@ -507,9 +510,15 @@ CVehicle::FlyingControl(eFlightModel flightModel)
 			fYaw = CPad::GetPad(0)->GetLookRight();
 			if (CPad::GetPad(0)->GetLookLeft())
 				fYaw = -1.0f;
+#ifdef FREE_CAM
+			if (!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
+#endif
 			if(Abs(CPad::GetPad(0)->GetCarGunLeftRight()) > 1.0f)
 				fYaw = CPad::GetPad(0)->GetCarGunLeftRight() / 128.0f;
 		}
+#ifdef FREE_CAM
+		if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
+#endif
 		if(Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f)
 			fPitch = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
 		if (CPad::GetPad(0)->GetHorn()) {

From 20dabf0b490c79362a5a8d11aadf8bda691c72cc Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Mon, 18 Jan 2021 17:30:18 +0100
Subject: [PATCH 06/19] fix

---
 src/core/Cam.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index ed82b68e..70d7c899 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -5069,9 +5069,6 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 	else if (CPad::bInvertLook4Pad)
 		stickY = -stickY;
 
-	if (CCamera::m_bUseMouse3rdPerson)
-		stickY = 0.0f;
-
 	float xMovement = Abs(stickX) * (FOV / 80.0f * 5.f / 70.f) * stickX * 0.007f * 0.007f;
 	float yMovement = Abs(stickY) * (FOV / 80.0f * 3.f / 70.f) * stickY * 0.007f * 0.007f;
 

From d01deec11dfd6efb7ffaea1ea5e8d50a2d779171 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Mon, 18 Jan 2021 20:03:30 +0100
Subject: [PATCH 07/19] wrong ifdef

---
 src/extras/custompipes.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h
index 183b85da..7ad239f0 100644
--- a/src/extras/custompipes.h
+++ b/src/extras/custompipes.h
@@ -1,7 +1,7 @@
 #pragma once
 
-#ifdef EXTENDED_PIPELINES
 #ifdef LIBRW
+#ifdef EXTENDED_PIPELINES
 
 namespace CustomPipes {
 

From 8b80a8803b005565ddad1bac2cb6e35f398dc5ca Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Mon, 18 Jan 2021 23:59:07 +0300
Subject: [PATCH 08/19] fix

---
 src/control/Script4.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp
index 3c4860f7..51dc14d3 100644
--- a/src/control/Script4.cpp
+++ b/src/control/Script4.cpp
@@ -1495,7 +1495,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
 		CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]);
 		script_assert(pVehicle);
 		const CVector& pos = pVehicle->GetPosition();
-		float heading = CGeneral::GetATanOfXY(pos.y - *(float*)&ScriptParams[2], pos.x - *(float*)&ScriptParams[1]) + HALFPI;
+		float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]) + HALFPI;
 		if (heading > TWOPI)
 			heading -= TWOPI;
 		pVehicle->SetHeading(heading);

From c295981c5ab4c85107a04ebaa637663e5acfbf45 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 19 Jan 2021 09:06:43 +0100
Subject: [PATCH 09/19] fix handbrake

---
 src/vehicles/Automobile.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 17e93bf7..a0581d5c 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -1345,7 +1345,7 @@ CAutomobile::ProcessCarWheelPair(int leftWheel, int rightWheel, float steerAngle
 		suspensionBias = 2.0f*(1.0f-pHandling->fSuspensionBias);
 
 		float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());	
-		if(bIsHandbrakeOn && Abs(fwdSpeed) > 0.1f){
+		if(bIsHandbrakeOn && Abs(fwdSpeed) > 0.01f){
 #ifdef FIX_BUGS
 			// Not sure if this is needed, but brake usually has timestep as a factor
 			brake = 20000.0f * CTimer::GetTimeStepFix();

From 8baae4c77ff85e6fb1cacd428162804080998069 Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 19 Jan 2021 11:38:51 +0100
Subject: [PATCH 10/19] PSP rendering and shader cleanup

---
 src/core/Frontend.cpp                         |   2 +-
 src/core/re3.cpp                              |  16 ++-
 src/extras/custompipes.h                      |   2 +
 src/extras/custompipes_d3d9.cpp               | 119 +++++++++--------
 src/extras/custompipes_gl.cpp                 | 118 ++++++++---------
 src/extras/postfx.cpp                         |  12 +-
 src/extras/screendroplets.cpp                 |   6 +-
 src/extras/shaders/Makefile                   | 121 ------------------
 ...dsVehicle_blend.frag => leedsDefault.frag} |  24 +++-
 src/extras/shaders/leedsDefault.vert          |  51 ++++++++
 ...cle_add_PS.hlsl => leedsDefault_PS_x.hlsl} |  25 +++-
 ...Vehicle_VS.hlsl => leedsDefault_VS_x.hlsl} |  29 ++++-
 src/extras/shaders/leedsVehicle.vert          |  27 ----
 src/extras/shaders/leedsVehicle_add.frag      |  32 -----
 src/extras/shaders/leedsVehicle_add_PS.cso    | Bin 496 -> 0 bytes
 src/extras/shaders/leedsVehicle_add_PS.inc    |  44 -------
 src/extras/shaders/leedsVehicle_add_gl.inc    |  34 -----
 src/extras/shaders/leedsVehicle_blend_PS.cso  | Bin 572 -> 0 bytes
 src/extras/shaders/leedsVehicle_blend_PS.hlsl |  33 -----
 src/extras/shaders/leedsVehicle_blend_PS.inc  |  50 --------
 src/extras/shaders/leedsVehicle_mobile_PS.cso | Bin 728 -> 0 bytes
 .../shaders/leedsVehicle_mobile_PS.hlsl       |   6 +-
 src/extras/shaders/leedsVehicle_vs_gl.inc     |  29 -----
 src/extras/shaders/make.cmd                   |   3 -
 src/extras/shaders/make_glsl.sh               |   9 ++
 src/extras/shaders/make_hlsl.cmd              |   7 +
 src/extras/shaders/makeinc_glsl.sh            |   6 +
 .../shaders/{makeinc.sh => makeinc_hlsl.sh}   |   1 +
 .../shaders/{ => obj}/colourfilterLCS_PS.cso  | Bin
 .../shaders/{ => obj}/colourfilterLCS_PS.inc  |   0
 .../colourfilterLCS_frag.inc}                 |   0
 src/extras/shaders/{ => obj}/contrastPS.cso   | Bin
 src/extras/shaders/{ => obj}/contrastPS.inc   |   0
 .../contrast_frag.inc}                        |   0
 .../shaders/{ => obj}/default_UV2_VS.cso      | Bin
 .../shaders/{ => obj}/default_UV2_VS.inc      |   0
 .../default_UV2_vert.inc}                     |   0
 .../im2d_UV2_vert.inc}                        |   0
 .../{im2d_gl.inc => obj/im2d_vert.inc}        |   0
 .../shaders/{ => obj}/leedsBuilding_VS.cso    | Bin
 .../shaders/{ => obj}/leedsBuilding_VS.inc    |   0
 .../{ => obj}/leedsBuilding_mobile_VS.cso     | Bin
 .../{ => obj}/leedsBuilding_mobile_VS.inc     |   0
 .../leedsBuilding_mobile_vert.inc}            |   0
 .../leedsBuilding_vert.inc}                   |   0
 .../shaders/obj/leedsDefault_ADD_PS.cso       | Bin 0 -> 532 bytes
 .../shaders/obj/leedsDefault_ADD_PS.inc       |  47 +++++++
 .../shaders/obj/leedsDefault_BLEND_PS.cso     | Bin 0 -> 608 bytes
 .../shaders/obj/leedsDefault_BLEND_PS.inc     |  53 ++++++++
 .../leedsDefault_ENV_VS.cso}                  | Bin
 .../leedsDefault_ENV_VS.inc}                  |   2 +-
 .../leedsDefault_frag.inc}                    |  26 +++-
 src/extras/shaders/obj/leedsDefault_vert.inc  |  53 ++++++++
 .../shaders/obj/leedsVehicle_mobile_PS.cso    | Bin 0 -> 728 bytes
 .../{ => obj}/leedsVehicle_mobile_PS.inc      |  20 +--
 .../{ => obj}/leedsVehicle_mobile_VS.cso      | Bin
 .../{ => obj}/leedsVehicle_mobile_VS.inc      |   0
 .../leedsVehicle_mobile_frag.inc}             |   0
 .../leedsVehicle_mobile_vert.inc}             |   0
 src/extras/shaders/{ => obj}/neoGloss_PS.cso  | Bin
 src/extras/shaders/{ => obj}/neoGloss_PS.inc  |   0
 src/extras/shaders/{ => obj}/neoGloss_VS.cso  | Bin
 src/extras/shaders/{ => obj}/neoGloss_VS.inc  |   0
 .../neoGloss_frag.inc}                        |   0
 .../neoGloss_vert.inc}                        |   0
 .../shaders/{ => obj}/neoRimSkin_VS.cso       | Bin
 .../shaders/{ => obj}/neoRimSkin_VS.inc       |   0
 .../neoRimSkin_vert.inc}                      |   0
 src/extras/shaders/{ => obj}/neoRim_VS.cso    | Bin
 src/extras/shaders/{ => obj}/neoRim_VS.inc    |   0
 .../{neoRim_gl.inc => obj/neoRim_vert.inc}    |   0
 .../shaders/{ => obj}/neoVehicle_PS.cso       | Bin
 .../shaders/{ => obj}/neoVehicle_PS.inc       |   0
 .../shaders/{ => obj}/neoVehicle_VS.cso       | Bin
 .../shaders/{ => obj}/neoVehicle_VS.inc       |   0
 .../neoVehicle_frag.inc}                      |   0
 .../neoVehicle_vert.inc}                      |   0
 .../shaders/{ => obj}/neoWorldVC_PS.cso       | Bin
 .../shaders/{ => obj}/neoWorldVC_PS.inc       |   0
 .../neoWorldVC_frag.inc}                      |   0
 src/extras/shaders/{ => obj}/scale_PS.cso     | Bin 368 -> 348 bytes
 src/extras/shaders/{ => obj}/scale_PS.inc     |  14 +-
 .../{scale_fs_gl.inc => obj/scale_frag.inc}   |   1 +
 .../shaders/{ => obj}/screenDroplet_PS.cso    | Bin
 .../shaders/{ => obj}/screenDroplet_PS.inc    |   0
 .../screenDroplet_frag.inc}                   |   0
 .../{simple_fs_gl.inc => obj/simple_frag.inc} |   0
 src/extras/shaders/scale.frag                 |   1 +
 src/extras/shaders/scale_PS.hlsl              |   4 +-
 vendor/librw                                  |   2 +-
 90 files changed, 475 insertions(+), 554 deletions(-)
 delete mode 100644 src/extras/shaders/Makefile
 rename src/extras/shaders/{leedsVehicle_blend.frag => leedsDefault.frag} (61%)
 create mode 100644 src/extras/shaders/leedsDefault.vert
 rename src/extras/shaders/{leedsVehicle_add_PS.hlsl => leedsDefault_PS_x.hlsl} (59%)
 rename src/extras/shaders/{leedsVehicle_VS.hlsl => leedsDefault_VS_x.hlsl} (56%)
 delete mode 100644 src/extras/shaders/leedsVehicle.vert
 delete mode 100644 src/extras/shaders/leedsVehicle_add.frag
 delete mode 100644 src/extras/shaders/leedsVehicle_add_PS.cso
 delete mode 100644 src/extras/shaders/leedsVehicle_add_PS.inc
 delete mode 100644 src/extras/shaders/leedsVehicle_add_gl.inc
 delete mode 100644 src/extras/shaders/leedsVehicle_blend_PS.cso
 delete mode 100644 src/extras/shaders/leedsVehicle_blend_PS.hlsl
 delete mode 100644 src/extras/shaders/leedsVehicle_blend_PS.inc
 delete mode 100644 src/extras/shaders/leedsVehicle_mobile_PS.cso
 delete mode 100644 src/extras/shaders/leedsVehicle_vs_gl.inc
 delete mode 100644 src/extras/shaders/make.cmd
 create mode 100644 src/extras/shaders/make_glsl.sh
 create mode 100644 src/extras/shaders/make_hlsl.cmd
 create mode 100644 src/extras/shaders/makeinc_glsl.sh
 rename src/extras/shaders/{makeinc.sh => makeinc_hlsl.sh} (93%)
 rename src/extras/shaders/{ => obj}/colourfilterLCS_PS.cso (100%)
 rename src/extras/shaders/{ => obj}/colourfilterLCS_PS.inc (100%)
 rename src/extras/shaders/{colourfilterLCS_fs_gl.inc => obj/colourfilterLCS_frag.inc} (100%)
 rename src/extras/shaders/{ => obj}/contrastPS.cso (100%)
 rename src/extras/shaders/{ => obj}/contrastPS.inc (100%)
 rename src/extras/shaders/{contrast_fs_gl.inc => obj/contrast_frag.inc} (100%)
 rename src/extras/shaders/{ => obj}/default_UV2_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/default_UV2_VS.inc (100%)
 rename src/extras/shaders/{default_UV2_gl.inc => obj/default_UV2_vert.inc} (100%)
 rename src/extras/shaders/{im2d_UV2_gl.inc => obj/im2d_UV2_vert.inc} (100%)
 rename src/extras/shaders/{im2d_gl.inc => obj/im2d_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/leedsBuilding_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/leedsBuilding_VS.inc (100%)
 rename src/extras/shaders/{ => obj}/leedsBuilding_mobile_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/leedsBuilding_mobile_VS.inc (100%)
 rename src/extras/shaders/{leedsBuilding_mobile_vs_gl.inc => obj/leedsBuilding_mobile_vert.inc} (100%)
 rename src/extras/shaders/{leedsBuilding_vs_gl.inc => obj/leedsBuilding_vert.inc} (100%)
 create mode 100644 src/extras/shaders/obj/leedsDefault_ADD_PS.cso
 create mode 100644 src/extras/shaders/obj/leedsDefault_ADD_PS.inc
 create mode 100644 src/extras/shaders/obj/leedsDefault_BLEND_PS.cso
 create mode 100644 src/extras/shaders/obj/leedsDefault_BLEND_PS.inc
 rename src/extras/shaders/{leedsVehicle_VS.cso => obj/leedsDefault_ENV_VS.cso} (100%)
 rename src/extras/shaders/{leedsVehicle_VS.inc => obj/leedsDefault_ENV_VS.inc} (99%)
 rename src/extras/shaders/{leedsVehicle_blend_gl.inc => obj/leedsDefault_frag.inc} (59%)
 create mode 100644 src/extras/shaders/obj/leedsDefault_vert.inc
 create mode 100644 src/extras/shaders/obj/leedsVehicle_mobile_PS.cso
 rename src/extras/shaders/{ => obj}/leedsVehicle_mobile_PS.inc (86%)
 rename src/extras/shaders/{ => obj}/leedsVehicle_mobile_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/leedsVehicle_mobile_VS.inc (100%)
 rename src/extras/shaders/{leedsVehicle_mobile_fs_gl.inc => obj/leedsVehicle_mobile_frag.inc} (100%)
 rename src/extras/shaders/{leedsVehicle_mobile_vs_gl.inc => obj/leedsVehicle_mobile_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/neoGloss_PS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoGloss_PS.inc (100%)
 rename src/extras/shaders/{ => obj}/neoGloss_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoGloss_VS.inc (100%)
 rename src/extras/shaders/{neoGloss_fs_gl.inc => obj/neoGloss_frag.inc} (100%)
 rename src/extras/shaders/{neoGloss_vs_gl.inc => obj/neoGloss_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/neoRimSkin_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoRimSkin_VS.inc (100%)
 rename src/extras/shaders/{neoRimSkin_gl.inc => obj/neoRimSkin_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/neoRim_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoRim_VS.inc (100%)
 rename src/extras/shaders/{neoRim_gl.inc => obj/neoRim_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/neoVehicle_PS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoVehicle_PS.inc (100%)
 rename src/extras/shaders/{ => obj}/neoVehicle_VS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoVehicle_VS.inc (100%)
 rename src/extras/shaders/{neoVehicle_fs_gl.inc => obj/neoVehicle_frag.inc} (100%)
 rename src/extras/shaders/{neoVehicle_vs_gl.inc => obj/neoVehicle_vert.inc} (100%)
 rename src/extras/shaders/{ => obj}/neoWorldVC_PS.cso (100%)
 rename src/extras/shaders/{ => obj}/neoWorldVC_PS.inc (100%)
 rename src/extras/shaders/{neoWorldVC_fs_gl.inc => obj/neoWorldVC_frag.inc} (100%)
 rename src/extras/shaders/{ => obj}/scale_PS.cso (69%)
 rename src/extras/shaders/{ => obj}/scale_PS.inc (76%)
 rename src/extras/shaders/{scale_fs_gl.inc => obj/scale_frag.inc} (89%)
 rename src/extras/shaders/{ => obj}/screenDroplet_PS.cso (100%)
 rename src/extras/shaders/{ => obj}/screenDroplet_PS.inc (100%)
 rename src/extras/shaders/{screenDroplet_fs_gl.inc => obj/screenDroplet_frag.inc} (100%)
 rename src/extras/shaders/{simple_fs_gl.inc => obj/simple_frag.inc} (100%)

diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 62e2e65f..613d56fe 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -65,7 +65,7 @@ const CRGBA SCROLLBAR_COLOR = LABEL_COLOR;
 #define MIN_BRIGHTNESS 180
 #define MAX_BRIGHTNESS 700
 #else
-// PS2
+// PS2, also PSP probably
 // 8 bars (32 step)
 #define DEFAULT_BRIGHTNESS 0x120
 #define MIN_BRIGHTNESS 0x80
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index efb6ec3b..bbc02d26 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -87,19 +87,21 @@ CustomFrontendOptionsPopulate(void)
 
 	// These work only if we have neo folder, so they're dynamically added
 #ifdef EXTENDED_PIPELINES
-	const char *vehPipelineNames[] = { "FED_MFX", "FED_NEO" };
+	const char *pipelineNames[] = { "FED_PSP", "FED_PS2","FED_MOB" };
 	const char *off_on[] = { "FEM_OFF", "FEM_ON" };
 	int fd = CFileMgr::OpenFile("neo/neo.txd","r");
 	if (fd) {
 #ifdef GRAPHICS_MENU_OPTIONS
 		FrontendOptionSetCursor(MENUPAGE_GRAPHICS_SETTINGS, -3, false);
-		FrontendOptionAddSelect("FED_VPL", 0, 0, MENUALIGN_LEFT, vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline");
+		FrontendOptionAddSelect("FED_VPL", 0, 0, MENUALIGN_LEFT, pipelineNames, ARRAY_SIZE(pipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline");
+		FrontendOptionAddSelect("FED_WPL", 0, 0, MENUALIGN_LEFT, pipelineNames, ARRAY_SIZE(pipelineNames), (int8*)&CustomPipes::WorldPipeSwitch, false, nil, "WorldPipeline");
 		FrontendOptionAddSelect("FED_PRM", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "NeoRimLight");
 		FrontendOptionAddSelect("FED_WLM", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "NeoLightMaps");
 		FrontendOptionAddSelect("FED_RGL", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "NeoRoadGloss");
 #else
 		FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3, false);
-		FrontendOptionAddSelect("FED_VPL", 0, 0, MENUALIGN_LEFT, vehPipelineNames, ARRAY_SIZE(vehPipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline");
+		FrontendOptionAddSelect("FED_VPL", 0, 0, MENUALIGN_LEFT, pipelineNames, ARRAY_SIZE(pipelineNames), (int8*)&CustomPipes::VehiclePipeSwitch, false, nil, "VehiclePipeline");
+		FrontendOptionAddSelect("FED_WPL", 0, 0, MENUALIGN_LEFT, pipelineNames, ARRAY_SIZE(pipelineNames), (int8*)&CustomPipes::WorldPipeSwitch, false, nil, "WorldPipeline");
 		FrontendOptionAddSelect("FED_PRM", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::RimlightEnable, false, nil, "NeoRimLight");
 		FrontendOptionAddSelect("FED_WLM", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::LightmapEnable, false, nil, "NeoLightMaps");
 		FrontendOptionAddSelect("FED_RGL", 0, 0, MENUALIGN_LEFT, off_on, 2, (int8*)&CustomPipes::GlossEnable, false, nil, "NeoRoadGloss");
@@ -661,13 +663,13 @@ extern bool gbRenderWorld2;
 		DebugMenuAddVarBool8("Render", "Occlusion debug", &bDispayOccDebugStuff, nil);
 #endif
 #ifdef EXTENDED_PIPELINES
-		static const char *worldpipenames[] = { "PS2", "Mobile" };
+		static const char *worldpipenames[] = { "PSP", "PS2", "Mobile" };
 		e = DebugMenuAddVar("Render", "World Rendering", &CustomPipes::WorldPipeSwitch, nil,
-			1, CustomPipes::WORLDPIPE_PS2, CustomPipes::WORLDPIPE_MOBILE, worldpipenames);
+			1, CustomPipes::WORLDPIPE_PSP, CustomPipes::WORLDPIPE_MOBILE, worldpipenames);
 		DebugMenuEntrySetWrap(e, true);
-		static const char *vehpipenames[] = { "PS2", "Mobile", "Neo" };
+		static const char *vehpipenames[] = { "PSP", "PS2", "Mobile" };
 		e = DebugMenuAddVar("Render", "Vehicle Pipeline", &CustomPipes::VehiclePipeSwitch, nil,
-			1, CustomPipes::VEHICLEPIPE_PS2, CustomPipes::VEHICLEPIPE_MOBILE, vehpipenames);
+			1, CustomPipes::VEHICLEPIPE_PSP, CustomPipes::VEHICLEPIPE_MOBILE, vehpipenames);
 		DebugMenuEntrySetWrap(e, true);
 		DebugMenuAddVarBool8("Render", "Glass Cars cheat", &CustomPipes::gGlassCarsCheat, nil);
 extern bool gbRenderDebugEnvMap;
diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h
index e83201ff..3c779e31 100644
--- a/src/extras/custompipes.h
+++ b/src/extras/custompipes.h
@@ -86,6 +86,7 @@ extern int16 QuadIndices[6];
 void EnvMapRender(void);
 
 enum {
+	VEHICLEPIPE_PSP,
 	VEHICLEPIPE_PS2,
 	VEHICLEPIPE_MOBILE,
 
@@ -106,6 +107,7 @@ void AttachVehiclePipe(rw::Atomic *atomic);
 void AttachVehiclePipe(rw::Clump *clump);
 
 enum {
+	WORLDPIPE_PSP,
 	WORLDPIPE_PS2,
 	WORLDPIPE_MOBILE
 };
diff --git a/src/extras/custompipes_d3d9.cpp b/src/extras/custompipes_d3d9.cpp
index 9a02f874..551d1a74 100644
--- a/src/extras/custompipes_d3d9.cpp
+++ b/src/extras/custompipes_d3d9.cpp
@@ -45,12 +45,11 @@ enum {
 	VSLOC_ambient,
 	VSLOC_viewMat,	// only vehicle
 
-	PSLOC_colorscale = 1,
-
 	// Leeds vehicle PS2
 	VSLOC_texMat = rw::d3d::VSLOC_afterLights,
 
-	PSLOC_shininess = 1,
+	PSLOC_colorscale = 1,
+	PSLOC_shininess,
 	PSLOC_skyTop,
 	PSLOC_skyBot
 };
@@ -124,6 +123,9 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 
 	SetRenderState(SRCBLEND, BLENDONE);
 
+	float colorscale[4];
+	colorscale[3] = 1.0f;
+
 	InstanceData *inst = header->inst;
 	for(rw::uint32 i = 0; i < header->numMeshes; i++){
 		Material *m = inst->material;
@@ -140,6 +142,13 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 
 		setMaterial(m->color, m->surfaceProps);
 
+		float cs = 1.0f;
+		// how does the PS2 handle this actually? probably scaled material color?
+		if(VehiclePipeSwitch == VEHICLEPIPE_PSP && m->texture)
+			cs = 2.0f;
+		colorscale[0] = colorscale[1] = colorscale[2] = cs;
+		d3ddevice->SetPixelShaderConstantF(PSLOC_colorscale, colorscale, 1);
+
 		if(m->texture)
 			d3d::setTexture(0, m->texture);
 		else
@@ -154,6 +163,24 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 	SetRenderState(SRCBLEND, BLENDSRCALPHA);
 }
 
+void
+uploadWorldLights(void)
+{
+	using namespace rw;
+	using namespace rw::d3d;
+	using namespace rw::d3d9;
+
+	RGBAf amb, emiss;
+	amb.red = CTimeCycle::GetAmbientRed();
+	amb.green = CTimeCycle::GetAmbientGreen();
+	amb.blue = CTimeCycle::GetAmbientBlue();
+	amb.alpha = 1.0f;
+	emiss = pAmbient->color;
+
+	d3ddevice->SetVertexShaderConstantF(VSLOC_ambient, (float*)&amb, 1);
+	d3ddevice->SetVertexShaderConstantF(VSLOC_emissive, (float*)&emiss, 1);
+}
+
 void
 leedsVehicleRenderCB_mobile(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 {
@@ -172,15 +199,7 @@ leedsVehicleRenderCB_mobile(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *he
 	setVertexShader(leedsVehicle_mobile_VS);
 	setPixelShader(leedsVehicle_mobile_PS);
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	d3ddevice->SetVertexShaderConstantF(VSLOC_ambient, (float*)&amb, 1);
-	d3ddevice->SetVertexShaderConstantF(VSLOC_emissive, (float*)&emiss, 1);
+	uploadWorldLights();
 
 	RGBAf skyTop, skyBot;
 	skyTop.red = CTimeCycle::GetSkyTopRed()/255.0f;
@@ -265,7 +284,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 	using namespace rw::d3d9;
 
 	// TODO: make this less of a kludge
-	if(VehiclePipeSwitch == VEHICLEPIPE_PS2){
+	if(VehiclePipeSwitch == VEHICLEPIPE_PSP || VehiclePipeSwitch == VEHICLEPIPE_PS2){
 		leedsVehicleRenderCB(atomic, header);
 	//	matFXGlobals.pipelines[rw::platform]->render(atomic);
 		return;
@@ -337,31 +356,31 @@ CreateVehiclePipe(void)
 //		fp = ReadTweakValueTable(fp, SpecColor);
 //	}
 
-#include "shaders/neoVehicle_VS.inc"
+#include "shaders/obj/neoVehicle_VS.inc"
 	neoVehicle_VS = rw::d3d::createVertexShader(neoVehicle_VS_cso);
 	assert(neoVehicle_VS);
 
-#include "shaders/neoVehicle_PS.inc"
+#include "shaders/obj/neoVehicle_PS.inc"
 	neoVehicle_PS = rw::d3d::createPixelShader(neoVehicle_PS_cso);
 	assert(neoVehicle_PS);
 
-#include "shaders/leedsVehicle_VS.inc"
-	leedsVehicle_VS = rw::d3d::createVertexShader(leedsVehicle_VS_cso);
+#include "shaders/obj/leedsDefault_ENV_VS.inc"
+	leedsVehicle_VS = rw::d3d::createVertexShader(leedsDefault_ENV_VS_cso);
 	assert(leedsVehicle_VS);
 
-#include "shaders/leedsVehicle_mobile_VS.inc"
+#include "shaders/obj/leedsVehicle_mobile_VS.inc"
 	leedsVehicle_mobile_VS = rw::d3d::createVertexShader(leedsVehicle_mobile_VS_cso);
 	assert(leedsVehicle_mobile_VS);
 
-#include "shaders/leedsVehicle_blend_PS.inc"
-	leedsVehicle_blend_PS = rw::d3d::createPixelShader(leedsVehicle_blend_PS_cso);
+#include "shaders/obj/leedsDefault_BLEND_PS.inc"
+	leedsVehicle_blend_PS = rw::d3d::createPixelShader(leedsDefault_BLEND_PS_cso);
 	assert(leedsVehicle_blend_PS);
 
-#include "shaders/leedsVehicle_add_PS.inc"
-	leedsVehicle_add_PS = rw::d3d::createPixelShader(leedsVehicle_add_PS_cso);
+#include "shaders/obj/leedsDefault_ADD_PS.inc"
+	leedsVehicle_add_PS = rw::d3d::createPixelShader(leedsDefault_ADD_PS_cso);
 	assert(leedsVehicle_add_PS);
 
-#include "shaders/leedsVehicle_mobile_PS.inc"
+#include "shaders/obj/leedsVehicle_mobile_PS.inc"
 	leedsVehicle_mobile_PS = rw::d3d::createPixelShader(leedsVehicle_mobile_PS_cso);
 	assert(leedsVehicle_mobile_PS);
 
@@ -424,15 +443,7 @@ worldRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 
 	uploadMatrices(atomic->getFrame()->getLTM());
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	d3ddevice->SetVertexShaderConstantF(VSLOC_ambient, (float*)&amb, 1);
-	d3ddevice->SetVertexShaderConstantF(VSLOC_emissive, (float*)&emiss, 1);
+	uploadWorldLights();
 
 	float colorscale[4];
 	colorscale[3] = 1.0f;
@@ -442,7 +453,7 @@ worldRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 		Material *m = inst->material;
 
 		float cs = 1.0f;
-		if(WorldPipeSwitch == WORLDPIPE_PS2 && m->texture)
+		if(WorldPipeSwitch != WORLDPIPE_MOBILE && m->texture)
 			cs = 255/128.0f;
 		colorscale[0] = colorscale[1] = colorscale[2] = cs;
 		d3ddevice->SetPixelShaderConstantF(PSLOC_colorscale, colorscale, 1);
@@ -469,13 +480,13 @@ CreateWorldPipe(void)
 //	else
 //		ReadTweakValueTable((char*)work_buff, WorldLightmapBlend);
 
-#include "shaders/leedsBuilding_VS.inc"
+#include "shaders/obj/leedsBuilding_VS.inc"
 	leedsBuilding_VS = rw::d3d::createVertexShader(leedsBuilding_VS_cso);
 	assert(leedsBuilding_VS);
-#include "shaders/leedsBuilding_mobile_VS.inc"
+#include "shaders/obj/leedsBuilding_mobile_VS.inc"
 	leedsBuilding_mobile_VS = rw::d3d::createVertexShader(leedsBuilding_mobile_VS_cso);
 	assert(leedsBuilding_mobile_VS);
-#include "shaders/scale_PS.inc"
+#include "shaders/obj/scale_PS.inc"
 	scale_PS = rw::d3d::createPixelShader(scale_PS_cso);
 	assert(scale_PS);
 
@@ -559,11 +570,11 @@ glossRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header)
 void
 CreateGlossPipe(void)
 {
-#include "shaders/neoGloss_VS.inc"
+#include "shaders/obj/neoGloss_VS.inc"
 	neoGloss_VS = rw::d3d::createVertexShader(neoGloss_VS_cso);
 	assert(neoGloss_VS);
 
-#include "shaders/neoGloss_PS.inc"
+#include "shaders/obj/neoGloss_PS.inc"
 	neoGloss_PS = rw::d3d::createPixelShader(neoGloss_PS_cso);
 	assert(neoGloss_PS);
 
@@ -725,11 +736,11 @@ CreateRimLightPipes(void)
 	}
 
 
-#include "shaders/neoRim_VS.inc"
+#include "shaders/obj/neoRim_VS.inc"
 	neoRim_VS = rw::d3d::createVertexShader(neoRim_VS_cso);
 	assert(neoRim_VS);
 
-#include "shaders/neoRimSkin_VS.inc"
+#include "shaders/obj/neoRimSkin_VS.inc"
 	neoRimSkin_VS = rw::d3d::createVertexShader(neoRimSkin_VS_cso);
 	assert(neoRimSkin_VS);
 
@@ -850,15 +861,7 @@ AtomicFirstPass(RpAtomic *atomic, int pass)
 			setPixelShader(CustomPipes::scale_PS);
 			d3ddevice->SetVertexShaderConstantF(VSLOC_combined, (float*)&building->combinedMat, 4);
 
-			RGBAf amb, emiss;
-			amb.red = CTimeCycle::GetAmbientRed();
-			amb.green = CTimeCycle::GetAmbientGreen();
-			amb.blue = CTimeCycle::GetAmbientBlue();
-			amb.alpha = 1.0f;
-			emiss = pAmbient->color;
-
-			d3ddevice->SetVertexShaderConstantF(CustomPipes::VSLOC_ambient, (float*)&amb, 1);
-			d3ddevice->SetVertexShaderConstantF(CustomPipes::VSLOC_emissive, (float*)&emiss, 1);
+			CustomPipes::uploadWorldLights();
 
 			colorscale[3] = 1.0f;
 
@@ -866,14 +869,14 @@ AtomicFirstPass(RpAtomic *atomic, int pass)
 		}
 
 		float cs = 1.0f;
-		if(CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 && m->texture)
+		if(CustomPipes::WorldPipeSwitch != CustomPipes::WORLDPIPE_MOBILE && m->texture)
 			cs = 255/128.0f;
 		colorscale[0] = colorscale[1] = colorscale[2] = cs;
 		d3ddevice->SetPixelShaderConstantF(CustomPipes::PSLOC_colorscale, colorscale, 1);
 
 		d3d::setTexture(0, m->texture);
 
-		setMaterial(m->color, m->surfaceProps, 0.5f);
+		setMaterial(m->color, m->surfaceProps, CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 ? 0.5f : 1.0f);
 
 		drawInst(building->instHeader, inst);
 	}
@@ -913,15 +916,7 @@ RenderBlendPass(int pass)
 		setVertexShader(CustomPipes::leedsBuilding_VS);
 	setPixelShader(CustomPipes::scale_PS);
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	d3ddevice->SetVertexShaderConstantF(CustomPipes::VSLOC_ambient, (float*)&amb, 1);
-	d3ddevice->SetVertexShaderConstantF(CustomPipes::VSLOC_emissive, (float*)&emiss, 1);
+	CustomPipes::uploadWorldLights();
 
 	float colorscale[4];
 	colorscale[3] = 1.0f;
@@ -944,7 +939,7 @@ RenderBlendPass(int pass)
 				continue;	// already done this one
 
 			float cs = 1.0f;
-			if(CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 && m->texture)
+			if(CustomPipes::WorldPipeSwitch != CustomPipes::WORLDPIPE_MOBILE && m->texture)
 				cs = 255/128.0f;
 			colorscale[0] = colorscale[1] = colorscale[2] = cs;
 			d3ddevice->SetPixelShaderConstantF(CustomPipes::PSLOC_colorscale, colorscale, 1);
@@ -953,7 +948,7 @@ RenderBlendPass(int pass)
 
 			rw::RGBA color = m->color;
 			color.alpha = (color.alpha * building->fadeAlpha)/255;
-			setMaterial(color, m->surfaceProps, 0.5f);
+			setMaterial(color, m->surfaceProps, CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 ? 0.5f : 1.0f);
 
 			drawInst(building->instHeader, inst);
 		}
diff --git a/src/extras/custompipes_gl.cpp b/src/extras/custompipes_gl.cpp
index eeb62b8d..46efdd8a 100644
--- a/src/extras/custompipes_gl.cpp
+++ b/src/extras/custompipes_gl.cpp
@@ -132,6 +132,9 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 
 	SetRenderState(SRCBLEND, BLENDONE);
 
+	float colorscale[4];
+	colorscale[3] = 1.0f;
+
 	while(n--){
 		m = inst->material;
 
@@ -147,6 +150,13 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 
 		setMaterial(m->color, m->surfaceProps);
 
+		float cs = 1.0f;
+		// how does the PS2 handle this actually? probably scaled material color?
+		if(VehiclePipeSwitch == VEHICLEPIPE_PSP && m->texture)
+			cs = 2.0f;
+		colorscale[0] = colorscale[1] = colorscale[2] = cs;
+		glUniform4fv(U(u_colorscale), 1, colorscale);
+
 		setTexture(0, m->texture);
 
 		drawInst(header, inst);
@@ -162,6 +172,23 @@ leedsVehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 #endif
 }
 
+void
+uploadWorldLights(void)
+{
+	using namespace rw;
+	using namespace rw::gl3;
+
+	RGBAf amb, emiss;
+	amb.red = CTimeCycle::GetAmbientRed();
+	amb.green = CTimeCycle::GetAmbientGreen();
+	amb.blue = CTimeCycle::GetAmbientBlue();
+	amb.alpha = 1.0f;
+	emiss = pAmbient->color;
+
+	glUniform4fv(U(CustomPipes::u_amb), 1, (float*)&amb);
+	glUniform4fv(U(CustomPipes::u_emiss), 1, (float*)&emiss);
+}
+
 static void
 leedsVehicleRenderCB_mobile(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 {
@@ -186,15 +213,7 @@ leedsVehicleRenderCB_mobile(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *hea
 
 	leedsVehicleShader_mobile->use();
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	glUniform4fv(U(u_amb), 1, (float*)&amb);
-	glUniform4fv(U(u_emiss), 1, (float*)&emiss);
+	uploadWorldLights();
 
 	RGBAf skyTop, skyBot;
 	skyTop.red = CTimeCycle::GetSkyTopRed()/255.0f;
@@ -276,7 +295,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 	using namespace rw::gl3;
 
 	// TODO: make this less of a kludge
-	if(VehiclePipeSwitch == VEHICLEPIPE_PS2){
+	if(VehiclePipeSwitch == VEHICLEPIPE_PSP || VehiclePipeSwitch == VEHICLEPIPE_PS2){
 		leedsVehicleRenderCB(atomic, header);
 //		matFXGlobals.pipelines[rw::platform]->render(atomic);
 		return;
@@ -361,8 +380,8 @@ CreateVehiclePipe(void)
 
 
 	{
-#include "shaders/neoVehicle_fs_gl.inc"
-#include "shaders/neoVehicle_vs_gl.inc"
+#include "shaders/obj/neoVehicle_frag.inc"
+#include "shaders/obj/neoVehicle_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, neoVehicle_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, neoVehicle_frag_src, nil };
 	neoVehicleShader = Shader::create(vs, fs);
@@ -370,12 +389,11 @@ CreateVehiclePipe(void)
 	}
 
 	{
-#include "shaders/leedsVehicle_add_gl.inc"
-#include "shaders/leedsVehicle_blend_gl.inc"
-#include "shaders/leedsVehicle_vs_gl.inc"
-	const char *vs[] = { shaderDecl, header_vert_src, leedsVehicle_vert_src, nil };
-	const char *fs_add[] = { shaderDecl, header_frag_src, leedsVehicle_add_frag_src, nil };
-	const char *fs_blend[] = { shaderDecl, header_frag_src, leedsVehicle_blend_frag_src, nil };
+#include "shaders/obj/leedsDefault_vert.inc"
+#include "shaders/obj/leedsDefault_frag.inc"
+	const char *vs[] = { shaderDecl, header_vert_src, "#define ENVMAP\n", leedsDefault_vert_src, nil };
+	const char *fs_add[] = { shaderDecl, header_frag_src, "#define PASS_ADD\n", leedsDefault_frag_src, nil };
+	const char *fs_blend[] = { shaderDecl, header_frag_src, "#define PASS_BLEND\n", leedsDefault_frag_src, nil };
 	leedsVehicleShader_add = Shader::create(vs, fs_add);
 	assert(leedsVehicleShader_add);
 	leedsVehicleShader_blend = Shader::create(vs, fs_blend);
@@ -383,8 +401,8 @@ CreateVehiclePipe(void)
 	}
 
 	{
-#include "shaders/leedsVehicle_mobile_fs_gl.inc"
-#include "shaders/leedsVehicle_mobile_vs_gl.inc"
+#include "shaders/obj/leedsVehicle_mobile_frag.inc"
+#include "shaders/obj/leedsVehicle_mobile_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, leedsVehicle_mobile_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, leedsVehicle_mobile_frag_src, nil };
 	leedsVehicleShader_mobile = Shader::create(vs, fs);
@@ -453,15 +471,7 @@ worldRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 	else
 		CustomPipes::leedsWorldShader->use();
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	glUniform4fv(U(u_amb), 1, (float*)&amb);
-	glUniform4fv(U(u_emiss), 1, (float*)&emiss);
+	uploadWorldLights();
 
 	float colorscale[4];
 	colorscale[3] = 1.0f;
@@ -470,14 +480,14 @@ worldRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header)
 		m = inst->material;
 
 		float cs = 1.0f;
-		if(WorldPipeSwitch == WORLDPIPE_PS2 && m->texture)
+		if(WorldPipeSwitch != WORLDPIPE_MOBILE && m->texture)
 			cs = 255/128.0f;
 		colorscale[0] = colorscale[1] = colorscale[2] = cs;
 		glUniform4fv(U(u_colorscale), 1, colorscale);
 
 		setTexture(0, m->texture);
 
-		setMaterial(m->color, m->surfaceProps, 0.5f);
+		setMaterial(m->color, m->surfaceProps, CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 ? 0.5f : 1.0f);
 
 		rw::SetRenderState(VERTEXALPHA, inst->vertexAlpha || m->color.alpha != 0xFF);
 
@@ -501,9 +511,9 @@ CreateWorldPipe(void)
 //		ReadTweakValueTable((char*)work_buff, WorldLightmapBlend);
 
 	{
-#include "shaders/scale_fs_gl.inc"
-#include "shaders/leedsBuilding_vs_gl.inc"
-#include "shaders/leedsBuilding_mobile_vs_gl.inc"
+#include "shaders/obj/scale_frag.inc"
+#include "shaders/obj/leedsBuilding_vert.inc"
+#include "shaders/obj/leedsBuilding_mobile_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, leedsBuilding_vert_src, nil };
 	const char *vs_mobile[] = { shaderDecl, header_vert_src, leedsBuilding_mobile_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, scale_frag_src, nil };
@@ -610,8 +620,8 @@ CreateGlossPipe(void)
 	using namespace rw::gl3;
 
 	{
-#include "shaders/neoGloss_fs_gl.inc"
-#include "shaders/neoGloss_vs_gl.inc"
+#include "shaders/obj/neoGloss_frag.inc"
+#include "shaders/obj/neoGloss_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, neoGloss_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, neoGloss_frag_src, nil };
 	neoGlossShader = Shader::create(vs, fs);
@@ -782,8 +792,8 @@ CreateRimLightPipes(void)
 	}
 
 	{
-#include "shaders/simple_fs_gl.inc"
-#include "shaders/neoRimSkin_gl.inc"
+#include "shaders/obj/simple_frag.inc"
+#include "shaders/obj/neoRimSkin_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, neoRimSkin_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil };
 	neoRimSkinShader = Shader::create(vs, fs);
@@ -791,8 +801,8 @@ CreateRimLightPipes(void)
 	}
 
 	{
-#include "shaders/simple_fs_gl.inc"
-#include "shaders/neoRim_gl.inc"
+#include "shaders/obj/simple_frag.inc"
+#include "shaders/obj/neoRim_vert.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, neoRim_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil };
 	neoRimShader = Shader::create(vs, fs);
@@ -936,25 +946,17 @@ AtomicFirstPass(RpAtomic *atomic, int pass)
 			setAttribPointers(building->instHeader->attribDesc, building->instHeader->numAttribs);
 #endif
 
-			RGBAf amb, emiss;
-			amb.red = CTimeCycle::GetAmbientRed();
-			amb.green = CTimeCycle::GetAmbientGreen();
-			amb.blue = CTimeCycle::GetAmbientBlue();
-			amb.alpha = 1.0f;
-			emiss = pAmbient->color;
-
-			glUniform4fv(U(CustomPipes::u_amb), 1, (float*)&amb);
-			glUniform4fv(U(CustomPipes::u_emiss), 1, (float*)&emiss);
+			CustomPipes::uploadWorldLights();
 
 			colorscale[3] = 1.0f;
 
 			setupDone = true;
 		}
 
-		setMaterial(m->color, m->surfaceProps, 0.5f);
+		setMaterial(m->color, m->surfaceProps, CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 ? 0.5f : 1.0f);
 
 		float cs = 1.0f;
-		if(CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 && m->texture)
+		if(CustomPipes::WorldPipeSwitch != CustomPipes::WORLDPIPE_MOBILE && m->texture)
 			cs = 255/128.0f;
 		colorscale[0] = colorscale[1] = colorscale[2] = cs;
 		glUniform4fv(U(CustomPipes::u_colorscale), 1, colorscale);
@@ -999,15 +1001,7 @@ RenderBlendPass(int pass)
 	else
 		CustomPipes::leedsWorldShader->use();
 
-	RGBAf amb, emiss;
-	amb.red = CTimeCycle::GetAmbientRed();
-	amb.green = CTimeCycle::GetAmbientGreen();
-	amb.blue = CTimeCycle::GetAmbientBlue();
-	amb.alpha = 1.0f;
-	emiss = pAmbient->color;
-
-	glUniform4fv(U(CustomPipes::u_amb), 1, (float*)&amb);
-	glUniform4fv(U(CustomPipes::u_emiss), 1, (float*)&emiss);
+	CustomPipes::uploadWorldLights();
 
 	float colorscale[4];
 	colorscale[3] = 1.0f;
@@ -1035,10 +1029,10 @@ RenderBlendPass(int pass)
 
 			rw::RGBA color = m->color;
 			color.alpha = (color.alpha * building->fadeAlpha)/255;
-			setMaterial(color, m->surfaceProps, 0.5f);
+			setMaterial(color, m->surfaceProps, CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 ? 0.5f : 1.0f);
 
 			float cs = 1.0f;
-			if(CustomPipes::WorldPipeSwitch == CustomPipes::WORLDPIPE_PS2 && m->texture)
+			if(CustomPipes::WorldPipeSwitch != CustomPipes::WORLDPIPE_MOBILE && m->texture)
 				cs = 255/128.0f;
 			colorscale[0] = colorscale[1] = colorscale[2] = cs;
 			glUniform4fv(U(CustomPipes::u_colorscale), 1, colorscale);
diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp
index b07b5426..360b4f7a 100644
--- a/src/extras/postfx.cpp
+++ b/src/extras/postfx.cpp
@@ -143,17 +143,17 @@ CPostFX::Open(RwCamera *cam)
 
 
 #ifdef RW_D3D9
-#include "shaders/colourfilterLCS_PS.inc"
+#include "shaders/obj/colourfilterLCS_PS.inc"
 	colourfilterLCS_PS = rw::d3d::createPixelShader(colourfilterLCS_PS_cso);
-#include "shaders/contrastPS.inc"
+#include "shaders/obj/contrastPS.inc"
 	contrast_PS = rw::d3d::createPixelShader(contrastPS_cso);
 #endif
 #ifdef RW_OPENGL
 	using namespace rw::gl3;
 
 	{
-#include "shaders/im2d_gl.inc"
-#include "shaders/colourfilterLCS_fs_gl.inc"
+#include "shaders/obj/im2d_vert.inc"
+#include "shaders/obj/colourfilterLCS_frag.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, colourfilterLCS_frag_src, nil };
 	colourFilterLCS = Shader::create(vs, fs);
@@ -161,8 +161,8 @@ CPostFX::Open(RwCamera *cam)
 	}
 
 	{
-#include "shaders/im2d_gl.inc"
-#include "shaders/contrast_fs_gl.inc"
+#include "shaders/obj/im2d_vert.inc"
+#include "shaders/obj/contrast_frag.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, contrast_frag_src, nil };
 	contrast = Shader::create(vs, fs);
diff --git a/src/extras/screendroplets.cpp b/src/extras/screendroplets.cpp
index ac3a17b2..963b7624 100644
--- a/src/extras/screendroplets.cpp
+++ b/src/extras/screendroplets.cpp
@@ -112,14 +112,14 @@ ScreenDroplets::InitDraw(void)
 
 	openim2d_uv2();
 #ifdef RW_D3D9
-#include "shaders/screenDroplet_PS.inc"
+#include "shaders/obj/screenDroplet_PS.inc"
 	screenDroplet_PS = rw::d3d::createPixelShader(screenDroplet_PS_cso);
 #endif
 #ifdef RW_GL3
 	using namespace rw::gl3;
 	{
-#include "shaders/im2d_UV2_gl.inc"
-#include "shaders/screenDroplet_fs_gl.inc"
+#include "shaders/obj/im2d_UV2_vert.inc"
+#include "shaders/obj/screenDroplet_frag.inc"
 	const char *vs[] = { shaderDecl, header_vert_src, im2d_UV2_vert_src, nil };
 	const char *fs[] = { shaderDecl, header_frag_src, screenDroplet_frag_src, nil };
 	screenDroplet = Shader::create(vs, fs);
diff --git a/src/extras/shaders/Makefile b/src/extras/shaders/Makefile
deleted file mode 100644
index 393ab660..00000000
--- a/src/extras/shaders/Makefile
+++ /dev/null
@@ -1,121 +0,0 @@
-all: im2d_gl.inc simple_fs_gl.inc default_UV2_gl.inc \
-	colourfilterLCS_fs_gl.inc contrast_fs_gl.inc \
-	neoRim_gl.inc neoRimSkin_gl.inc \
-	neoWorldVC_fs_gl.inc neoGloss_vs_gl.inc neoGloss_fs_gl.inc \
-	neoVehicle_vs_gl.inc neoVehicle_fs_gl.inc \
-	im2d_UV2_gl.inc screenDroplet_fs_gl.inc \
-	leedsBuilding_vs_gl.inc leedsBuilding_mobile_vs_gl.inc scale_fs_gl.inc \
-	leedsVehicle_vs_gl.inc leedsVehicle_add_gl.inc leedsVehicle_blend_gl.inc \
-	leedsVehicle_mobile_vs_gl.inc leedsVehicle_mobile_fs_gl.inc
-
-im2d_gl.inc: im2d.vert
-	(echo 'const char *im2d_vert_src =';\
-	 sed 's/..*/"&\\n"/' im2d.vert;\
-	 echo ';') >im2d_gl.inc
-
-colourfilterLCS_fs_gl.inc: colourfilterLCS.frag
-	(echo 'const char *colourfilterLCS_frag_src =';\
-	 sed 's/..*/"&\\n"/' colourfilterLCS.frag;\
-	 echo ';') >colourfilterLCS_fs_gl.inc
-simple_fs_gl.inc: simple.frag
-	(echo 'const char *simple_frag_src =';\
-	 sed 's/..*/"&\\n"/' simple.frag;\
-	 echo ';') >simple_fs_gl.inc
-
-default_UV2_gl.inc: default_UV2.vert
-	(echo 'const char *default_UV2_vert_src =';\
-	 sed 's/..*/"&\\n"/' default_UV2.vert;\
-	 echo ';') >default_UV2_gl.inc
-
-
-
-contrast_fs_gl.inc: contrast.frag
-	(echo 'const char *contrast_frag_src =';\
-	 sed 's/..*/"&\\n"/' contrast.frag;\
-	 echo ';') >contrast_fs_gl.inc
-
-
-neoRim_gl.inc: neoRim.vert
-	(echo 'const char *neoRim_vert_src =';\
-	 sed 's/..*/"&\\n"/' neoRim.vert;\
-	 echo ';') >neoRim_gl.inc
-
-neoRimSkin_gl.inc: neoRimSkin.vert
-	(echo 'const char *neoRimSkin_vert_src =';\
-	 sed 's/..*/"&\\n"/' neoRimSkin.vert;\
-	 echo ';') >neoRimSkin_gl.inc
-
-neoWorldVC_fs_gl.inc: neoWorldVC.frag
-	(echo 'const char *neoWorldVC_frag_src =';\
-	 sed 's/..*/"&\\n"/' neoWorldVC.frag;\
-	 echo ';') >neoWorldVC_fs_gl.inc
-
-neoGloss_fs_gl.inc: neoGloss.frag
-	(echo 'const char *neoGloss_frag_src =';\
-	 sed 's/..*/"&\\n"/' neoGloss.frag;\
-	 echo ';') >neoGloss_fs_gl.inc
-
-neoGloss_vs_gl.inc: neoGloss.vert
-	(echo 'const char *neoGloss_vert_src =';\
-	 sed 's/..*/"&\\n"/' neoGloss.vert;\
-	 echo ';') >neoGloss_vs_gl.inc
-
-neoVehicle_vs_gl.inc: neoVehicle.vert
-	(echo 'const char *neoVehicle_vert_src =';\
-	 sed 's/..*/"&\\n"/' neoVehicle.vert;\
-	 echo ';') >neoVehicle_vs_gl.inc
-
-neoVehicle_fs_gl.inc: neoVehicle.frag
-	(echo 'const char *neoVehicle_frag_src =';\
-	 sed 's/..*/"&\\n"/' neoVehicle.frag;\
-	 echo ';') >neoVehicle_fs_gl.inc
-
-im2d_UV2_gl.inc: im2d_UV2.vert
-	(echo 'const char *im2d_UV2_vert_src =';\
-	 sed 's/..*/"&\\n"/' im2d_UV2.vert;\
-	 echo ';') >im2d_UV2_gl.inc
-
-screenDroplet_fs_gl.inc: screenDroplet.frag
-	(echo 'const char *screenDroplet_frag_src =';\
-	 sed 's/..*/"&\\n"/' screenDroplet.frag;\
-	 echo ';') >screenDroplet_fs_gl.inc
-
-leedsBuilding_vs_gl.inc: leedsBuilding.vert
-	(echo 'const char *leedsBuilding_vert_src =';\
-	 sed 's/..*/"&\\n"/' leedsBuilding.vert;\
-	 echo ';') >leedsBuilding_vs_gl.inc
-
-leedsBuilding_mobile_vs_gl.inc: leedsBuilding_mobile.vert
-	(echo 'const char *leedsBuilding_mobile_vert_src =';\
-	 sed 's/..*/"&\\n"/' leedsBuilding_mobile.vert;\
-	 echo ';') >leedsBuilding_mobile_vs_gl.inc
-
-scale_fs_gl.inc: scale.frag
-	(echo 'const char *scale_frag_src =';\
-	 sed 's/..*/"&\\n"/' scale.frag;\
-	 echo ';') >scale_fs_gl.inc
-
-leedsVehicle_vs_gl.inc: leedsVehicle.vert
-	(echo 'const char *leedsVehicle_vert_src =';\
-	 sed 's/..*/"&\\n"/' leedsVehicle.vert;\
-	 echo ';') >leedsVehicle_vs_gl.inc
-
-leedsVehicle_add_gl.inc: leedsVehicle_add.frag
-	(echo 'const char *leedsVehicle_add_frag_src =';\
-	 sed 's/..*/"&\\n"/' leedsVehicle_add.frag;\
-	 echo ';') >leedsVehicle_add_gl.inc
-
-leedsVehicle_blend_gl.inc: leedsVehicle_blend.frag
-	(echo 'const char *leedsVehicle_blend_frag_src =';\
-	 sed 's/..*/"&\\n"/' leedsVehicle_blend.frag;\
-	 echo ';') >leedsVehicle_blend_gl.inc
-
-leedsVehicle_mobile_vs_gl.inc: leedsVehicle_mobile.vert
-	(echo 'const char *leedsVehicle_mobile_vert_src =';\
-	 sed 's/..*/"&\\n"/' leedsVehicle_mobile.vert;\
-	 echo ';') >leedsVehicle_mobile_vs_gl.inc
-
-leedsVehicle_mobile_fs_gl.inc: leedsVehicle_mobile.frag
-	(echo 'const char *leedsVehicle_mobile_frag_src =';\
-	 sed 's/..*/"&\\n"/' leedsVehicle_mobile.frag;\
-	 echo ';') >leedsVehicle_mobile_fs_gl.inc
diff --git a/src/extras/shaders/leedsVehicle_blend.frag b/src/extras/shaders/leedsDefault.frag
similarity index 61%
rename from src/extras/shaders/leedsVehicle_blend.frag
rename to src/extras/shaders/leedsDefault.frag
index a3fab072..3955e6a5 100644
--- a/src/extras/shaders/leedsVehicle_blend.frag
+++ b/src/extras/shaders/leedsDefault.frag
@@ -2,29 +2,45 @@ uniform sampler2D tex0;
 uniform sampler2D tex1;
 
 uniform float u_fxparams;
+uniform vec4 u_colorscale;
 
 #define shininess (u_fxparams)
 
 FSIN vec4 v_color;
 FSIN vec2 v_tex0;
+#if defined(PASS_BLEND) || defined(PASS_ADD)
 FSIN vec2 v_tex1;
+#endif
 FSIN float v_fog;
 
 void
 main(void)
 {
-	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));
+	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y))*u_colorscale;
+	pass1.rgb = clamp(pass1.rgb, 0.0, 1.0);
+	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);
+
+	vec4 color;
+#if defined(PASS_BLEND) || defined(PASS_ADD)
 	vec4 pass2 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));
 	pass2.a *= shininess;
-
-	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);
 	pass2.rgb = mix(vec3(0.0, 0.0, 0.0), pass2.rgb, v_fog);
 
 	// We simulate drawing this in two passes.
+#if defined(PASS_ADD)
+	// First pass with standard blending, second with addition
+	// We premultiply alpha so render state should be one.
+	color.rgb = pass1.rgb*pass1.a + pass2.rgb*pass2.a;
+	color.a = pass1.a;
+#elif defined(PASS_BLEND)
 	// We premultiply alpha so render state should be one.
-	vec4 color;
 	color.rgb = pass1.rgb*pass1.a*(1.0-pass2.a) + pass2.rgb*pass2.a;
 	color.a = pass1.a*(1.0-pass2.a) + pass2.a;
+#endif
+
+#else
+	color = pass1;
+#endif
 
 	DoAlphaTest(color.a);
 
diff --git a/src/extras/shaders/leedsDefault.vert b/src/extras/shaders/leedsDefault.vert
new file mode 100644
index 00000000..9cb18a66
--- /dev/null
+++ b/src/extras/shaders/leedsDefault.vert
@@ -0,0 +1,51 @@
+#ifdef ENVMAP
+uniform mat4 u_texMatrix;
+#endif
+#ifdef SKIN
+uniform mat4 u_boneMatrices[64];
+#endif
+
+VSIN(ATTRIB_POS)	vec3 in_pos;
+
+VSOUT vec4 v_color;
+VSOUT vec2 v_tex0;
+#ifdef ENVMAP
+VSOUT vec2 v_tex1;
+#endif
+VSOUT float v_fog;
+
+void
+main(void)
+{
+#ifdef SKIN
+	vec3 SkinVertex = vec3(0.0, 0.0, 0.0);
+	vec3 SkinNormal = vec3(0.0, 0.0, 0.0);
+	for(int i = 0; i < 4; i++){
+		SkinVertex += (u_boneMatrices[int(in_indices[i])] * vec4(in_pos, 1.0)).xyz * in_weights[i];
+		SkinNormal += (mat3(u_boneMatrices[int(in_indices[i])]) * in_normal) * in_weights[i];
+	}
+
+	vec4 Vertex = u_world * vec4(SkinVertex, 1.0);
+	gl_Position = u_proj * u_view * Vertex;
+	vec3 Normal = mat3(u_world) * SkinNormal;
+#else
+	vec4 Vertex = u_world * vec4(in_pos, 1.0);
+	gl_Position = u_proj * u_view * Vertex;
+	vec3 Normal = mat3(u_world) * in_normal;
+#endif
+
+	v_tex0 = in_tex0;
+#ifdef ENVMAP
+	v_tex1 = (u_texMatrix * vec4(Normal, 1.0)).xy;
+#endif
+
+	v_color = in_color;
+	v_color.rgb += u_ambLight.rgb*surfAmbient;
+	v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;
+	// PS2 clamps before material color
+	// PSP clamps after...maybe another constant for this?
+	v_color = clamp(v_color, 0.0, 1.0);
+	v_color *= u_matColor;
+
+	v_fog = DoFog(gl_Position.w);
+}
diff --git a/src/extras/shaders/leedsVehicle_add_PS.hlsl b/src/extras/shaders/leedsDefault_PS_x.hlsl
similarity index 59%
rename from src/extras/shaders/leedsVehicle_add_PS.hlsl
rename to src/extras/shaders/leedsDefault_PS_x.hlsl
index 943926cf..0b546523 100644
--- a/src/extras/shaders/leedsVehicle_add_PS.hlsl
+++ b/src/extras/shaders/leedsDefault_PS_x.hlsl
@@ -1,7 +1,9 @@
 struct VS_out {
 	float4 Position		: POSITION;
 	float3 TexCoord0	: TEXCOORD0;
+#if defined(PASS_BLEND) || defined(PASS_ADD)
 	float2 TexCoord1	: TEXCOORD1;
+#endif
 	float4 Color		: COLOR0;
 };
 
@@ -10,25 +12,38 @@ sampler2D envTex : register(s1);
 
 float4 fogColor : register(c0);
 
-float4 fxparams : register(c1);
+float4 colorscale : register(c1);
+float4 fxparams : register(c2);
 
 #define shininess (fxparams.x)
 
 float4 main(VS_out input) : COLOR
 {
-	float4 pass1 = input.Color*tex2D(diffTex, input.TexCoord0.xy);
+	float4 pass1 = input.Color*tex2D(diffTex, input.TexCoord0.xy)*colorscale;
+	pass1.rgb = clamp(pass1.rgb, 0.0, 1.0);
+	pass1.rgb = lerp(fogColor.rgb, pass1.rgb, input.TexCoord0.z);
+
+	float4 color;
+#if defined(PASS_BLEND) || defined(PASS_ADD)
 	float4 pass2 = tex2D(envTex, input.TexCoord1.xy);
 	pass2.a *= shininess;
-
-	pass1.rgb = lerp(fogColor.rgb, pass1.rgb, input.TexCoord0.z);
 	pass2.rgb = lerp(float3(0.0, 0.0, 0.0), pass2.rgb, input.TexCoord0.z);
 
 	// We simulate drawing this in two passes.
+#if defined(PASS_ADD)
 	// First pass with standard blending, second with addition
 	// We premultiply alpha so render state should be one.
-	float4 color;
 	color.rgb = pass1.rgb*pass1.a + pass2.rgb*pass2.a;
 	color.a = pass1.a;
+#elif defined(PASS_BLEND)
+	// We premultiply alpha so render state should be one.
+	color.rgb = pass1.rgb*pass1.a*(1.0-pass2.a) + pass2.rgb*pass2.a;
+	color.a = pass1.a*(1.0-pass2.a) + pass2.a;
+#endif
+
+#else
+	color = pass1;
+#endif
 
 	return color;
 }
diff --git a/src/extras/shaders/leedsVehicle_VS.hlsl b/src/extras/shaders/leedsDefault_VS_x.hlsl
similarity index 56%
rename from src/extras/shaders/leedsVehicle_VS.hlsl
rename to src/extras/shaders/leedsDefault_VS_x.hlsl
index eb53313a..58bee097 100644
--- a/src/extras/shaders/leedsVehicle_VS.hlsl
+++ b/src/extras/shaders/leedsDefault_VS_x.hlsl
@@ -1,6 +1,11 @@
 #include "standardConstants.h"
 
+#ifdef ENVMAP
 float4x4	texMat	: register(c41);
+#endif
+#ifdef SKIN
+float4x3 boneMatrices[64] : register(c41);
+#endif
 
 struct VS_in
 {
@@ -8,12 +13,18 @@ struct VS_in
 	float3 Normal		: NORMAL;
 	float2 TexCoord		: TEXCOORD0;
 	float4 Prelight		: COLOR0;
+#ifdef SKIN
+	float4 Weights		: BLENDWEIGHT;
+	int4 Indices		: BLENDINDICES;
+#endif
 };
 
 struct VS_out {
 	float4 Position		: POSITION;
 	float3 TexCoord0	: TEXCOORD0;	// also fog
+#ifdef ENVMAP
 	float2 TexCoord1	: TEXCOORD1;
+#endif
 	float4 Color		: COLOR0;
 };
 
@@ -22,12 +33,27 @@ VS_out main(in VS_in input)
 {
 	VS_out output;
 
+#ifdef SKIN
+	int j;
+	float3 SkinVertex = float3(0.0, 0.0, 0.0);
+	float3 SkinNormal = float3(0.0, 0.0, 0.0);
+	for(j = 0; j < 4; j++){
+		SkinVertex += mul(input.Position, boneMatrices[input.Indices[j]]).xyz * input.Weights[j];
+		SkinNormal += mul(input.Normal, (float3x3)boneMatrices[input.Indices[j]]).xyz * input.Weights[j];
+	}
+	output.Position = mul(combinedMat, SkinVertex);
+//	float3 V = mul(worldMat, SkinVertex).xyz;
+	float3 N = mul(normalMat, SkinNormal);
+#else
 	output.Position = mul(combinedMat, input.Position);
-	float3 V = mul(worldMat, input.Position).xyz;
+//	float3 V = mul(worldMat, input.Position).xyz;
 	float3 N = mul(normalMat, input.Normal);
+#endif
 
 	output.TexCoord0.xy = input.TexCoord;
+#ifdef ENVMAP
 	output.TexCoord1 = mul(texMat, float4(N, 1.0)).xy;
+#endif
 
 	output.Color = input.Prelight;
 	output.Color.rgb += ambientLight.rgb * surfAmbient;
@@ -36,6 +62,7 @@ VS_out main(in VS_in input)
 	for(i = 0; i < numDirLights; i++)
 		output.Color.xyz += DoDirLight(lights[i+firstDirLight], N)*surfDiffuse;
 	// PS2 clamps before material color
+	// PSP clamps after...maybe another constant for this?
 	output.Color = clamp(output.Color, 0.0, 1.0);
 	output.Color *= matCol;
 
diff --git a/src/extras/shaders/leedsVehicle.vert b/src/extras/shaders/leedsVehicle.vert
deleted file mode 100644
index b93c7ea0..00000000
--- a/src/extras/shaders/leedsVehicle.vert
+++ /dev/null
@@ -1,27 +0,0 @@
-uniform mat4 u_texMatrix;
-
-VSIN(ATTRIB_POS)	vec3 in_pos;
-
-VSOUT vec4 v_color;
-VSOUT vec2 v_tex0;
-VSOUT vec2 v_tex1;
-VSOUT float v_fog;
-
-void
-main(void)
-{
-	vec4 Vertex = u_world * vec4(in_pos, 1.0);
-	gl_Position = u_proj * u_view * Vertex;
-	vec3 Normal = mat3(u_world) * in_normal;
-
-	v_tex0 = in_tex0;
-	v_tex1 = (u_texMatrix * vec4(Normal, 1.0)).xy;
-
-	v_color = in_color;
-	v_color.rgb += u_ambLight.rgb*surfAmbient;
-	v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;
-	v_color = clamp(v_color, 0.0, 1.0);
-	v_color *= u_matColor;
-
-	v_fog = DoFog(gl_Position.w);
-}
diff --git a/src/extras/shaders/leedsVehicle_add.frag b/src/extras/shaders/leedsVehicle_add.frag
deleted file mode 100644
index e9bcef74..00000000
--- a/src/extras/shaders/leedsVehicle_add.frag
+++ /dev/null
@@ -1,32 +0,0 @@
-uniform sampler2D tex0;
-uniform sampler2D tex1;
-
-uniform float u_fxparams;
-
-#define shininess (u_fxparams)
-
-FSIN vec4 v_color;
-FSIN vec2 v_tex0;
-FSIN vec2 v_tex1;
-FSIN float v_fog;
-
-void
-main(void)
-{
-	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));
-	vec4 pass2 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));
-	pass2.a *= shininess;
-
-	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);
-	pass2.rgb = mix(vec3(0.0, 0.0, 0.0), pass2.rgb, v_fog);
-
-	// We simulate drawing this in two passes.
-	// We premultiply alpha so render state should be one.
-	vec4 color;
-	color.rgb = pass1.rgb*pass1.a + pass2.rgb*pass2.a;
-	color.a = pass1.a;
-
-	DoAlphaTest(color.a);
-
-	FRAGCOLOR(color);
-}
diff --git a/src/extras/shaders/leedsVehicle_add_PS.cso b/src/extras/shaders/leedsVehicle_add_PS.cso
deleted file mode 100644
index 11db8b0eadbbe198b3a07144e5263766db701ae5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 496
zcmZ8dF;2rk5S+Uh;sVJZK*A+77B-?t2T4N_8j?PWNDPq@E^;E2(gh`jA3za06gMu@
z((w?#gJbS&gTzYf-I<-8wGLA2Z+(T{@Va{p;EM@z4vWDMz$eR`*|Jb#&1&L>*`h$;
z5U-X2-dH75@cU77d&^b2hMUadcsSj_!I5>~85`55XG7=z`B**l)LbRV^IX`g4)>~v
zH_LG{UaYWOjiS*xZfEz2TB&&LpWdDMH~m51A3TmH)5Pzo#d0=h(+Q$Z(7B9)i!cn0
z=SlV3DbOyOo_BtGz{_ergX?XZUa;@lr}0vOvJh@*v4BUfvH<acox8-E8q~OL=FDAD
v%?;L;<J&s|cAnAGaPLMV;d0+-boQs&6}4t-ILSSOW$nd#T=R&_RBPY|i+Wu+

diff --git a/src/extras/shaders/leedsVehicle_add_PS.inc b/src/extras/shaders/leedsVehicle_add_PS.inc
deleted file mode 100644
index dc8378f4..00000000
--- a/src/extras/shaders/leedsVehicle_add_PS.inc
+++ /dev/null
@@ -1,44 +0,0 @@
-static unsigned char leedsVehicle_add_PS_cso[] = {
-  0x00, 0x02, 0xff, 0xff, 0xfe, 0xff, 0x40, 0x00, 0x43, 0x54, 0x41, 0x42,
-  0x1c, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff,
-  0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0xc1, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x84, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00,
-  0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
-  0x01, 0x00, 0x06, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x64, 0x69, 0x66, 0x66, 0x54, 0x65, 0x78, 0x00, 0x04, 0x00, 0x0c, 0x00,
-  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x65, 0x6e, 0x76, 0x54, 0x65, 0x78, 0x00, 0xab, 0x04, 0x00, 0x0c, 0x00,
-  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x66, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0xab, 0xab, 0xab,
-  0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x66, 0x78, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,
-  0x00, 0x70, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72,
-  0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c,
-  0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f,
-  0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e,
-  0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x07, 0xb0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0xb0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x01, 0x08, 0x0f, 0xa0,
-  0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xb0,
-  0x01, 0x08, 0xe4, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0f, 0x80,
-  0x00, 0x00, 0xe4, 0xb0, 0x00, 0x08, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03,
-  0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xff, 0x80, 0x01, 0x00, 0x00, 0xa0,
-  0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xaa, 0xb0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80,
-  0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x04, 0x00, 0x00, 0x04,
-  0x01, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0xa1, 0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x08, 0x80,
-  0x01, 0x00, 0xff, 0x80, 0x00, 0x00, 0xff, 0x90, 0x04, 0x00, 0x00, 0x04,
-  0x01, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x01, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x02, 0x00, 0x07, 0x80,
-  0x01, 0x00, 0xe4, 0x80, 0x02, 0x00, 0xff, 0x80, 0x00, 0x00, 0xe4, 0x80,
-  0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80, 0x02, 0x00, 0xe4, 0x80,
-  0xff, 0xff, 0x00, 0x00
-};
diff --git a/src/extras/shaders/leedsVehicle_add_gl.inc b/src/extras/shaders/leedsVehicle_add_gl.inc
deleted file mode 100644
index a9835b13..00000000
--- a/src/extras/shaders/leedsVehicle_add_gl.inc
+++ /dev/null
@@ -1,34 +0,0 @@
-const char *leedsVehicle_add_frag_src =
-"uniform sampler2D tex0;\n"
-"uniform sampler2D tex1;\n"
-
-"uniform float u_fxparams;\n"
-
-"#define shininess (u_fxparams)\n"
-
-"FSIN vec4 v_color;\n"
-"FSIN vec2 v_tex0;\n"
-"FSIN vec2 v_tex1;\n"
-"FSIN float v_fog;\n"
-
-"void\n"
-"main(void)\n"
-"{\n"
-"	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n"
-"	vec4 pass2 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));\n"
-"	pass2.a *= shininess;\n"
-
-"	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);\n"
-"	pass2.rgb = mix(vec3(0.0, 0.0, 0.0), pass2.rgb, v_fog);\n"
-
-"	// We simulate drawing this in two passes.\n"
-"	// We premultiply alpha so render state should be one.\n"
-"	vec4 color;\n"
-"	color.rgb = pass1.rgb*pass1.a + pass2.rgb*pass2.a;\n"
-"	color.a = pass1.a;\n"
-
-"	DoAlphaTest(color.a);\n"
-
-"	FRAGCOLOR(color);\n"
-"}\n"
-;
diff --git a/src/extras/shaders/leedsVehicle_blend_PS.cso b/src/extras/shaders/leedsVehicle_blend_PS.cso
deleted file mode 100644
index 8d1048039f42ac74424500173845a4f12cf6bde3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 572
zcmZ8eu};EJ6g}@1q=QKlXA?W>LImT$q{8BWgThW4p-KXl6k-@_;^@#1aHyN1OGj5X
zKcwGbJ@>U};!98OIj8rY*S<m*#dmRz-teNk58#Ucy&8*XDBzQ2Mp#B_tXO3|6BZj3
zcJN{x;FVPqiud=*`!HVFxAn$T-ycrasA1P6a2vBG507G}|9wBW>jkqQM4G0`>{{bo
zx%~CQ3%&Ugi{+?2I>y!XHVl@5zj6<6j@--spzjXuz40V;d%=7$oso2!?M}0E+HRh-
zS}n=E2I?A40z_w3tSJZO=R`mw+j8#z%K;~@{1~>AY`G%unj>>Kn`f|dqZOP;Q7dYm
zF|UR^j|r)7bu(j=7lQb&XOmSuN!cTF(vwG`6?2$Ny~#vt*wh7qgwPtwaLH5EGybP1
f!n}t?Px53&6MO8lm?^x>&1IgkPGoVPq5ysXwX0}+

diff --git a/src/extras/shaders/leedsVehicle_blend_PS.hlsl b/src/extras/shaders/leedsVehicle_blend_PS.hlsl
deleted file mode 100644
index e32970b2..00000000
--- a/src/extras/shaders/leedsVehicle_blend_PS.hlsl
+++ /dev/null
@@ -1,33 +0,0 @@
-struct VS_out {
-	float4 Position		: POSITION;
-	float3 TexCoord0	: TEXCOORD0;
-	float2 TexCoord1	: TEXCOORD1;
-	float4 Color		: COLOR0;
-};
-
-sampler2D diffTex : register(s0);
-sampler2D envTex : register(s1);
-
-float4 fogColor : register(c0);
-
-float4 fxparams : register(c1);
-
-#define shininess (fxparams.x)
-
-float4 main(VS_out input) : COLOR
-{
-	float4 pass1 = input.Color*tex2D(diffTex, input.TexCoord0.xy);
-	float4 pass2 = tex2D(envTex, input.TexCoord1.xy);
-	pass2.a *= shininess;
-
-	pass1.rgb = lerp(fogColor.rgb, pass1.rgb, input.TexCoord0.z);
-	pass2.rgb = lerp(float3(0.0, 0.0, 0.0), pass2.rgb, input.TexCoord0.z);
-
-	// We simulate drawing this in two passes.
-	// We premultiply alpha so render state should be one.
-	float4 color;
-	color.rgb = pass1.rgb*pass1.a*(1.0-pass2.a) + pass2.rgb*pass2.a;
-	color.a = pass1.a*(1.0-pass2.a) + pass2.a;
-
-	return color;
-}
diff --git a/src/extras/shaders/leedsVehicle_blend_PS.inc b/src/extras/shaders/leedsVehicle_blend_PS.inc
deleted file mode 100644
index 94fb000c..00000000
--- a/src/extras/shaders/leedsVehicle_blend_PS.inc
+++ /dev/null
@@ -1,50 +0,0 @@
-static unsigned char leedsVehicle_blend_PS_cso[] = {
-  0x00, 0x02, 0xff, 0xff, 0xfe, 0xff, 0x40, 0x00, 0x43, 0x54, 0x41, 0x42,
-  0x1c, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff,
-  0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0xc1, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x02, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x84, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00,
-  0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
-  0x01, 0x00, 0x06, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x64, 0x69, 0x66, 0x66, 0x54, 0x65, 0x78, 0x00, 0x04, 0x00, 0x0c, 0x00,
-  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x65, 0x6e, 0x76, 0x54, 0x65, 0x78, 0x00, 0xab, 0x04, 0x00, 0x0c, 0x00,
-  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x66, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0xab, 0xab, 0xab,
-  0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x66, 0x78, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,
-  0x00, 0x70, 0x73, 0x5f, 0x32, 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72,
-  0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c,
-  0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f,
-  0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e,
-  0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0xab, 0xab,
-  0x51, 0x00, 0x00, 0x05, 0x02, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x07, 0xb0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x03, 0xb0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0f, 0x90,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0,
-  0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x01, 0x08, 0x0f, 0xa0,
-  0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xb0,
-  0x00, 0x08, 0xe4, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0f, 0x80,
-  0x01, 0x00, 0xe4, 0xb0, 0x01, 0x08, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04,
-  0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x90, 0x00, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0xa1, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x80,
-  0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xff, 0x90, 0x04, 0x00, 0x00, 0x04,
-  0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x00, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80,
-  0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x05, 0x00, 0x00, 0x03,
-  0x01, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xaa, 0xb0,
-  0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x08, 0x80, 0x01, 0x00, 0xff, 0x80,
-  0x01, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x80,
-  0x01, 0x00, 0x00, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x08, 0x80,
-  0x01, 0x00, 0xff, 0x80, 0x02, 0x00, 0x00, 0x81, 0x02, 0x00, 0x00, 0xa0,
-  0x04, 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, 0x80, 0x00, 0x00, 0xff, 0x80,
-  0x01, 0x00, 0xff, 0x80, 0x02, 0x00, 0xff, 0x80, 0x12, 0x00, 0x00, 0x04,
-  0x03, 0x00, 0x07, 0x80, 0x02, 0x00, 0xff, 0x80, 0x01, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80,
-  0x03, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00
-};
diff --git a/src/extras/shaders/leedsVehicle_mobile_PS.cso b/src/extras/shaders/leedsVehicle_mobile_PS.cso
deleted file mode 100644
index 04ffcf8e8d8ae1bec38489bf0937fad175e3a0c8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 728
zcmZ9JJx{_=6o%h^@DXEZ;^bf=qb>w64lI7a;(!AJGa*8i2$ldbxYd8a;ONkqI&^S%
z@dp@xfdh-1zrgyQ+m;w_b9&Et?t4zpJ%t{IKVbv4)@gMIKu+U}EX_?~FwW2(=^853
z@g$t<nPyO+A&nPBfH&?sP2>ALW}k{hx`cfxCfPZB$2tbg(z$J{S#Mz5t^OP)Hp%6Q
zR{!=+u>YUi&Q;ABIurQ5uc_|Lb&fqBcPHJ^6w{mgsxu>(?~6r?xaEv7o_5NeBF+bw
z6KCq!v;5x0e*Uc9tmm88-Clo^uQ{XfU`VG@C|3%V!*b!ER4T!504Woe2e`+y*SIW%
zrxY)qkRK&{HyV}82?vSKe%8MJ#|NxMtXUvyd5N#luc}{TvCb+$cIC+!HDp`^E06!e
z5MRUUL1%0NChJNZm@58I`8q6@=dQ+l(MXPtw&+xyEiyx~rDCk>rdZoRmO2DtQM^rk
zs7&g}xx_s4QfSkn9AT^<=R_Lzt<HH@xr^8$=_RVEm@B<-W;|a8(jRr6+?jI`-wi|H
E7n;v~c>n+a

diff --git a/src/extras/shaders/leedsVehicle_mobile_PS.hlsl b/src/extras/shaders/leedsVehicle_mobile_PS.hlsl
index da09b872..a343b32f 100644
--- a/src/extras/shaders/leedsVehicle_mobile_PS.hlsl
+++ b/src/extras/shaders/leedsVehicle_mobile_PS.hlsl
@@ -14,9 +14,9 @@ sampler2D envTex : register(s1);
 
 float4 fogColor : register(c0);
 
-float4 fxparams : register(c1);
-float3 skyTop : register(c2);
-float3 skyBot : register(c3);
+float4 fxparams : register(c2);
+float3 skyTop : register(c3);
+float3 skyBot : register(c4);
 
 #define shininess (fxparams.x)
 
diff --git a/src/extras/shaders/leedsVehicle_vs_gl.inc b/src/extras/shaders/leedsVehicle_vs_gl.inc
deleted file mode 100644
index eb36b6e9..00000000
--- a/src/extras/shaders/leedsVehicle_vs_gl.inc
+++ /dev/null
@@ -1,29 +0,0 @@
-const char *leedsVehicle_vert_src =
-"uniform mat4 u_texMatrix;\n"
-
-"VSIN(ATTRIB_POS)	vec3 in_pos;\n"
-
-"VSOUT vec4 v_color;\n"
-"VSOUT vec2 v_tex0;\n"
-"VSOUT vec2 v_tex1;\n"
-"VSOUT float v_fog;\n"
-
-"void\n"
-"main(void)\n"
-"{\n"
-"	vec4 Vertex = u_world * vec4(in_pos, 1.0);\n"
-"	gl_Position = u_proj * u_view * Vertex;\n"
-"	vec3 Normal = mat3(u_world) * in_normal;\n"
-
-"	v_tex0 = in_tex0;\n"
-"	v_tex1 = (u_texMatrix * vec4(Normal, 1.0)).xy;\n"
-
-"	v_color = in_color;\n"
-"	v_color.rgb += u_ambLight.rgb*surfAmbient;\n"
-"	v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n"
-"	v_color = clamp(v_color, 0.0, 1.0);\n"
-"	v_color *= u_matColor;\n"
-
-"	v_fog = DoFog(gl_Position.w);\n"
-"}\n"
-;
diff --git a/src/extras/shaders/make.cmd b/src/extras/shaders/make.cmd
deleted file mode 100644
index 8404ac6c..00000000
--- a/src/extras/shaders/make.cmd
+++ /dev/null
@@ -1,3 +0,0 @@
-@echo off
-for %%f in (*PS.hlsl) do "%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T ps_2_0 /nologo /E main /Fo %%~nf.cso %%f
-for %%f in (*VS.hlsl) do "%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T vs_2_0 /nologo /E main /Fo %%~nf.cso %%f
diff --git a/src/extras/shaders/make_glsl.sh b/src/extras/shaders/make_glsl.sh
new file mode 100644
index 00000000..0af98961
--- /dev/null
+++ b/src/extras/shaders/make_glsl.sh
@@ -0,0 +1,9 @@
+#!sh
+for i in *.vert; do
+	echo $i
+	./makeinc_glsl.sh $i
+done
+for i in *.frag; do
+	echo $i
+	./makeinc_glsl.sh $i
+done
diff --git a/src/extras/shaders/make_hlsl.cmd b/src/extras/shaders/make_hlsl.cmd
new file mode 100644
index 00000000..ae3aacb9
--- /dev/null
+++ b/src/extras/shaders/make_hlsl.cmd
@@ -0,0 +1,7 @@
+@echo off
+for %%f in (*PS.hlsl) do "%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T ps_2_0 /nologo /E main /Fo obj\%%~nf.cso %%f
+for %%f in (*VS.hlsl) do "%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T vs_2_0 /nologo /E main /Fo obj\%%~nf.cso %%f
+
+"%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T vs_2_0 /nologo /E main /DENVMAP /Fo obj\leedsDefault_ENV_VS.cso leedsDefault_VS_x.hlsl
+"%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T ps_2_0 /nologo /E main /DPASS_ADD /Fo obj\leedsDefault_ADD_PS.cso leedsDefault_PS_x.hlsl
+"%DXSDK_DIR%\Utilities\bin\x86\fxc.exe" /T ps_2_0 /nologo /E main /DPASS_BLEND /Fo obj\leedsDefault_BLEND_PS.cso leedsDefault_PS_x.hlsl
diff --git a/src/extras/shaders/makeinc_glsl.sh b/src/extras/shaders/makeinc_glsl.sh
new file mode 100644
index 00000000..2bc6a387
--- /dev/null
+++ b/src/extras/shaders/makeinc_glsl.sh
@@ -0,0 +1,6 @@
+#!sh
+ext=${1##*.}
+name=${1%.*}
+(echo "const char *${name}_${ext}_src =";\
+sed 's/..*/"&\\n"/' $1;\
+echo ';') > obj/${name}_${ext}.inc
diff --git a/src/extras/shaders/makeinc.sh b/src/extras/shaders/makeinc_hlsl.sh
similarity index 93%
rename from src/extras/shaders/makeinc.sh
rename to src/extras/shaders/makeinc_hlsl.sh
index a649af33..a5b12867 100644
--- a/src/extras/shaders/makeinc.sh
+++ b/src/extras/shaders/makeinc_hlsl.sh
@@ -1,4 +1,5 @@
 #!sh
+cd obj
 for i in *cso; do
 	(echo -n 'static '
 	xxd -i $i | grep -v '_len = ') > ${i%cso}inc
diff --git a/src/extras/shaders/colourfilterLCS_PS.cso b/src/extras/shaders/obj/colourfilterLCS_PS.cso
similarity index 100%
rename from src/extras/shaders/colourfilterLCS_PS.cso
rename to src/extras/shaders/obj/colourfilterLCS_PS.cso
diff --git a/src/extras/shaders/colourfilterLCS_PS.inc b/src/extras/shaders/obj/colourfilterLCS_PS.inc
similarity index 100%
rename from src/extras/shaders/colourfilterLCS_PS.inc
rename to src/extras/shaders/obj/colourfilterLCS_PS.inc
diff --git a/src/extras/shaders/colourfilterLCS_fs_gl.inc b/src/extras/shaders/obj/colourfilterLCS_frag.inc
similarity index 100%
rename from src/extras/shaders/colourfilterLCS_fs_gl.inc
rename to src/extras/shaders/obj/colourfilterLCS_frag.inc
diff --git a/src/extras/shaders/contrastPS.cso b/src/extras/shaders/obj/contrastPS.cso
similarity index 100%
rename from src/extras/shaders/contrastPS.cso
rename to src/extras/shaders/obj/contrastPS.cso
diff --git a/src/extras/shaders/contrastPS.inc b/src/extras/shaders/obj/contrastPS.inc
similarity index 100%
rename from src/extras/shaders/contrastPS.inc
rename to src/extras/shaders/obj/contrastPS.inc
diff --git a/src/extras/shaders/contrast_fs_gl.inc b/src/extras/shaders/obj/contrast_frag.inc
similarity index 100%
rename from src/extras/shaders/contrast_fs_gl.inc
rename to src/extras/shaders/obj/contrast_frag.inc
diff --git a/src/extras/shaders/default_UV2_VS.cso b/src/extras/shaders/obj/default_UV2_VS.cso
similarity index 100%
rename from src/extras/shaders/default_UV2_VS.cso
rename to src/extras/shaders/obj/default_UV2_VS.cso
diff --git a/src/extras/shaders/default_UV2_VS.inc b/src/extras/shaders/obj/default_UV2_VS.inc
similarity index 100%
rename from src/extras/shaders/default_UV2_VS.inc
rename to src/extras/shaders/obj/default_UV2_VS.inc
diff --git a/src/extras/shaders/default_UV2_gl.inc b/src/extras/shaders/obj/default_UV2_vert.inc
similarity index 100%
rename from src/extras/shaders/default_UV2_gl.inc
rename to src/extras/shaders/obj/default_UV2_vert.inc
diff --git a/src/extras/shaders/im2d_UV2_gl.inc b/src/extras/shaders/obj/im2d_UV2_vert.inc
similarity index 100%
rename from src/extras/shaders/im2d_UV2_gl.inc
rename to src/extras/shaders/obj/im2d_UV2_vert.inc
diff --git a/src/extras/shaders/im2d_gl.inc b/src/extras/shaders/obj/im2d_vert.inc
similarity index 100%
rename from src/extras/shaders/im2d_gl.inc
rename to src/extras/shaders/obj/im2d_vert.inc
diff --git a/src/extras/shaders/leedsBuilding_VS.cso b/src/extras/shaders/obj/leedsBuilding_VS.cso
similarity index 100%
rename from src/extras/shaders/leedsBuilding_VS.cso
rename to src/extras/shaders/obj/leedsBuilding_VS.cso
diff --git a/src/extras/shaders/leedsBuilding_VS.inc b/src/extras/shaders/obj/leedsBuilding_VS.inc
similarity index 100%
rename from src/extras/shaders/leedsBuilding_VS.inc
rename to src/extras/shaders/obj/leedsBuilding_VS.inc
diff --git a/src/extras/shaders/leedsBuilding_mobile_VS.cso b/src/extras/shaders/obj/leedsBuilding_mobile_VS.cso
similarity index 100%
rename from src/extras/shaders/leedsBuilding_mobile_VS.cso
rename to src/extras/shaders/obj/leedsBuilding_mobile_VS.cso
diff --git a/src/extras/shaders/leedsBuilding_mobile_VS.inc b/src/extras/shaders/obj/leedsBuilding_mobile_VS.inc
similarity index 100%
rename from src/extras/shaders/leedsBuilding_mobile_VS.inc
rename to src/extras/shaders/obj/leedsBuilding_mobile_VS.inc
diff --git a/src/extras/shaders/leedsBuilding_mobile_vs_gl.inc b/src/extras/shaders/obj/leedsBuilding_mobile_vert.inc
similarity index 100%
rename from src/extras/shaders/leedsBuilding_mobile_vs_gl.inc
rename to src/extras/shaders/obj/leedsBuilding_mobile_vert.inc
diff --git a/src/extras/shaders/leedsBuilding_vs_gl.inc b/src/extras/shaders/obj/leedsBuilding_vert.inc
similarity index 100%
rename from src/extras/shaders/leedsBuilding_vs_gl.inc
rename to src/extras/shaders/obj/leedsBuilding_vert.inc
diff --git a/src/extras/shaders/obj/leedsDefault_ADD_PS.cso b/src/extras/shaders/obj/leedsDefault_ADD_PS.cso
new file mode 100644
index 0000000000000000000000000000000000000000..db862fdb5824572b1b03183f8ea8a954dacd5e21
GIT binary patch
literal 532
zcmZ9IF;Bu!6ot<#RT^W`#KpzLj=B(wabOe%9dHqL(m<;uU`cBXV}F1HKfr;(i7p)+
z{RytFPWU%`p8IHt@g*nkp6|YU@^WEm{iCnY>0h>w0DMy*+u<c13i#rcQ5KEDE}mJ-
zd7)~QV&_!=&l^=M-@O|GeDJm?c~{MT8YYQ*TQ-a*agq*$Nr+sT6r26c8I7Z;AI@Q8
z-=tSOe0UO^|L0MB*O53x^I4Dt(-gCG&>WoMW;{&dG>#s<liO48y4&k|z58GkCSE6=
z&c+iKtwyueXk9cL=f3YF&yP3X&wzSS)%@SK2HZu-7jWEVRV&tQvm!TBSQpA!8?WFp
zYh8ezd*%uqdYy4crLRk$S{0kVcx{+?nP;B(#a~ah<X$X=L(@M1Yzs2GD$4gun@o{e
PoL6P0%<$i4Mr+^~m7!t+

literal 0
HcmV?d00001

diff --git a/src/extras/shaders/obj/leedsDefault_ADD_PS.inc b/src/extras/shaders/obj/leedsDefault_ADD_PS.inc
new file mode 100644
index 00000000..7a04522f
--- /dev/null
+++ b/src/extras/shaders/obj/leedsDefault_ADD_PS.inc
@@ -0,0 +1,47 @@
+static unsigned char leedsDefault_ADD_PS_cso[] = {
+  0x00, 0x02, 0xff, 0xff, 0xfe, 0xff, 0x47, 0x00, 0x43, 0x54, 0x41, 0x42,
+  0x1c, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff,
+  0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0xde, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+  0x01, 0x00, 0x06, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x9c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+  0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0xbc, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x02, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xd5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00,
+  0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f,
+  0x72, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00,
+  0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x64, 0x69, 0x66, 0x66, 0x54, 0x65, 0x78, 0x00, 0x04, 0x00, 0x0c, 0x00,
+  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x65, 0x6e, 0x76, 0x54, 0x65, 0x78, 0x00, 0xab, 0x04, 0x00, 0x0c, 0x00,
+  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x66, 0x78, 0x70,
+  0x61, 0x72, 0x61, 0x6d, 0x73, 0x00, 0x70, 0x73, 0x5f, 0x32, 0x5f, 0x30,
+  0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28,
+  0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64,
+  0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20,
+  0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31,
+  0x31, 0x00, 0xab, 0xab, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x07, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x01, 0x00, 0x03, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90,
+  0x00, 0x08, 0x0f, 0xa0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90,
+  0x01, 0x08, 0x0f, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80,
+  0x01, 0x00, 0xe4, 0xb0, 0x01, 0x08, 0xe4, 0xa0, 0x42, 0x00, 0x00, 0x03,
+  0x01, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xb0, 0x00, 0x08, 0xe4, 0xa0,
+  0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xff, 0x80,
+  0x02, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80,
+  0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x05, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xe4, 0x80,
+  0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0x80,
+  0x00, 0x00, 0xe4, 0x90, 0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x0f, 0x80,
+  0x01, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02,
+  0x01, 0x00, 0x17, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x12, 0x00, 0x00, 0x04,
+  0x02, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x01, 0x00, 0xe4, 0x80,
+  0x00, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x07, 0x80,
+  0x02, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xff, 0x80, 0x00, 0x00, 0xe4, 0x80,
+  0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0x80,
+  0xff, 0xff, 0x00, 0x00
+};
diff --git a/src/extras/shaders/obj/leedsDefault_BLEND_PS.cso b/src/extras/shaders/obj/leedsDefault_BLEND_PS.cso
new file mode 100644
index 0000000000000000000000000000000000000000..e875c7958234cf6ccc322fea692de702f12666ef
GIT binary patch
literal 608
zcmZ8du};EJ6g{skLX1fh7Z(#d>OutLz+{9$2OJc3(m<;uU`cBXW8EG200#yqx^!^#
z6I@-L>Tg)jeYC{*lAC+Zx%Zy;-i49pKlueZ{qy!dfNut<RhWcB0bfip!yr-E!ZWd)
z7lz4Dth|cA^TsfXzIUwvAIt_r`pVf)t%>9IMjHl`AdH6Y#6zOAi^cl-jK;p-_vWy$
zquop0yMGip`LFxIZAa|j&u4DvP9w~sL3417tMM=lqQHM}4sVW}%Wkjh^zPh|7do9_
zIvY<2TJ>hD-a2j8Pa2H|lH?kwn6Q`J!ddYgoetLDih*icV!nHW0eeyC3)Jjoi4}2M
zug>OdmZFwvu3*QCT#<ACT&=E4&*Cp<&yxS=O82A|?*f*AD)A~6&M4+Z%VUF@%q#YA
zmf9*6&h3*+9oo-CO=F9GidbqU@+UrIDVo&9ub9#In)Kv6HSx`uVeqe<%i=r-egXPV
BY)}9I

literal 0
HcmV?d00001

diff --git a/src/extras/shaders/obj/leedsDefault_BLEND_PS.inc b/src/extras/shaders/obj/leedsDefault_BLEND_PS.inc
new file mode 100644
index 00000000..be3a6d96
--- /dev/null
+++ b/src/extras/shaders/obj/leedsDefault_BLEND_PS.inc
@@ -0,0 +1,53 @@
+static unsigned char leedsDefault_BLEND_PS_cso[] = {
+  0x00, 0x02, 0xff, 0xff, 0xfe, 0xff, 0x47, 0x00, 0x43, 0x54, 0x41, 0x42,
+  0x1c, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff,
+  0x05, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0xde, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
+  0x01, 0x00, 0x06, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x9c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+  0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0xbc, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x02, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xd5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00,
+  0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f,
+  0x72, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0xab, 0x01, 0x00, 0x03, 0x00,
+  0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x64, 0x69, 0x66, 0x66, 0x54, 0x65, 0x78, 0x00, 0x04, 0x00, 0x0c, 0x00,
+  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x65, 0x6e, 0x76, 0x54, 0x65, 0x78, 0x00, 0xab, 0x04, 0x00, 0x0c, 0x00,
+  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x66, 0x78, 0x70,
+  0x61, 0x72, 0x61, 0x6d, 0x73, 0x00, 0x70, 0x73, 0x5f, 0x32, 0x5f, 0x30,
+  0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28,
+  0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, 0x61, 0x64,
+  0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20,
+  0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, 0x31, 0x31,
+  0x31, 0x00, 0xab, 0xab, 0x51, 0x00, 0x00, 0x05, 0x03, 0x00, 0x0f, 0xa0,
+  0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x07, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x01, 0x00, 0x03, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80,
+  0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90,
+  0x00, 0x08, 0x0f, 0xa0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90,
+  0x01, 0x08, 0x0f, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80,
+  0x00, 0x00, 0xe4, 0xb0, 0x00, 0x08, 0xe4, 0xa0, 0x42, 0x00, 0x00, 0x03,
+  0x01, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xb0, 0x01, 0x08, 0xe4, 0xa0,
+  0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80,
+  0x00, 0x00, 0xe4, 0x90, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80,
+  0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02,
+  0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x12, 0x00, 0x00, 0x04,
+  0x02, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x00, 0x00, 0xe4, 0x80,
+  0x00, 0x00, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x80,
+  0x00, 0x00, 0xff, 0x80, 0x02, 0x00, 0xe4, 0x80, 0x05, 0x00, 0x00, 0x03,
+  0x01, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xaa, 0xb0,
+  0x05, 0x00, 0x00, 0x03, 0x02, 0x00, 0x01, 0x80, 0x01, 0x00, 0xff, 0x80,
+  0x02, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x08, 0x80,
+  0x02, 0x00, 0x00, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x08, 0x80,
+  0x01, 0x00, 0xff, 0x80, 0x03, 0x00, 0xff, 0x81, 0x03, 0x00, 0x00, 0xa0,
+  0x04, 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, 0x80, 0x00, 0x00, 0xff, 0x80,
+  0x01, 0x00, 0xff, 0x80, 0x02, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x04,
+  0x03, 0x00, 0x07, 0x80, 0x02, 0x00, 0x00, 0x80, 0x01, 0x00, 0xe4, 0x80,
+  0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80,
+  0x03, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00
+};
diff --git a/src/extras/shaders/leedsVehicle_VS.cso b/src/extras/shaders/obj/leedsDefault_ENV_VS.cso
similarity index 100%
rename from src/extras/shaders/leedsVehicle_VS.cso
rename to src/extras/shaders/obj/leedsDefault_ENV_VS.cso
diff --git a/src/extras/shaders/leedsVehicle_VS.inc b/src/extras/shaders/obj/leedsDefault_ENV_VS.inc
similarity index 99%
rename from src/extras/shaders/leedsVehicle_VS.inc
rename to src/extras/shaders/obj/leedsDefault_ENV_VS.inc
index 89527d72..ed27d470 100644
--- a/src/extras/shaders/leedsVehicle_VS.inc
+++ b/src/extras/shaders/obj/leedsDefault_ENV_VS.inc
@@ -1,4 +1,4 @@
-static unsigned char leedsVehicle_VS_cso[] = {
+static unsigned char leedsDefault_ENV_VS_cso[] = {
   0x00, 0x02, 0xfe, 0xff, 0xfe, 0xff, 0x8d, 0x00, 0x43, 0x54, 0x41, 0x42,
   0x1c, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff,
   0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
diff --git a/src/extras/shaders/leedsVehicle_blend_gl.inc b/src/extras/shaders/obj/leedsDefault_frag.inc
similarity index 59%
rename from src/extras/shaders/leedsVehicle_blend_gl.inc
rename to src/extras/shaders/obj/leedsDefault_frag.inc
index 707afb10..312a32a3 100644
--- a/src/extras/shaders/leedsVehicle_blend_gl.inc
+++ b/src/extras/shaders/obj/leedsDefault_frag.inc
@@ -1,31 +1,47 @@
-const char *leedsVehicle_blend_frag_src =
+const char *leedsDefault_frag_src =
 "uniform sampler2D tex0;\n"
 "uniform sampler2D tex1;\n"
 
 "uniform float u_fxparams;\n"
+"uniform vec4 u_colorscale;\n"
 
 "#define shininess (u_fxparams)\n"
 
 "FSIN vec4 v_color;\n"
 "FSIN vec2 v_tex0;\n"
+"#if defined(PASS_BLEND) || defined(PASS_ADD)\n"
 "FSIN vec2 v_tex1;\n"
+"#endif\n"
 "FSIN float v_fog;\n"
 
 "void\n"
 "main(void)\n"
 "{\n"
-"	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n"
+"	vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y))*u_colorscale;\n"
+"	pass1.rgb = clamp(pass1.rgb, 0.0, 1.0);\n"
+"	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);\n"
+
+"	vec4 color;\n"
+"#if defined(PASS_BLEND) || defined(PASS_ADD)\n"
 "	vec4 pass2 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));\n"
 "	pass2.a *= shininess;\n"
-
-"	pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);\n"
 "	pass2.rgb = mix(vec3(0.0, 0.0, 0.0), pass2.rgb, v_fog);\n"
 
 "	// We simulate drawing this in two passes.\n"
+"#if defined(PASS_ADD)\n"
+"	// First pass with standard blending, second with addition\n"
+"	// We premultiply alpha so render state should be one.\n"
+"	color.rgb = pass1.rgb*pass1.a + pass2.rgb*pass2.a;\n"
+"	color.a = pass1.a;\n"
+"#elif defined(PASS_BLEND)\n"
 "	// We premultiply alpha so render state should be one.\n"
-"	vec4 color;\n"
 "	color.rgb = pass1.rgb*pass1.a*(1.0-pass2.a) + pass2.rgb*pass2.a;\n"
 "	color.a = pass1.a*(1.0-pass2.a) + pass2.a;\n"
+"#endif\n"
+
+"#else\n"
+"	color = pass1;\n"
+"#endif\n"
 
 "	DoAlphaTest(color.a);\n"
 
diff --git a/src/extras/shaders/obj/leedsDefault_vert.inc b/src/extras/shaders/obj/leedsDefault_vert.inc
new file mode 100644
index 00000000..4ff94fd4
--- /dev/null
+++ b/src/extras/shaders/obj/leedsDefault_vert.inc
@@ -0,0 +1,53 @@
+const char *leedsDefault_vert_src =
+"#ifdef ENVMAP\n"
+"uniform mat4 u_texMatrix;\n"
+"#endif\n"
+"#ifdef SKIN\n"
+"uniform mat4 u_boneMatrices[64];\n"
+"#endif\n"
+
+"VSIN(ATTRIB_POS)	vec3 in_pos;\n"
+
+"VSOUT vec4 v_color;\n"
+"VSOUT vec2 v_tex0;\n"
+"#ifdef ENVMAP\n"
+"VSOUT vec2 v_tex1;\n"
+"#endif\n"
+"VSOUT float v_fog;\n"
+
+"void\n"
+"main(void)\n"
+"{\n"
+"#ifdef SKIN\n"
+"	vec3 SkinVertex = vec3(0.0, 0.0, 0.0);\n"
+"	vec3 SkinNormal = vec3(0.0, 0.0, 0.0);\n"
+"	for(int i = 0; i < 4; i++){\n"
+"		SkinVertex += (u_boneMatrices[int(in_indices[i])] * vec4(in_pos, 1.0)).xyz * in_weights[i];\n"
+"		SkinNormal += (mat3(u_boneMatrices[int(in_indices[i])]) * in_normal) * in_weights[i];\n"
+"	}\n"
+
+"	vec4 Vertex = u_world * vec4(SkinVertex, 1.0);\n"
+"	gl_Position = u_proj * u_view * Vertex;\n"
+"	vec3 Normal = mat3(u_world) * SkinNormal;\n"
+"#else\n"
+"	vec4 Vertex = u_world * vec4(in_pos, 1.0);\n"
+"	gl_Position = u_proj * u_view * Vertex;\n"
+"	vec3 Normal = mat3(u_world) * in_normal;\n"
+"#endif\n"
+
+"	v_tex0 = in_tex0;\n"
+"#ifdef ENVMAP\n"
+"	v_tex1 = (u_texMatrix * vec4(Normal, 1.0)).xy;\n"
+"#endif\n"
+
+"	v_color = in_color;\n"
+"	v_color.rgb += u_ambLight.rgb*surfAmbient;\n"
+"	v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n"
+"	// PS2 clamps before material color\n"
+"	// PSP clamps after...maybe another constant for this?\n"
+"	v_color = clamp(v_color, 0.0, 1.0);\n"
+"	v_color *= u_matColor;\n"
+
+"	v_fog = DoFog(gl_Position.w);\n"
+"}\n"
+;
diff --git a/src/extras/shaders/obj/leedsVehicle_mobile_PS.cso b/src/extras/shaders/obj/leedsVehicle_mobile_PS.cso
new file mode 100644
index 0000000000000000000000000000000000000000..b6f70b5b3b5d0ff4f5f2e62fad74af67311340f7
GIT binary patch
literal 728
zcmZ9JzfQtX6vn^X79_^l#L2-#MqP+t99aAVivtb{%!VjcB3J^(;C6ij21kd^)Pcd>
z#Ro7xfkPKJpTPQ^+tR_?eC;{Ed(PM1Q&@5Q8=s=yI;w2|SXI1{<@t~t%$KMqhPFv9
zJPYS~p==f?<nd|<@Xn`2Dc(O)_GOqwww$qV!yK|T{G@eE*d>mu8N2LxUaLESgB5bQ
zlGVMv7aacQo_|&M`~C=F7%Jl>??{$68FogU!5HJ4hnjy!F7Fa0i@4<vF&v*)&UbLq
zyBPUn-@7YrooyG78_h<sdEL3}j*4}EFzodiR7;g=sk&Dw?Uu`Bgr`7G!3_X?K)t25
z5S}x9=a77V!8empX-;^)i1|HP%voeH;7-$;DGF||h!x|S`86(mqB#mtAY)Wm(hj14
z|H777A$qi#JAgx9$>$VnKTW>{S6hg*V!zZ#kA=3>8J{&W+pw8o^wl|f+bFOOb5WA7
zYa6kV_{hHG+zWDOQ%R37`lmff4L!_0&njmTO&8yicp9eVTR1cB&*ThJ$8*5qTqM?U
G4EzDN8GVBQ

literal 0
HcmV?d00001

diff --git a/src/extras/shaders/leedsVehicle_mobile_PS.inc b/src/extras/shaders/obj/leedsVehicle_mobile_PS.inc
similarity index 86%
rename from src/extras/shaders/leedsVehicle_mobile_PS.inc
rename to src/extras/shaders/obj/leedsVehicle_mobile_PS.inc
index ab8cc048..946b1c7a 100644
--- a/src/extras/shaders/leedsVehicle_mobile_PS.inc
+++ b/src/extras/shaders/obj/leedsVehicle_mobile_PS.inc
@@ -7,11 +7,11 @@ static unsigned char leedsVehicle_mobile_PS_cso[] = {
   0xac, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00,
   0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00,
   0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
-  0x01, 0x00, 0x06, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+  0x01, 0x00, 0x0a, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xe9, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x12, 0x00,
   0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0xf0, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x64, 0x69, 0x66, 0x66, 0x54, 0x65, 0x78, 0x00,
   0x04, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x65, 0x6e, 0x76, 0x54, 0x65, 0x78, 0x00, 0xab,
@@ -27,7 +27,7 @@ static unsigned char leedsVehicle_mobile_PS_cso[] = {
   0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70,
   0x69, 0x6c, 0x65, 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35,
   0x32, 0x2e, 0x33, 0x31, 0x31, 0x31, 0x00, 0xab, 0x51, 0x00, 0x00, 0x05,
-  0x04, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0xbf,
+  0x01, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0xbf,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x05,
   0x05, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x30, 0x40, 0x00, 0x00, 0x80, 0x3e,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x02,
@@ -38,13 +38,13 @@ static unsigned char leedsVehicle_mobile_PS_cso[] = {
   0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0, 0x1f, 0x00, 0x00, 0x02,
   0x00, 0x00, 0x00, 0x90, 0x01, 0x08, 0x0f, 0xa0, 0x42, 0x00, 0x00, 0x03,
   0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xb0, 0x00, 0x08, 0xe4, 0xa0,
-  0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x07, 0x80, 0x03, 0x00, 0xe4, 0xa0,
+  0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x07, 0x80, 0x04, 0x00, 0xe4, 0xa0,
   0x02, 0x00, 0x00, 0x03, 0x01, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x81,
-  0x02, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x02, 0x00, 0x03, 0x80,
-  0x01, 0x00, 0xe4, 0xb0, 0x04, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0xd2, 0xa0,
+  0x03, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x02, 0x00, 0x03, 0x80,
+  0x01, 0x00, 0xe4, 0xb0, 0x01, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0xd2, 0xa0,
   0x42, 0x00, 0x00, 0x03, 0x02, 0x00, 0x0f, 0x80, 0x02, 0x00, 0xe4, 0x80,
   0x01, 0x08, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x07, 0x80,
-  0x02, 0x00, 0x55, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x03, 0x00, 0xe4, 0xa0,
+  0x02, 0x00, 0x55, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x04, 0x00, 0xe4, 0xa0,
   0x12, 0x00, 0x00, 0x04, 0x03, 0x00, 0x07, 0x80, 0x02, 0x00, 0xaa, 0x80,
   0x01, 0x00, 0xe4, 0x80, 0x02, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x03,
   0x03, 0x00, 0x08, 0x80, 0x02, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00, 0xb0,
@@ -53,7 +53,7 @@ static unsigned char leedsVehicle_mobile_PS_cso[] = {
   0x03, 0x00, 0xff, 0x80, 0x05, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x55, 0xa0,
   0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x08, 0x80, 0x03, 0x00, 0xff, 0x80,
   0x02, 0x00, 0x55, 0xb0, 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x08, 0x80,
-  0x03, 0x00, 0xff, 0x80, 0x01, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x03,
+  0x03, 0x00, 0xff, 0x80, 0x02, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x03,
   0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x90,
   0x04, 0x00, 0x00, 0x04, 0x01, 0x00, 0x07, 0x80, 0x03, 0x00, 0xff, 0x80,
   0x03, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x12, 0x00, 0x00, 0x04,
diff --git a/src/extras/shaders/leedsVehicle_mobile_VS.cso b/src/extras/shaders/obj/leedsVehicle_mobile_VS.cso
similarity index 100%
rename from src/extras/shaders/leedsVehicle_mobile_VS.cso
rename to src/extras/shaders/obj/leedsVehicle_mobile_VS.cso
diff --git a/src/extras/shaders/leedsVehicle_mobile_VS.inc b/src/extras/shaders/obj/leedsVehicle_mobile_VS.inc
similarity index 100%
rename from src/extras/shaders/leedsVehicle_mobile_VS.inc
rename to src/extras/shaders/obj/leedsVehicle_mobile_VS.inc
diff --git a/src/extras/shaders/leedsVehicle_mobile_fs_gl.inc b/src/extras/shaders/obj/leedsVehicle_mobile_frag.inc
similarity index 100%
rename from src/extras/shaders/leedsVehicle_mobile_fs_gl.inc
rename to src/extras/shaders/obj/leedsVehicle_mobile_frag.inc
diff --git a/src/extras/shaders/leedsVehicle_mobile_vs_gl.inc b/src/extras/shaders/obj/leedsVehicle_mobile_vert.inc
similarity index 100%
rename from src/extras/shaders/leedsVehicle_mobile_vs_gl.inc
rename to src/extras/shaders/obj/leedsVehicle_mobile_vert.inc
diff --git a/src/extras/shaders/neoGloss_PS.cso b/src/extras/shaders/obj/neoGloss_PS.cso
similarity index 100%
rename from src/extras/shaders/neoGloss_PS.cso
rename to src/extras/shaders/obj/neoGloss_PS.cso
diff --git a/src/extras/shaders/neoGloss_PS.inc b/src/extras/shaders/obj/neoGloss_PS.inc
similarity index 100%
rename from src/extras/shaders/neoGloss_PS.inc
rename to src/extras/shaders/obj/neoGloss_PS.inc
diff --git a/src/extras/shaders/neoGloss_VS.cso b/src/extras/shaders/obj/neoGloss_VS.cso
similarity index 100%
rename from src/extras/shaders/neoGloss_VS.cso
rename to src/extras/shaders/obj/neoGloss_VS.cso
diff --git a/src/extras/shaders/neoGloss_VS.inc b/src/extras/shaders/obj/neoGloss_VS.inc
similarity index 100%
rename from src/extras/shaders/neoGloss_VS.inc
rename to src/extras/shaders/obj/neoGloss_VS.inc
diff --git a/src/extras/shaders/neoGloss_fs_gl.inc b/src/extras/shaders/obj/neoGloss_frag.inc
similarity index 100%
rename from src/extras/shaders/neoGloss_fs_gl.inc
rename to src/extras/shaders/obj/neoGloss_frag.inc
diff --git a/src/extras/shaders/neoGloss_vs_gl.inc b/src/extras/shaders/obj/neoGloss_vert.inc
similarity index 100%
rename from src/extras/shaders/neoGloss_vs_gl.inc
rename to src/extras/shaders/obj/neoGloss_vert.inc
diff --git a/src/extras/shaders/neoRimSkin_VS.cso b/src/extras/shaders/obj/neoRimSkin_VS.cso
similarity index 100%
rename from src/extras/shaders/neoRimSkin_VS.cso
rename to src/extras/shaders/obj/neoRimSkin_VS.cso
diff --git a/src/extras/shaders/neoRimSkin_VS.inc b/src/extras/shaders/obj/neoRimSkin_VS.inc
similarity index 100%
rename from src/extras/shaders/neoRimSkin_VS.inc
rename to src/extras/shaders/obj/neoRimSkin_VS.inc
diff --git a/src/extras/shaders/neoRimSkin_gl.inc b/src/extras/shaders/obj/neoRimSkin_vert.inc
similarity index 100%
rename from src/extras/shaders/neoRimSkin_gl.inc
rename to src/extras/shaders/obj/neoRimSkin_vert.inc
diff --git a/src/extras/shaders/neoRim_VS.cso b/src/extras/shaders/obj/neoRim_VS.cso
similarity index 100%
rename from src/extras/shaders/neoRim_VS.cso
rename to src/extras/shaders/obj/neoRim_VS.cso
diff --git a/src/extras/shaders/neoRim_VS.inc b/src/extras/shaders/obj/neoRim_VS.inc
similarity index 100%
rename from src/extras/shaders/neoRim_VS.inc
rename to src/extras/shaders/obj/neoRim_VS.inc
diff --git a/src/extras/shaders/neoRim_gl.inc b/src/extras/shaders/obj/neoRim_vert.inc
similarity index 100%
rename from src/extras/shaders/neoRim_gl.inc
rename to src/extras/shaders/obj/neoRim_vert.inc
diff --git a/src/extras/shaders/neoVehicle_PS.cso b/src/extras/shaders/obj/neoVehicle_PS.cso
similarity index 100%
rename from src/extras/shaders/neoVehicle_PS.cso
rename to src/extras/shaders/obj/neoVehicle_PS.cso
diff --git a/src/extras/shaders/neoVehicle_PS.inc b/src/extras/shaders/obj/neoVehicle_PS.inc
similarity index 100%
rename from src/extras/shaders/neoVehicle_PS.inc
rename to src/extras/shaders/obj/neoVehicle_PS.inc
diff --git a/src/extras/shaders/neoVehicle_VS.cso b/src/extras/shaders/obj/neoVehicle_VS.cso
similarity index 100%
rename from src/extras/shaders/neoVehicle_VS.cso
rename to src/extras/shaders/obj/neoVehicle_VS.cso
diff --git a/src/extras/shaders/neoVehicle_VS.inc b/src/extras/shaders/obj/neoVehicle_VS.inc
similarity index 100%
rename from src/extras/shaders/neoVehicle_VS.inc
rename to src/extras/shaders/obj/neoVehicle_VS.inc
diff --git a/src/extras/shaders/neoVehicle_fs_gl.inc b/src/extras/shaders/obj/neoVehicle_frag.inc
similarity index 100%
rename from src/extras/shaders/neoVehicle_fs_gl.inc
rename to src/extras/shaders/obj/neoVehicle_frag.inc
diff --git a/src/extras/shaders/neoVehicle_vs_gl.inc b/src/extras/shaders/obj/neoVehicle_vert.inc
similarity index 100%
rename from src/extras/shaders/neoVehicle_vs_gl.inc
rename to src/extras/shaders/obj/neoVehicle_vert.inc
diff --git a/src/extras/shaders/neoWorldVC_PS.cso b/src/extras/shaders/obj/neoWorldVC_PS.cso
similarity index 100%
rename from src/extras/shaders/neoWorldVC_PS.cso
rename to src/extras/shaders/obj/neoWorldVC_PS.cso
diff --git a/src/extras/shaders/neoWorldVC_PS.inc b/src/extras/shaders/obj/neoWorldVC_PS.inc
similarity index 100%
rename from src/extras/shaders/neoWorldVC_PS.inc
rename to src/extras/shaders/obj/neoWorldVC_PS.inc
diff --git a/src/extras/shaders/neoWorldVC_fs_gl.inc b/src/extras/shaders/obj/neoWorldVC_frag.inc
similarity index 100%
rename from src/extras/shaders/neoWorldVC_fs_gl.inc
rename to src/extras/shaders/obj/neoWorldVC_frag.inc
diff --git a/src/extras/shaders/scale_PS.cso b/src/extras/shaders/obj/scale_PS.cso
similarity index 69%
rename from src/extras/shaders/scale_PS.cso
rename to src/extras/shaders/obj/scale_PS.cso
index d7f7374ca56a40314173d452b93f4dedceb53d2b..7d8e07340b7e69464ee468650159ecc8875ce73d 100644
GIT binary patch
delta 76
zcmeysbcbn!1fvTh!;=N93=GT+4EzlY3{OCK0wV(h6C;B-m@mY@z{0@54rH&|08|SS
QTL6-0;DD(A|DS;Y0J_W)tpET3

delta 96
zcmcb^^nq!E1Y-mP!;=Y&3=B++4D1a+_5v0L1|R~n8yJCnAZ}!3U|?os-~h`12a5d%
atAVIrwE?IHtPf-c0|!4yPs9KJ3=9BUV;9l@

diff --git a/src/extras/shaders/scale_PS.inc b/src/extras/shaders/obj/scale_PS.inc
similarity index 76%
rename from src/extras/shaders/scale_PS.inc
rename to src/extras/shaders/obj/scale_PS.inc
index 5f711ac8..e8f42e38 100644
--- a/src/extras/shaders/scale_PS.inc
+++ b/src/extras/shaders/obj/scale_PS.inc
@@ -22,12 +22,10 @@ static unsigned char scale_PS_cso[] = {
   0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0,
   0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xb0,
   0x00, 0x08, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80,
-  0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x90, 0x01, 0x00, 0x00, 0x02,
-  0x01, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04,
-  0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0,
-  0x01, 0x00, 0xe4, 0x81, 0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x08, 0x80,
-  0x00, 0x00, 0xff, 0x80, 0x01, 0x00, 0xff, 0xa0, 0x04, 0x00, 0x00, 0x04,
-  0x01, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0, 0x00, 0x00, 0xe4, 0x80,
-  0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80,
-  0x01, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00
+  0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03,
+  0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x90,
+  0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x17, 0x80, 0x00, 0x00, 0xe4, 0x80,
+  0x12, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xaa, 0xb0,
+  0x01, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0xa0, 0x01, 0x00, 0x00, 0x02,
+  0x00, 0x08, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00
 };
diff --git a/src/extras/shaders/scale_fs_gl.inc b/src/extras/shaders/obj/scale_frag.inc
similarity index 89%
rename from src/extras/shaders/scale_fs_gl.inc
rename to src/extras/shaders/obj/scale_frag.inc
index 8d9563e2..14082bb9 100644
--- a/src/extras/shaders/scale_fs_gl.inc
+++ b/src/extras/shaders/obj/scale_frag.inc
@@ -11,6 +11,7 @@ const char *scale_frag_src =
 "{\n"
 "	vec4 color;\n"
 "	color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y))*u_colorscale;\n"
+"	color.rgb = clamp(color.rgb, 0.0, 1.0);\n"
 "	color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n"
 "	DoAlphaTest(color.a);\n"
 
diff --git a/src/extras/shaders/screenDroplet_PS.cso b/src/extras/shaders/obj/screenDroplet_PS.cso
similarity index 100%
rename from src/extras/shaders/screenDroplet_PS.cso
rename to src/extras/shaders/obj/screenDroplet_PS.cso
diff --git a/src/extras/shaders/screenDroplet_PS.inc b/src/extras/shaders/obj/screenDroplet_PS.inc
similarity index 100%
rename from src/extras/shaders/screenDroplet_PS.inc
rename to src/extras/shaders/obj/screenDroplet_PS.inc
diff --git a/src/extras/shaders/screenDroplet_fs_gl.inc b/src/extras/shaders/obj/screenDroplet_frag.inc
similarity index 100%
rename from src/extras/shaders/screenDroplet_fs_gl.inc
rename to src/extras/shaders/obj/screenDroplet_frag.inc
diff --git a/src/extras/shaders/simple_fs_gl.inc b/src/extras/shaders/obj/simple_frag.inc
similarity index 100%
rename from src/extras/shaders/simple_fs_gl.inc
rename to src/extras/shaders/obj/simple_frag.inc
diff --git a/src/extras/shaders/scale.frag b/src/extras/shaders/scale.frag
index 29165154..7d9d1ff4 100644
--- a/src/extras/shaders/scale.frag
+++ b/src/extras/shaders/scale.frag
@@ -10,6 +10,7 @@ main(void)
 {
 	vec4 color;
 	color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y))*u_colorscale;
+	color.rgb = clamp(color.rgb, 0.0, 1.0);
 	color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);
 	DoAlphaTest(color.a);
 
diff --git a/src/extras/shaders/scale_PS.hlsl b/src/extras/shaders/scale_PS.hlsl
index 92466e94..54da9c82 100644
--- a/src/extras/shaders/scale_PS.hlsl
+++ b/src/extras/shaders/scale_PS.hlsl
@@ -12,8 +12,8 @@ float4 colorscale : register(c1);
 float4 main(VS_out input) : COLOR
 {
 	float4 color = input.Color;
-	color *= tex2D(tex0, input.TexCoord0.xy);
-	color *= colorscale;
+	color *= tex2D(tex0, input.TexCoord0.xy)*colorscale;
+	color.rgb = clamp(color.rgb, 0.0, 1.0);
 	color.rgb = lerp(fogColor.rgb, color.rgb, input.TexCoord0.z);
 	return color;
 }
diff --git a/vendor/librw b/vendor/librw
index 61b288a9..78d540fc 160000
--- a/vendor/librw
+++ b/vendor/librw
@@ -1 +1 @@
-Subproject commit 61b288a9fe72ae4073c0ac5fd2a5815ed510c8c8
+Subproject commit 78d540fce0ca090b07377cee40d73eadfb7a699d

From 7e136a792f381b4c1d310c7058d779e9e87aeb6c Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 19 Jan 2021 20:42:16 +0100
Subject: [PATCH 11/19] work on colourfilters

---
 src/core/Camera.cpp                           |   5 +-
 src/core/re3.cpp                              |   4 +-
 src/extras/postfx.cpp                         |  93 ++++++++++++------
 src/extras/postfx.h                           |   5 +-
 src/extras/shaders/colourfilterLCS_PS.hlsl    |   5 +-
 src/extras/shaders/obj/colourfilterLCS_PS.cso | Bin 292 -> 308 bytes
 src/extras/shaders/obj/colourfilterLCS_PS.inc |  11 ++-
 src/fakerw/fake.cpp                           |   3 +
 src/fakerw/rwcore.h                           |   3 +
 9 files changed, 81 insertions(+), 48 deletions(-)

diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 992c7d74..951b7c41 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -3863,7 +3863,7 @@ CCamera::GetScreenFadeStatus(void)
 }
 
 
-
+//--LCS: TODO
 void
 CCamera::RenderMotionBlur(void)
 {
@@ -3872,7 +3872,8 @@ CCamera::RenderMotionBlur(void)
 
 	CMBlur::MotionBlurRender(m_pRwCamera,
 		m_BlurRed, m_BlurGreen, m_BlurBlue,
-		m_motionBlur, m_BlurType, m_imotionBlurAddAlpha);
+//		m_motionBlur, m_BlurType, m_imotionBlurAddAlpha);
+		m_motionBlur, m_BlurType, 32);	// hack hack
 }
 
 void
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index bbc02d26..12b49c9a 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -651,8 +651,8 @@ extern bool gbRenderWorld2;
 #endif
 
 #ifdef EXTENDED_COLOURFILTER
-		static const char *filternames[] = { "None", "PS2" };
-		e = DebugMenuAddVar("Render", "Colourfilter", &CPostFX::EffectSwitch, nil, 1, CPostFX::POSTFX_OFF, CPostFX::POSTFX_NORMAL, filternames);
+		static const char *filternames[] = { "None", "PSP", "PS2" };
+		e = DebugMenuAddVar("Render", "Colourfilter", &CPostFX::EffectSwitch, nil, 1, CPostFX::POSTFX_OFF, CPostFX::POSTFX_PS2, filternames);
 		DebugMenuEntrySetWrap(e, true);
 		DebugMenuAddVar("Render", "Intensity", &CPostFX::Intensity, nil, 0.05f, 0, 10.0f);
 		DebugMenuAddVarBool8("Render", "Blur", &CPostFX::BlurOn, nil);
diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp
index 360b4f7a..a9e0604b 100644
--- a/src/extras/postfx.cpp
+++ b/src/extras/postfx.cpp
@@ -16,13 +16,15 @@
 RwRaster *CPostFX::pFrontBuffer;
 RwRaster *CPostFX::pBackBuffer;
 bool CPostFX::bJustInitialised;
-int CPostFX::EffectSwitch = POSTFX_NORMAL;
+int CPostFX::EffectSwitch = POSTFX_PS2;
 bool CPostFX::BlurOn = false;
 bool CPostFX::MotionBlurOn = false;
 
 static RwIm2DVertex Vertex[4];
 static RwIm2DVertex Vertex2[4];
 static RwImVertexIndex Index[6] = { 0, 1, 2, 0, 2, 3 };
+static RwIm2DVertex BlurVertex[12];
+static RwImVertexIndex BlurIndex[18] = { 0, 1, 2, 0, 2, 3,  4, 5, 6, 4, 6, 7,  8, 9, 10, 8, 10, 11 };
 
 #ifdef RW_D3D9
 void *colourfilterLCS_PS;
@@ -205,9 +207,44 @@ CPostFX::Close(void)
 #endif
 }
 
+static float blurOffset = 0.6f;//3.0f/16.0f;	// not quite sure sure about this
+static float blurIntensity = 0.25f;
+
 void
 CPostFX::RenderOverlayBlur(RwCamera *cam, int32 r, int32 g, int32 b, int32 a)
 {
+	memcpy(BlurVertex, Vertex, sizeof(Vertex));
+	memcpy(BlurVertex+4, Vertex, sizeof(Vertex));
+	memcpy(BlurVertex+8, Vertex, sizeof(Vertex));
+	int intensity = 255*blurIntensity;
+	int i;
+	for(i = 0; i < 4; i++){
+		RwIm2DVertexSetScreenX(&BlurVertex[i], RwIm2DVertexGetScreenX(&BlurVertex[i]) + blurOffset);
+		RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity);
+	}
+	for(i = 4; i < 8; i++){
+		RwIm2DVertexSetScreenX(&BlurVertex[i], RwIm2DVertexGetScreenX(&BlurVertex[i]) + blurOffset);
+		RwIm2DVertexSetScreenY(&BlurVertex[i], RwIm2DVertexGetScreenY(&BlurVertex[i]) + blurOffset);
+		RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity);
+	}
+	for(i = 8; i < 12; i++){
+		RwIm2DVertexSetScreenY(&BlurVertex[i], RwIm2DVertexGetScreenY(&BlurVertex[i]) + blurOffset);
+		RwIm2DVertexSetIntRGBA(&BlurVertex[i], 255, 255, 255, intensity);
+	}
+
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pBackBuffer);
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+	RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+	RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+
+	RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, BlurVertex, 12, BlurIndex, 18);
+
+	// this sucks: should render colourfilter with blending instead
+	// but can't change equation to subtraction for PSP here
+	GetBackBuffer(cam);
+
+/* the old way
 	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, pFrontBuffer);
 	RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
 
@@ -240,6 +277,7 @@ CPostFX::RenderOverlayBlur(RwCamera *cam, int32 r, int32 g, int32 b, int32 a)
 
 	RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, Vertex, 4, Index, 6);
 	RwIm2DRenderIndexedPrimitive(rwPRIMTYPETRILIST, BlurOn ? Vertex2 : Vertex, 4, Index, 6);
+*/
 }
 
 void
@@ -291,7 +329,7 @@ CPostFX::RenderOverlayShader(RwCamera *cam, int32 r, int32 g, int32 b, int32 a)
 		blurcolors[0] = r*f/255.0f;
 		blurcolors[1] = g*f/255.0f;
 		blurcolors[2] = b*f/255.0f;
-		blurcolors[3] = 30/255.0f;
+		blurcolors[3] = EffectSwitch == POSTFX_PSP ? -1.0f : 1.0f;
 #ifdef RW_D3D9
 		rw::d3d::d3ddevice->SetPixelShaderConstantF(10, blurcolors, 1);
 		rw::d3d::im2dOverridePS = colourfilterLCS_PS;
@@ -339,11 +377,8 @@ CPostFX::NeedBackBuffer(void)
 	case POSTFX_SIMPLE:
 		// no actual rendering here
 		return false;
-	case POSTFX_NORMAL:
-		if(MotionBlurOn)
-			return false;
-		else
-			return true;
+	case POSTFX_PSP:
+	case POSTFX_PS2:
 	case POSTFX_MOBILE:
 		return true;
 	}
@@ -354,24 +389,11 @@ bool
 CPostFX::NeedFrontBuffer(int32 type)
 {
 	// Last frame -- needed for motion blur
-	if(CMBlur::Drunkness > 0.0f)
+	if(MotionBlurOn)
 		return true;
 	if(type == MOTION_BLUR_SNIPER)
 		return true;
 
-	switch(EffectSwitch){
-	case POSTFX_OFF:
-	case POSTFX_SIMPLE:
-		// no actual rendering here
-		return false;
-	case POSTFX_NORMAL:
-		if(MotionBlurOn)
-			return true;
-		else
-			return false;
-	case POSTFX_MOBILE:
-		return false;
-	}
 	return false;
 }
 
@@ -386,11 +408,17 @@ CPostFX::GetBackBuffer(RwCamera *cam)
 void
 CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha)
 {
+	// LCS PS2 blur is drawn in three passes:
+	//  blend frame with current frame 3 times to blur a bit
+	//  blend one more time with colour filter
+	//  motion blur like normal
+
 	if(pFrontBuffer == nil)
 		Open(cam);
 	assert(pFrontBuffer);
 	assert(pBackBuffer);
 
+/*	// LCS: don't need that anymore
 	if(type == MOTION_BLUR_LIGHT_SCENE){
 		SmoothColor(red, green, blue, blur);
 		red = AvgRed;
@@ -398,6 +426,7 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu
 		blue = AvgBlue;
 		blur = AvgAlpha;
 	}
+*/
 
 	if(NeedBackBuffer())
 		GetBackBuffer(cam);
@@ -405,10 +434,15 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu
 	DefinedState();
 
 	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
-	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST);
 	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
 	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
 
+	if(BlurOn)
+		RenderOverlayBlur(cam, 0, 0, 0, 0);
+
+	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST);
+
+	// TODO(LCS): check this out
 	if(type == MOTION_BLUR_SNIPER){
 		if(!bJustInitialised)
 			RenderOverlaySniper(cam, red, green, blue, blur);
@@ -417,21 +451,16 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu
 	case POSTFX_SIMPLE:
 		// no actual rendering here
 		break;
-	case POSTFX_NORMAL:
-		if(MotionBlurOn){
-			if(!bJustInitialised)
-				RenderOverlayBlur(cam, red, green, blue, blur);
-		}else{
-			RenderOverlayShader(cam, red, green, blue, blur);
-		}
-		break;
+	case POSTFX_PSP:
+	case POSTFX_PS2:
 	case POSTFX_MOBILE:
 		RenderOverlayShader(cam, red, green, blue, blur);
 		break;
 	}
 
-	if(!bJustInitialised)
-		RenderMotionBlur(cam, 175.0f * CMBlur::Drunkness);
+	if(MotionBlurOn)
+		if(!bJustInitialised)
+			RenderMotionBlur(cam, bluralpha);
 
 	RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
 	RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
diff --git a/src/extras/postfx.h b/src/extras/postfx.h
index 9538f8e1..232c151b 100644
--- a/src/extras/postfx.h
+++ b/src/extras/postfx.h
@@ -7,9 +7,8 @@ class CPostFX
 public:
 	enum {
 		POSTFX_OFF,
-//		POSTFX_SIMPLE,
-		POSTFX_NORMAL,
-//		POSTFX_MOBILE
+		POSTFX_PSP,
+		POSTFX_PS2,
 
 		// not so sensible for the moment
 		POSTFX_SIMPLE = -1,
diff --git a/src/extras/shaders/colourfilterLCS_PS.hlsl b/src/extras/shaders/colourfilterLCS_PS.hlsl
index bd91567d..df1beefc 100644
--- a/src/extras/shaders/colourfilterLCS_PS.hlsl
+++ b/src/extras/shaders/colourfilterLCS_PS.hlsl
@@ -1,13 +1,10 @@
 sampler2D tex : register(s0);
 float4 blurcol : register(c10);
 
-//float4 blurcols[10] : register(c15);
-
-
 float4 main(in float2 texcoord : TEXCOORD0) : COLOR0
 {
 	float4 dst = tex2D(tex, texcoord.xy);
-	dst += dst*blurcol;
+	dst += dst*blurcol*blurcol.a;
 	dst.a = 1.0;
 	return dst;
 }
diff --git a/src/extras/shaders/obj/colourfilterLCS_PS.cso b/src/extras/shaders/obj/colourfilterLCS_PS.cso
index e5ffa3f191465e8611778f35f764aa98217a7a7b..17f2d6129d7f4e63cfb3fa932ad446cd17f71dfe 100644
GIT binary patch
delta 42
tcmZ3&w1sKH7kO3&24+SE_67!qCk<Q-PZqE+FaQyI10$IKe=;+pA^_po3O4`%

delta 26
gcmdnOw1jEG7k(B71|VW@U|@LCz{T)nvM{3}0A2qEnE(I)

diff --git a/src/extras/shaders/obj/colourfilterLCS_PS.inc b/src/extras/shaders/obj/colourfilterLCS_PS.inc
index f9eeab52..20738662 100644
--- a/src/extras/shaders/obj/colourfilterLCS_PS.inc
+++ b/src/extras/shaders/obj/colourfilterLCS_PS.inc
@@ -19,9 +19,10 @@ static unsigned char colourfilterLCS_PS_cso[] = {
   0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03, 0xb0,
   0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x08, 0x0f, 0xa0,
   0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0xb0,
-  0x00, 0x08, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x07, 0x80,
-  0x00, 0x00, 0xe4, 0x80, 0x0a, 0x00, 0xe4, 0xa0, 0x00, 0x00, 0xe4, 0x80,
-  0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, 0xa0,
-  0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80,
-  0xff, 0xff, 0x00, 0x00
+  0x00, 0x08, 0xe4, 0xa0, 0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x07, 0x80,
+  0x00, 0x00, 0xe4, 0x80, 0x0a, 0x00, 0xe4, 0xa0, 0x04, 0x00, 0x00, 0x04,
+  0x00, 0x00, 0x07, 0x80, 0x01, 0x00, 0xe4, 0x80, 0x0a, 0x00, 0xff, 0xa0,
+  0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x08, 0x80,
+  0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x0f, 0x80,
+  0x00, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00
 };
diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp
index 7f89c233..835cb849 100644
--- a/src/fakerw/fake.cpp
+++ b/src/fakerw/fake.cpp
@@ -411,6 +411,9 @@ void RwIm2DVertexSetRecipCameraZ(RwIm2DVertex *vert, RwReal recipz) { vert->setR
 void RwIm2DVertexSetScreenX(RwIm2DVertex *vert, RwReal scrnx) { vert->setScreenX(scrnx); }
 void RwIm2DVertexSetScreenY(RwIm2DVertex *vert, RwReal scrny) { vert->setScreenY(scrny); }
 void RwIm2DVertexSetScreenZ(RwIm2DVertex *vert, RwReal scrnz) { vert->setScreenZ(scrnz); }
+float RwIm2DVertexGetScreenX(RwIm2DVertex *vert) { return vert->getScreenX(); }
+float RwIm2DVertexGetScreenY(RwIm2DVertex *vert) { return vert->getScreenY(); }
+float RwIm2DVertexGetScreenZ(RwIm2DVertex *vert) { return vert->getScreenZ(); }
 void RwIm2DVertexSetU(RwIm2DVertex *vert, RwReal texU, RwReal recipz) { vert->setU(texU, recipz); }
 void RwIm2DVertexSetV(RwIm2DVertex *vert, RwReal texV, RwReal recipz) { vert->setV(texV, recipz); }
 void RwIm2DVertexSetIntRGBA(RwIm2DVertex *vert, RwUInt8 red, RwUInt8 green, RwUInt8 blue, RwUInt8 alpha) { vert->setColor(red, green, blue, alpha); }
diff --git a/src/fakerw/rwcore.h b/src/fakerw/rwcore.h
index e5d21865..7a142abd 100644
--- a/src/fakerw/rwcore.h
+++ b/src/fakerw/rwcore.h
@@ -34,6 +34,9 @@ void RwIm2DVertexSetRecipCameraZ(RwIm2DVertex *vert, RwReal recipz);
 void RwIm2DVertexSetScreenX(RwIm2DVertex *vert, RwReal scrnx);
 void RwIm2DVertexSetScreenY(RwIm2DVertex *vert, RwReal scrny);
 void RwIm2DVertexSetScreenZ(RwIm2DVertex *vert, RwReal scrnz);
+float RwIm2DVertexGetScreenX(RwIm2DVertex *vert);
+float RwIm2DVertexGetScreenY(RwIm2DVertex *vert);
+float RwIm2DVertexGetScreenZ(RwIm2DVertex *vert);
 void RwIm2DVertexSetU(RwIm2DVertex *vert, RwReal texU, RwReal recipz);
 void RwIm2DVertexSetV(RwIm2DVertex *vert, RwReal texV, RwReal recipz);
 void RwIm2DVertexSetIntRGBA(RwIm2DVertex *vert, RwUInt8 red, RwUInt8 green, RwUInt8 blue, RwUInt8 alpha);

From 2c1c5debca859c8f1330f45e9d5d65c8e55b8a0c Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Tue, 19 Jan 2021 21:33:09 +0100
Subject: [PATCH 12/19] pc radar fix

---
 src/core/Radar.cpp      | 2 +-
 src/render/Sprite2d.cpp | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp
index 6fbc2280..5ead82f2 100644
--- a/src/core/Radar.cpp
+++ b/src/core/Radar.cpp
@@ -679,7 +679,7 @@ void CRadar::DrawRadarMask()
 		CVector2D(-1.0, -1.0f)
 	};
 
-	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+	RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)nil);
 	RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
 	RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
 	RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
diff --git a/src/render/Sprite2d.cpp b/src/render/Sprite2d.cpp
index 0cd0e8bb..92f326f8 100644
--- a/src/render/Sprite2d.cpp
+++ b/src/render/Sprite2d.cpp
@@ -277,7 +277,11 @@ CSprite2d::SetMaskVertices(int n, float *positions)
 		RwIm2DVertexSetScreenZ(&maVertices[i], NearScreenZ);
 		RwIm2DVertexSetCameraZ(&maVertices[i], NearCamZ);
 		RwIm2DVertexSetRecipCameraZ(&maVertices[i], RecipNearClip);
-		RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255);	// 0, 0, 0, 0 on PC
+#if !defined(GTA_PS2_STUFF) && defined(RWLIBS)
+		RwIm2DVertexSetIntRGBA(&maVertices[i], 0, 0, 0, 0);
+#else
+		RwIm2DVertexSetIntRGBA(&maVertices[i], 255, 255, 255, 255);
+#endif
 	}
 }
 

From 9b820cc0b6e644f928feead82a50471076ad0dcf Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Wed, 20 Jan 2021 14:23:03 +0200
Subject: [PATCH 13/19] Fix CFont::PrintStringFromBottom

---
 src/render/Font.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/render/Font.cpp b/src/render/Font.cpp
index 3798c5f2..de1ee8b4 100644
--- a/src/render/Font.cpp
+++ b/src/render/Font.cpp
@@ -741,7 +741,7 @@ void
 CFont::PrintStringFromBottom(float x, float y, wchar *str)
 {
 	y -= (32.0f * Details.scaleY / 2.0f + 2.0f * Details.scaleY) * GetNumberLines(x, y, str);
-	if (Details.slant == 0.0f)
+	if (Details.slant != 0.0f)
 		y -= ((Details.slantRefX - x) * Details.slant + Details.slantRefY);
 	PrintString(x, y, str);
 }

From 8590457d41190c83fe75e265ffff8c73ae9d8d59 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Wed, 20 Jan 2021 13:57:03 +0100
Subject: [PATCH 14/19] free cam inversion fix

---
 src/core/Cam.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 70d7c899..eedc16bb 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -5060,7 +5060,7 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 
 	// Using GetCarGun(LR/UD) will give us same unprocessed RightStick value as SA
 	float stickX = -(pad->GetCarGunLeftRight());
-	float stickY = pad->GetCarGunUpDown();
+	float stickY = -pad->GetCarGunUpDown();
 
 	// In SA this checks for m_bUseMouse3rdPerson so num2 / num8 do not move camera
 	// when Keyboard & Mouse controls are used. To make it work better with III/VC, check for actual pad state instead

From ba34d7218359ceb76dd525bdffbee5974505b425 Mon Sep 17 00:00:00 2001
From: withmorten <morten.with@gmail.com>
Date: Wed, 20 Jan 2021 13:57:03 +0100
Subject: [PATCH 15/19] free cam inversion fix

---
 src/core/Cam.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 47c944a5..63d8b30b 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -5064,7 +5064,7 @@ CCam::Process_FollowCar_SA(const CVector& CameraTarget, float TargetOrientation,
 
 	// Using GetCarGun(LR/UD) will give us same unprocessed RightStick value as SA
 	float stickX = -(pad->GetCarGunLeftRight());
-	float stickY = pad->GetCarGunUpDown();
+	float stickY = -pad->GetCarGunUpDown();
 
 	// In SA this checks for m_bUseMouse3rdPerson so num2 / num8 do not move camera
 	// when Keyboard & Mouse controls are used. To make it work better with III/VC, check for actual pad state instead

From 3b52b683e309a6d8f6f25d29ec5f703984ab2458 Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Wed, 20 Jan 2021 18:59:33 +0200
Subject: [PATCH 16/19] Sync matrix with master

---
 src/control/Replay.cpp   |   2 +-
 src/core/Camera.cpp      |  45 +++-
 src/core/Camera.h        |   6 +-
 src/entities/Entity.cpp  |   6 +-
 src/math/Matrix.cpp      | 446 ++++++++++++++++++++-------------------
 src/math/Matrix.h        | 102 +++++----
 src/math/Vector.cpp      |  18 +-
 src/render/SpecialFX.cpp |   2 +-
 8 files changed, 345 insertions(+), 282 deletions(-)

diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index e7e0ea8c..a99979e9 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -336,7 +336,7 @@ void CReplay::RecordThisFrame(void)
 		GoToNextBlock();
 	tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset];
 	general->type = REPLAYPACKET_GENERAL;
-	general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix());
+	general->camera_pos.CopyOnlyMatrix(TheCamera.GetMatrix());
 	general->player_pos = FindPlayerCoors();
 	general->in_rcvehicle = CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ? true : false;
 	Record.m_nOffset += sizeof(*general);
diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp
index 992c7d74..7a9d3247 100644
--- a/src/core/Camera.cpp
+++ b/src/core/Camera.cpp
@@ -4055,9 +4055,17 @@ CCamera::CalculateDerivedValues(void)
 bool
 CCamera::IsPointVisible(const CVector &center, const CMatrix *mat)
 {
-	RwV3d c;
-	c = center;
-	RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
+#ifdef GTA_PS2
+	CVuVector c;
+	TransformPoint(c, *mat, center);
+#else
+	CVector c = center;
+	#ifdef FIX_BUGS
+		c = *mat * center;
+	#else
+		RwV3dTransformPoints(&c, &c, 1, (RwMatrix*)mat);
+	#endif
+#endif
 	if(c.y < CDraw::GetNearClipZ()) return false;
 	if(c.y > CDraw::GetFarClipZ()) return false;
 	if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false;
@@ -4070,9 +4078,17 @@ CCamera::IsPointVisible(const CVector &center, const CMatrix *mat)
 bool
 CCamera::IsSphereVisible(const CVector &center, float radius, const CMatrix *mat)
 {
-	RwV3d c;
-	c = center;
-	RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
+#ifdef GTA_PS2
+	CVuVector c;
+	TransformPoint(c, *mat, center);
+#else
+	CVector c = center;
+	#ifdef FIX_BUGS
+		c = *mat * center;
+	#else
+		RwV3dTransformPoints(&c, &c, 1, (RwMatrix*)mat);
+	#endif
+#endif
 	if(c.y + radius < CDraw::GetNearClipZ()) return false;
 	if(c.y - radius > CDraw::GetFarClipZ()) return false;
 	if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false;
@@ -4090,11 +4106,24 @@ CCamera::IsSphereVisible(const CVector &center, float radius)
 }
 
 bool
-CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
+#ifdef GTA_PS2
+CCamera::IsBoxVisible(CVuVector *box, const CMatrix *mat)
+#else
+CCamera::IsBoxVisible(CVector *box, const CMatrix *mat)
+#endif
 {
 	int i;
 	int frustumTests[6] = { 0 };
-	RwV3dTransformPoints(box, box, 8, &mat->m_matrix);
+#ifdef GTA_PS2
+	TransformPoints(box, 8, *mat, box);
+#else
+	#ifdef FIX_BUGS
+		for (i = 0; i < 8; i++)
+			box[i] = *mat * box[i];
+	#else
+		RwV3dTransformPoints(box, box, 8, (RwMatrix*)mat);
+	#endif
+#endif
 
 	for(i = 0; i < 8; i++){
 		if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++;
diff --git a/src/core/Camera.h b/src/core/Camera.h
index 4da7b499..538ff067 100644
--- a/src/core/Camera.h
+++ b/src/core/Camera.h
@@ -633,7 +633,11 @@ public:
 	bool IsPointVisible(const CVector &center, const CMatrix *mat);
 	bool IsSphereVisible(const CVector &center, float radius, const CMatrix *mat);
 	bool IsSphereVisible(const CVector &center, float radius);
-	bool IsBoxVisible(RwV3d *box, const CMatrix *mat);
+#ifdef GTA_PS2
+	bool IsBoxVisible(CVuVector *box, const CMatrix *mat);
+#else
+	bool IsBoxVisible(CVector *box, const CMatrix *mat);
+#endif
 };
 
 VALIDATE_SIZE(CCamera, 0xE9D8);
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 862d2562..9a849218 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -447,7 +447,11 @@ CEntity::GetIsOnScreen(void)
 bool
 CEntity::GetIsOnScreenComplex(void)
 {
-	RwV3d boundBox[8];
+#ifdef GTA_PS2
+	CVuVector boundBox[8];
+#else
+	CVector boundBox[8];
+#endif
 
 	if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix()))
 		return true;
diff --git a/src/math/Matrix.cpp b/src/math/Matrix.cpp
index 3ac3e2b9..c0d909cb 100644
--- a/src/math/Matrix.cpp
+++ b/src/math/Matrix.cpp
@@ -60,14 +60,20 @@ CMatrix::Detach(void)
 void
 CMatrix::Update(void)
 {
-	m_matrix = *m_attachment;
+	GetRight() = m_attachment->right;
+	GetForward() = m_attachment->up;
+	GetUp() = m_attachment->at;
+	GetPosition() = m_attachment->pos;
 }
 
 void
 CMatrix::UpdateRW(void)
 {
 	if (m_attachment) {
-		*m_attachment = m_matrix;
+		m_attachment->right = GetRight();
+		m_attachment->up = GetForward();
+		m_attachment->at = GetUp();
+		m_attachment->pos = GetPosition();
 		RwMatrixUpdate(m_attachment);
 	}
 }
@@ -75,104 +81,96 @@ CMatrix::UpdateRW(void)
 void
 CMatrix::operator=(CMatrix const &rhs)
 {
-	m_matrix = rhs.m_matrix;
+	memcpy(this, &rhs, sizeof(f));
 	if (m_attachment)
 		UpdateRW();
 }
 
 void
-CMatrix::CopyOnlyMatrix(CMatrix *other)
+CMatrix::CopyOnlyMatrix(const CMatrix &other)
 {
-	m_matrix = other->m_matrix;
+	memcpy(this, &other, sizeof(f));
 }
 
 CMatrix &
 CMatrix::operator+=(CMatrix const &rhs)
 {
-	m_matrix.right.x += rhs.m_matrix.right.x;
-	m_matrix.up.x += rhs.m_matrix.up.x;
-	m_matrix.at.x += rhs.m_matrix.at.x;
-	m_matrix.right.y += rhs.m_matrix.right.y;
-	m_matrix.up.y += rhs.m_matrix.up.y;
-	m_matrix.at.y += rhs.m_matrix.at.y;
-	m_matrix.right.z += rhs.m_matrix.right.z;
-	m_matrix.up.z += rhs.m_matrix.up.z;
-	m_matrix.at.z += rhs.m_matrix.at.z;
-	m_matrix.pos.x += rhs.m_matrix.pos.x;
-	m_matrix.pos.y += rhs.m_matrix.pos.y;
-	m_matrix.pos.z += rhs.m_matrix.pos.z;
+	GetRight() += rhs.GetRight();
+	GetForward() += rhs.GetForward();
+	GetUp() += rhs.GetUp();
+	GetPosition() += rhs.GetPosition();
 	return *this;
 }
 
 void
 CMatrix::SetUnity(void)
 {
-	m_matrix.right.x = 1.0f;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = 0.0f;
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = 1.0f;
-	m_matrix.up.z = 0.0f;
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = 1.0f;
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	rx = 1.0f;
+	ry = 0.0f;
+	rz = 0.0f;
+	fx = 0.0f;
+	fy = 1.0f;
+	fz = 0.0f;
+	ux = 0.0f;
+	uy = 0.0f;
+	uz = 1.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 void
 CMatrix::ResetOrientation(void)
 {
-	m_matrix.right.x = 1.0f;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = 0.0f;
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = 1.0f;
-	m_matrix.up.z = 0.0f;
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = 1.0f;
+	rx = 1.0f;
+	ry = 0.0f;
+	rz = 0.0f;
+	fx = 0.0f;
+	fy = 1.0f;
+	fz = 0.0f;
+	ux = 0.0f;
+	uy = 0.0f;
+	uz = 1.0f;
 }
 
 void
 CMatrix::SetScale(float s)
 {
-	m_matrix.right.x = s;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = 0.0f;
+	rx = s;
+	ry = 0.0f;
+	rz = 0.0f;
 
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = s;
-	m_matrix.up.z = 0.0f;
+	fx = 0.0f;
+	fy = s;
+	fz = 0.0f;
 
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = s;
+	ux = 0.0f;
+	uy = 0.0f;
+	uz = s;
 
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 void
 CMatrix::SetTranslate(float x, float y, float z)
 {
-	m_matrix.right.x = 1.0f;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = 0.0f;
+	rx = 1.0f;
+	ry = 0.0f;
+	rz = 0.0f;
 
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = 1.0f;
-	m_matrix.up.z = 0.0f;
+	fx = 0.0f;
+	fy = 1.0f;
+	fz = 0.0f;
 
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = 1.0f;
+	ux = 0.0f;
+	uy = 0.0f;
+	uz = 1.0f;
 
-	m_matrix.pos.x = x;
-	m_matrix.pos.y = y;
-	m_matrix.pos.z = z;
+	px = x;
+	py = y;
+	pz = z;
 }
 
 void
@@ -181,17 +179,17 @@ CMatrix::SetRotateXOnly(float angle)
 	float c = Cos(angle);
 	float s = Sin(angle);
 
-	m_matrix.right.x = 1.0f;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = 0.0f;
+	rx = 1.0f;
+	ry = 0.0f;
+	rz = 0.0f;
 
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = c;
-	m_matrix.up.z = s;
+	fx = 0.0f;
+	fy = c;
+	fz = s;
 
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = -s;
-	m_matrix.at.z = c;
+	ux = 0.0f;
+	uy = -s;
+	uz = c;
 }
 
 void
@@ -200,17 +198,17 @@ CMatrix::SetRotateYOnly(float angle)
 	float c = Cos(angle);
 	float s = Sin(angle);
 
-	m_matrix.right.x = c;
-	m_matrix.right.y = 0.0f;
-	m_matrix.right.z = -s;
+	rx = c;
+	ry = 0.0f;
+	rz = -s;
 
-	m_matrix.up.x = 0.0f;
-	m_matrix.up.y = 1.0f;
-	m_matrix.up.z = 0.0f;
+	fx = 0.0f;
+	fy = 1.0f;
+	fz = 0.0f;
 
-	m_matrix.at.x = s;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = c;
+	ux = s;
+	uy = 0.0f;
+	uz = c;
 }
 
 void
@@ -219,26 +217,26 @@ CMatrix::SetRotateZOnly(float angle)
 	float c = Cos(angle);
 	float s = Sin(angle);
 
-	m_matrix.right.x = c;
-	m_matrix.right.y = s;
-	m_matrix.right.z = 0.0f;
+	rx = c;
+	ry = s;
+	rz = 0.0f;
 
-	m_matrix.up.x = -s;
-	m_matrix.up.y = c;
-	m_matrix.up.z = 0.0f;
+	fx = -s;
+	fy = c;
+	fz = 0.0f;
 
-	m_matrix.at.x = 0.0f;
-	m_matrix.at.y = 0.0f;
-	m_matrix.at.z = 1.0f;
+	ux = 0.0f;
+	uy = 0.0f;
+	uz = 1.0f;
 }
 
 void
 CMatrix::SetRotateX(float angle)
 {
 	SetRotateXOnly(angle);
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 
@@ -246,18 +244,18 @@ void
 CMatrix::SetRotateY(float angle)
 {
 	SetRotateYOnly(angle);
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 void
 CMatrix::SetRotateZ(float angle)
 {
 	SetRotateZOnly(angle);
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 void
@@ -270,21 +268,21 @@ CMatrix::SetRotate(float xAngle, float yAngle, float zAngle)
 	float cZ = Cos(zAngle);
 	float sZ = Sin(zAngle);
 
-	m_matrix.right.x = cZ * cY - (sZ * sX) * sY;
-	m_matrix.right.y = (cZ * sX) * sY + sZ * cY;
-	m_matrix.right.z = -cX * sY;
+	rx = cZ * cY - (sZ * sX) * sY;
+	ry = (cZ * sX) * sY + sZ * cY;
+	rz = -cX * sY;
 
-	m_matrix.up.x = -sZ * cX;
-	m_matrix.up.y = cZ * cX;
-	m_matrix.up.z = sX;
+	fx = -sZ * cX;
+	fy = cZ * cX;
+	fz = sX;
 
-	m_matrix.at.x = (sZ * sX) * cY + cZ * sY;
-	m_matrix.at.y = sZ * sY - (cZ * sX) * cY;
-	m_matrix.at.z = cX * cY;
+	ux = (sZ * sX) * cY + cZ * sY;
+	uy = sZ * sY - (cZ * sX) * cY;
+	uz = cX * cY;
 
-	m_matrix.pos.x = 0.0f;
-	m_matrix.pos.y = 0.0f;
-	m_matrix.pos.z = 0.0f;
+	px = 0.0f;
+	py = 0.0f;
+	pz = 0.0f;
 }
 
 void
@@ -293,23 +291,23 @@ CMatrix::RotateX(float x)
 	float c = Cos(x);
 	float s = Sin(x);
 
-	float ry = m_matrix.right.y;
-	float rz = m_matrix.right.z;
-	float uy = m_matrix.up.y;
-	float uz = m_matrix.up.z;
-	float ay = m_matrix.at.y;
-	float az = m_matrix.at.z;
-	float py = m_matrix.pos.y;
-	float pz = m_matrix.pos.z;
+	float ry = this->ry;
+	float rz = this->rz;
+	float uy = this->fy;
+	float uz = this->fz;
+	float ay = this->uy;
+	float az = this->uz;
+	float py = this->py;
+	float pz = this->pz;
 
-	m_matrix.right.y = c * ry - s * rz;
-	m_matrix.right.z = c * rz + s * ry;
-	m_matrix.up.y = c * uy - s * uz;
-	m_matrix.up.z = c * uz + s * uy;
-	m_matrix.at.y = c * ay - s * az;
-	m_matrix.at.z = c * az + s * ay;
-	m_matrix.pos.y = c * py - s * pz;
-	m_matrix.pos.z = c * pz + s * py;
+	this->ry = c * ry - s * rz;
+	this->rz = c * rz + s * ry;
+	this->fy = c * uy - s * uz;
+	this->fz = c * uz + s * uy;
+	this->uy = c * ay - s * az;
+	this->uz = c * az + s * ay;
+	this->py = c * py - s * pz;
+	this->pz = c * pz + s * py;
 }
 
 void
@@ -318,23 +316,23 @@ CMatrix::RotateY(float y)
 	float c = Cos(y);
 	float s = Sin(y);
 
-	float rx = m_matrix.right.x;
-	float rz = m_matrix.right.z;
-	float ux = m_matrix.up.x;
-	float uz = m_matrix.up.z;
-	float ax = m_matrix.at.x;
-	float az = m_matrix.at.z;
-	float px = m_matrix.pos.x;
-	float pz = m_matrix.pos.z;
+	float rx = this->rx;
+	float rz = this->rz;
+	float ux = this->fx;
+	float uz = this->fz;
+	float ax = this->ux;
+	float az = this->uz;
+	float px = this->px;
+	float pz = this->pz;
 
-	m_matrix.right.x = c * rx + s * rz;
-	m_matrix.right.z = c * rz - s * rx;
-	m_matrix.up.x = c * ux + s * uz;
-	m_matrix.up.z = c * uz - s * ux;
-	m_matrix.at.x = c * ax + s * az;
-	m_matrix.at.z = c * az - s * ax;
-	m_matrix.pos.x = c * px + s * pz;
-	m_matrix.pos.z = c * pz - s * px;
+	this->rx = c * rx + s * rz;
+	this->rz = c * rz - s * rx;
+	this->fx = c * ux + s * uz;
+	this->fz = c * uz - s * ux;
+	this->ux = c * ax + s * az;
+	this->uz = c * az - s * ax;
+	this->px = c * px + s * pz;
+	this->pz = c * pz - s * px;
 }
 
 void
@@ -343,23 +341,23 @@ CMatrix::RotateZ(float z)
 	float c = Cos(z);
 	float s = Sin(z);
 
-	float ry = m_matrix.right.y;
-	float rx = m_matrix.right.x;
-	float uy = m_matrix.up.y;
-	float ux = m_matrix.up.x;
-	float ay = m_matrix.at.y;
-	float ax = m_matrix.at.x;
-	float py = m_matrix.pos.y;
-	float px = m_matrix.pos.x;
+	float ry = this->ry;
+	float rx = this->rx;
+	float uy = this->fy;
+	float ux = this->fx;
+	float ay = this->uy;
+	float ax = this->ux;
+	float py = this->py;
+	float px = this->px;
 
-	m_matrix.right.x = c * rx - s * ry;
-	m_matrix.right.y = c * ry + s * rx;
-	m_matrix.up.x = c * ux - s * uy;
-	m_matrix.up.y = c * uy + s * ux;
-	m_matrix.at.x = c * ax - s * ay;
-	m_matrix.at.y = c * ay + s * ax;
-	m_matrix.pos.x = c * px - s * py;
-	m_matrix.pos.y = c * py + s * px;
+	this->rx = c * rx - s * ry;
+	this->ry = c * ry + s * rx;
+	this->fx = c * ux - s * uy;
+	this->fy = c * uy + s * ux;
+	this->ux = c * ax - s * ay;
+	this->uy = c * ay + s * ax;
+	this->px = c * px - s * py;
+	this->py = c * py + s * px;
 
 }
 
@@ -373,18 +371,18 @@ CMatrix::Rotate(float x, float y, float z)
 	float cZ = Cos(z);
 	float sZ = Sin(z);
 	
-	float rx = m_matrix.right.x;
-	float ry = m_matrix.right.y;
-	float rz = m_matrix.right.z;
-	float ux = m_matrix.up.x;
-	float uy = m_matrix.up.y;
-	float uz = m_matrix.up.z;
-	float ax = m_matrix.at.x;
-	float ay = m_matrix.at.y;
-	float az = m_matrix.at.z;
-	float px = m_matrix.pos.x;
-	float py = m_matrix.pos.y;
-	float pz = m_matrix.pos.z;
+	float rx = this->rx;
+	float ry = this->ry;
+	float rz = this->rz;
+	float ux = this->fx;
+	float uy = this->fy;
+	float uz = this->fz;
+	float ax = this->ux;
+	float ay = this->uy;
+	float az = this->uz;
+	float px = this->px;
+	float py = this->py;
+	float pz = this->pz;
 
 	float x1 = cZ * cY - (sZ * sX) * sY;
 	float x2 = (cZ * sX) * sY + sZ * cY;
@@ -396,18 +394,18 @@ CMatrix::Rotate(float x, float y, float z)
 	float z2 = sZ * sY - (cZ * sX) * cY;
 	float z3 = cX * cY;
 
-	m_matrix.right.x = x1 * rx + y1 * ry + z1 * rz;
-	m_matrix.right.y = x2 * rx + y2 * ry + z2 * rz;
-	m_matrix.right.z = x3 * rx + y3 * ry + z3 * rz;
-	m_matrix.up.x = x1 * ux + y1 * uy + z1 * uz;
-	m_matrix.up.y = x2 * ux + y2 * uy + z2 * uz;
-	m_matrix.up.z = x3 * ux + y3 * uy + z3 * uz;
-	m_matrix.at.x = x1 * ax + y1 * ay + z1 * az;
-	m_matrix.at.y = x2 * ax + y2 * ay + z2 * az;
-	m_matrix.at.z = x3 * ax + y3 * ay + z3 * az;
-	m_matrix.pos.x = x1 * px + y1 * py + z1 * pz;
-	m_matrix.pos.y = x2 * px + y2 * py + z2 * pz;
-	m_matrix.pos.z = x3 * px + y3 * py + z3 * pz;
+	this->rx = x1 * rx + y1 * ry + z1 * rz;
+	this->ry = x2 * rx + y2 * ry + z2 * rz;
+	this->rz = x3 * rx + y3 * ry + z3 * rz;
+	this->fx = x1 * ux + y1 * uy + z1 * uz;
+	this->fy = x2 * ux + y2 * uy + z2 * uz;
+	this->fz = x3 * ux + y3 * uy + z3 * uz;
+	this->ux = x1 * ax + y1 * ay + z1 * az;
+	this->uy = x2 * ax + y2 * ay + z2 * az;
+	this->uz = x3 * ax + y3 * ay + z3 * az;
+	this->px = x1 * px + y1 * py + z1 * pz;
+	this->py = x2 * px + y2 * py + z2 * pz;
+	this->pz = x3 * px + y3 * py + z3 * pz;
 }
 
 CMatrix &
@@ -436,21 +434,18 @@ operator*(const CMatrix &m1, const CMatrix &m2)
 {
 	// TODO: VU0 code
 	CMatrix out;
-	RwMatrix *dst = &out.m_matrix;
-	const RwMatrix *src1 = &m1.m_matrix;
-	const RwMatrix *src2 = &m2.m_matrix;
-	dst->right.x = src1->right.x * src2->right.x + src1->up.x * src2->right.y + src1->at.x * src2->right.z;
-	dst->right.y = src1->right.y * src2->right.x + src1->up.y * src2->right.y + src1->at.y * src2->right.z;
-	dst->right.z = src1->right.z * src2->right.x + src1->up.z * src2->right.y + src1->at.z * src2->right.z;
-	dst->up.x = src1->right.x * src2->up.x + src1->up.x * src2->up.y + src1->at.x * src2->up.z;
-	dst->up.y = src1->right.y * src2->up.x + src1->up.y * src2->up.y + src1->at.y * src2->up.z;
-	dst->up.z = src1->right.z * src2->up.x + src1->up.z * src2->up.y + src1->at.z * src2->up.z;
-	dst->at.x = src1->right.x * src2->at.x + src1->up.x * src2->at.y + src1->at.x * src2->at.z;
-	dst->at.y = src1->right.y * src2->at.x + src1->up.y * src2->at.y + src1->at.y * src2->at.z;
-	dst->at.z = src1->right.z * src2->at.x + src1->up.z * src2->at.y + src1->at.z * src2->at.z;
-	dst->pos.x = src1->right.x * src2->pos.x + src1->up.x * src2->pos.y + src1->at.x * src2->pos.z + src1->pos.x;
-	dst->pos.y = src1->right.y * src2->pos.x + src1->up.y * src2->pos.y + src1->at.y * src2->pos.z + src1->pos.y;
-	dst->pos.z = src1->right.z * src2->pos.x + src1->up.z * src2->pos.y + src1->at.z * src2->pos.z + src1->pos.z;
+	out.rx = m1.rx * m2.rx + m1.fx * m2.ry + m1.ux * m2.rz;
+	out.ry = m1.ry * m2.rx + m1.fy * m2.ry + m1.uy * m2.rz;
+	out.rz = m1.rz * m2.rx + m1.fz * m2.ry + m1.uz * m2.rz;
+	out.fx = m1.rx * m2.fx + m1.fx * m2.fy + m1.ux * m2.fz;
+	out.fy = m1.ry * m2.fx + m1.fy * m2.fy + m1.uy * m2.fz;
+	out.fz = m1.rz * m2.fx + m1.fz * m2.fy + m1.uz * m2.fz;
+	out.ux = m1.rx * m2.ux + m1.fx * m2.uy + m1.ux * m2.uz;
+	out.uy = m1.ry * m2.ux + m1.fy * m2.uy + m1.uy * m2.uz;
+	out.uz = m1.rz * m2.ux + m1.fz * m2.uy + m1.uz * m2.uz;
+	out.px = m1.rx * m2.px + m1.fx * m2.py + m1.ux * m2.pz + m1.px;
+	out.py = m1.ry * m2.px + m1.fy * m2.py + m1.uy * m2.pz + m1.py;
+	out.pz = m1.rz * m2.px + m1.fz * m2.py + m1.uz * m2.pz + m1.pz;
 	return out;
 }
 
@@ -458,43 +453,50 @@ CMatrix &
 Invert(const CMatrix &src, CMatrix &dst)
 {
 	// TODO: VU0 code
-	float (*scr_fm)[4] = (float (*)[4])&src.m_matrix;
-	float (*dst_fm)[4] = (float (*)[4])&dst.m_matrix;
+	dst.f[3][0] = dst.f[3][1] = dst.f[3][2] = 0.0f;
 
-	dst_fm[3][0] = dst_fm[3][1] = dst_fm[3][2] = 0.0f;
+	dst.f[0][0] = src.f[0][0];
+	dst.f[0][1] = src.f[1][0];
+	dst.f[0][2] = src.f[2][0];
 
-	dst_fm[0][0] = scr_fm[0][0];
-	dst_fm[0][1] = scr_fm[1][0];
-	dst_fm[0][2] = scr_fm[2][0];
+	dst.f[1][0] = src.f[0][1];
+	dst.f[1][1] = src.f[1][1];
+	dst.f[1][2] = src.f[2][1];
 
-	dst_fm[1][0] = scr_fm[0][1];
-	dst_fm[1][1] = scr_fm[1][1];
-	dst_fm[1][2] = scr_fm[2][1];
-
-	dst_fm[2][0] = scr_fm[0][2];
-	dst_fm[2][1] = scr_fm[1][2];
-	dst_fm[2][2] = scr_fm[2][2];
+	dst.f[2][0] = src.f[0][2];
+	dst.f[2][1] = src.f[1][2];
+	dst.f[2][2] = src.f[2][2];
 
 
-	dst_fm[3][0] += dst_fm[0][0] * scr_fm[3][0];
-	dst_fm[3][1] += dst_fm[0][1] * scr_fm[3][0];
-	dst_fm[3][2] += dst_fm[0][2] * scr_fm[3][0];
+	dst.f[3][0] += dst.f[0][0] * src.f[3][0];
+	dst.f[3][1] += dst.f[0][1] * src.f[3][0];
+	dst.f[3][2] += dst.f[0][2] * src.f[3][0];
 
-	dst_fm[3][0] += dst_fm[1][0] * scr_fm[3][1];
-	dst_fm[3][1] += dst_fm[1][1] * scr_fm[3][1];
-	dst_fm[3][2] += dst_fm[1][2] * scr_fm[3][1];
+	dst.f[3][0] += dst.f[1][0] * src.f[3][1];
+	dst.f[3][1] += dst.f[1][1] * src.f[3][1];
+	dst.f[3][2] += dst.f[1][2] * src.f[3][1];
 
-	dst_fm[3][0] += dst_fm[2][0] * scr_fm[3][2];
-	dst_fm[3][1] += dst_fm[2][1] * scr_fm[3][2];
-	dst_fm[3][2] += dst_fm[2][2] * scr_fm[3][2];
+	dst.f[3][0] += dst.f[2][0] * src.f[3][2];
+	dst.f[3][1] += dst.f[2][1] * src.f[3][2];
+	dst.f[3][2] += dst.f[2][2] * src.f[3][2];
 
-	dst_fm[3][0] = -dst_fm[3][0];
-	dst_fm[3][1] = -dst_fm[3][1];
-	dst_fm[3][2] = -dst_fm[3][2];
+	dst.f[3][0] = -dst.f[3][0];
+	dst.f[3][1] = -dst.f[3][1];
+	dst.f[3][2] = -dst.f[3][2];
 
 	return dst;
 }
 
+void
+CMatrix::CopyToRwMatrix(RwMatrix* matrix)
+{
+	matrix->right = GetRight();
+	matrix->up = GetForward();
+	matrix->at = GetUp();
+	matrix->pos = GetPosition();
+	RwMatrixUpdate(matrix);
+}
+
 CMatrix
 Invert(const CMatrix &matrix)
 {
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index d32b1d93..6da4c767 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -3,9 +3,36 @@
 class CMatrix
 {
 public:
-	RwMatrix m_matrix;
+#ifdef GTA_PS2
+	union
+	{
+		float f[4][4];
+		struct
+		{
+			float rx, ry, rz;
+			RwMatrix *m_attachment;
+			float fx, fy, fz;
+			bool m_hasRwMatrix;	// are we the owner?
+			float ux, uy, uz, uw;
+			float px, py, pz, pw;
+		};
+	};
+#else
+	union
+	{
+		float f[4][4];
+		struct
+		{
+			float rx, ry, rz, rw;
+			float fx, fy, fz, fw;
+			float ux, uy, uz, uw;
+			float px, py, pz, pw;
+		};
+	};
+
 	RwMatrix *m_attachment;
 	bool m_hasRwMatrix;	// are we the owner?
+#endif
 
 	CMatrix(void);
 	CMatrix(CMatrix const &m);
@@ -25,36 +52,39 @@ public:
 	CMatrix &operator+=(CMatrix const &rhs);
 	CMatrix &operator*=(CMatrix const &rhs);
 
-	const CVector &GetPosition(void) const { return *(CVector*)&m_matrix.pos; }
-	CVector& GetPosition(void) { return *(CVector*)&m_matrix.pos; }
-	CVector &GetRight(void) { return *(CVector*)&m_matrix.right; }
-	CVector &GetForward(void) { return *(CVector*)&m_matrix.up; }
-	CVector &GetUp(void) { return *(CVector*)&m_matrix.at; }
+	CVector &GetPosition(void) { return *(CVector*)&px; }
+	CVector &GetRight(void) { return *(CVector*)&rx; }
+	CVector &GetForward(void) { return *(CVector*)&fx; }
+	CVector &GetUp(void) { return *(CVector*)&ux; }
+
+	const CVector &GetPosition(void) const { return *(CVector*)&px; }
+	const CVector &GetRight(void) const { return *(CVector*)&rx; }
+	const CVector &GetForward(void) const { return *(CVector*)&fx; }
+	const CVector &GetUp(void) const { return *(CVector*)&ux; }
+
 
 	void SetTranslate(float x, float y, float z);
 	void SetTranslate(const CVector &trans){ SetTranslate(trans.x, trans.y, trans.z); }
 	void Translate(float x, float y, float z){
-		m_matrix.pos.x += x;
-		m_matrix.pos.y += y;
-		m_matrix.pos.z += z;
+		px += x;
+		py += y;
+		pz += z;
 	}
 	void Translate(const CVector &trans){ Translate(trans.x, trans.y, trans.z); }
 
 	void SetScale(float s);
 	void Scale(float scale)
 	{
-		float *pFloatMatrix = (float*)&m_matrix;
 		for (int i = 0; i < 3; i++)
 			for (int j = 0; j < 3; j++)
-				pFloatMatrix[i * 4 + j] *= scale;
+				f[i][j] *= scale;
 	}
 	void Scale(float sx, float sy, float sz)
 	{
-		float *pFloatMatrix = (float*)&m_matrix;
 		for (int i = 0; i < 3; i++){
-			pFloatMatrix[i * 4 + 0] *= sx;
-			pFloatMatrix[i * 4 + 1] *= sy;
-			pFloatMatrix[i * 4 + 2] *= sz;
+			f[i][0] *= sx;
+			f[i][1] *= sy;
+			f[i][2] *= sz;
 		}
 	}
 
@@ -66,17 +96,17 @@ public:
 		float c = Cos(angle);
 		float s = Sin(angle);
 
-		m_matrix.right.x = c * scale;
-		m_matrix.right.y = s * scale;
-		m_matrix.right.z = 0.0f;
+		rx = c * scale;
+		ry = s * scale;
+		rz = 0.0f;
 
-		m_matrix.up.x = -s * scale;
-		m_matrix.up.y = c * scale;
-		m_matrix.up.z = 0.0f;
+		fx = -s * scale;
+		fy = c * scale;
+		fz = 0.0f;
 
-		m_matrix.at.x = 0.0f;
-		m_matrix.at.y = 0.0f;
-		m_matrix.at.z = scale;
+		ux = 0.0f;
+		uy = 0.0f;
+		uz = scale;
 	}
 	void SetRotateX(float angle);
 	void SetRotateY(float angle);
@@ -88,22 +118,16 @@ public:
 	void RotateZ(float z);
 
 	void Reorthogonalise(void);
-	void CopyOnlyMatrix(CMatrix *other);
+	void CopyOnlyMatrix(const CMatrix &other);
 	void SetUnity(void);
 	void ResetOrientation(void);
-	void CopyRwMatrix(RwMatrix *matrix){
-		m_matrix = *matrix;
-	}
 	
-	void CopyToRwMatrix(RwMatrix *matrix){
-		*matrix = m_matrix;
-		RwMatrixUpdate(matrix);
-	}
+	void CopyToRwMatrix(RwMatrix* matrix);
 	
 	void SetTranslateOnly(float x, float y, float z) {
-		m_matrix.pos.x = x;
-		m_matrix.pos.y = y;
-		m_matrix.pos.z = z;
+		px = x;
+		py = y;
+		pz = z;
 	}
 	void SetTranslateOnly(const CVector& pos) {
 		SetTranslateOnly(pos.x, pos.y, pos.z);
@@ -117,11 +141,11 @@ CMatrix Invert(const CMatrix &matrix);
 CMatrix operator*(const CMatrix &m1, const CMatrix &m2);
 inline CVector MultiplyInverse(const CMatrix &mat, const CVector &vec)
 {
-	CVector v(vec.x - mat.m_matrix.pos.x, vec.y - mat.m_matrix.pos.y, vec.z - mat.m_matrix.pos.z);
+	CVector v(vec.x - mat.px, vec.y - mat.py, vec.z - mat.pz);
 	return CVector(
-		mat.m_matrix.right.x * v.x + mat.m_matrix.right.y * v.y + mat.m_matrix.right.z * v.z,
-		mat.m_matrix.up.x * v.x + mat.m_matrix.up.y * v.y + mat.m_matrix.up.z * v.z,
-		mat.m_matrix.at.x * v.x + mat.m_matrix.at.y * v.y + mat.m_matrix.at.z * v.z);
+		mat.rx * v.x + mat.ry * v.y + mat.rz * v.z,
+		mat.fx * v.x + mat.fy * v.y + mat.fz * v.z,
+		mat.ux * v.x + mat.uy * v.y + mat.uz * v.z);
 }
 
 
diff --git a/src/math/Vector.cpp b/src/math/Vector.cpp
index 42e1828e..ee76e555 100644
--- a/src/math/Vector.cpp
+++ b/src/math/Vector.cpp
@@ -23,24 +23,24 @@ CVector
 Multiply3x3(const CMatrix &mat, const CVector &vec)
 {
 	// TODO: VU0 code
-	return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z,
-	               mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z,
-	               mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z);
+	return CVector(mat.rx * vec.x + mat.fx * vec.y + mat.ux * vec.z,
+	               mat.ry * vec.x + mat.fy * vec.y + mat.uy * vec.z,
+	               mat.rz * vec.x + mat.fz * vec.y + mat.uz * vec.z);
 }
 
 CVector
 Multiply3x3(const CVector &vec, const CMatrix &mat)
 {
-	return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.right.y * vec.y + mat.m_matrix.right.z * vec.z,
-	               mat.m_matrix.up.x * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.up.z * vec.z,
-	               mat.m_matrix.at.x * vec.x + mat.m_matrix.at.y * vec.y + mat.m_matrix.at.z * vec.z);
+	return CVector(mat.rx * vec.x + mat.ry * vec.y + mat.rz * vec.z,
+	               mat.fx * vec.x + mat.fy * vec.y + mat.fz * vec.z,
+	               mat.ux * vec.x + mat.uy * vec.y + mat.uz * vec.z);
 }
 
 CVector
 operator*(const CMatrix &mat, const CVector &vec)
 {
 	// TODO: VU0 code
-	return CVector(mat.m_matrix.right.x * vec.x + mat.m_matrix.up.x * vec.y + mat.m_matrix.at.x * vec.z + mat.m_matrix.pos.x,
-	               mat.m_matrix.right.y * vec.x + mat.m_matrix.up.y * vec.y + mat.m_matrix.at.y * vec.z + mat.m_matrix.pos.y,
-	               mat.m_matrix.right.z * vec.x + mat.m_matrix.up.z * vec.y + mat.m_matrix.at.z * vec.z + mat.m_matrix.pos.z);
+	return CVector(mat.rx * vec.x + mat.fx * vec.y + mat.ux * vec.z + mat.px,
+	               mat.ry * vec.x + mat.fy * vec.y + mat.uy * vec.z + mat.py,
+	               mat.rz * vec.x + mat.fz * vec.y + mat.uz * vec.z + mat.pz);
 }
diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp
index 4eed988d..18e7fd34 100644
--- a/src/render/SpecialFX.cpp
+++ b/src/render/SpecialFX.cpp
@@ -871,7 +871,7 @@ C3dMarkers::PlaceMarker(uint32 identifier, uint16 type, CVector &pos, float size
 				pMarker->m_Color.alpha = (float)a * 0.4f * someSin + a;
 		}
 		if (pMarker->m_nRotateRate != 0) {
-			RwV3d pos = pMarker->m_Matrix.m_matrix.pos;
+			CVector pos = pMarker->m_Matrix.GetPosition();
 			pMarker->m_Matrix.RotateZ(DEGTORAD(pMarker->m_nRotateRate * CTimer::GetTimeStep()));
 			pMarker->m_Matrix.GetPosition() = pos;
 		}

From c7c7eff9180afc3e0271bdbdad28297fcd374694 Mon Sep 17 00:00:00 2001
From: Sergeanur <s.anureev@yandex.ua>
Date: Tue, 19 Jan 2021 21:32:55 +0200
Subject: [PATCH 17/19] Get rid of bitfields in CPool

# Conflicts:
#	src/core/templates.h
---
 src/control/Garages.cpp |  8 ++---
 src/core/Pools.cpp      |  2 +-
 src/core/templates.h    | 71 ++++++++++++++++++++++++++---------------
 3 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 1e547a38..1fecdf22 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -1526,7 +1526,7 @@ void CGarage::RefreshDoorPointers(bool bCreate)
 	m_bRecreateDoorOnNextRefresh = false;
 	if (m_pDoor1) {
 		if (m_bDoor1IsDummy) {
-			if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1)))
+			if (CPools::GetDummyPool()->GetIsFree(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1)))
 				bNeedToFindDoorEntities = true;
 			else {
 				if (m_bDoor1PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor1) & 0x7F))
@@ -1536,7 +1536,7 @@ void CGarage::RefreshDoorPointers(bool bCreate)
 			}
 		}
 		else {
-			if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1)))
+			if (CPools::GetObjectPool()->GetIsFree(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1)))
 				bNeedToFindDoorEntities = true;
 			else {
 				if (m_bDoor1PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor1) & 0x7F))
@@ -1548,7 +1548,7 @@ void CGarage::RefreshDoorPointers(bool bCreate)
 	}
 	if (m_pDoor2) {
 		if (m_bDoor2IsDummy) {
-			if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2)))
+			if (CPools::GetDummyPool()->GetIsFree(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2)))
 				bNeedToFindDoorEntities = true;
 			else {
 				if (m_bDoor2PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor2) & 0x7F))
@@ -1558,7 +1558,7 @@ void CGarage::RefreshDoorPointers(bool bCreate)
 			}
 		}
 		else {
-			if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2)))
+			if (CPools::GetObjectPool()->GetIsFree(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2)))
 				bNeedToFindDoorEntities = true;
 			else {
 				if (m_bDoor2PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor2) & 0x7F))
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index ee60f316..bd246b71 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -111,7 +111,7 @@ CPools::CheckPoolsEmpty()
 void
 CPools::MakeSureSlotInObjectPoolIsEmpty(int32 slot)
 {
-	if (ms_pObjectPool->IsFreeSlot(slot)) return;
+	if (ms_pObjectPool->GetIsFree(slot)) return;
 
 	CObject *object = ms_pObjectPool->GetSlot(slot);
 	if (object->ObjectCreatedBy == TEMP_OBJECT) {
diff --git a/src/core/templates.h b/src/core/templates.h
index 19881219..7bc85ee6 100644
--- a/src/core/templates.h
+++ b/src/core/templates.h
@@ -29,38 +29,58 @@ public:
 	}
 };
 
+#define POOLFLAG_ID     0x7f
+#define POOLFLAG_ISFREE 0x80
+
 template<typename T, typename U = T>
 class CPool
 {
 	U     *m_entries;
-	union Flags {
-		struct {
-			uint8 id   : 7;
-			uint8 free : 1;
-		};
-			uint8 u;
-	}     *m_flags;
+	uint8 *m_flags;
 	int32  m_size;
 	int32  m_allocPtr;
 
 public:
 	CPool(int32 size, const char *name){
 		m_entries = (U*)new uint8[sizeof(U)*size];
-		m_flags = (Flags*)new uint8[sizeof(Flags)*size];
+		m_flags = new uint8[size];
 		m_size = size;
 		m_allocPtr = -1;
 		for(int i = 0; i < size; i++){
-			m_flags[i].id   = 0;
-			m_flags[i].free = 1;
+			SetId(i, 0);
+			SetIsFree(i, true);
 		}
 	}
+
+	int GetId(int i) const
+	{
+		return m_flags[i] & POOLFLAG_ID;
+	}
+
+	bool GetIsFree(int i) const
+	{
+		return !!(m_flags[i] & POOLFLAG_ISFREE);
+	}
+
+	void SetId(int i, int id)
+	{
+		m_flags[i] = (m_flags[i] & POOLFLAG_ISFREE) | (id & POOLFLAG_ID);
+	}
+
+	void SetIsFree(int i, bool isFree)
+	{
+		if (isFree)
+			m_flags[i] |= POOLFLAG_ISFREE;
+		else
+			m_flags[i] &= ~POOLFLAG_ISFREE;
+	}
 	~CPool() {
 		Flush();
 	}
 	void Flush() {
 		if (m_size > 0) {
 			delete[] (uint8*)m_entries;
-			delete[] (uint8*)m_flags;
+			delete[] m_flags;
 			m_entries = nil;
 			m_flags = nil;
 			m_size = 0;
@@ -86,9 +106,9 @@ public:
 				m_allocPtr = 0;
 			}
 #endif
-		while(!m_flags[m_allocPtr].free);
-		m_flags[m_allocPtr].free = 0;
-		m_flags[m_allocPtr].id++;
+		while(!GetIsFree(m_allocPtr));
+		SetIsFree(m_allocPtr, false);
+		SetId(m_allocPtr, GetId(m_allocPtr)+1);
 		return (T*)&m_entries[m_allocPtr];
 	}
 	T *New(int32 handle){
@@ -98,37 +118,37 @@ public:
 	}
 	void SetNotFreeAt(int32 handle){
 		int idx = handle>>8;
-		m_flags[idx].free = 0;
-		m_flags[idx].id = handle & 0x7F;
+		SetIsFree(idx, false);
+		SetId(idx, handle & POOLFLAG_ID);
 		for(m_allocPtr = 0; m_allocPtr < m_size; m_allocPtr++)
-			if(m_flags[m_allocPtr].free)
+			if(GetIsFree(m_allocPtr))
 				return;
 	}
 	void Delete(T *entry){
 		int i = GetJustIndex(entry);
-		m_flags[i].free = 1;
+		SetIsFree(i, true);
 		if(i < m_allocPtr)
 			m_allocPtr = i;
 	}
 	T *GetSlot(int i){
-		return m_flags[i].free ? nil : (T*)&m_entries[i];
+		return GetIsFree(i) ? nil : (T*)&m_entries[i];
 	}
 	T *GetAt(int handle){
 #ifdef FIX_BUGS
 		if (handle == -1)
 			return nil;
 #endif
-		return m_flags[handle>>8].u == (handle & 0xFF) ?
+		return m_flags[handle>>8] == (handle & 0xFF) ?
 		       (T*)&m_entries[handle >> 8] : nil;
 	}
 	int32 GetIndex(T* entry) {
 		int i = GetJustIndex_NoFreeAssert(entry);
-		return m_flags[i].u + (i << 8);
+		return m_flags[i] + (i<<8);
 	}
 	int32 GetJustIndex(T* entry) {
 		int index = GetJustIndex_NoFreeAssert(entry);
 		assert((U*)entry == (U*)&m_entries[index]); // cast is unsafe - check required
-		assert(!IsFreeSlot(index));
+		assert(!GetIsFree(index));
 		return index;
 	}
 	int32 GetJustIndex_NoFreeAssert(T* entry) {
@@ -140,13 +160,12 @@ public:
 		int i;
 		int n = 0;
 		for(i = 0; i < m_size; i++)
-			if(!m_flags[i].free)
+			if(!GetIsFree(i))
 				n++;
 		return n;
 	}
-	bool IsFreeSlot(int i) { return !!m_flags[i].free; }
 	void ClearStorage(uint8 *&flags, U *&entries){
-		delete[] (uint8*)flags;
+		delete[] flags;
 		delete[] (uint8*)entries;
 		flags = nil;
 		entries = nil;
@@ -155,7 +174,7 @@ public:
 	void CopyBack(uint8 *&flags, U *&entries){
 		memcpy(m_flags, flags, sizeof(uint8)*m_size);
 		memcpy(m_entries, entries, sizeof(U)*m_size);
-		debug("Size copied:%d (%d)\n", sizeof(U)*m_size, sizeof(Flags)*m_size);
+		debug("Size copied:%d (%d)\n", sizeof(U)*m_size, m_size);
 		m_allocPtr = 0;
 		ClearStorage(flags, entries);
 		debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */

From 24de9f92e8513cfe0f6eedc6b69b3ff5bc282ffe Mon Sep 17 00:00:00 2001
From: aap <aap@papnet.eu>
Date: Thu, 21 Jan 2021 10:21:42 +0100
Subject: [PATCH 18/19] enable screenshots for librw; update librw

---
 src/skel/glfw/glfw.cpp | 4 ++++
 src/skel/win/win.cpp   | 4 ++++
 vendor/librw           | 2 +-
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp
index f039819c..9b2a768e 100644
--- a/src/skel/glfw/glfw.cpp
+++ b/src/skel/glfw/glfw.cpp
@@ -216,6 +216,10 @@ psGrabScreen(RwCamera *pCamera)
 		RwImageSetFromRaster(pImage, pRaster);
 		return pImage;
 	}
+#else
+	rw::Image *image = RwCameraGetRaster(pCamera)->toImage();
+	if(image)
+		return image;
 #endif
 	return nil;
 }
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index 1fd959f2..a5f721c8 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -257,6 +257,10 @@ psGrabScreen(RwCamera *pCamera)
 		RwImageSetFromRaster(pImage, pRaster);
 		return pImage;
 	}
+#else
+	rw::Image *image = RwCameraGetRaster(pCamera)->toImage();
+	if(image)
+		return image;
 #endif
 	return nil;
 }
diff --git a/vendor/librw b/vendor/librw
index 61b288a9..9260bddc 160000
--- a/vendor/librw
+++ b/vendor/librw
@@ -1 +1 @@
-Subproject commit 61b288a9fe72ae4073c0ac5fd2a5815ed510c8c8
+Subproject commit 9260bddc66f70eb51adf0749fa835fed1562c178

From f0097ff7333dd270126cc7dea0ed4c54141f86a9 Mon Sep 17 00:00:00 2001
From: Nikolay Korolev <nickvnuk@gmail.com>
Date: Thu, 21 Jan 2021 16:09:58 +0300
Subject: [PATCH 19/19] fix

---
 src/modelinfo/ModelIndices.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 182a0cea..836c4092 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -35,7 +35,7 @@
 	X("veg_treea1",		MI_TREE3) \
 	X("veg_treeb1",		MI_TREE6) \
 	X("veg_treea3",		MI_TREE8) \
-	X("doc_crane_cab",	MODELID_CRANE_1) \
+	X("doc_crane_cab0",	MODELID_CRANE_1) \
 	X("doc_crane_cab01",	MODELID_CRANE_2) \
 	X("doc_crane_cab02",	MODELID_CRANE_3) \
 	X("doc_crane_cab03",	MODELID_CRANE_4) \