From 36fa5ec2bf64ed73cdf52181fafe01aeb2926244 Mon Sep 17 00:00:00 2001 From: prefect Date: Wed, 15 Feb 2006 00:45:16 +0000 Subject: [PATCH] * clean up CLightEnv a bit * add CLightEnv::m_TerrainShadowTransparency * shadows will let a fraction of diffuse light through * added JS LightEnv objects, so the lighting environment can be changed from the console * new element TerrainShadowTransparency supported in the scenario .xml format, changed cantabrian_generated with an example This was SVN commit r3513. --- .../data/mods/official/maps/scenario_v4.dtd | 3 +- .../maps/scenarios/cantabrian_generated.xml | 4 +- source/graphics/GameView.cpp | 86 ++++-- source/graphics/GameView.h | 47 ++-- source/graphics/LightEnv.cpp | 53 ++++ source/graphics/LightEnv.h | 114 ++++---- source/graphics/MapReader.cpp | 11 +- source/graphics/RenderableObject.h | 14 +- .../scripting/JSInterface_LightEnv.cpp | 246 ++++++++++++++++++ .../graphics/scripting/JSInterface_LightEnv.h | 23 ++ source/ps/GameSetup/GameSetup.cpp | 9 +- .../renderer/FixedFunctionModelRenderer.cpp | 58 ++--- source/renderer/HWLightingModelRenderer.cpp | 2 +- source/renderer/InstancingModelRenderer.cpp | 2 +- source/renderer/Renderer.cpp | 13 +- source/renderer/TerrainRenderer.cpp | 138 +++++++--- source/renderer/TransparencyRenderer.cpp | 2 +- source/scripting/ScriptGlue.cpp | 15 +- 18 files changed, 649 insertions(+), 191 deletions(-) create mode 100644 source/graphics/LightEnv.cpp create mode 100644 source/graphics/scripting/JSInterface_LightEnv.cpp create mode 100644 source/graphics/scripting/JSInterface_LightEnv.h diff --git a/binaries/data/mods/official/maps/scenario_v4.dtd b/binaries/data/mods/official/maps/scenario_v4.dtd index bbe68a9317..7fa8f3b431 100644 --- a/binaries/data/mods/official/maps/scenario_v4.dtd +++ b/binaries/data/mods/official/maps/scenario_v4.dtd @@ -1,6 +1,6 @@ - + + diff --git a/binaries/data/mods/official/maps/scenarios/cantabrian_generated.xml b/binaries/data/mods/official/maps/scenarios/cantabrian_generated.xml index 5ab2f4f079..0677c2d779 100644 --- a/binaries/data/mods/official/maps/scenarios/cantabrian_generated.xml +++ b/binaries/data/mods/official/maps/scenarios/cantabrian_generated.xml @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60ec0b6cdc50f6433ba19f0ea5612937dbc941aac94d106ffca8691db1e00fe8 -size 1170686 +oid sha256:d326228fa27def17a3e23b790ca957f00ef622f32ab7c91f9a65c9c8b41232cb +size 1170748 diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index f5457031d2..3b72c76c80 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -85,7 +85,7 @@ CGameView::CGameView(CGame *pGame): m_UnitView=NULL; m_UnitAttach=NULL; - /* //TEST TRACK + /* //TEST TRACK int Test_Nodes=15; int Test_Variance=10.0f; //rand() % Test_Variance distortion of linear points int Test_Space=30; @@ -98,7 +98,7 @@ CGameView::CGameView(CGame *pGame): CCinemaData Test_Data; TNSpline Test_Spline; CCinemaTrack Test_Track; - + //linear generation with variance factor for (int i=0; iGetTerrain()); @@ -345,8 +347,8 @@ void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjec //locks the camera in place void CGameView::CameraLock(CVector3D Trans, bool smooth) { - m_Terrain=g_Game->GetWorld()->GetTerrain(); - float height=m_Terrain->getExactGroundLevel( + CTerrain* pTerrain = m_pWorld->GetTerrain(); + float height=pTerrain->getExactGroundLevel( m_ViewCamera.m_Orientation._14 + Trans.X, m_ViewCamera.m_Orientation._34 + Trans.Z) + g_YMinOffset; //is requested position within limits? @@ -368,8 +370,8 @@ void CGameView::CameraLock(CVector3D Trans, bool smooth) void CGameView::CameraLock(float x, float y, float z, bool smooth) { - m_Terrain=g_Game->GetWorld()->GetTerrain(); - float height=m_Terrain->getExactGroundLevel( + CTerrain* pTerrain = m_pWorld->GetTerrain(); + float height = pTerrain->getExactGroundLevel( m_ViewCamera.m_Orientation._14 + x, m_ViewCamera.m_Orientation._34 + z) + g_YMinOffset; //is requested position within limits? @@ -409,6 +411,8 @@ void CGameView::RenderNoCull() m_CullCamera = m_ViewCamera; g_Renderer.SetCamera(m_ViewCamera, m_CullCamera); + CheckLightEnv(); + uint i,j; const std::vector& units=pUnitMan->GetUnits(); for (i=0;iSetDirty(RENDERDATA_UPDATE_COLOR); + + const std::vector& props = model->GetProps(); + for(uint i = 0; i < props.size(); ++i) { + MarkUpdateColorRecursive(props[i].m_Model); + } +} + +void CGameView::CheckLightEnv() +{ + if (m_cachedLightEnv == g_LightEnv) + return; + + m_cachedLightEnv = g_LightEnv; + CTerrain* pTerrain = m_pWorld->GetTerrain(); + + if (!pTerrain) + return; + + PROFILE("update light env"); + pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR); + + const std::vector& units = m_pWorld->GetUnitManager()->GetUnits(); + for(int i = 0; i < units.size(); ++i) { + MarkUpdateColorRecursive(units[i]->GetModel()); + } +} + void CGameView::UnloadResources() { @@ -488,7 +522,7 @@ void CGameView::Update(float DeltaTime) m_ViewCamera.UpdateFrustum(); return; } - + if (m_TrackManager.IsPlaying()) { if(!m_TrackManager.Update(DeltaTime)) @@ -696,7 +730,7 @@ void CGameView::Update(float DeltaTime) CameraLock(forwards_horizontal * (m_ViewScrollSpeed * DeltaTime)); } - + //Temporary hack for cinematic interface if ( hotkeys[HOTKEY_CAMERA_CINEMA_ADD] ) { @@ -704,7 +738,7 @@ void CGameView::Update(float DeltaTime) if (it->GetNodeCount() == 0) m_TestTrack.m_StartRotation = m_ViewCamera.m_Orientation.GetRotation().m_V; - it->AddNode(m_ViewCamera.m_Orientation.GetTranslation(), 1.5f); + it->AddNode(m_ViewCamera.m_Orientation.GetTranslation(), 1.5f); it->UpdateSpline(); } if ( hotkeys[HOTKEY_CAMERA_CINEMA_DELETE] ) @@ -720,7 +754,7 @@ void CGameView::Update(float DeltaTime) } if ( hotkeys[HOTKEY_CAMERA_CINEMA_QUEUE] ) m_TrackManager.QueueTrack("test", false); - + // Smoothed zooming (move a certain percentage towards the desired zoom distance every frame) // Note that scroll wheel zooming is event-based and handled in game_view_handler @@ -875,7 +909,7 @@ InReaction CGameView::HandleEvent(const SDL_Event* ev) PopCameraTarget(); currentBookmark = -1; break; - + default: return( IN_PASS ); } diff --git a/source/graphics/GameView.h b/source/graphics/GameView.h index 2be70fc2c6..b359c929af 100755 --- a/source/graphics/GameView.h +++ b/source/graphics/GameView.h @@ -9,6 +9,7 @@ extern float g_YMinOffset; #include "CinemaTrack.h" #include "ModelDef.h" #include "Vector3D.h" +#include "LightEnv.h" #include "scripting/ScriptableObject.h" #include "lib/input.h" @@ -26,34 +27,39 @@ class CGameView: public CJSObject { CGame *m_pGame; CWorld *m_pWorld; - CTerrain *m_Terrain; - + /** * m_ViewCamera: this camera controls the eye position when rendering */ CCamera m_ViewCamera; - + /** * m_CullCamera: this camera controls the frustum that is used for culling * and shadow calculations - * + * * Note that all code that works with camera movements should only change * m_ViewCamera. The render functions automatically sync the cull camera to * the view camera depending on the value of m_LockCullCamera. */ CCamera m_CullCamera; - + /** * m_LockCullCamera: When @c true, the cull camera is locked in place. * When @c false, the cull camera follows the view camera. - * + * * Exposed to JS as gameView.lockCullCamera */ bool m_LockCullCamera; - + + /** + * m_cachedLightEnv: Cache global lighting environment. This is used to check whether the + * environment has changed during the last frame, so that vertex data can be updated etc. + */ + CLightEnv m_cachedLightEnv; + CCinemaManager m_TrackManager; CCinemaTrack m_TestTrack; - + //////////////////////////////////////// // Settings float m_ViewScrollSpeed; @@ -81,7 +87,10 @@ class CGameView: public CJSObject // Accumulate zooming changes across frames for smoothness float m_ZoomDelta; - + + // Check whether lighting environment has changed and update vertex data if necessary + void CheckLightEnv(); + // RenderTerrain: iterate through all terrain patches and submit all patches // in viewing frustum to the renderer, for terrain, water and LOS painting void RenderTerrain(CTerrain *pTerrain); @@ -89,18 +98,18 @@ class CGameView: public CJSObject // RenderModels: iterate through model list and submit all models in viewing // frustum to the Renderer void RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjectileManager); - + // SubmitModelRecursive: recurse down given model, submitting it and all its // descendents to the renderer void SubmitModelRecursive(CModel *pModel); - + // InitResources(): Load all graphics resources (textures, actor objects and // alpha maps) required by the game //void InitResources(); // UnloadResources(): Unload all graphics resources loaded by InitResources void UnloadResources(); - + // JS Interface bool JSI_StartCustomSelection(JSContext *cx, uintN argc, jsval *argv); bool JSI_EndCustomSelection(JSContext *cx, uintN argc, jsval *argv); @@ -110,15 +119,15 @@ class CGameView: public CJSObject public: CGameView(CGame *pGame); ~CGameView(); - + void RegisterInit(CGameAttributes *pAttribs); int Initialize(CGameAttributes *pGameAttributes); - // Update: Update all the view information (i.e. rotate camera, scroll, + // Update: Update all the view information (i.e. rotate camera, scroll, // whatever). This will *not* change any World information - only the // *presentation* void Update(float DeltaTime); - + // Render: Render the World void Render(); @@ -132,12 +141,12 @@ public: // RenderNoCull: render absolutely everything to a blank frame to force // renderer to load required assets void RenderNoCull(); - + // Camera Control Functions (used by input handler) void ResetCamera(); void ResetCameraOrientation(); void RotateAboutTarget(); - + void PushCameraTarget( const CVector3D& target ); void SetCameraTarget( const CVector3D& target ); void PopCameraTarget(); @@ -146,10 +155,10 @@ public: void ToUnitView(CEntity* target, CModel* prop); //Keep view the same but follow the unit void AttachToUnit(CEntity* target) { m_UnitAttach = target; } - + bool IsAttached () { if( m_UnitAttach ) { return true; } return false; } bool IsUnitView () { if( m_UnitView ) { return true; } return false; } - + inline CCamera *GetCamera() { return &m_ViewCamera; } }; diff --git a/source/graphics/LightEnv.cpp b/source/graphics/LightEnv.cpp new file mode 100644 index 0000000000..1d24e4e3a7 --- /dev/null +++ b/source/graphics/LightEnv.cpp @@ -0,0 +1,53 @@ +/** + * ========================================================================= + * File : LightEnv.cpp + * Project : Pyrogenesis + * Description : CLightEnv implementation + * + * @author Nicolai Hähnle + * ========================================================================= + */ + +#include "precompiled.h" + +#include "maths/MathUtil.h" + +#include "graphics/LightEnv.h" + + +CLightEnv::CLightEnv() + : m_Elevation(DEGTORAD(45)), + m_Rotation(DEGTORAD(270)), + m_TerrainShadowTransparency(0.0), + m_SunColor(1,1,1), + m_TerrainAmbientColor(0.4f,0.4f,0.4f), + m_UnitsAmbientColor(0.4f,0.4f,0.4f) +{ + CalculateSunDirection(); +} + +void CLightEnv::SetElevation(float f) +{ + m_Elevation = f; + CalculateSunDirection(); +} + +void CLightEnv::SetRotation(float f) +{ + m_Rotation = f; + CalculateSunDirection(); +} + +void CLightEnv::SetTerrainShadowTransparency(float f) +{ + m_TerrainShadowTransparency = f; +} + +void CLightEnv::CalculateSunDirection() +{ + m_SunDir.Y=-float(sin(m_Elevation)); + float scale=1+m_SunDir.Y; + m_SunDir.X=scale*float(sin(m_Rotation)); + m_SunDir.Z=scale*float(cos(m_Rotation)); + m_SunDir.Normalize(); +} diff --git a/source/graphics/LightEnv.h b/source/graphics/LightEnv.h index 03391fb200..41104c2e96 100755 --- a/source/graphics/LightEnv.h +++ b/source/graphics/LightEnv.h @@ -1,16 +1,13 @@ -/////////////////////////////////////////////////////////////////////////////// -// -// Name: LightEnv.h -// Author: Rich Cross -// Contact: rich@wildfiregames.com -// -// Description: class describing current lighting environment - -// at the minute, this is only sunlight and ambient light -// parameters; will be extended to handle dynamic lights at some -// later date -// -/////////////////////////////////////////////////////////////////////////////// - +/** + * ========================================================================= + * File : LightEnv.h + * Project : Pyrogenesis + * Description : CLightEnv, a class describing the current lights + * + * @author Rich Cross + * @author Nicolai Hähnle + * ========================================================================= + */ #ifndef __LIGHTENV_H #define __LIGHTENV_H @@ -20,52 +17,62 @@ class CMapWriter; class CMapReader; -class CEditorData; -class CMainFrame; -class CLightSettingsDlg; -/////////////////////////////////////////////////////////////////////////////// -// CLightEnv: description of a lighting environment - contains all the -// necessary parameters for representation of the lighting within a scenario +/** + * Class CLightEnv: description of a lighting environment - contains all the + * necessary parameters for representation of the lighting within a scenario + */ class CLightEnv { friend class CMapWriter; friend class CMapReader; friend class CXMLReader; +/* Trying to compile ScEd? ;) friend class CEditorData; friend class CMainFrame; friend class CLightSettingsDlg; -// weird accessor order to preserve memory layout of the class -public: - RGBColor m_SunColor; +*/ private: + /** + * m_Elevation: Height of sun above the horizon, in radians. + * For example, an elevation of PI/2 means the sun is straight up. + */ float m_Elevation; + + /** + * m_Rotation: Direction of sun on the compass, in radians. + * For example, a rotation of zero means the sun is in the direction (0,0,-1) + * and a rotation of PI/2 means the sun is in the direction (1,0,0) (not taking + * elevation into account). + */ float m_Rotation; -public: - RGBColor m_TerrainAmbientColor; - RGBColor m_UnitsAmbientColor; + + /** + * m_TerrainShadowTransparency: Fraction of diffuse light that reaches shadowed terrain. + * A value of 0.0 means shadowed polygons get only ambient light, while a value of 1.0 + * means shadows don't have any effect at all. + */ + float m_TerrainShadowTransparency; + CVector3D m_SunDir; - // get sun direction from a rotation and elevation; defined such that: - // 0 rotation = (0,0,1) - // PI/2 rotation = (-1,0,0) - // 0 elevation = (0,0,0) - // PI/2 elevation = (0,-1,0) +public: + RGBColor m_SunColor; + RGBColor m_TerrainAmbientColor; + RGBColor m_UnitsAmbientColor; - float GetElevation() { return m_Elevation; } - float GetRotation() { return m_Rotation; } +public: + CLightEnv(); - void SetElevation(float f) - { - m_Elevation = f; - CalculateSunDirection(); - } + float GetElevation() const { return m_Elevation; } + float GetRotation() const { return m_Rotation; } + const CVector3D& GetSunDir() const { return m_SunDir; } + float GetTerrainShadowTransparency() const { return m_TerrainShadowTransparency; } - void SetRotation(float f) - { - m_Rotation = f; - CalculateSunDirection(); - } + void SetElevation(float f); + void SetRotation(float f); + + void SetTerrainShadowTransparency(float f); /** * EvaluateTerrain: Calculate brightness of a point of the terrain with the given normal @@ -118,15 +125,24 @@ public: color = CVector3D(0,0,0); } -private: - void CalculateSunDirection() + // Comparison operators + bool operator==(const CLightEnv& o) const { - m_SunDir.Y=-float(sin(m_Elevation)); - float scale=1+m_SunDir.Y; - m_SunDir.X=scale*float(sin(m_Rotation)); - m_SunDir.Z=scale*float(cos(m_Rotation)); - m_SunDir.Normalize(); + return m_Elevation == o.m_Elevation && + m_Rotation == o.m_Rotation && + m_TerrainShadowTransparency == o.m_TerrainShadowTransparency && + m_SunColor == o.m_SunColor && + m_TerrainAmbientColor == o.m_TerrainAmbientColor && + m_UnitsAmbientColor == o.m_UnitsAmbientColor; } + + bool operator!=(const CLightEnv& o) const + { + return !(*this == o); + } + +private: + void CalculateSunDirection(); }; #endif diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index 2b9297a589..a846e3d647 100755 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -41,7 +41,7 @@ void CMapReader::LoadMap(const char* filename, CTerrain *pTerrain_, CUnitManager // [25ms] unpacker.Read(filename,"PSMP"); - // check version + // check version if (unpacker.GetVersion() < FILE_READ_VERSION) { throw CFileUnpacker::CFileVersionError(); } @@ -174,8 +174,8 @@ int CMapReader::UnpackTerrain() // ApplyData: take all the input data, and rebuild the scene from it int CMapReader::ApplyData() { - // initialise the terrain - pTerrain->Initialize(m_MapSize, &m_Heightmap[0]); + // initialise the terrain + pTerrain->Initialize(m_MapSize, &m_Heightmap[0]); // setup the textures on the minipatches STileDesc* tileptr = &m_Tiles[0]; @@ -323,6 +323,7 @@ void CXMLReader::ReadEnvironment(XMBElement parent) EL(sunrotation); EL(terrainambientcolour); EL(unitsambientcolour); + EL(terrainshadowtransparency); AT(r); AT(g); AT(b); #undef AT #undef EL @@ -361,6 +362,10 @@ void CXMLReader::ReadEnvironment(XMBElement parent) CStr(attrs.getNamedItem(at_g)).ToFloat(), CStr(attrs.getNamedItem(at_b)).ToFloat()); } + else if (element_name == el_terrainshadowtransparency) + { + m_MapReader.m_LightEnv.SetTerrainShadowTransparency(CStr(element.getText()).ToFloat()); + } else debug_warn("Invalid XML data - DTD shouldn't allow this"); } diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h index 86d78a1f32..f387cae93a 100755 --- a/source/graphics/RenderableObject.h +++ b/source/graphics/RenderableObject.h @@ -18,14 +18,14 @@ // need updating #define RENDERDATA_UPDATE_VERTICES (1<<1) #define RENDERDATA_UPDATE_INDICES (1<<2) -#define RENDERDATA_UPDATE_TRANSFORM (1<<3) +#define RENDERDATA_UPDATE_COLOR (1<<4) /////////////////////////////////////////////////////////////////////////////// -// CRenderData: base class of all the renderer's renderdata classes - the -// derived class stores necessary information for rendering an object of a +// CRenderData: base class of all the renderer's renderdata classes - the +// derived class stores necessary information for rendering an object of a // particular type -class CRenderData +class CRenderData { public: CRenderData() : m_UpdateFlags(0) {} @@ -36,7 +36,7 @@ public: /////////////////////////////////////////////////////////////////////////////// // CRenderableObject: base class of all renderable objects - patches, models, -// sprites, etc; stores position and bound information, and a pointer to +// sprites, etc; stores position and bound information, and a pointer to // some renderdata necessary for the renderer to actually render it class CRenderableObject { @@ -85,9 +85,9 @@ public: void InvalidateBounds() { m_BoundsValid = false; } // Set the object renderdata and free previous renderdata, if any. - void SetRenderData(CRenderData* renderdata) { + void SetRenderData(CRenderData* renderdata) { delete m_RenderData; - m_RenderData = renderdata; + m_RenderData = renderdata; } // return object renderdata - can be null if renderer hasn't yet diff --git a/source/graphics/scripting/JSInterface_LightEnv.cpp b/source/graphics/scripting/JSInterface_LightEnv.cpp new file mode 100644 index 0000000000..876061b8cf --- /dev/null +++ b/source/graphics/scripting/JSInterface_LightEnv.cpp @@ -0,0 +1,246 @@ +/** + * ========================================================================= + * File : JSInterface_LightEnv.cpp + * Project : Pyrogenesis + * Description : Provide the LightEnv object type for JavaScript + * + * @author Nicolai Hähnle + * ========================================================================= + */ + +#include "precompiled.h" + +#include "maths/scripting/JSInterface_Vector3D.h" + +#include "graphics/scripting/JSInterface_LightEnv.h" +#include "graphics/LightEnv.h" + +#include "ps/World.h" + +#include "scripting/JSConversions.h" + + +namespace JSI_LightEnv { + +namespace { + +extern JSClass JSI_class; + +/** + * This enumeration is used to index properties with the JavaScript implementation. + */ +enum +{ + lightenv_elevation, + lightenv_rotation, + lightenv_terrainShadowTransparency, + lightenv_sun, + lightenv_terrainAmbient, + lightenv_unitsAmbient +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// LightEnv_Info, the private structure that holds data for individual LightEnv objects + +struct LightEnv_Info : public IPropertyOwner +{ + CLightEnv* m_Data; + bool m_EngineOwned; + + // Create a new LightEnv that will only be used by JavaScript + LightEnv_Info() + { + m_Data = new CLightEnv; + m_EngineOwned = false; + } + + // Use the given CLightEnv from the engine. The caller must guarantee that + // the copy object will not be deleted. + LightEnv_Info(CLightEnv* copy) + { + m_Data = copy; + m_EngineOwned = true; + } + + ~LightEnv_Info() + { + if (!m_EngineOwned) + delete m_Data; + } +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Construction and finalization of LightEnvs + +/** + * construct: the LightEnv constructor has been called from JavaScript, so create a new + * LightEnv object + */ +JSBool construct(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* UNUSED(argv), jsval* rval) +{ + JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL); + + if(argc == 0) + { + JS_SetPrivate(cx, lightenv, new LightEnv_Info); + } + else + { + JS_ReportError(cx, "[LightEnv] Too many arguments to constructor"); + *rval = JSVAL_NULL; + return JS_TRUE; + } + + *rval = OBJECT_TO_JSVAL(lightenv); + return JS_TRUE; +} + +/** + * finalize: callback from the JS engine to indicate we should free our private data + */ +void finalize(JSContext* cx, JSObject* obj) +{ + delete (LightEnv_Info*)JS_GetPrivate(cx, obj); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Accessing properties of a LightEnv object + +// Can't use ToJSVal here because we need live updates from the vectors +JSBool getVectorProperty(JSContext* cx, LightEnv_Info* lightenvInfo, CVector3D* vec, jsval* vp) +{ + JSObject* vector3d = JS_NewObject(cx, &JSI_Vector3D::JSI_class, NULL, NULL); + JS_SetPrivate(cx, vector3d, new JSI_Vector3D::Vector3D_Info(vec, lightenvInfo)); + *vp = OBJECT_TO_JSVAL(vector3d); + return JS_TRUE; +} + + +JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp) +{ + if (!JSVAL_IS_INT(id)) + return JS_TRUE ; + + LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj); + if (!lightenvInfo) + { + JS_ReportError(cx, "[LightEnv] Invalid Reference"); + return JS_TRUE; + } + + CLightEnv* lightenv = lightenvInfo->m_Data; + + switch(ToPrimitive(id)) { + case lightenv_elevation: *vp = ToJSVal(lightenv->GetElevation()); break; + case lightenv_rotation: *vp = ToJSVal(lightenv->GetRotation()); break; + case lightenv_terrainShadowTransparency: *vp = ToJSVal(lightenv->GetTerrainShadowTransparency()); break; + case lightenv_sun: return getVectorProperty(cx, lightenvInfo, &lightenv->m_SunColor, vp); + case lightenv_terrainAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_TerrainAmbientColor, vp); + case lightenv_unitsAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_UnitsAmbientColor, vp); + default: break; + } + + return JS_TRUE; +} + + +JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp) +{ + if (!JSVAL_IS_INT(id)) + return( JS_TRUE ); + + LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj); + if (!lightenvInfo) + { + JS_ReportError(cx, "[LightEnv] Invalid reference"); + return JS_TRUE; + } + + CLightEnv* lightenv = lightenvInfo->m_Data; + + switch(ToPrimitive(id)) { + case lightenv_elevation: lightenv->SetElevation(ToPrimitive(*vp)); break; + case lightenv_rotation: lightenv->SetRotation(ToPrimitive(*vp)); break; + case lightenv_terrainShadowTransparency: lightenv->SetTerrainShadowTransparency(ToPrimitive(*vp)); break; + case lightenv_sun: lightenv->m_SunColor = ToPrimitive(*vp); break; + case lightenv_terrainAmbient: lightenv->m_TerrainAmbientColor = ToPrimitive(*vp); break; + case lightenv_unitsAmbient: lightenv->m_UnitsAmbientColor = ToPrimitive(*vp); break; + default: break; + } + + return JS_TRUE; +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Registration of LightEnv class with JavaScript + +JSClass JSI_class = { + "LightEnv", JSCLASS_HAS_PRIVATE, + JS_PropertyStub, JS_PropertyStub, + getProperty, setProperty, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, finalize, + NULL, NULL, NULL, NULL +}; + +JSPropertySpec JSI_props[] = +{ + { "elevation", lightenv_elevation, JSPROP_ENUMERATE }, + { "rotation", lightenv_rotation, JSPROP_ENUMERATE }, + { "terrainShadowTransparency", lightenv_terrainShadowTransparency, JSPROP_ENUMERATE }, + { "sun", lightenv_sun, JSPROP_ENUMERATE }, + { "terrainAmbient", lightenv_terrainAmbient, JSPROP_ENUMERATE }, + { "unitsAmbient", lightenv_unitsAmbient, JSPROP_ENUMERATE }, + { 0 }, +}; + +JSFunctionSpec JSI_methods[] = +{ + { 0 } +}; + +}; // anonymous namespace + +/** + * init: called by GameSetup to register the LightEnv class with the JS engine. + */ +void init() +{ + g_ScriptingHost.DefineCustomObjectType( &JSI_class, construct, 0, JSI_props, JSI_methods, NULL, NULL ); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Accessing the global lightenv + +JSBool getLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp) +{ + JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL); + JS_SetPrivate(cx, lightenv, new LightEnv_Info(&g_LightEnv)); + *vp = OBJECT_TO_JSVAL(lightenv); + return JS_TRUE; +} + +JSBool setLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp) +{ + JSObject* lightenv = JSVAL_TO_OBJECT(*vp); + LightEnv_Info* lightenvInfo; + + if (!JSVAL_IS_OBJECT(*vp) || NULL == (lightenvInfo = (LightEnv_Info*)JS_GetInstancePrivate(cx, lightenv, &JSI_class, NULL))) + { + JS_ReportError( cx, "[LightEnv] Invalid object" ); + } + else + { + g_LightEnv = *lightenvInfo->m_Data; + } + + return JS_TRUE; +} + +}; // namespace JSI_LightEnv + diff --git a/source/graphics/scripting/JSInterface_LightEnv.h b/source/graphics/scripting/JSInterface_LightEnv.h new file mode 100644 index 0000000000..55b088f3b8 --- /dev/null +++ b/source/graphics/scripting/JSInterface_LightEnv.h @@ -0,0 +1,23 @@ +/** + * ========================================================================= + * File : JSInterface_LightEnv.h + * Project : Pyrogenesis + * Description : Provide the LightEnv object type for JavaScript + * + * @author Nicolai Hähnle + * ========================================================================= + */ + +#ifndef JSI_LIGHTENV_INCLUDED +#define JSI_LIGHTENV_INCLUDED + +#include "scripting/ScriptingHost.h" + +namespace JSI_LightEnv +{ + void init(); + JSBool getLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); + JSBool setLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp ); +}; + +#endif diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index e036abda80..d4a6043397 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -62,6 +62,7 @@ #include "scripting/JSInterface_Camera.h" #include "scripting/JSInterface_Selection.h" #include "scripting/JSInterface_Console.h" +#include "graphics/scripting/JSInterface_LightEnv.h" #include "scripting/JSCollection.h" #include "scripting/DOMEvent.h" #ifndef NO_GUI @@ -522,6 +523,7 @@ static void InitScripting() JSI_Camera::init(); JSI_Console::init(); + JSI_LightEnv::init(); new CGameEvents; } @@ -660,14 +662,9 @@ static void InitRenderer() MICROLOG(L"init renderer"); g_Renderer.Open(g_xres,g_yres,g_bpp); - // Setup default lighting environment. Since the Renderer accesses the + // Setup lighting environment. Since the Renderer accesses the // lighting environment through a pointer, this has to be done before // the first Frame. - g_LightEnv.m_SunColor=RGBColor(1,1,1); - g_LightEnv.SetRotation(DEGTORAD(270)); - g_LightEnv.SetElevation(DEGTORAD(45)); - g_LightEnv.m_TerrainAmbientColor=RGBColor(0.4f,0.4f,0.4f); - g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f); g_Renderer.SetLightEnv(&g_LightEnv); // I haven't seen the camera affecting GUI rendering and such, but the diff --git a/source/renderer/FixedFunctionModelRenderer.cpp b/source/renderer/FixedFunctionModelRenderer.cpp index 7646468042..5819407f35 100644 --- a/source/renderer/FixedFunctionModelRenderer.cpp +++ b/source/renderer/FixedFunctionModelRenderer.cpp @@ -36,13 +36,13 @@ struct FFModelDef : public CModelDefRPrivate { /// Indices are the same for all models, so share them u16* m_Indices; - + /// Static per-CModelDef vertex array VertexArray m_Array; - + /// UV coordinates are stored in the static array VertexArray::Attribute m_UV; - + FFModelDef(CModelDefPtr mdef); ~FFModelDef() { delete[] m_Indices; } }; @@ -52,21 +52,21 @@ FFModelDef::FFModelDef(CModelDefPtr mdef) : m_Array(false) { size_t numVertices = mdef->GetNumVertices(); - + m_UV.type = GL_FLOAT; m_UV.elems = 2; m_Array.AddAttribute(&m_UV); - + m_Array.SetNumVertices(numVertices); m_Array.Layout(); VertexArrayIterator UVit = m_UV.GetIterator(); - + ModelRenderer::BuildUV(mdef, UVit); - + m_Array.Upload(); m_Array.FreeBackingStore(); - + m_Indices = new u16[mdef->GetNumFaces()*3]; ModelRenderer::BuildIndices(mdef, m_Indices); } @@ -76,11 +76,11 @@ struct FFModel { /// Dynamic per-CModel vertex array VertexArray m_Array; - + /// Position and lighting are recalculated on CPU every frame VertexArray::Attribute m_Position; VertexArray::Attribute m_Color; - + FFModel() : m_Array(true) { } }; @@ -89,7 +89,7 @@ struct FixedFunctionModelRendererInternals { /// Transformed vertex normals - required for recalculating lighting on skinned models std::vector normals; - + /// Previously prepared modeldef FFModelDef* ffmodeldef; }; @@ -130,7 +130,7 @@ void* FixedFunctionModelRenderer::CreateModelData(CModel* model) ffmodel->m_Color.type = GL_UNSIGNED_BYTE; ffmodel->m_Color.elems = 4; ffmodel->m_Array.AddAttribute(&ffmodel->m_Color); - + ffmodel->m_Array.SetNumVertices(mdef->GetNumVertices()); ffmodel->m_Array.Layout(); @@ -142,25 +142,25 @@ void* FixedFunctionModelRenderer::CreateModelData(CModel* model) void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, u32 updateflags) { FFModel* ffmodel = (FFModel*)data; - - if (updateflags & RENDERDATA_UPDATE_VERTICES) + + if (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR)) { CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); - + // build vertices if (m->normals.size() < numVertices) m->normals.resize(numVertices); - + VertexArrayIterator Position = ffmodel->m_Position.GetIterator(); VertexArrayIterator Normal = VertexArrayIterator((char*)&m->normals[0], sizeof(CVector3D)); - + ModelRenderer::BuildPositionAndNormals(model, Position, Normal); - + VertexArrayIterator Color = ffmodel->m_Color.GetIterator(); - + ModelRenderer::BuildColor4ub(model, Normal, Color); - + // upload everything to vertex buffer ffmodel->m_Array.Upload(); } @@ -172,7 +172,7 @@ void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, u32 void FixedFunctionModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data) { FFModel* ffmodel = (FFModel*)data; - + delete ffmodel; } @@ -181,7 +181,7 @@ void FixedFunctionModelRenderer::DestroyModelData(CModel* UNUSED(model), void* d void FixedFunctionModelRenderer::BeginPass(uint streamflags) { glEnableClientState(GL_VERTEX_ARRAY); - + if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); } @@ -192,7 +192,7 @@ void FixedFunctionModelRenderer::EndPass(uint streamflags) { if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); - + glDisableClientState(GL_VERTEX_ARRAY); } @@ -201,14 +201,14 @@ void FixedFunctionModelRenderer::EndPass(uint streamflags) void FixedFunctionModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr def) { m->ffmodeldef = (FFModelDef*)def->GetRenderData(m); - + debug_assert(m->ffmodeldef); - + if (streamflags & STREAM_UV0) { u8* base = m->ffmodeldef->m_Array.Bind(); GLsizei stride = (GLsizei)m->ffmodeldef->m_Array.GetStride(); - + glTexCoordPointer(2, GL_FLOAT, stride, base + m->ffmodeldef->m_UV.offset); } } @@ -219,13 +219,13 @@ void FixedFunctionModelRenderer::RenderModel(uint streamflags, CModel* model, vo { CModelDefPtr mdldef = model->GetModelDef(); FFModel* ffmodel = (FFModel*)data; - + u8* base = ffmodel->m_Array.Bind(); GLsizei stride = (GLsizei)ffmodel->m_Array.GetStride(); - + glVertexPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset); if (streamflags & STREAM_COLOR) - glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset); + glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset); // render the lot size_t numFaces = mdldef->GetNumFaces(); diff --git a/source/renderer/HWLightingModelRenderer.cpp b/source/renderer/HWLightingModelRenderer.cpp index 92d84b2e32..f1199fa1c7 100644 --- a/source/renderer/HWLightingModelRenderer.cpp +++ b/source/renderer/HWLightingModelRenderer.cpp @@ -184,7 +184,7 @@ void HWLightingModelRenderer::BeginPass(uint streamflags) idx = g_Renderer.m_VertexShader->m_ModelLight_Ambient; pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X); idx = g_Renderer.m_VertexShader->m_ModelLight_SunDir; - pglUniform3fvARB(idx, 1, &lightEnv.m_SunDir.X); + pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X); idx = g_Renderer.m_VertexShader->m_ModelLight_SunColor; pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X); diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp index 64d5d4f605..8392f6087c 100644 --- a/source/renderer/InstancingModelRenderer.cpp +++ b/source/renderer/InstancingModelRenderer.cpp @@ -164,7 +164,7 @@ void InstancingModelRenderer::BeginPass(uint streamflags) idx = g_Renderer.m_VertexShader->m_InstancingLight_Ambient; pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X); idx = g_Renderer.m_VertexShader->m_InstancingLight_SunDir; - pglUniform3fvARB(idx, 1, &lightEnv.m_SunDir.X); + pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X); idx = g_Renderer.m_VertexShader->m_InstancingLight_SunColor; pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index ac14700e56..6d0e09e451 100755 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -366,8 +366,14 @@ void CRenderer::EnumCaps() if (oglHaveExtension("GL_ARB_vertex_shader")) m_Caps.m_VertexShader=true; } + if (0 == oglHaveExtensions(0, "GL_ARB_shadow", "GL_ARB_depth_texture", 0)) { - m_Caps.m_DepthTextureShadows = true; + // According to Delphi3d.net, all relevant graphics chips that support depth textures + // (i.e. Geforce3+, Radeon9500+, even i915) also have >= 4 TMUs, so this restriction + // isn't actually a restriction, and it helps with integrating depth texture + // shadows into rendering paths. + if (ogl_max_tex_units >= 4) + m_Caps.m_DepthTextureShadows = true; } } @@ -587,7 +593,7 @@ void CRenderer::BeginFrame() m_Stats.Reset(); // init per frame stuff - m->shadow->SetupFrame(m_CullCamera, m_LightEnv->m_SunDir); + m->shadow->SetupFrame(m_CullCamera, m_LightEnv->GetSunDir()); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -606,7 +612,8 @@ void CRenderer::RenderShadowMap() m->shadow->BeginRender(); - glColor3ub(0, 0, 0); + float shadowTransp = m_LightEnv->GetTerrainShadowTransparency(); + glColor3f(shadowTransp, shadowTransp, shadowTransp); // Figure out transparent rendering strategy RenderModifierPtr transparentShadows = m_Models.ModTransparentShadow; diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index cce225deb9..303c335954 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -151,7 +151,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - float one[4] = { 1.f, 1.f, 1.f, 1.f }; + static const float one[4] = { 1.f, 1.f, 1.f, 1.f }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one); for(uint i = 0; i < m->visiblePatches.size(); ++i) @@ -197,51 +197,114 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Now apply lighting - // Light color is Ambient + ShadowTerm * Diffuse + const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + glBlendFunc(GL_DST_COLOR, GL_ZERO); - pglActiveTextureARB(GL_TEXTURE0); // Diffuse * Shadow - if (shadow) - glBindTexture(GL_TEXTURE_2D, shadow->GetTexture()); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - - pglActiveTextureARB(GL_TEXTURE1); // + Ambient - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); - - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X); - - pglActiveTextureARB(GL_TEXTURE0); - - if (shadow) + if (!shadow) { - const CMatrix3D& texturematrix = shadow->GetTextureMatrix(); + pglActiveTextureARB(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(&texturematrix._11); - glMatrixMode(GL_MODELVIEW); + // Shadow rendering disabled: Ambient + Diffuse + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X); } else { - glBindTexture(GL_TEXTURE_2D, 0); + const CMatrix3D& texturematrix = shadow->GetTextureMatrix(); + + pglActiveTextureARB(GL_TEXTURE0); + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(&texturematrix._11); + glMatrixMode(GL_MODELVIEW); + + glBindTexture(GL_TEXTURE_2D, shadow->GetTexture()); + + if (shadow->GetUseDepthTexture()) + { + // Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + float shadowTransp = g_Renderer.GetLightEnv().GetTerrainShadowTransparency(); + float color[4] = { shadowTransp, shadowTransp, shadowTransp, 1.0 }; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color); + + pglActiveTextureARB(GL_TEXTURE1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE0); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + pglActiveTextureARB(GL_TEXTURE2); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, shadow->GetTexture()); // Need a valid texture or the unit will be disabled + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X); + } + else + { + // Ambient + Diffuse * Shadow + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + pglActiveTextureARB(GL_TEXTURE1); // + Ambient + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X); + } } + + pglActiveTextureARB(GL_TEXTURE0); pglClientActiveTextureARB(GL_TEXTURE0); for (uint i = 0; i < m->visiblePatches.size(); ++i) @@ -255,6 +318,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) glMatrixMode(GL_MODELVIEW); // restore OpenGL state + g_Renderer.BindTexture(2,0); g_Renderer.BindTexture(1,0); pglClientActiveTextureARB(GL_TEXTURE0); diff --git a/source/renderer/TransparencyRenderer.cpp b/source/renderer/TransparencyRenderer.cpp index e10a1d389d..274ec2e588 100755 --- a/source/renderer/TransparencyRenderer.cpp +++ b/source/renderer/TransparencyRenderer.cpp @@ -219,7 +219,7 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 up { PSModel* psmdl = (PSModel*)data; - if (updateflags & RENDERDATA_UPDATE_VERTICES) + if (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR)) { CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 6119d1a4c2..6b6a3f574b 100755 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -35,6 +35,7 @@ #include "scripting/JSInterface_Camera.h" #include "scripting/JSInterface_Console.h" #include "scripting/JSInterface_VFS.h" +#include "graphics/scripting/JSInterface_LightEnv.h" #include "scripting/JSConversions.h" #include "renderer/WaterManager.h" #ifndef NO_GUI @@ -204,7 +205,7 @@ JSBool issueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv entities.push_back( (ToNative(argv[0])) ->me); else entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0])); - + //Destroy old listeners if we're explicitly being reassigned for ( size_t i=0; i < entities.size(); i++) { @@ -925,7 +926,7 @@ JSBool setWaterAlphaOffset( JSContext* cx, JSObject* UNUSED(globalObject), uint JSBool isPaused( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) { REQUIRE_NO_PARAMS( isPaused ); - + if( !g_Game ) { JS_ReportError( cx, "Game is not started" ); @@ -940,17 +941,17 @@ JSBool isPaused( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval JSBool setPaused( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* UNUSED(rval) ) { REQUIRE_PARAMS( 1, setPaused ); - + if( !g_Game ) { JS_ReportError( cx, "Game is not started" ); return JS_FALSE; } - try + try { g_Game->m_Paused = ToPrimitive( argv[0] ); - } + } catch( PSERROR_Scripting_ConversionFailed ) { JS_ReportError( cx, "Invalid parameter to setPaused" ); @@ -963,7 +964,7 @@ JSBool setPaused( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsva JSBool getGameTime( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval ) { REQUIRE_NO_PARAMS( getGameTime ); - + if( !g_Game ) { JS_ReportError( cx, "Game is not started" ); @@ -1177,6 +1178,7 @@ enum ScriptGlobalTinyIDs GLOBAL_GROUPSARRAY, GLOBAL_CAMERA, GLOBAL_CONSOLE, + GLOBAL_LIGHTENV }; // shorthand @@ -1189,6 +1191,7 @@ JSPropertySpec ScriptGlobalTable[] = { "groups" , GLOBAL_GROUPSARRAY, PERM, JSI_Selection::getGroups, JSI_Selection::setGroups }, { "camera" , GLOBAL_CAMERA, PERM, JSI_Camera::getCamera, JSI_Camera::setCamera }, { "console" , GLOBAL_CONSOLE, PERM | CONST, JSI_Console::getConsole, 0 }, + { "lightenv" , GLOBAL_LIGHTENV, PERM, JSI_LightEnv::getLightEnv, JSI_LightEnv::setLightEnv }, { "entities" , 0, PERM | CONST, GetEntitySet, 0 }, { "players" , 0, PERM | CONST, GetPlayerSet, 0 }, { "localPlayer", 0, PERM , GetLocalPlayer, SetLocalPlayer },