mirror of
https://github.com/Relintai/godot-lportal.git
synced 2025-04-19 21:43:10 +02:00
More realtime support
This commit is contained in:
parent
2a63205867
commit
204f4a43d4
32
larea.cpp
Normal file
32
larea.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "larea.h"
|
||||
|
||||
void LArea::Create(String szName)
|
||||
{
|
||||
m_iFirstRoom = 0;
|
||||
m_iNumRooms = 0;
|
||||
|
||||
m_iFirstLight = 0;
|
||||
m_iNumLights = 0;
|
||||
|
||||
m_szName = szName;
|
||||
}
|
38
larea.h
Normal file
38
larea.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "core/ustring.h"
|
||||
|
||||
class LArea
|
||||
{
|
||||
public:
|
||||
void Create(String szName);
|
||||
|
||||
String m_szName;
|
||||
|
||||
int m_iFirstRoom;
|
||||
int m_iNumRooms;
|
||||
|
||||
// each area contains a list of global lights that affect this area
|
||||
int m_iFirstLight;
|
||||
int m_iNumLights;
|
||||
};
|
20
ldebug.cpp
20
ldebug.cpp
@ -1,3 +1,23 @@
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "ldebug.h"
|
||||
|
||||
namespace Lawn
|
||||
|
26
ldebug.h
26
ldebug.h
@ -1,12 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// most of the performance sensitive debug output will be compiled out in release builds
|
||||
// you won't be able to get frame debugging of the visibility tree though.
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
#define LPRINT_RUN(a, b) {String sz;\
|
||||
for (int n=0; n<Lawn::LDebug::m_iTabDepth; n++)\
|
||||
sz += "\t";\
|
||||
LPRINT(a, sz + b);}
|
||||
|
||||
//#define LPRINT_RUN(a, b) ;
|
||||
|
||||
#else
|
||||
#define LPRINT_RUN(a, b) ;
|
||||
#endif
|
||||
@ -23,6 +47,8 @@ Lawn::LDebug::print(b);\
|
||||
Lawn::LDebug::print(String("\tWARNING : ") + b);\
|
||||
}
|
||||
|
||||
String ftos(float f) {return String(Variant(f));}
|
||||
|
||||
|
||||
namespace Lawn
|
||||
{
|
||||
|
70
ldob.cpp
70
ldob.cpp
@ -62,16 +62,76 @@ void LHidable::Show(bool bShow)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
void LLight::SetDefaults()
|
||||
const char * LSource::m_szTypes[] = {"CAM", "DIR", "SPOT", "OMNI", };
|
||||
const char * LSource::m_szClasses[] = {"STATIC", "ROOM", "DYN", };
|
||||
|
||||
void LSource::Source_SetDefaults()
|
||||
{
|
||||
m_GodotID = 0;
|
||||
m_eType = LT_DIRECTIONAL;
|
||||
m_fSpread = 0.0f; // for spotlight
|
||||
m_fMaxDist = 100.0f;
|
||||
m_eType = ST_CAMERA;
|
||||
m_eClass = SC_STATIC;
|
||||
m_fSpread = 0.0f;
|
||||
m_fRange = FLT_MAX;
|
||||
m_RoomID = -1;
|
||||
|
||||
// spotlight spread definition (light.cpp, line 146)
|
||||
// float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
|
||||
}
|
||||
|
||||
String LSource::MakeDebugString() const
|
||||
{
|
||||
String sz = "SOURCE : ";
|
||||
sz += String(m_szTypes[m_eType]) + " - ";
|
||||
sz += String(m_szClasses[m_eClass]) + "\tpos ";
|
||||
|
||||
sz += String(Variant(m_ptPos)) + "\tdir ";
|
||||
sz += String(Variant(m_ptDir)) + "\n";
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
|
||||
void LLight::Light_SetDefaults()
|
||||
{
|
||||
m_Source.Source_SetDefaults();
|
||||
|
||||
m_GodotID = 0;
|
||||
// m_eType = LT_DIRECTIONAL;
|
||||
// m_eClass = LT_STATIC;
|
||||
// m_fSpread = 0.0f; // for spotlight
|
||||
// m_fMaxDist = 100.0f;
|
||||
// m_RoomID = -1;
|
||||
|
||||
m_FirstCaster = 0;
|
||||
m_NumCasters = 0;
|
||||
|
||||
m_NumAffectedRooms = 0;
|
||||
m_iArea = -1;
|
||||
}
|
||||
|
||||
bool LLight::AddAffectedRoom(int room_id)
|
||||
{
|
||||
if (m_NumAffectedRooms >= MAX_AFFECTED_ROOMS)
|
||||
return false;
|
||||
m_AffectedRooms[m_NumAffectedRooms++] = room_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// dynamic light update
|
||||
void LLight::Update()
|
||||
{
|
||||
// firstly, has it crossed into another room like the dobs
|
||||
}
|
||||
|
||||
String LLight::MakeDebugString() const
|
||||
{
|
||||
String sz;
|
||||
sz += m_Source.MakeDebugString();
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
|
75
ldob.h
75
ldob.h
@ -73,30 +73,83 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class LLight : public LHidable
|
||||
//class LCamera
|
||||
// trace source can be camera or light
|
||||
class LSource
|
||||
{
|
||||
public:
|
||||
enum eLightType
|
||||
enum eSourceType
|
||||
{
|
||||
LT_DIRECTIONAL,
|
||||
LT_SPOTLIGHT,
|
||||
LT_OMNI,
|
||||
ST_CAMERA, // frustum planes will have been added
|
||||
ST_DIRECTIONAL,
|
||||
ST_SPOTLIGHT, // trace should add back plane and cone planes
|
||||
ST_OMNI, // no planes, can go in any direction
|
||||
};
|
||||
void SetDefaults();
|
||||
Light * GetGodotLight();
|
||||
|
||||
enum eSourceClass
|
||||
{
|
||||
SC_STATIC, // non moving light
|
||||
SC_ROOM, // only moves within the room
|
||||
SC_DYNAMIC, // can move between rooms (register as a DOB)
|
||||
};
|
||||
|
||||
|
||||
void Source_SetDefaults();
|
||||
String MakeDebugString() const;
|
||||
|
||||
// funcs
|
||||
bool IsGlobal() const {return m_RoomID == -1;}
|
||||
|
||||
Vector3 m_ptDir;
|
||||
// all in world space, culling done in world space
|
||||
Vector3 m_ptPos;
|
||||
ObjectID m_GodotID;
|
||||
eLightType m_eType;
|
||||
Vector3 m_ptDir;
|
||||
eSourceType m_eType;
|
||||
eSourceClass m_eClass;
|
||||
|
||||
float m_fSpread; // for spotlight
|
||||
float m_fMaxDist; // shadow distance not light distance
|
||||
float m_fRange; // shadow distance not light distance
|
||||
|
||||
// source room
|
||||
int m_RoomID; // or -1 for global lights
|
||||
|
||||
private:
|
||||
static const char * m_szTypes[];
|
||||
static const char * m_szClasses[];
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LLight : public LHidable
|
||||
{
|
||||
public:
|
||||
enum {MAX_AFFECTED_ROOMS=64};
|
||||
|
||||
LSource m_Source;
|
||||
ObjectID m_GodotID;
|
||||
// shadow casters
|
||||
int m_FirstCaster;
|
||||
int m_NumCasters;
|
||||
|
||||
// funcs
|
||||
|
||||
// for dynamic lights
|
||||
// move them light dobs across planes
|
||||
// and update the rooms that are affected by the light
|
||||
void Update();
|
||||
String MakeDebugString() const;
|
||||
|
||||
void Light_SetDefaults();
|
||||
Light * GetGodotLight();
|
||||
|
||||
|
||||
bool AddAffectedRoom(int room_id);
|
||||
void ClearAffectedRooms() {m_NumAffectedRooms = 0;}
|
||||
|
||||
// keep a list of the rooms affected by this light
|
||||
uint16_t m_AffectedRooms[MAX_AFFECTED_ROOMS];
|
||||
int m_NumAffectedRooms;
|
||||
|
||||
// for global lights, this is the area or -1 if unset
|
||||
int m_iArea;
|
||||
String m_szArea; // set to the area string in the case of area lights, else ""
|
||||
};
|
||||
|
1003
lmain_camera.cpp
Normal file
1003
lmain_camera.cpp
Normal file
File diff suppressed because it is too large
Load Diff
101
lmain_camera.h
Normal file
101
lmain_camera.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//#define LMAINCAMERA_CALC_LUT
|
||||
|
||||
// we get the main camera clipping planes and derive the points from 3 plane equations
|
||||
// in order to cull shadow casters to the camera frustum
|
||||
class LMainCamera
|
||||
{
|
||||
public:
|
||||
// same order as godot
|
||||
enum ePlane {
|
||||
P_NEAR,
|
||||
P_FAR,
|
||||
P_LEFT,
|
||||
P_TOP,
|
||||
P_RIGHT,
|
||||
P_BOTTOM,
|
||||
P_TOTAL,
|
||||
};
|
||||
|
||||
// same order as godot
|
||||
enum ePoint {
|
||||
PT_FAR_LEFT_TOP,
|
||||
PT_FAR_LEFT_BOTTOM,
|
||||
PT_FAR_RIGHT_TOP,
|
||||
PT_FAR_RIGHT_BOTTOM,
|
||||
PT_NEAR_LEFT_TOP,
|
||||
PT_NEAR_LEFT_BOTTOM,
|
||||
PT_NEAR_RIGHT_TOP,
|
||||
PT_NEAR_RIGHT_BOTTOM,
|
||||
};
|
||||
|
||||
static const char * m_szPlanes[];
|
||||
static const char * m_szPoints[];
|
||||
|
||||
// 6 bits, 6 planes
|
||||
enum { NUM_CAM_PLANES = 6,
|
||||
NUM_CAM_POINTS = 8,
|
||||
MAX_CULL_PLANES = 16,
|
||||
LUT_SIZE = 64,
|
||||
};
|
||||
|
||||
// create the LUT
|
||||
LMainCamera();
|
||||
|
||||
bool Prepare(LRoomManager &manager, Camera * pCam);
|
||||
|
||||
// main use of this object, we can create a clipping volume that is a mix of the light frustum and the camera volume
|
||||
bool AddCameraLightPlanes(LRoomManager &manager, const LSource &lsource, LVector<Plane> &planes) const;
|
||||
|
||||
LVector<Plane> m_Planes;
|
||||
LVector<Vector3> m_Points;
|
||||
|
||||
// centre of camera frustum
|
||||
Vector3 m_ptCentre;
|
||||
|
||||
private:
|
||||
bool AddCameraLightPlanes_Directional(LRoomManager &manager, const LSource &lsource, LVector<Plane> &planes) const;
|
||||
String String_PlaneBF(unsigned int BF);
|
||||
|
||||
#ifdef LMAINCAMERA_CALC_LUT
|
||||
void GetNeighbours(ePlane p, ePlane neigh_planes[4]) const;
|
||||
void GetCornersOfPlanes( ePlane _fpPlane0, ePlane _fpPlane1, ePoint _fpRet[2] ) const;
|
||||
void CreateLUT();
|
||||
void CompactLUT_Entry(int n);
|
||||
void DebugPrintLUT();
|
||||
void DebugPrintLUT_AsTable();
|
||||
void AddLUT(int p0, int p1, ePoint pts[2]);
|
||||
void AddLUT_Entry(unsigned int n, ePoint pts[2]);
|
||||
String DebugStringLUT_Entry(const LVector<uint8_t> &entry);
|
||||
String String_LUTEntry(const LVector<uint8_t> &entry);
|
||||
|
||||
// contains a list of points for each combination of plane facing directions
|
||||
LVector<uint8_t> m_LUT[LUT_SIZE];
|
||||
#endif
|
||||
|
||||
// precalculated LUT
|
||||
static uint8_t m_LUT_EntrySizes[LUT_SIZE];
|
||||
static uint8_t m_LUT_Entries[LUT_SIZE][8];
|
||||
};
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "ldebug.h"
|
||||
#include "lroom_manager.h"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool LPortal::NameStartsWith(Node * pNode, String szSearch)
|
||||
{
|
||||
@ -86,7 +86,7 @@ void LPortal::AddLightPlanes(LRoomManager &manager, const LLight &light, LVector
|
||||
int nPoints = pts.size();
|
||||
ERR_FAIL_COND(nPoints < 3);
|
||||
|
||||
if (light.m_eType == LLight::LT_DIRECTIONAL)
|
||||
if (light.m_Source.m_eType == LSource::ST_DIRECTIONAL)
|
||||
{
|
||||
// assuming ortho light
|
||||
const int max_points = 32;
|
||||
@ -96,7 +96,7 @@ void LPortal::AddLightPlanes(LRoomManager &manager, const LLight &light, LVector
|
||||
nPoints = max_points;
|
||||
|
||||
// transform pushed points
|
||||
Vector3 ptPush = light.m_ptDir * 2.0;
|
||||
Vector3 ptPush = light.m_Source.m_ptDir * 2.0;
|
||||
|
||||
for (int n=0; n<nPoints; n++)
|
||||
{
|
||||
@ -146,7 +146,7 @@ void LPortal::AddLightPlanes(LRoomManager &manager, const LLight &light, LVector
|
||||
for (int n=0; n<nPoints; n++)
|
||||
{
|
||||
int nPLUS = (n + 1) % nPoints;
|
||||
p = Plane(pts[nPLUS], pts[n], light.m_ptPos);
|
||||
p = Plane(pts[nPLUS], pts[n], light.m_Source.m_ptPos);
|
||||
if (bReverse) p = -p;
|
||||
planes.push_back(p);
|
||||
Debug_CheckPlaneValidity(p);
|
||||
|
@ -1,3 +1,10 @@
|
||||
// defines
|
||||
|
||||
// frame debug strings
|
||||
#define LDEBUG_CAMERA
|
||||
#define LDEBUG_LIGHTS
|
||||
#define LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
|
||||
// single compilation unit
|
||||
#include "register_types.cpp"
|
||||
#include "ldebug.cpp"
|
||||
@ -11,3 +18,7 @@
|
||||
#include "lbitfield_dynamic.cpp"
|
||||
#include "lhelper.cpp"
|
||||
#include "lscene_saver.cpp"
|
||||
#include "ltrace.cpp"
|
||||
#include "lmain_camera.cpp"
|
||||
#include "larea.cpp"
|
||||
|
||||
|
97
lroom.cpp
97
lroom.cpp
@ -192,43 +192,67 @@ void LRoom::SoftShow(VisualInstance * pVI, uint32_t show_flags)
|
||||
}
|
||||
|
||||
|
||||
bool LRoom::RemoveLocalLight(int light_id)
|
||||
{
|
||||
int found = m_LocalLights.find(light_id);
|
||||
if (found == -1)
|
||||
return false;
|
||||
|
||||
m_LocalLights.remove_unsorted(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// naive version, adds all the non visible objects in visible rooms as shadow casters
|
||||
void LRoom::AddShadowCasters(LRoomManager &manager)
|
||||
{
|
||||
LPRINT_RUN(2, "ADDSHADOWCASTERS room " + get_name() + ", " + itos(m_iNumShadowCasters_SOB) + " shadow casters");
|
||||
|
||||
#ifdef LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
if (manager.m_bDebugFrameString)
|
||||
manager.DebugString_Add("Room " + itos(m_RoomID) + " local lights : ");
|
||||
#endif
|
||||
|
||||
// add all the active lights in this room
|
||||
for (int n=0; n<m_LocalLights.size(); n++)
|
||||
{
|
||||
int lightID = m_LocalLights[n];
|
||||
if (!manager.m_BF_ActiveLights.GetBit(lightID))
|
||||
{
|
||||
manager.m_BF_ActiveLights.SetBit(lightID, true);
|
||||
manager.m_ActiveLights.push_back(lightID);
|
||||
manager.Light_FrameProcess(lightID);
|
||||
|
||||
// add all shadow casters for this light (new method)
|
||||
const LLight &light = manager.m_Lights[lightID];
|
||||
int last_caster = light.m_FirstCaster + light.m_NumCasters;
|
||||
for (int c=light.m_FirstCaster; c<last_caster; c++)
|
||||
{
|
||||
int sobID = manager.m_LightCasters_SOB[c];
|
||||
|
||||
// only add to the caster list if not in it already (does this check need to happen, can this ever occur?)
|
||||
if (!manager.m_BF_caster_SOBs.GetBit(sobID))
|
||||
{
|
||||
LPRINT_RUN(2, "\t" + itos(sobID) + ", " + manager.m_SOBs[sobID].GetSpatial()->get_name());
|
||||
manager.m_BF_caster_SOBs.SetBit(sobID, true);
|
||||
manager.m_CasterList_SOBs.push_back(sobID);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LPRINT(2, "\t" + itos(sobID) + ", ALREADY CASTER " + manager.m_SOBs[sobID].GetSpatial()->get_name());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#ifdef LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
if (manager.m_bDebugFrameString)
|
||||
manager.DebugString_Add(itos(lightID) + ", ");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
if (manager.m_bDebugFrameString)
|
||||
manager.DebugString_Add("\n");
|
||||
#endif
|
||||
|
||||
// NEW .. global area directional lights
|
||||
// could be done with area bitflags... more efficiently
|
||||
for (int n=0; n<m_GlobalLights.size(); n++)
|
||||
{
|
||||
int lightID = m_GlobalLights[n];
|
||||
manager.Light_FrameProcess(lightID);
|
||||
}
|
||||
|
||||
/*
|
||||
for (int n=0; n<m_Areas.size(); n++)
|
||||
{
|
||||
int areaID = m_Areas[n];
|
||||
const LArea &area = manager.m_Areas[areaID];
|
||||
|
||||
int last_light = area.m_iFirstLight + area.m_iNumLights;
|
||||
|
||||
for (int l=area.m_iFirstLight; l<last_light; l++)
|
||||
{
|
||||
int lightID = manager.m_AreaLights[l];
|
||||
manager.Light_FrameProcess(lightID);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// new!! use precalced list of shadow casters
|
||||
// int last = m_iFirstShadowCaster_SOB + m_iNumShadowCasters_SOB;
|
||||
@ -322,12 +346,24 @@ void LRoom::Release(LRoomManager &manager)
|
||||
if (pS)
|
||||
{
|
||||
// signifies released or unregistered
|
||||
manager.Obj_SetRoomNum(pS, -2);
|
||||
manager.Meta_SetRoomNum(pS, -2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool LRoom::IsInArea(int area) const
|
||||
{
|
||||
for (int n=0; n<m_Areas.size(); n++)
|
||||
{
|
||||
if (m_Areas[n] == area)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// allows us to show / hide all dobs as the room visibility changes
|
||||
void LRoom::Room_MakeVisible(bool bVisible)
|
||||
{
|
||||
@ -404,7 +440,7 @@ void LRoom::Debug_ShowAll(bool bActive)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void LRoom::FirstTouch(LRoomManager &manager)
|
||||
{
|
||||
// set the frame counter
|
||||
@ -430,9 +466,10 @@ void LRoom::FirstTouch(LRoomManager &manager)
|
||||
for (int n=0; n<m_DOBs.size(); n++)
|
||||
m_DOBs[n].m_bVisible = false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int first_portal_plane)
|
||||
/*
|
||||
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LSource &cam, const LVector<Plane> &planes, int first_portal_plane)
|
||||
{
|
||||
// prevent too much depth
|
||||
if (depth > 8)
|
||||
@ -668,5 +705,5 @@ void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, cons
|
||||
|
||||
} // for p through portals
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
23
lroom.h
23
lroom.h
@ -39,14 +39,6 @@ class LPortal;
|
||||
class LRoomManager;
|
||||
class MeshInstance;
|
||||
|
||||
class LCamera
|
||||
{
|
||||
public:
|
||||
// all in world space, culling done in world space
|
||||
Vector3 m_ptPos;
|
||||
Vector3 m_ptDir;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LRoom
|
||||
@ -71,6 +63,12 @@ public:
|
||||
// local lights affecting this room
|
||||
LVector<int> m_LocalLights;
|
||||
|
||||
// global lights affecting this room
|
||||
LVector<int> m_GlobalLights;
|
||||
|
||||
// areas this room is in
|
||||
LVector<int> m_Areas;
|
||||
|
||||
// portals are stored in the manager in a contiguous list
|
||||
int m_iFirstPortal;
|
||||
int m_iNumPortals;
|
||||
@ -100,8 +98,8 @@ public:
|
||||
const String &get_name() const {return m_szName;}
|
||||
|
||||
// main function
|
||||
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int first_portal_plane = 1);
|
||||
void FirstTouch(LRoomManager &manager);
|
||||
// void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LSource &cam, const LVector<Plane> &planes, int first_portal_plane = 1);
|
||||
// void FirstTouch(LRoomManager &manager);
|
||||
|
||||
|
||||
// allows us to show / hide all dobs as the room visibility changes
|
||||
@ -129,6 +127,10 @@ public:
|
||||
LRoom();
|
||||
Spatial * GetGodotRoom() const;
|
||||
|
||||
// light casting .. changing the local light list
|
||||
bool RemoveLocalLight(int light_id);
|
||||
void AddLocalLight(int light_id) {m_LocalLights.push_back(light_id);}
|
||||
|
||||
// retained purely for debugging visualization
|
||||
Geometry::MeshData m_Bound_MeshData;
|
||||
|
||||
@ -137,6 +139,7 @@ public:
|
||||
// and the camera will hide them with a cull mask. This is so that
|
||||
// objects can still be rendered outside immediate view for casting shadows.
|
||||
static void SoftShow(VisualInstance * pVI, uint32_t show_flags);
|
||||
bool IsInArea(int area) const;
|
||||
|
||||
private:
|
||||
// whether lportal thinks this room is currently visible
|
||||
|
@ -43,20 +43,6 @@ void LRoomConverter::Convert(LRoomManager &manager, bool bVerbose, bool bPrepara
|
||||
// except when requested by explicitly clearing this flag.
|
||||
Lawn::LDebug::m_bRunning = (bVerbose == false);
|
||||
|
||||
// test pool vector
|
||||
// PoolVector<Vector2> arr;
|
||||
// arr.append(Vector2(0, 0));
|
||||
// arr.append(Vector2(1, 0));
|
||||
// arr.append(Vector2(2, 0));
|
||||
// arr.insert(1, arr[1]);
|
||||
|
||||
// LPRINT(5, "DEBUG POOLVECTOR");
|
||||
// for (int n=0; n<arr.size(); n++)
|
||||
// {
|
||||
// LPRINT(2, String(Variant(arr[n])));
|
||||
// }
|
||||
|
||||
|
||||
if (!m_bFinalRun)
|
||||
{
|
||||
LPRINT(5, "running convert PREPARATION RUN");
|
||||
@ -76,10 +62,11 @@ void LRoomConverter::Convert(LRoomManager &manager, bool bVerbose, bool bPrepara
|
||||
|
||||
int count = CountRooms();
|
||||
|
||||
int num_global_lights = LMAN->m_Lights.size();
|
||||
//int num_global_lights = LMAN->m_Lights.size();
|
||||
|
||||
// make sure bitfield is right size for number of rooms
|
||||
LMAN->m_BF_visible_rooms.Create(count);
|
||||
LMAN->m_LightRender.m_BF_Temp_Visible_Rooms.Create(count);
|
||||
|
||||
LMAN->m_Rooms.resize(count);
|
||||
|
||||
@ -99,12 +86,16 @@ void LRoomConverter::Convert(LRoomManager &manager, bool bVerbose, bool bPrepara
|
||||
LMAN->m_BF_master_SOBs.Create(num_sobs);
|
||||
LMAN->m_BF_master_SOBs_prev.Create(num_sobs);
|
||||
|
||||
LMAN->m_LightRender.m_BF_Temp_SOBs.Create(num_sobs);
|
||||
|
||||
LMAN->m_BF_ActiveLights.Create(LMAN->m_Lights.size());
|
||||
LMAN->m_BF_ActiveLights_prev.Create(LMAN->m_Lights.size());
|
||||
LMAN->m_BF_ProcessedLights.Create(LMAN->m_Lights.size());
|
||||
|
||||
// must be done after the bitfields
|
||||
Convert_Lights();
|
||||
Convert_ShadowCasters();
|
||||
Convert_AreaLights();
|
||||
|
||||
// hide all in preparation for first frame
|
||||
//LMAN->ShowAll(false);
|
||||
@ -119,6 +110,33 @@ void LRoomConverter::Convert(LRoomManager &manager, bool bVerbose, bool bPrepara
|
||||
|
||||
|
||||
|
||||
int LRoomConverter::Convert_Rooms_Recursive(Node * pParent, int count, int area)
|
||||
{
|
||||
for (int n=0; n<pParent->get_child_count(); n++)
|
||||
{
|
||||
Node * pChild = pParent->get_child(n);
|
||||
|
||||
if (Node_IsRoom(pChild))
|
||||
{
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pChild);
|
||||
assert (pSpat);
|
||||
|
||||
Convert_Room(pSpat, count++, area);
|
||||
}
|
||||
else if (Node_IsArea(pChild))
|
||||
{
|
||||
// get the area name
|
||||
String szArea = LPortal::FindNameAfter(pChild, "area_");
|
||||
|
||||
// find or create an area with this name
|
||||
int area_child = Area_FindOrCreate(szArea);
|
||||
count = Convert_Rooms_Recursive(pChild, count, area_child);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void LRoomConverter::Convert_Rooms()
|
||||
{
|
||||
@ -126,22 +144,27 @@ void LRoomConverter::Convert_Rooms()
|
||||
|
||||
// first find all room empties and convert to LRooms
|
||||
int count = 0;
|
||||
int area = -1;
|
||||
|
||||
for (int n=0; n<LROOMLIST->get_child_count(); n++)
|
||||
count = Convert_Rooms_Recursive(LROOMLIST, count, area);
|
||||
}
|
||||
|
||||
int LRoomConverter::Area_FindOrCreate(String szName)
|
||||
{
|
||||
for (int n=0; n<LMAN->m_Areas.size(); n++)
|
||||
{
|
||||
Node * pChild = LROOMLIST->get_child(n);
|
||||
|
||||
if (!Node_IsRoom(pChild))
|
||||
continue;
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pChild);
|
||||
assert (pSpat);
|
||||
|
||||
Convert_Room(pSpat, count++);
|
||||
if (LMAN->m_Areas[n].m_szName == szName)
|
||||
return n;
|
||||
}
|
||||
|
||||
// create
|
||||
LArea area;
|
||||
area.Create(szName);
|
||||
LMAN->m_Areas.push_back(area);
|
||||
return LMAN->m_Areas.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
int LRoomConverter::FindRoom_ByName(String szName) const
|
||||
{
|
||||
for (int n=0; n<LMAN->m_Rooms.size(); n++)
|
||||
@ -179,6 +202,14 @@ void LRoomConverter::Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &l
|
||||
{
|
||||
Node * pChild = pParent->get_child(n);
|
||||
|
||||
// ignore invisible
|
||||
Spatial * pSpatialChild = Object::cast_to<Spatial>(pChild);
|
||||
if (pSpatialChild && (pSpatialChild->is_visible_in_tree() == false))
|
||||
{
|
||||
pSpatialChild->queue_delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
// we are not interested in portal meshes, as they will be deleted later in conversion
|
||||
if (Node_IsPortal(pChild))
|
||||
continue;
|
||||
@ -196,6 +227,13 @@ void LRoomConverter::Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &l
|
||||
continue;
|
||||
}
|
||||
|
||||
// area
|
||||
if (Node_IsArea(pChild))
|
||||
{
|
||||
LRoom_DetectedArea(lroom, pChild);
|
||||
continue;
|
||||
}
|
||||
|
||||
VisualInstance * pVI = Object::cast_to<VisualInstance>(pChild);
|
||||
if (pVI)
|
||||
{
|
||||
@ -234,13 +272,21 @@ void LRoomConverter::Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &l
|
||||
|
||||
}
|
||||
|
||||
bool LRoomConverter::Convert_Room(Spatial * pNode, int lroomID)
|
||||
// areaID could be -1 if unset
|
||||
bool LRoomConverter::Convert_Room(Spatial * pNode, int lroomID, int areaID)
|
||||
{
|
||||
// get the room part of the name
|
||||
String szFullName = pNode->get_name();
|
||||
String szRoom = LPortal::FindNameAfter(pNode, "room_");
|
||||
|
||||
LPRINT(4, "Convert_Room : " + szFullName);
|
||||
if (areaID == -1)
|
||||
{
|
||||
LPRINT(4, "Convert_Room : " + szFullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
LPRINT(4, "Convert_Room : " + szFullName + " area_id " + itos(areaID));
|
||||
}
|
||||
|
||||
// get a reference to the lroom we are writing to
|
||||
LRoom &lroom = LMAN->m_Rooms[lroomID];
|
||||
@ -252,11 +298,15 @@ bool LRoomConverter::Convert_Room(Spatial * pNode, int lroomID)
|
||||
// save the room ID on the godot room metadata
|
||||
// This is used when registering DOBs and teleporting them with hints
|
||||
// i.e. the Godot room is used to lookup the room ID of the startroom.
|
||||
LMAN->Obj_SetRoomNum(pNode, lroomID);
|
||||
LMAN->Meta_SetRoomNum(pNode, lroomID);
|
||||
|
||||
// create a new LRoom to exchange the children over to, and delete the original empty
|
||||
lroom.m_szName = szRoom;
|
||||
|
||||
// area
|
||||
if (areaID != -1)
|
||||
lroom.m_Areas.push_back(areaID);
|
||||
|
||||
// keep a running bounding volume as we go through the visual instances
|
||||
// to determine the overall bound of the room
|
||||
LAABB bb_room;
|
||||
@ -390,33 +440,180 @@ bool LRoomConverter::Convert_Bound(LRoom &lroom, MeshInstance * pMI)
|
||||
|
||||
//}
|
||||
|
||||
void LRoomConverter::Convert_AreaLights()
|
||||
{
|
||||
// list the rooms in each area
|
||||
for (int a=0; a<LMAN->m_Areas.size(); a++)
|
||||
{
|
||||
LArea &area = LMAN->m_Areas[a];
|
||||
|
||||
// add every room in this area to the light affected rooms list
|
||||
for (int r=0; r<LMAN->m_Rooms.size(); r++)
|
||||
{
|
||||
LRoom &room = LMAN->m_Rooms[r];
|
||||
if (room.IsInArea(a))
|
||||
{
|
||||
// add the room to the area room list
|
||||
if (area.m_iNumRooms == 0)
|
||||
area.m_iFirstRoom = LMAN->m_AreaRooms.size();
|
||||
|
||||
area.m_iNumRooms += 1;
|
||||
LMAN->m_AreaRooms.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// first identify which lights are area lights, and match area strings to area IDs
|
||||
for (int n=0; n<LMAN->m_Lights.size(); n++)
|
||||
{
|
||||
LLight &l = LMAN->m_Lights[n];
|
||||
|
||||
// global area light?
|
||||
if (!l.m_Source.IsGlobal())
|
||||
continue;
|
||||
|
||||
assert (l.m_iArea == -1);
|
||||
|
||||
// match area string to area
|
||||
// find the area
|
||||
for (int n=0; n<LMAN->m_Areas.size(); n++)
|
||||
{
|
||||
if (LMAN->m_Areas[n].m_szName == l.m_szArea)
|
||||
{
|
||||
l.m_iArea = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// area not found?
|
||||
if (l.m_iArea == -1)
|
||||
{
|
||||
LWARN(2, "Convert_AreaLights area not found : " + l.m_szArea);
|
||||
}
|
||||
else
|
||||
{
|
||||
LPRINT(5,"Area light " + itos (n) + " area " + l.m_szArea + " found area_id " + itos(l.m_iArea));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add each light within an area to the area light list
|
||||
for (int a=0; a<LMAN->m_Areas.size(); a++)
|
||||
{
|
||||
LArea &area = LMAN->m_Areas[a];
|
||||
|
||||
for (int n=0; n<LMAN->m_Lights.size(); n++)
|
||||
{
|
||||
LLight &l = LMAN->m_Lights[n];
|
||||
|
||||
int areaID = l.m_iArea;
|
||||
if (areaID != a)
|
||||
continue;
|
||||
|
||||
// this light affects this area
|
||||
if (area.m_iNumLights == 0)
|
||||
area.m_iFirstLight = LMAN->m_AreaLights.size();
|
||||
|
||||
LMAN->m_AreaLights.push_back(n);
|
||||
area.m_iNumLights++;
|
||||
|
||||
|
||||
} // for n
|
||||
} // for a
|
||||
|
||||
// for each global light we can calculate the affected rooms
|
||||
for (int n=0; n<LMAN->m_Lights.size(); n++)
|
||||
{
|
||||
LLight &l = LMAN->m_Lights[n];
|
||||
|
||||
int areaID = l.m_iArea;
|
||||
|
||||
// not a global light
|
||||
if (areaID == -1)
|
||||
continue;
|
||||
|
||||
LPRINT(5,"Area light " + itos (n) + " affected rooms:");
|
||||
|
||||
// add every room in this area to the light affected rooms list
|
||||
for (int r=0; r<LMAN->m_Rooms.size(); r++)
|
||||
{
|
||||
LRoom &room = LMAN->m_Rooms[r];
|
||||
if (room.IsInArea(areaID))
|
||||
{
|
||||
//l.AddAffectedRoom(r); // no need as this is now done by area
|
||||
LPRINT(5,"\t" + itos (r));
|
||||
|
||||
// store the global lights on the room
|
||||
room.m_GlobalLights.push_back(n);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LRoomConverter::Convert_Lights()
|
||||
{
|
||||
// trace local lights out from rooms and add to each room the light affects
|
||||
for (int n=0; n<LMAN->m_Lights.size(); n++)
|
||||
{
|
||||
LLight &l = LMAN->m_Lights[n];
|
||||
if (l.IsGlobal())
|
||||
if (l.m_Source.IsGlobal())
|
||||
continue; // ignore globals .. affect all rooms
|
||||
|
||||
Light_Trace(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LRoomConverter::Light_Trace(int iLightID)
|
||||
{
|
||||
// get the light
|
||||
LLight &l = LMAN->m_Lights[iLightID];
|
||||
LPRINT(5,"_____________________________________________________________");
|
||||
LPRINT(5,"\nLight_Trace " + itos (iLightID));
|
||||
|
||||
LMAN->m_Trace.Trace_Light(*LMAN, l, LTrace::LR_CONVERT);
|
||||
|
||||
// now save the data from the trace
|
||||
LRoomManager::LLightRender &lr = LMAN->m_LightRender;
|
||||
|
||||
// visible rooms
|
||||
for (int n=0; n<lr.m_Temp_Visible_Rooms.size(); n++)
|
||||
{
|
||||
int room_id = lr.m_Temp_Visible_Rooms[n];
|
||||
LRoom &room = *LMAN->GetRoom(room_id);
|
||||
|
||||
room.AddLocalLight(iLightID);
|
||||
|
||||
// store the affected room on the light
|
||||
l.AddAffectedRoom(room_id);
|
||||
}
|
||||
|
||||
|
||||
// sobs
|
||||
for (int n=0; n<lr.m_Temp_Visible_SOBs.size(); n++)
|
||||
{
|
||||
int sob_id = lr.m_Temp_Visible_SOBs[n];
|
||||
|
||||
// first?
|
||||
if (!l.m_NumCasters)
|
||||
l.m_FirstCaster = LMAN->m_LightCasters_SOB.size();
|
||||
|
||||
LMAN->m_LightCasters_SOB.push_back(sob_id);
|
||||
l.m_NumCasters++;
|
||||
}
|
||||
|
||||
LPRINT(5, itos(lr.m_Temp_Visible_Rooms.size()) + " visible rooms, " + itos (lr.m_Temp_Visible_SOBs.size()) + " visible SOBs.\n");
|
||||
|
||||
/*
|
||||
// blank this each time as it is used to create the list of casters
|
||||
LMAN->m_BF_caster_SOBs.Blank();
|
||||
|
||||
// get the light
|
||||
LLight &l = LMAN->m_Lights[iLightID];
|
||||
|
||||
LPRINT(5,"\nLight_Trace " + itos (iLightID) + " direction " + l.m_ptDir);
|
||||
|
||||
// reset the planes pool for each render out from the source room
|
||||
LMAN->m_Pool.Reset();
|
||||
|
||||
|
||||
// the first set of planes are blank
|
||||
unsigned int pool_member = LMAN->m_Pool.Request();
|
||||
assert (pool_member != -1);
|
||||
@ -426,10 +623,11 @@ void LRoomConverter::Light_Trace(int iLightID)
|
||||
|
||||
Lawn::LDebug::m_iTabDepth = 0;
|
||||
|
||||
Light_TraceRecursive(0, LMAN->m_Rooms[l.m_RoomID], l, iLightID, planes);
|
||||
Light_TraceRecursive(0, LMAN->m_Rooms[l.m_Source.m_RoomID], l, iLightID, planes);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void LRoomConverter::Light_TraceRecursive(int depth, LRoom &lroom, LLight &light, int iLightID, const LVector<Plane> &planes)
|
||||
{
|
||||
// prevent too much depth
|
||||
@ -458,6 +656,9 @@ void LRoomConverter::Light_TraceRecursive(int depth, LRoom &lroom, LLight &light
|
||||
if (!bAlreadyInList)
|
||||
{
|
||||
lroom.m_LocalLights.push_back(iLightID);
|
||||
|
||||
// store the affected room on the light
|
||||
light.AddAffectedRoom(lroom.m_RoomID);
|
||||
}
|
||||
|
||||
// add each light caster that is within the planes to the light caster list
|
||||
@ -519,7 +720,7 @@ void LRoomConverter::Light_TraceRecursive(int depth, LRoom &lroom, LLight &light
|
||||
|
||||
LPRINT_RUN(2, "\tPORTAL " + itos (n) + " (" + itos(portalID) + ") " + port.get_name() + " normal " + port.m_Plane.normal);
|
||||
|
||||
float dot = port.m_Plane.normal.dot(light.m_ptDir);
|
||||
float dot = port.m_Plane.normal.dot(light.m_Source.m_ptDir);
|
||||
|
||||
if (dot <= 0.0f)
|
||||
{
|
||||
@ -596,7 +797,7 @@ void LRoomConverter::Light_TraceRecursive(int depth, LRoom &lroom, LLight &light
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
void LRoomConverter::Convert_ShadowCasters()
|
||||
{
|
||||
@ -608,22 +809,22 @@ void LRoomConverter::Convert_ShadowCasters()
|
||||
{
|
||||
const LLight &light = LMAN->m_Lights[l];
|
||||
String sz = "Light " + itos (l);
|
||||
if (light.IsGlobal())
|
||||
if (light.m_Source.IsGlobal())
|
||||
sz += " GLOBAL";
|
||||
else
|
||||
sz += " LOCAL from room " + itos(light.m_RoomID);
|
||||
sz += " LOCAL from room " + itos(light.m_Source.m_RoomID);
|
||||
|
||||
LPRINT(5, sz + " direction " + light.m_ptDir);
|
||||
LPRINT(5, sz + " direction " + light.m_Source.m_ptDir);
|
||||
|
||||
for (int n=0; n<LMAN->m_Rooms.size(); n++)
|
||||
{
|
||||
LRoom &lroom = LMAN->m_Rooms[n];
|
||||
|
||||
// global lights affect every room
|
||||
bool bAffectsRoom = true;
|
||||
bool bAffectsRoom = false; // true
|
||||
|
||||
// if the light is local, does it affect this room?
|
||||
if (!light.IsGlobal())
|
||||
if (!light.m_Source.IsGlobal())
|
||||
{
|
||||
// a local light .. does it affect this room?
|
||||
bAffectsRoom = false;
|
||||
@ -720,8 +921,22 @@ int LRoomConverter::CountRooms()
|
||||
|
||||
for (int n=0; n<nChildren; n++)
|
||||
{
|
||||
if (Node_IsRoom(LROOMLIST->get_child(n)))
|
||||
Node * pChild = LROOMLIST->get_child(n);
|
||||
if (Node_IsRoom(pChild))
|
||||
count++;
|
||||
else
|
||||
{
|
||||
// also check the children if this is an area
|
||||
if (Node_IsArea(pChild))
|
||||
{
|
||||
for (int c=0; c<pChild->get_child_count(); c++)
|
||||
{
|
||||
Node * pChild2 = pChild->get_child(c);
|
||||
if (Node_IsRoom(pChild2))
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
@ -761,6 +976,7 @@ int LRoomConverter::CountRooms()
|
||||
// return;
|
||||
//}
|
||||
|
||||
/*
|
||||
void LRoomConverter::Light_AddCaster_SOB(LLight &light, int sobID)
|
||||
{
|
||||
// we will reuse the rendering bitflags for shadow casters for this ... to check for double entries (fnaa fnaa)
|
||||
@ -780,7 +996,7 @@ void LRoomConverter::Light_AddCaster_SOB(LLight &light, int sobID)
|
||||
LMAN->m_LightCasters_SOB.push_back(sobID);
|
||||
light.m_NumCasters++;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
void LRoomConverter::LRoom_AddShadowCaster_SOB(LRoom &lroom, int sobID)
|
||||
{
|
||||
@ -907,14 +1123,14 @@ void LRoomConverter::LRoom_FindShadowCasters_Recursive(LRoom &source_lroom, int
|
||||
|
||||
// cull with light direction
|
||||
float dot;
|
||||
if (light.m_eType == LLight::LT_DIRECTIONAL)
|
||||
if (light.m_Source.m_eType == LSource::ST_DIRECTIONAL)
|
||||
{
|
||||
dot = port.m_Plane.normal.dot(light.m_ptDir);
|
||||
dot = port.m_Plane.normal.dot(light.m_Source.m_ptDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cull with light direction to portal
|
||||
Vector3 ptLightToPort = port.m_ptCentre - light.m_ptPos;
|
||||
Vector3 ptLightToPort = port.m_ptCentre - light.m_Source.m_ptPos;
|
||||
dot = port.m_Plane.normal.dot(ptLightToPort);
|
||||
}
|
||||
|
||||
@ -1090,6 +1306,26 @@ void LRoomConverter::LRoom_MakePortalFinalList(LRoom &lroom, LTempRoom &troom)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LRoomConverter::LRoom_DetectedArea(LRoom &lroom, Node * pNode)
|
||||
{
|
||||
// find the area name
|
||||
String szArea = LPortal::FindNameAfter(pNode, "area_");
|
||||
|
||||
// find or create an area with this name
|
||||
int area = Area_FindOrCreate(szArea);
|
||||
|
||||
// check for duplicates? maybe a level design mistake?
|
||||
if (lroom.m_Areas.find(area) != -1)
|
||||
{
|
||||
LWARN(2, "LRoom_DetectedArea : duplicate area in room, ignoring : " + szArea);
|
||||
return;
|
||||
}
|
||||
|
||||
// add it to the lroom
|
||||
lroom.m_Areas.push_back(area);
|
||||
}
|
||||
|
||||
void LRoomConverter::LRoom_DetectedLight(LRoom &lroom, Node * pNode)
|
||||
{
|
||||
Light * pLight = Object::cast_to<Light>(pNode);
|
||||
@ -1214,6 +1450,18 @@ bool LRoomConverter::Node_IsLight(Node * pNode) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LRoomConverter::Node_IsArea(Node * pNode) const
|
||||
{
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pNode);
|
||||
if (!pSpat)
|
||||
return false;
|
||||
|
||||
if (LPortal::NameStartsWith(pSpat, "area_"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LRoomConverter::Node_IsRoom(Node * pNode) const
|
||||
{
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
class LRoomManager;
|
||||
class LRoom;
|
||||
class LArea;
|
||||
class MeshInstance;
|
||||
|
||||
// simple min max aabb
|
||||
@ -87,7 +88,8 @@ private:
|
||||
int CountRooms();
|
||||
|
||||
void Convert_Rooms();
|
||||
bool Convert_Room(Spatial * pNode, int lroomID);
|
||||
int Convert_Rooms_Recursive(Node * pParent, int count, int area);
|
||||
bool Convert_Room(Spatial * pNode, int lroomID, int areaID);
|
||||
void Convert_Room_FindObjects_Recursive(Node * pParent, LRoom &lroom, LAABB &bb_room);
|
||||
void Convert_Room_SetDefaultCullMask_Recursive(Node * pParent);
|
||||
|
||||
@ -96,7 +98,7 @@ private:
|
||||
bool Convert_Bound(LRoom &lroom, MeshInstance * pMI);
|
||||
void Convert_ShadowCasters();
|
||||
void Convert_Lights();
|
||||
// void Convert_HideAll();
|
||||
void Convert_AreaLights();
|
||||
|
||||
|
||||
void LRoom_DetectPortalMeshes(LRoom &lroom, LTempRoom &troom);
|
||||
@ -109,11 +111,9 @@ private:
|
||||
// lights
|
||||
void LRoom_DetectedLight(LRoom &lroom, Node * pNode);
|
||||
void Light_Trace(int iLightID);
|
||||
void Light_TraceRecursive(int depth, LRoom &lroom, LLight &light, int iLightID, const LVector<Plane> &planes);
|
||||
void Light_AddCaster_SOB(LLight &light, int sobID);
|
||||
void LRoom_DetectedArea(LRoom &lroom, Node * pNode);
|
||||
|
||||
// shadows
|
||||
// void LRoom_FindShadowCasters(LRoom &lroom, int lightID, const LLight &light);
|
||||
void LRoom_FindShadowCasters_FromLight(LRoom &lroom, const LLight &light);
|
||||
void LRoom_FindShadowCasters_Recursive(LRoom &source_lroom, int depth, LRoom &lroom, const LLight &light, const LVector<Plane> &planes);
|
||||
void LRoom_AddShadowCaster_SOB(LRoom &lroom, int sobID);
|
||||
@ -124,13 +124,14 @@ private:
|
||||
|
||||
// helper
|
||||
bool Node_IsRoom(Node * pNode) const;
|
||||
bool Node_IsArea(Node * pNode) const;
|
||||
bool Node_IsPortal(Node * pNode) const;
|
||||
bool Node_IsBound(Node * pNode) const;
|
||||
bool Node_IsIgnore(Node * pNode) const;
|
||||
bool Node_IsLight(Node * pNode) const;
|
||||
|
||||
int FindRoom_ByName(String szName) const;
|
||||
|
||||
int Area_FindOrCreate(String szName);
|
||||
|
||||
|
||||
// set up on entry
|
||||
|
@ -45,6 +45,9 @@ LRoomManager::LRoomManager()
|
||||
m_ID_DebugPlanes = 0;
|
||||
m_ID_DebugBounds = 0;
|
||||
m_ID_DebugLights = 0;
|
||||
m_ID_DebugLightVolumes = 0;
|
||||
m_ID_DebugFrustums = 0;
|
||||
|
||||
m_ID_RoomList = 0;
|
||||
|
||||
m_uiFrameCounter = 0;
|
||||
@ -59,6 +62,9 @@ LRoomManager::LRoomManager()
|
||||
m_bDebugPlanes = false;
|
||||
m_bDebugBounds = false;
|
||||
m_bDebugLights = false;
|
||||
m_bDebugLightVolumes = false;
|
||||
m_bDebugFrustums = false;
|
||||
m_bDebugFrameString = false;
|
||||
|
||||
m_pRoomList = 0;
|
||||
|
||||
@ -148,14 +154,31 @@ LRoom &LRoomManager::Portal_GetLinkedRoom(const LPortal &port)
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::Obj_SetRoomNum(Node * pNode, int num)
|
||||
// for lights we store the light ID in the metadata
|
||||
void LRoomManager::Meta_SetLightID(Node * pNode, int id)
|
||||
{
|
||||
pNode->set_meta("_llight", id);
|
||||
}
|
||||
|
||||
int LRoomManager::Meta_GetLightID(Node * pNode) const
|
||||
{
|
||||
//assert (pNode->has_meta("_lroom"));
|
||||
Variant v = pNode->get_meta("_llight");
|
||||
if (v.get_type() == Variant::NIL)
|
||||
return -1;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::Meta_SetRoomNum(Node * pNode, int num)
|
||||
{
|
||||
pNode->set_meta("_lroom", num);
|
||||
|
||||
assert (Obj_GetRoomNum(pNode) == num);
|
||||
assert (Meta_GetRoomNum(pNode) == num);
|
||||
}
|
||||
|
||||
int LRoomManager::Obj_GetRoomNum(Node * pNode) const
|
||||
int LRoomManager::Meta_GetRoomNum(Node * pNode) const
|
||||
{
|
||||
//assert (pNode->has_meta("_lroom"));
|
||||
Variant v = pNode->get_meta("_lroom");
|
||||
@ -167,7 +190,7 @@ int LRoomManager::Obj_GetRoomNum(Node * pNode) const
|
||||
|
||||
LRoom * LRoomManager::GetRoomFromDOB(Node * pNode)
|
||||
{
|
||||
int iRoom = Obj_GetRoomNum(pNode);
|
||||
int iRoom = Meta_GetRoomNum(pNode);
|
||||
if (iRoom < 0)
|
||||
{
|
||||
if (iRoom == -1)
|
||||
@ -211,7 +234,7 @@ bool LRoomManager::dob_register_hint(Node * pDOB, float radius, Node * pRoom)
|
||||
}
|
||||
|
||||
|
||||
int iRoom = Obj_GetRoomNum(pRoom);
|
||||
int iRoom = Meta_GetRoomNum(pRoom);
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pDOB);
|
||||
if (!pSpat)
|
||||
@ -267,7 +290,49 @@ void LRoomManager::CreateDebug()
|
||||
move_child(b, get_child_count()-1);
|
||||
m_ID_DebugLights = b->get_instance_id();
|
||||
b->set_material_override(m_mat_Debug_Bounds);
|
||||
//b->hide();
|
||||
b->hide();
|
||||
}
|
||||
|
||||
{
|
||||
ImmediateGeometry * p = memnew(ImmediateGeometry);
|
||||
p->set_name("debug_lightvolumes");
|
||||
add_child(p);
|
||||
move_child(p, get_child_count()-1);
|
||||
|
||||
m_ID_DebugLightVolumes = p->get_instance_id();
|
||||
|
||||
// m_mat_Debug_Planes->set_as_toplevel(true);
|
||||
|
||||
m_mat_Debug_LightVolumes = Ref<SpatialMaterial>(memnew(SpatialMaterial));
|
||||
m_mat_Debug_LightVolumes->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
||||
// m_mat_Debug_Planes->set_line_width(6.0);
|
||||
// m_mat_Debug_Planes->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
|
||||
// m_mat_Debug_Planes->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
|
||||
// m_mat_Debug_Planes->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
|
||||
m_mat_Debug_LightVolumes->set_albedo(Color(0, 1, 1, 1));
|
||||
p->set_material_override(m_mat_Debug_LightVolumes);
|
||||
p->hide();
|
||||
}
|
||||
|
||||
{
|
||||
ImmediateGeometry * p = memnew(ImmediateGeometry);
|
||||
p->set_name("debug_frustums");
|
||||
add_child(p);
|
||||
move_child(p, get_child_count()-1);
|
||||
|
||||
m_ID_DebugFrustums = p->get_instance_id();
|
||||
|
||||
// m_mat_Debug_Planes->set_as_toplevel(true);
|
||||
|
||||
m_mat_Debug_Frustums = Ref<SpatialMaterial>(memnew(SpatialMaterial));
|
||||
m_mat_Debug_Frustums->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
||||
// m_mat_Debug_Planes->set_line_width(6.0);
|
||||
// m_mat_Debug_Planes->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
|
||||
// m_mat_Debug_Planes->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
|
||||
// m_mat_Debug_Planes->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
|
||||
m_mat_Debug_Frustums->set_albedo(Color(1, 0, 0, 1));
|
||||
p->set_material_override(m_mat_Debug_Frustums);
|
||||
p->hide();
|
||||
}
|
||||
|
||||
}
|
||||
@ -321,7 +386,7 @@ bool LRoomManager::DobRegister(Spatial * pDOB, float radius, int iRoom)
|
||||
pRoom->DOB_Add(dob);
|
||||
|
||||
// save the room ID on the dob metadata
|
||||
Obj_SetRoomNum(pDOB, iRoom);
|
||||
Meta_SetRoomNum(pDOB, iRoom);
|
||||
|
||||
// change visibility
|
||||
DobChangeVisibility(pDOB, 0, pRoom);
|
||||
@ -396,7 +461,7 @@ int LRoomManager::dob_update(Node * pDOB)
|
||||
DobChangeVisibility(pSpat, pRoom, pNewRoom);
|
||||
|
||||
// save the room ID on the dob metadata
|
||||
Obj_SetRoomNum(pSpat, iRoomNum);
|
||||
Meta_SetRoomNum(pSpat, iRoomNum);
|
||||
|
||||
// new room number
|
||||
return iRoomNum;
|
||||
@ -425,7 +490,7 @@ bool LRoomManager::dob_teleport_hint(Node * pDOB, Node * pRoom)
|
||||
}
|
||||
|
||||
|
||||
int iRoom = Obj_GetRoomNum(pRoom);
|
||||
int iRoom = Meta_GetRoomNum(pRoom);
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pDOB);
|
||||
if (!pSpat)
|
||||
@ -471,7 +536,7 @@ bool LRoomManager::DobTeleport(Spatial * pDOB, int iNewRoomID)
|
||||
pOldRoom->DOB_Remove(dob_id);
|
||||
|
||||
// save the room ID on the dob metadata
|
||||
Obj_SetRoomNum(pDOB, iNewRoomID);
|
||||
Meta_SetRoomNum(pDOB, iNewRoomID);
|
||||
|
||||
// change visibility
|
||||
DobChangeVisibility(pDOB, pOldRoom, pNewRoom);
|
||||
@ -509,7 +574,7 @@ bool LRoomManager::dob_unregister(Node * pDOB)
|
||||
LRoom * pRoom = GetRoomFromDOB(pDOB);
|
||||
|
||||
// change the meta data on the DOB .. this will catch trying to update an unregistered DOB
|
||||
Obj_SetRoomNum(pDOB, -2);
|
||||
Meta_SetRoomNum(pDOB, -2);
|
||||
|
||||
if (pRoom)
|
||||
{
|
||||
@ -521,8 +586,135 @@ bool LRoomManager::dob_unregister(Node * pDOB)
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::Light_FrameProcess(int lightID)
|
||||
{
|
||||
if (!m_BF_ProcessedLights.GetBit(lightID))
|
||||
{
|
||||
m_BF_ProcessedLights.SetBit(lightID, true);
|
||||
|
||||
// some lights may be processed but found not to intersect the camera frustum
|
||||
if (Light_FindCasters(lightID))
|
||||
{
|
||||
m_BF_ActiveLights.SetBit(lightID, true);
|
||||
m_ActiveLights.push_back(lightID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we are centralizing the tracing out from static and dynamic lights for each frame to this function
|
||||
// returns false if the entire light should be culled
|
||||
bool LRoomManager::Light_FindCasters(int lightID)
|
||||
{
|
||||
// add all shadow casters for this light (new method)
|
||||
const LLight &light = m_Lights[lightID];
|
||||
/*
|
||||
if (light.m_eClass == LLight::LT_STATIC)
|
||||
{
|
||||
int last_caster = light.m_FirstCaster + light.m_NumCasters;
|
||||
for (int c=light.m_FirstCaster; c<last_caster; c++)
|
||||
{
|
||||
int sobID = m_LightCasters_SOB[c];
|
||||
|
||||
// only add to the caster list if not in it already (does this check need to happen, can this ever occur?)
|
||||
if (!m_BF_caster_SOBs.GetBit(sobID))
|
||||
{
|
||||
LPRINT_RUN(2, "\t" + itos(sobID) + ", " + m_SOBs[sobID].GetSpatial()->get_name());
|
||||
m_BF_caster_SOBs.SetBit(sobID, true);
|
||||
m_CasterList_SOBs.push_back(sobID);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LPRINT(2, "\t" + itos(sobID) + ", ALREADY CASTER " + manager.m_SOBs[sobID].GetSpatial()->get_name());
|
||||
}
|
||||
|
||||
} // for c through caster
|
||||
} // static lights have a list of SOB casters
|
||||
*/
|
||||
|
||||
// special case of global area lights
|
||||
if (light.m_iArea != -1)
|
||||
{
|
||||
// special trace for area light
|
||||
if (m_Trace.Trace_Light(*this, light, LTrace::LR_ALL) == false)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// can only deal with lights in rooms for now
|
||||
if (light.m_Source.m_RoomID == -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
LRoom * pRoom = GetRoom(light.m_Source.m_RoomID);
|
||||
if (!pRoom)
|
||||
return true;
|
||||
|
||||
if (m_Trace.Trace_Light(*this, light, LTrace::LR_ALL) == false)
|
||||
return false;
|
||||
|
||||
} // non-area light
|
||||
|
||||
/*
|
||||
// we now need to trace either just DOBs (in the case of static lights)
|
||||
// or SOBs and DOBs (in the case of dynamic lights)
|
||||
m_LightRender.m_BF_Temp_SOBs.Blank();
|
||||
m_LightRender.m_Temp_Visible_SOBs.clear();
|
||||
|
||||
const LSource &cam = light.m_Source;
|
||||
// cam.Source_SetDefaults();
|
||||
// cam.m_ptPos = light.m_ptPos;
|
||||
// cam.m_ptDir = light.m_ptDir;
|
||||
|
||||
m_Trace.Trace_Prepare(*this, cam, m_LightRender.m_BF_Temp_SOBs, m_BF_visible_rooms, m_LightRender.m_Temp_Visible_SOBs, *m_pCurr_VisibleRoomList);
|
||||
|
||||
|
||||
unsigned int pool_member = m_Pool.Request();
|
||||
assert (pool_member != -1);
|
||||
|
||||
LVector<Plane> &planes = m_Pool.Get(pool_member);
|
||||
planes.clear();
|
||||
|
||||
// create subset planes of light frustum and camera frustum
|
||||
m_MainCamera.AddCameraLightPlanes(*this, cam, planes);
|
||||
|
||||
m_Trace.Trace_Begin(*pRoom, planes);
|
||||
|
||||
// we no longer need these planes
|
||||
m_Pool.Free(pool_member);
|
||||
*/
|
||||
// process the sobs that were visible
|
||||
for (int n=0; n<m_LightRender.m_Temp_Visible_SOBs.size(); n++)
|
||||
{
|
||||
int sobID = m_LightRender.m_Temp_Visible_SOBs[n];
|
||||
|
||||
// only add to the caster list if not in it already (does this check need to happen, can this ever occur?)
|
||||
if (!m_BF_caster_SOBs.GetBit(sobID))
|
||||
{
|
||||
LPRINT_RUN(2, "\t" + itos(sobID) + ", " + m_SOBs[sobID].GetSpatial()->get_name());
|
||||
m_BF_caster_SOBs.SetBit(sobID, true);
|
||||
m_CasterList_SOBs.push_back(sobID);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LPRINT(2, "\t" + itos(sobID) + ", ALREADY CASTER " + manager.m_SOBs[sobID].GetSpatial()->get_name());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LRoomManager::Light_UpdateTransform(LLight &light, const Light &glight) const
|
||||
{
|
||||
// assert (glight.is_in_tree());
|
||||
Transform tr = glight.get_global_transform();
|
||||
light.m_Source.m_ptPos = tr.origin;
|
||||
light.m_Source.m_ptDir = -tr.basis.get_axis(2); // or possibly get_axis .. z is what we want
|
||||
}
|
||||
|
||||
// common stuff for global and local light creation
|
||||
bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
bool LRoomManager::LightCreate(Light * pLight, int roomID, String szArea)
|
||||
{
|
||||
// set culling flag for light
|
||||
// 1 is for lighting objects outside the room system
|
||||
@ -530,23 +722,21 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
|
||||
// create new light
|
||||
LLight l;
|
||||
l.SetDefaults();
|
||||
l.Light_SetDefaults();
|
||||
l.Hidable_Create(pLight);
|
||||
l.m_GodotID = pLight->get_instance_id();
|
||||
//l.m_iArea = areaID;
|
||||
|
||||
// store the area name as a string if an area light
|
||||
// as the areas aren't actually created until calling convert
|
||||
if (szArea != "")
|
||||
l.m_szArea = szArea;
|
||||
|
||||
LSource &lsource = l.m_Source;
|
||||
|
||||
// direction
|
||||
Transform tr = pLight->get_global_transform();
|
||||
l.m_ptPos = tr.origin;
|
||||
l.m_ptDir = -tr.basis.get_axis(2); // or possibly get_axis .. z is what we want
|
||||
l.m_RoomID = roomID;
|
||||
|
||||
l.m_fMaxDist = pLight->get_param(Light::PARAM_SHADOW_MAX_DISTANCE);
|
||||
|
||||
|
||||
//l.m_eType = LLight::LT_DIRECTIONAL;
|
||||
|
||||
//m_Lights.push_back(l);
|
||||
|
||||
Light_UpdateTransform(l, *pLight);
|
||||
lsource.m_RoomID = roomID;
|
||||
|
||||
bool bOK = false;
|
||||
|
||||
@ -555,8 +745,9 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
if (pSL)
|
||||
{
|
||||
LPRINT(2, "\tSPOTLIGHT detected " + pLight->get_name());
|
||||
l.m_eType = LLight::LT_SPOTLIGHT;
|
||||
l.m_fSpread = pSL->get_param(Light::PARAM_SPOT_ANGLE);
|
||||
lsource.m_eType = LSource::ST_SPOTLIGHT;
|
||||
lsource.m_fSpread = pSL->get_param(Light::PARAM_SPOT_ANGLE);
|
||||
lsource.m_fRange = pLight->get_param(Light::PARAM_RANGE);
|
||||
|
||||
bOK = true;
|
||||
}
|
||||
@ -565,7 +756,8 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
if (pOL)
|
||||
{
|
||||
LPRINT(2, "\tOMNILIGHT detected " + pLight->get_name());
|
||||
l.m_eType = LLight::LT_OMNI;
|
||||
lsource.m_eType = LSource::ST_OMNI;
|
||||
lsource.m_fRange = pLight->get_param(Light::PARAM_RANGE);
|
||||
bOK = true;
|
||||
}
|
||||
|
||||
@ -573,7 +765,10 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
if (pDL)
|
||||
{
|
||||
LPRINT(2, "\tDIRECTIONALLIGHT detected " + pLight->get_name());
|
||||
l.m_eType = LLight::LT_DIRECTIONAL;
|
||||
lsource.m_eType = LSource::ST_DIRECTIONAL;
|
||||
|
||||
// no range but max distance? NYI
|
||||
|
||||
bOK = true;
|
||||
}
|
||||
|
||||
@ -586,7 +781,7 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
|
||||
|
||||
// turn the local light off to start with
|
||||
if (!l.IsGlobal())
|
||||
if (!lsource.IsGlobal())
|
||||
{
|
||||
// l.Show(false);
|
||||
//pLight->hide();
|
||||
@ -598,10 +793,168 @@ bool LRoomManager::LightCreate(Light * pLight, int roomID)
|
||||
}
|
||||
|
||||
|
||||
bool LRoomManager::light_register(Node * pLightNode)
|
||||
bool LRoomManager::dynamic_light_register(Node * pLightNode, float radius)
|
||||
{
|
||||
CHECK_ROOM_LIST
|
||||
|
||||
if (!pLightNode)
|
||||
{
|
||||
WARN_PRINT_ONCE("dynamic_light_register : pLightNode is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectID light_id = pLightNode->get_instance_id();
|
||||
|
||||
// does the light already exist in the light list? I.e. was it imported as part of the roomlist?
|
||||
for (int n=0; n<m_Lights.size(); n++)
|
||||
{
|
||||
if (m_Lights[n].m_GodotID == light_id)
|
||||
{
|
||||
m_Lights[n].m_Source.m_eClass = LSource::SC_DYNAMIC;
|
||||
|
||||
// store the light ID in the metadata for the node
|
||||
Meta_SetLightID(pLightNode, n);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LRoomManager::dynamic_light_register_hint(Node * pLightNode, float radius, Node * pRoom)
|
||||
{
|
||||
// NYI
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LRoomManager::dynamic_light_unregister(Node * pLightNode)
|
||||
{
|
||||
// NYI
|
||||
return true;
|
||||
}
|
||||
|
||||
int LRoomManager::dynamic_light_update(Node * pLightNode) // returns room within
|
||||
{
|
||||
if (!pLightNode)
|
||||
{
|
||||
WARN_PRINT_ONCE("dynamic_light_update : pLightNode is NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pLightNode->is_inside_tree() == false)
|
||||
{
|
||||
#ifdef LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
if (m_bDebugFrameString)
|
||||
DebugString_Add("DynamicLight not in tree\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// find the light ID from meta data
|
||||
int light_id = Meta_GetLightID(pLightNode);
|
||||
|
||||
if ((unsigned int) light_id >= (unsigned int) m_Lights.size())
|
||||
{
|
||||
WARN_PRINT_ONCE("dynamic_light_update : meta light ID out of range");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LLight &light = m_Lights[light_id];
|
||||
|
||||
// update the llight transform from the node
|
||||
Light * pGLight = light.GetGodotLight();
|
||||
Light_UpdateTransform(light, *pGLight);
|
||||
|
||||
Spatial * pSpat = Object::cast_to<Spatial>(pGLight);
|
||||
if (!pSpat)
|
||||
return -1;
|
||||
|
||||
int iRoom = light.m_Source.m_RoomID;
|
||||
if (iRoom == -1)
|
||||
{
|
||||
WARN_PRINT_ONCE("dynamic_light_update : can't update global light");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
LRoom * pRoom = GetRoom(iRoom);
|
||||
if (pRoom == 0)
|
||||
{
|
||||
WARN_PRINT_ONCE("dynamic_light_update : pRoom is NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LRoom * pNewRoom = pRoom->DOB_Update(*this, pSpat);
|
||||
|
||||
if (pNewRoom)
|
||||
{
|
||||
// remove from the list in old room and add to list in new room, and change the metadata
|
||||
int iNewRoomID = pNewRoom->m_RoomID;
|
||||
light.m_Source.m_RoomID = iNewRoomID;
|
||||
|
||||
// change visibility
|
||||
//DobChangeVisibility(pSpat, pRoom, pNewRoom);
|
||||
}
|
||||
|
||||
|
||||
// update with a new Trace (we are assuming update is only called if the light has moved)
|
||||
// remove the old local lights
|
||||
for (int n=0; n<light.m_NumAffectedRooms; n++)
|
||||
{
|
||||
int r = light.m_AffectedRooms[n];
|
||||
GetRoom(r)->RemoveLocalLight(light_id);
|
||||
}
|
||||
light.ClearAffectedRooms();
|
||||
|
||||
|
||||
// now do a new trace, and add all the rooms that are hit
|
||||
m_Trace.Trace_Light(*this, light, LTrace::LR_ROOMS);
|
||||
|
||||
// we should now have a list of the rooms hit in m_LightRender.m_Temp_Visible_Rooms
|
||||
for (int n=0; n<m_LightRender.m_Temp_Visible_Rooms.size(); n++)
|
||||
{
|
||||
int r = m_LightRender.m_Temp_Visible_Rooms[n];
|
||||
|
||||
// add to the list on the light
|
||||
light.AddAffectedRoom(r);
|
||||
|
||||
// add to the list of local lights in the room
|
||||
GetRoom(r)->AddLocalLight(light_id);
|
||||
|
||||
}
|
||||
|
||||
// this may or may not have changed
|
||||
return light.m_Source.m_RoomID;
|
||||
}
|
||||
|
||||
void LRoomManager::DebugString_Light_AffectedRooms(int light_id)
|
||||
{
|
||||
#ifdef LDEBUG_LIGHT_AFFECTED_ROOMS
|
||||
if (m_bDebugFrameString)
|
||||
{
|
||||
const LLight &light = m_Lights[light_id];
|
||||
if (!light.m_bShow)
|
||||
return;
|
||||
|
||||
DebugString_Add("Light " + itos(light_id) + " affect room ");
|
||||
// affected rooms
|
||||
for (int n=0; n<light.m_NumAffectedRooms; n++)
|
||||
{
|
||||
int room_id = light.m_AffectedRooms[n];
|
||||
DebugString_Add(itos(room_id) + ", ");
|
||||
}
|
||||
DebugString_Add("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool LRoomManager::light_register(Node * pLightNode, String szArea)
|
||||
{
|
||||
//CHECK_ROOM_LIST
|
||||
|
||||
if (!pLightNode)
|
||||
{
|
||||
WARN_PRINT_ONCE("light_register : pLightNode is NULL");
|
||||
@ -617,7 +970,14 @@ bool LRoomManager::light_register(Node * pLightNode)
|
||||
return false;
|
||||
}
|
||||
|
||||
return LightCreate(pLight, -1);
|
||||
DirectionalLight * pDLight = Object::cast_to<DirectionalLight>(pLightNode);
|
||||
if (!pDLight)
|
||||
{
|
||||
WARN_PRINT_ONCE("light_register : only DirectionalLights are supported, place spotlights and omnis within rooms");
|
||||
return false;
|
||||
}
|
||||
|
||||
return LightCreate(pLight, -1, szArea);
|
||||
}
|
||||
|
||||
|
||||
@ -646,7 +1006,7 @@ void LRoomManager::DobChangeVisibility(Spatial * pDOB, const LRoom * pOld, const
|
||||
|
||||
int LRoomManager::dob_get_room_id(Node * pDOB)
|
||||
{
|
||||
return Obj_GetRoomNum(pDOB);
|
||||
return Meta_GetRoomNum(pDOB);
|
||||
}
|
||||
|
||||
// helpers to enable the client to manage switching on and off physics and AI
|
||||
@ -688,51 +1048,6 @@ Node * LRoomManager::rooms_get_room(int room_id)
|
||||
return pRoom->GetGodotRoom();
|
||||
}
|
||||
|
||||
void LRoomManager::rooms_set_debug_lights(bool bActive)
|
||||
{
|
||||
m_bDebugLights = bActive;
|
||||
Object * pObj = ObjectDB::get_instance(m_ID_DebugLights);
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj);
|
||||
if (!im)
|
||||
return;
|
||||
|
||||
if (bActive)
|
||||
im->show();
|
||||
else
|
||||
im->hide();
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::rooms_set_debug_bounds(bool bActive)
|
||||
{
|
||||
m_bDebugBounds = bActive;
|
||||
|
||||
Object * pObj = ObjectDB::get_instance(m_ID_DebugBounds);
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj);
|
||||
if (!im)
|
||||
return;
|
||||
|
||||
if (bActive)
|
||||
im->show();
|
||||
else
|
||||
im->hide();
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::rooms_set_debug_planes(bool bActive)
|
||||
{
|
||||
m_bDebugPlanes = bActive;
|
||||
|
||||
Object * pObj = ObjectDB::get_instance(m_ID_DebugPlanes);
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj);
|
||||
if (!im)
|
||||
return;
|
||||
|
||||
if (bActive)
|
||||
im->show();
|
||||
else
|
||||
im->hide();
|
||||
}
|
||||
|
||||
|
||||
// move the initial hiding to where the camera is set, so we can save the scene etc
|
||||
@ -748,7 +1063,7 @@ void LRoomManager::ShowAll(bool bShow)
|
||||
for (int n=0; n<m_Lights.size(); n++)
|
||||
{
|
||||
LLight &light = m_Lights[n];
|
||||
if (!light.IsGlobal())
|
||||
if (!light.m_Source.IsGlobal())
|
||||
light.Show(bShow);
|
||||
}
|
||||
|
||||
@ -787,12 +1102,6 @@ void LRoomManager::rooms_set_active(bool bActive)
|
||||
{
|
||||
LSob &sob = m_SOBs[n];
|
||||
sob.Show(!bActive);
|
||||
// Spatial * pS = sob.GetSpatial();
|
||||
// if (pS)
|
||||
// if (!bActive)
|
||||
// pS->show();
|
||||
// else
|
||||
// pS->hide();
|
||||
|
||||
VisualInstance * pVI = sob.GetVI();
|
||||
if (pVI)
|
||||
@ -809,6 +1118,12 @@ void LRoomManager::rooms_set_active(bool bActive)
|
||||
|
||||
}
|
||||
|
||||
String LRoomManager::rooms_get_debug_frame_string()
|
||||
{
|
||||
return m_szDebugString;
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::rooms_set_logging(int level)
|
||||
{
|
||||
// 0 is no logging, 6 is max logging (i.e. reverse of the priorities in the code)
|
||||
@ -989,8 +1304,12 @@ void LRoomManager::ReleaseResources(bool bPrepareConvert)
|
||||
m_LightCasters_SOB.clear();
|
||||
m_Rooms.clear(true);
|
||||
m_Portals.clear(true);
|
||||
m_Areas.clear(true);
|
||||
m_SOBs.clear();
|
||||
|
||||
m_AreaLights.clear(true);
|
||||
m_AreaRooms.clear(true);
|
||||
|
||||
if (!bPrepareConvert)
|
||||
m_Lights.clear();
|
||||
|
||||
@ -1018,6 +1337,13 @@ void LRoomManager::FrameUpdate_Prepare()
|
||||
{
|
||||
if (m_bDebugPlanes)
|
||||
m_DebugPlanes.clear();
|
||||
|
||||
if (m_bDebugLightVolumes)
|
||||
m_DebugLightVolumes.clear();
|
||||
|
||||
if (m_bDebugFrustums)
|
||||
m_DebugFrustums.clear();
|
||||
|
||||
// clear the visible room list to write to each frame
|
||||
m_pCurr_VisibleRoomList->clear();
|
||||
|
||||
@ -1040,6 +1366,7 @@ void LRoomManager::FrameUpdate_Prepare()
|
||||
m_ActiveLights_prev.copy_from(m_ActiveLights);
|
||||
m_ActiveLights.clear();
|
||||
m_BF_ActiveLights.Blank();
|
||||
m_BF_ProcessedLights.Blank();
|
||||
|
||||
// as we hit visible rooms we will mark them in a bitset, so we can hide any rooms
|
||||
// that are showing that haven't been hit this frame
|
||||
@ -1057,6 +1384,8 @@ bool LRoomManager::FrameUpdate()
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugString_Set("");
|
||||
|
||||
// could turn off internal processing? not that important
|
||||
if (!m_bActive)
|
||||
return false;
|
||||
@ -1101,11 +1430,26 @@ bool LRoomManager::FrameUpdate()
|
||||
return false;
|
||||
}
|
||||
|
||||
// lcamera contains the info needed for culling
|
||||
LCamera cam;
|
||||
#ifdef LDEBUG_CAMERA
|
||||
if (m_bDebugFrameString)
|
||||
DebugString_Add("Camera in room " + itos(pRoom->m_RoomID) + "\n");
|
||||
#endif
|
||||
|
||||
|
||||
// lcamera contains the info needed for running the recursive trace using the main camera
|
||||
LSource cam; cam.Source_SetDefaults();
|
||||
cam.m_ptPos = Vector3(0, 0, 0);
|
||||
cam.m_ptDir = Vector3 (-1, 0, 0);
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
assert (pCamera);
|
||||
Transform tr = pCamera->get_global_transform();
|
||||
cam.m_ptPos = tr.origin;
|
||||
cam.m_ptDir = -tr.basis.get_axis(2); // or possibly get_axis .. z is what we want
|
||||
|
||||
// if we can't prepare the frustum is invalid
|
||||
if (!m_MainCamera.Prepare(*this, pCamera))
|
||||
return false;
|
||||
|
||||
// the first set of planes are allocated and filled with the view frustum planes
|
||||
// Note that the visual server doesn't actually need to do view frustum culling as a result...
|
||||
@ -1116,18 +1460,16 @@ bool LRoomManager::FrameUpdate()
|
||||
LVector<Plane> &planes = m_Pool.Get(pool_member);
|
||||
planes.clear();
|
||||
|
||||
// get the camera desired and make into lcamera
|
||||
assert (pCamera);
|
||||
Transform tr = pCamera->get_global_transform();
|
||||
cam.m_ptPos = tr.origin;
|
||||
cam.m_ptDir = -tr.basis.get_axis(2); // or possibly get_axis .. z is what we want
|
||||
|
||||
// luckily godot already has a function to return a list of the camera clipping planes
|
||||
planes.copy_from(pCamera->get_frustum());
|
||||
planes.copy_from(m_MainCamera.m_Planes);
|
||||
|
||||
// the whole visibility algorithm is recursive, spreading out from the camera room,
|
||||
// rendering through any portals in view into other rooms, etc etc
|
||||
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes);
|
||||
m_Trace.Trace_Prepare(*this, cam, m_BF_visible_SOBs, m_BF_visible_rooms, m_VisibleList_SOBs, *m_pCurr_VisibleRoomList);
|
||||
m_Trace.Trace_Begin(*pRoom, planes);
|
||||
|
||||
// we no longer need these planes
|
||||
m_Pool.Free(pool_member);
|
||||
|
||||
// finally hide all the rooms that are currently visible but not in the visible bitfield as having been hit
|
||||
FrameUpdate_FinalizeRooms();
|
||||
@ -1221,7 +1563,12 @@ void LRoomManager::FrameUpdate_AddShadowCasters()
|
||||
m_Rooms[r].AddShadowCasters(*this);
|
||||
}
|
||||
|
||||
LPRINT(2, "TOTAL shadow casters " + itos(m_CasterList_SOBs.size()));
|
||||
#ifdef LDEBUG_LIGHTS
|
||||
if (m_bDebugFrameString)
|
||||
DebugString_Add("TOTAL shadow casters " + itos(m_CasterList_SOBs.size()) + "\n");
|
||||
#endif
|
||||
|
||||
LPRINT_RUN(2, "TOTAL shadow casters " + itos(m_CasterList_SOBs.size()));
|
||||
}
|
||||
|
||||
void LRoomManager::FrameUpdate_FinalizeVisibility_SoftShow()
|
||||
@ -1250,6 +1597,12 @@ void LRoomManager::FrameUpdate_FinalizeVisibility_SoftShow()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef LDEBUG_LIGHTS
|
||||
if (m_bDebugFrameString)
|
||||
DebugString_Add("nActiveLights " + itos(m_ActiveLights.size()) + "\n");
|
||||
#endif
|
||||
|
||||
// lights
|
||||
for (int n=0; n<m_ActiveLights.size(); n++)
|
||||
{
|
||||
@ -1272,10 +1625,15 @@ void LRoomManager::FrameUpdate_FinalizeVisibility_SoftShow()
|
||||
//pLight->set_shadow(false);
|
||||
//pLight->set_shadow(true);
|
||||
//pLight->set_cull_mask(1 | LRoom::LAYER_MASK_LIGHT);
|
||||
Vector3 ptBugFix = pLight->get_translation();
|
||||
pLight->set_translation(ptBugFix);
|
||||
|
||||
|
||||
// Vector3 ptBugFix = pLight->get_translation();
|
||||
// pLight->set_translation(ptBugFix);
|
||||
}
|
||||
}
|
||||
|
||||
// debug
|
||||
DebugString_Light_AffectedRooms(lid);
|
||||
}
|
||||
for (int n=0; n<m_ActiveLights_prev.size(); n++)
|
||||
{
|
||||
@ -1333,7 +1691,7 @@ void LRoomManager::FrameUpdate_FinalizeVisibility_WithinRooms()
|
||||
}
|
||||
|
||||
|
||||
void LRoomManager::FrameUpdate_DrawDebug(const LCamera &cam, const LRoom &lroom)
|
||||
void LRoomManager::FrameUpdate_DrawDebug(const LSource &cam, const LRoom &lroom)
|
||||
{
|
||||
// light portal planes
|
||||
if (m_bDebugLights)
|
||||
@ -1381,6 +1739,47 @@ void LRoomManager::FrameUpdate_DrawDebug(const LCamera &cam, const LRoom &lroom)
|
||||
im->end();
|
||||
}
|
||||
|
||||
if (m_bDebugLightVolumes)
|
||||
{
|
||||
Object * pObj = ObjectDB::get_instance(m_ID_DebugLightVolumes);
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj);
|
||||
if (!im)
|
||||
return;
|
||||
|
||||
im->clear();
|
||||
|
||||
im->begin(Mesh::PRIMITIVE_LINES, NULL);
|
||||
|
||||
int nVerts = m_DebugLightVolumes.size();
|
||||
|
||||
for (int n=0; n<nVerts; n++)
|
||||
{
|
||||
im->add_vertex(m_DebugLightVolumes[n]);
|
||||
}
|
||||
im->end();
|
||||
}
|
||||
|
||||
if (m_bDebugFrustums)
|
||||
{
|
||||
Object * pObj = ObjectDB::get_instance(m_ID_DebugFrustums);
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj);
|
||||
if (!im)
|
||||
return;
|
||||
|
||||
im->clear();
|
||||
|
||||
im->begin(Mesh::PRIMITIVE_LINES, NULL);
|
||||
|
||||
int nVerts = m_DebugFrustums.size();
|
||||
|
||||
for (int n=0; n<nVerts; n++)
|
||||
{
|
||||
im->add_vertex(m_DebugFrustums[n]);
|
||||
}
|
||||
im->end();
|
||||
}
|
||||
|
||||
|
||||
// if debug bounds are on and there is a bound for this room
|
||||
const Geometry::MeshData &md = lroom.m_Bound_MeshData;
|
||||
if (m_bDebugBounds && md.faces.size())
|
||||
@ -1461,6 +1860,11 @@ void LRoomManager::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_planes", "active"), &LRoomManager::rooms_set_debug_planes);
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_bounds", "active"), &LRoomManager::rooms_set_debug_bounds);
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_lights", "active"), &LRoomManager::rooms_set_debug_lights);
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_shadows", "active"), &LRoomManager::rooms_set_debug_shadows);
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_frustums", "active"), &LRoomManager::rooms_set_debug_frustums);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("rooms_set_debug_frame_string", "active"), &LRoomManager::rooms_set_debug_frame_string);
|
||||
ClassDB::bind_method(D_METHOD("rooms_get_debug_frame_string"), &LRoomManager::rooms_get_debug_frame_string);
|
||||
|
||||
// lightmapping
|
||||
ClassDB::bind_method(D_METHOD("rooms_convert_lightmap_internal", "proxy filename", "level filename"), &LRoomManager::rooms_convert_lightmap_internal);
|
||||
@ -1479,7 +1883,12 @@ void LRoomManager::_bind_methods()
|
||||
ClassDB::bind_method(D_METHOD("dob_get_room_id", "dob"), &LRoomManager::dob_get_room_id);
|
||||
|
||||
|
||||
ClassDB::bind_method(D_METHOD("light_register", "light"), &LRoomManager::light_register);
|
||||
ClassDB::bind_method(D_METHOD("light_register", "light", "area"), &LRoomManager::light_register);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("dynamic_light_register", "light", "radius"), &LRoomManager::dynamic_light_register);
|
||||
ClassDB::bind_method(D_METHOD("dynamic_light_register_hint", "light", "radius", "room"), &LRoomManager::dynamic_light_register_hint);
|
||||
ClassDB::bind_method(D_METHOD("dynamic_light_unregister", "light"), &LRoomManager::dynamic_light_unregister);
|
||||
ClassDB::bind_method(D_METHOD("dynamic_light_update", "light"), &LRoomManager::dynamic_light_update);
|
||||
|
||||
// helper
|
||||
ClassDB::bind_method(D_METHOD("rooms_get_room", "room id"), &LRoomManager::rooms_get_room);
|
||||
@ -1614,3 +2023,37 @@ void LRoomManager::ResolveRoomListPath()
|
||||
_set_rooms(NULL);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// rooms_set_debug commands .. done as macros to make easier to change
|
||||
|
||||
// macros to combine to single identifier
|
||||
//#define SCU_IDENT(x) x
|
||||
#define COMB_NX(A, B) A##B
|
||||
#define COMB_IDENT(A, B) COMB_NX(A,B)
|
||||
#define IMPLEMENT_DEBUG_MESH(a, b) void LRoomManager::COMB_IDENT(rooms_set_debug_, a)(bool bActive)\
|
||||
{\
|
||||
COMB_IDENT(m_bDebug, b) = bActive;\
|
||||
Object * pObj = ObjectDB::get_instance(COMB_IDENT(m_ID_Debug, b)); \
|
||||
ImmediateGeometry * im = Object::cast_to<ImmediateGeometry>(pObj); \
|
||||
if (!im) \
|
||||
return; \
|
||||
if (bActive) \
|
||||
im->show(); \
|
||||
else \
|
||||
im->hide(); \
|
||||
}
|
||||
|
||||
IMPLEMENT_DEBUG_MESH(shadows,LightVolumes)
|
||||
IMPLEMENT_DEBUG_MESH(frustums,Frustums)
|
||||
IMPLEMENT_DEBUG_MESH(lights,Lights)
|
||||
IMPLEMENT_DEBUG_MESH(bounds,Bounds)
|
||||
IMPLEMENT_DEBUG_MESH(planes,Planes)
|
||||
|
||||
#undef COMB_NX
|
||||
#undef COMB_IDENT
|
||||
#undef IMPLEMENT_DEBUG_MESH
|
||||
|
||||
void LRoomManager::rooms_set_debug_frame_string(bool bActive)
|
||||
{
|
||||
m_bDebugFrameString = bActive;
|
||||
}
|
||||
|
377
lroom_manager.h
377
lroom_manager.h
@ -32,9 +32,9 @@
|
||||
|
||||
#include "lroom.h"
|
||||
#include "lportal.h"
|
||||
|
||||
|
||||
|
||||
#include "larea.h"
|
||||
#include "ltrace.h"
|
||||
#include "lmain_camera.h"
|
||||
|
||||
class LRoomManager : public Spatial {
|
||||
GDCLASS(LRoomManager, Spatial);
|
||||
@ -42,7 +42,111 @@ class LRoomManager : public Spatial {
|
||||
friend class LRoom;
|
||||
friend class LRoomConverter;
|
||||
friend class LHelper;
|
||||
friend class LTrace;
|
||||
friend class LMainCamera;
|
||||
|
||||
public:
|
||||
// PUBLIC INTERFACE TO GDSCRIPT
|
||||
//______________________________________________________________________________________
|
||||
// Roomlist path
|
||||
void set_rooms(const Object *p_rooms);
|
||||
void _set_rooms(Object *p_rooms);
|
||||
void set_rooms_path(const NodePath &p_path);
|
||||
NodePath get_rooms_path() const;
|
||||
void remove_rooms_path();
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// MAIN
|
||||
// convert empties and meshes to rooms and portals
|
||||
bool rooms_convert(bool bVerbose, bool bDeleteLights);
|
||||
// free memory for current set of rooms, prepare for converting a new game level
|
||||
void rooms_release();
|
||||
|
||||
// choose which camera you want to use to determine visibility.
|
||||
// normally this will be your main camera, but you can choose another for debugging
|
||||
bool rooms_set_camera(Node * pCam);
|
||||
|
||||
// get the Godot room that is associated with an LPortal room
|
||||
// (can be used to find the name etc of a room ID returned by dob_update)
|
||||
Node * rooms_get_room(int room_id);
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// DOBS
|
||||
// Dynamic objects .. cameras, players, boxes etc
|
||||
// These are defined by their ability to move from room to room.
|
||||
// You can still move static objects within the same room (e.g. elevators, moving platforms)
|
||||
// as these don't require checks for changing rooms.
|
||||
bool dob_register(Node * pDOB, float radius);
|
||||
// register but let LPortal know which room the dob should start in
|
||||
bool dob_register_hint(Node * pDOB, float radius, Node * pRoom);
|
||||
|
||||
bool dob_unregister(Node * pDOB);
|
||||
|
||||
// returns the room ID within
|
||||
int dob_update(Node * pDOB);
|
||||
|
||||
// if we are moving the DOB possibly through multiple rooms, then teleport rather than detect
|
||||
// portal crossings
|
||||
bool dob_teleport(Node * pDOB);
|
||||
bool dob_teleport_hint(Node * pDOB, Node * pRoom);
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// LIGHTS
|
||||
// global directional lights that will apply to all rooms
|
||||
bool light_register(Node * pLightNode, String szArea);
|
||||
|
||||
// dynamic lights (spot or omni within rooms)
|
||||
bool dynamic_light_register(Node * pLightNode, float radius);
|
||||
bool dynamic_light_register_hint(Node * pLightNode, float radius, Node * pRoom);
|
||||
bool dynamic_light_unregister(Node * pLightNode);
|
||||
int dynamic_light_update(Node * pLightNode); // returns room within
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// LIGHTMAPS
|
||||
// helper function to merge SOB meshes for producing lightmaps VIA external blender workflow
|
||||
bool rooms_merge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_unmerge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshInstance_To);
|
||||
|
||||
// one function to do all the uv mapping and lightmap creation in one
|
||||
// (for godot lightmap workflow)
|
||||
MeshInstance * rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename);
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// HELPERS
|
||||
// helper function for general use .. LPortal has the functionality, why not...
|
||||
bool rooms_save_scene(Node * pNode, String szFilename);
|
||||
// helpers to enable the client to manage switching on and off physics and AI
|
||||
int rooms_get_num_rooms() const;
|
||||
bool rooms_is_room_visible(int room_id) const;
|
||||
Array rooms_get_visible_rooms() const;
|
||||
// helper func, not needed usually as dob_update returns the room
|
||||
int dob_get_room_id(Node * pDOB);
|
||||
|
||||
|
||||
//______________________________________________________________________________________
|
||||
// DEBUGGING
|
||||
// turn on and off culling for debugging
|
||||
void rooms_set_active(bool bActive);
|
||||
void rooms_set_debug_planes(bool bActive);
|
||||
void rooms_set_debug_bounds(bool bActive);
|
||||
void rooms_set_debug_lights(bool bActive);
|
||||
void rooms_set_debug_shadows(bool bActive);
|
||||
void rooms_set_debug_frustums(bool bActive);
|
||||
void rooms_set_debug_frame_string(bool bActive);
|
||||
|
||||
// 0 to 6 .. less to more
|
||||
// defaults to 4 which is (2) in our priorities (i.e. 6 - level)
|
||||
void rooms_set_logging(int level);
|
||||
|
||||
// optionally lportal can output some debug info in a string each frame
|
||||
String rooms_get_debug_frame_string();
|
||||
|
||||
// provide debugging output on the next frame
|
||||
void rooms_log_frame();
|
||||
|
||||
private:
|
||||
// PER FRAME STUFF
|
||||
|
||||
// godot ID of the camera (which should be registered as a DOB to allow moving between rooms)
|
||||
ObjectID m_ID_camera;
|
||||
@ -74,10 +178,105 @@ class LRoomManager : public Spatial {
|
||||
LVector<int> * m_pCurr_VisibleRoomList;
|
||||
LVector<int> * m_pPrev_VisibleRoomList;
|
||||
|
||||
// active lights
|
||||
LVector<int> m_ActiveLights;
|
||||
LVector<int> m_ActiveLights_prev;
|
||||
Lawn::LBitField_Dynamic m_BF_ActiveLights;
|
||||
Lawn::LBitField_Dynamic m_BF_ActiveLights_prev;
|
||||
|
||||
// some lights may be processed on a frame but found not to intersect the view frustum
|
||||
Lawn::LBitField_Dynamic m_BF_ProcessedLights;
|
||||
|
||||
// keep all the light rendering stuff together
|
||||
struct LLightRender
|
||||
{
|
||||
// each time we render from a light point of view, we reuse this list to store each caster ID
|
||||
Lawn::LBitField_Dynamic m_BF_Temp_SOBs;
|
||||
Lawn::LBitField_Dynamic m_BF_Temp_Visible_Rooms;
|
||||
LVector<int> m_Temp_Visible_SOBs;
|
||||
LVector<int> m_Temp_Visible_Rooms;
|
||||
} m_LightRender;
|
||||
|
||||
|
||||
// keep a frame counter, to mark when objects have been hit by the visiblity algorithm
|
||||
// already to prevent multiple hits on rooms and objects
|
||||
unsigned int m_uiFrameCounter;
|
||||
|
||||
private:
|
||||
// lists of rooms and portals, contiguous list so cache friendly
|
||||
LVector<LRoom> m_Rooms;
|
||||
LVector<LPortal> m_Portals;
|
||||
LVector<LArea> m_Areas;
|
||||
|
||||
// static objects
|
||||
LVector<LSob> m_SOBs;
|
||||
|
||||
// lights
|
||||
LVector<LLight> m_Lights;
|
||||
|
||||
// SHADOWS
|
||||
// master list of shadow casters for each room
|
||||
LVector<uint32_t> m_ShadowCasters_SOB; // not used any more?
|
||||
|
||||
// master list of casters for each light (precalculated list)
|
||||
LVector<uint32_t> m_LightCasters_SOB;
|
||||
|
||||
// AREAS
|
||||
// master list of lights affecting each area
|
||||
LVector<uint32_t> m_AreaLights;
|
||||
|
||||
// master list of rooms in each area
|
||||
LVector<uint32_t> m_AreaRooms;
|
||||
|
||||
// The recursive visibility function needs to allocate loads of planes.
|
||||
// We use a pool for this instead of allocating on the fly.
|
||||
LPlanesPool m_Pool;
|
||||
|
||||
|
||||
public:
|
||||
// whether debug planes is switched on
|
||||
bool m_bDebugPlanes;
|
||||
bool m_bDebugBounds;
|
||||
bool m_bDebugLights;
|
||||
bool m_bDebugLightVolumes;
|
||||
bool m_bDebugFrustums;
|
||||
|
||||
// the planes are shown as a list of lines from the camera to the portal verts
|
||||
LVector<Vector3> m_DebugPlanes;
|
||||
LVector<Vector3> m_DebugPortalLightPlanes;
|
||||
LVector<Vector3> m_DebugLightVolumes;
|
||||
LVector<Vector3> m_DebugFrustums;
|
||||
|
||||
// we are now referencing the rooms indirectly via a nodepath rather than directly being children
|
||||
// of the LRoomManager node
|
||||
NodePath m_path_RoomList;
|
||||
ObjectID m_ID_RoomList;
|
||||
|
||||
|
||||
private:
|
||||
LTrace m_Trace;
|
||||
// unchecked
|
||||
Spatial * m_pRoomList;
|
||||
LMainCamera m_MainCamera;
|
||||
|
||||
// DEBUGGING
|
||||
// 0 to 5
|
||||
int m_iLoggingLevel;
|
||||
|
||||
ObjectID m_ID_DebugPlanes;
|
||||
ObjectID m_ID_DebugBounds;
|
||||
ObjectID m_ID_DebugLights;
|
||||
ObjectID m_ID_DebugLightVolumes;
|
||||
ObjectID m_ID_DebugFrustums;
|
||||
|
||||
Ref<SpatialMaterial> m_mat_Debug_Planes;
|
||||
Ref<SpatialMaterial> m_mat_Debug_Bounds;
|
||||
Ref<SpatialMaterial> m_mat_Debug_LightVolumes;
|
||||
Ref<SpatialMaterial> m_mat_Debug_Frustums;
|
||||
|
||||
String m_szDebugString;
|
||||
bool m_bDebugFrameString;
|
||||
|
||||
// for debugging, can turn LPortal on and off
|
||||
bool m_bActive;
|
||||
|
||||
@ -85,38 +284,7 @@ class LRoomManager : public Spatial {
|
||||
bool m_bFrustumOnly;
|
||||
|
||||
private:
|
||||
// lists of rooms and portals, contiguous list so cache friendly
|
||||
LVector<LRoom> m_Rooms;
|
||||
LVector<LPortal> m_Portals;
|
||||
|
||||
// static objects
|
||||
LVector<LSob> m_SOBs;
|
||||
|
||||
// lights
|
||||
LVector<LLight> m_Lights;
|
||||
// active lights
|
||||
LVector<int> m_ActiveLights;
|
||||
LVector<int> m_ActiveLights_prev;
|
||||
Lawn::LBitField_Dynamic m_BF_ActiveLights;
|
||||
Lawn::LBitField_Dynamic m_BF_ActiveLights_prev;
|
||||
|
||||
// master list of shadow casters for each room
|
||||
LVector<uint32_t> m_ShadowCasters_SOB;
|
||||
|
||||
// master list of casters for each light
|
||||
LVector<uint32_t> m_LightCasters_SOB;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
// The recursive visibility function needs to allocate loads of planes.
|
||||
// We use a pool for this instead of allocating on the fly.
|
||||
LPlanesPool m_Pool;
|
||||
|
||||
// 0 to 5
|
||||
int m_iLoggingLevel;
|
||||
private:
|
||||
// PRIVATE FUNCS
|
||||
// this is where we do all the culling
|
||||
bool FrameUpdate();
|
||||
void FrameUpdate_Prepare();
|
||||
@ -130,19 +298,30 @@ private:
|
||||
void FrameUpdate_FrustumOnly();
|
||||
|
||||
// draw planes and room hulls
|
||||
void FrameUpdate_DrawDebug(const LCamera &cam, const LRoom &lroom);
|
||||
|
||||
void FrameUpdate_DrawDebug(const LSource &cam, const LRoom &lroom);
|
||||
|
||||
// internal
|
||||
LRoom &Portal_GetLinkedRoom(const LPortal &port);
|
||||
// dobs
|
||||
bool DobRegister(Spatial * pDOB, float radius, int iRoom);
|
||||
ObjectID DobRegister_FindVIRecursive(Node * pNode) const;
|
||||
bool DobTeleport(Spatial * pDOB, int iNewRoomID);
|
||||
bool LightCreate(Light * pLight, int roomID);
|
||||
void CreateDebug();
|
||||
void DobChangeVisibility(Spatial * pDOB, const LRoom * pOld, const LRoom * pNew);
|
||||
|
||||
void CreateDebug();
|
||||
void ReleaseResources(bool bPrepareConvert);
|
||||
void ShowAll(bool bShow);
|
||||
void ResolveRoomListPath();
|
||||
|
||||
// frame debug string
|
||||
void DebugString_Set(String sz) {m_szDebugString = sz;}
|
||||
void DebugString_Add(String sz) {m_szDebugString += sz;}
|
||||
void DebugString_Light_AffectedRooms(int light_id);
|
||||
|
||||
// now we are centralizing the tracing out from static and dynamic lights for each frame to this function
|
||||
bool LightCreate(Light * pLight, int roomID, String szArea = "");
|
||||
void Light_UpdateTransform(LLight &light, const Light &glight) const;
|
||||
void Light_FrameProcess(int lightID);
|
||||
bool Light_FindCasters(int lightID);
|
||||
|
||||
|
||||
// helper funcs
|
||||
@ -152,37 +331,16 @@ private:
|
||||
LRoom * GetRoomFromDOB(Node * pNode);
|
||||
int FindClosestRoom(const Vector3 &pt) const;
|
||||
|
||||
LRoom &Portal_GetLinkedRoom(const LPortal &port);
|
||||
|
||||
// for DOBs, we need some way of storing the room ID on them, so we use metadata (currently)
|
||||
// this is pretty gross but hey ho
|
||||
int Obj_GetRoomNum(Node * pNode) const;
|
||||
void Obj_SetRoomNum(Node * pNode, int num);
|
||||
int Meta_GetRoomNum(Node * pNode) const;
|
||||
void Meta_SetRoomNum(Node * pNode, int num);
|
||||
|
||||
public:
|
||||
// whether debug planes is switched on
|
||||
bool m_bDebugPlanes;
|
||||
bool m_bDebugBounds;
|
||||
bool m_bDebugLights;
|
||||
|
||||
// the planes are shown as a list of lines from the camera to the portal verts
|
||||
LVector<Vector3> m_DebugPlanes;
|
||||
LVector<Vector3> m_DebugPortalLightPlanes;
|
||||
|
||||
// we are now referencing the rooms indirectly via a nodepath rather than directly being children
|
||||
// of the LRoomManager node
|
||||
NodePath m_path_RoomList;
|
||||
ObjectID m_ID_RoomList;
|
||||
|
||||
private:
|
||||
ObjectID m_ID_DebugPlanes;
|
||||
ObjectID m_ID_DebugBounds;
|
||||
ObjectID m_ID_DebugLights;
|
||||
Ref<SpatialMaterial> m_mat_Debug_Planes;
|
||||
Ref<SpatialMaterial> m_mat_Debug_Bounds;
|
||||
|
||||
// unchecked
|
||||
Spatial * m_pRoomList;
|
||||
|
||||
void ResolveRoomListPath();
|
||||
// for lights we store the light ID in the metadata
|
||||
void Meta_SetLightID(Node * pNode, int id);
|
||||
int Meta_GetLightID(Node * pNode) const;
|
||||
|
||||
public:
|
||||
// makes sure m_pRoomList is up to date and valid
|
||||
@ -191,86 +349,13 @@ public:
|
||||
Spatial * GetRoomList_Checked();
|
||||
// unchecked, be sure to call checked version first which will set m_pRoomList
|
||||
Spatial * GetRoomList() const {return m_pRoomList;}
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
LRoomManager();
|
||||
|
||||
// PUBLIC INTERFACE TO GDSCRIPT
|
||||
void set_rooms(const Object *p_rooms);
|
||||
void _set_rooms(Object *p_rooms);
|
||||
void set_rooms_path(const NodePath &p_path);
|
||||
NodePath get_rooms_path() const;
|
||||
void remove_rooms_path();
|
||||
|
||||
|
||||
// convert empties and meshes to rooms and portals
|
||||
bool rooms_convert(bool bVerbose, bool bDeleteLights);
|
||||
|
||||
// free memory for current set of rooms, prepare for converting a new game level
|
||||
void rooms_release();
|
||||
|
||||
// choose which camera you want to use to determine visibility.
|
||||
// normally this will be your main camera, but you can choose another for debugging
|
||||
bool rooms_set_camera(Node * pCam);
|
||||
|
||||
// get the Godot room that is associated with an LPortal room
|
||||
// (can be used to find the name etc of a room ID returned by dob_update)
|
||||
Node * rooms_get_room(int room_id);
|
||||
|
||||
// helpers to enable the client to manage switching on and off physics and AI
|
||||
int rooms_get_num_rooms() const;
|
||||
bool rooms_is_room_visible(int room_id) const;
|
||||
Array rooms_get_visible_rooms() const;
|
||||
|
||||
|
||||
// helper function to merge SOB meshes for producing lightmaps VIA external blender workflow
|
||||
bool rooms_merge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_unmerge_sobs(Node * pMergeMeshInstance);
|
||||
bool rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshInstance_To);
|
||||
|
||||
// one function to do all the uv mapping and lightmap creation in one
|
||||
// (for godot lightmap workflow)
|
||||
MeshInstance * rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename);
|
||||
|
||||
// helper function for general use .. LPortal has the functionality, why not...
|
||||
bool rooms_save_scene(Node * pNode, String szFilename);
|
||||
|
||||
// turn on and off culling for debugging
|
||||
void rooms_set_active(bool bActive);
|
||||
void rooms_set_debug_planes(bool bActive);
|
||||
void rooms_set_debug_bounds(bool bActive);
|
||||
void rooms_set_debug_lights(bool bActive);
|
||||
|
||||
// 0 to 6 .. defaults to 4 which is (2) in our priorities (i.e. 6 - level)
|
||||
void rooms_set_logging(int level);
|
||||
|
||||
// provide debugging output on the next frame
|
||||
void rooms_log_frame();
|
||||
|
||||
// Dynamic objects .. cameras, players, boxes etc
|
||||
// These are defined by their ability to move from room to room.
|
||||
// You can still move static objects within the same room (e.g. elevators, moving platforms)
|
||||
// as these don't require checks for changing rooms.
|
||||
bool dob_register(Node * pDOB, float radius);
|
||||
// register but let LPortal know which room the dob should start in
|
||||
bool dob_register_hint(Node * pDOB, float radius, Node * pRoom);
|
||||
|
||||
bool dob_unregister(Node * pDOB);
|
||||
|
||||
// returns the room ID within
|
||||
int dob_update(Node * pDOB);
|
||||
|
||||
// if we are moving the DOB possibly through multiple rooms, then teleport rather than detect
|
||||
// portal crossings
|
||||
bool dob_teleport(Node * pDOB);
|
||||
bool dob_teleport_hint(Node * pDOB, Node * pRoom);
|
||||
|
||||
|
||||
// helper func, not needed usually as dob_update returns the room
|
||||
int dob_get_room_id(Node * pDOB);
|
||||
|
||||
// LIGHTS
|
||||
// global lights that will apply to all rooms
|
||||
bool light_register(Node * pLightNode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
606
ltrace.cpp
Normal file
606
ltrace.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "ltrace.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldob.h"
|
||||
#include "lportal.h"
|
||||
#include "lbitfield_dynamic.h"
|
||||
#include "lroom_manager.h"
|
||||
|
||||
#define LMAN m_pManager
|
||||
|
||||
|
||||
|
||||
//void LTrace::Trace_Prepare(LRoomManager &manager, const LCamera &cam, Lawn::LBitField_Dynamic &BF_SOBs, Lawn::LBitField_Dynamic &BF_DOBs, Lawn::LBitField_Dynamic &BF_Rooms, LVector<int> &visible_SOBs, LVector<int> &visible_DOBs, LVector<int> &visible_Rooms)
|
||||
void LTrace::Trace_Prepare(LRoomManager &manager, const LSource &cam, Lawn::LBitField_Dynamic &BF_SOBs, Lawn::LBitField_Dynamic &BF_Rooms, LVector<int> &visible_SOBs, LVector<int> &visible_Rooms)
|
||||
{
|
||||
m_pManager = &manager;
|
||||
m_pCamera = &cam;
|
||||
|
||||
// default
|
||||
m_TraceFlags = CULL_SOBS | CULL_DOBS | TOUCH_ROOMS | MAKE_ROOM_VISIBLE;
|
||||
|
||||
m_pBF_SOBs = &BF_SOBs;
|
||||
// m_pBF_DOBs = &BF_DOBs;
|
||||
m_pBF_Rooms = &BF_Rooms;
|
||||
m_pVisible_SOBs = &visible_SOBs;
|
||||
// m_pVisible_DOBs = &visible_DOBs;
|
||||
m_pVisible_Rooms = &visible_Rooms;
|
||||
}
|
||||
|
||||
void LTrace::CullSOBs(LRoom &room, const LVector<Plane> &planes)
|
||||
{
|
||||
// clip all objects in this room to the clipping planes
|
||||
int last_sob = room.m_iFirstSOB + room.m_iNumSOBs;
|
||||
for (int n=room.m_iFirstSOB; n<last_sob; n++)
|
||||
{
|
||||
LSob &sob = LMAN->m_SOBs[n];
|
||||
|
||||
//LPRINT_RUN(2, "sob " + itos(n) + " " + sob.GetSpatial()->get_name());
|
||||
|
||||
// already determined to be visible through another portal
|
||||
if (m_pBF_SOBs->GetBit(n))
|
||||
{
|
||||
//LPRINT_RUN(2, "\talready visible");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool bShow = true;
|
||||
|
||||
|
||||
// estimate the radius .. for now
|
||||
const AABB &bb = sob.m_aabb;
|
||||
|
||||
// print("\t\t\tculling object " + pObj->get_name());
|
||||
|
||||
for (int p=0; p<planes.size(); p++)
|
||||
{
|
||||
// float dist = planes[p].distance_to(pt);
|
||||
// print("\t\t\t\t" + itos(p) + " : dist " + String(Variant(dist)));
|
||||
|
||||
float r_min, r_max;
|
||||
bb.project_range_in_plane(planes[p], r_min, r_max);
|
||||
|
||||
// print("\t\t\t\t" + itos(p) + " : r_min " + String(Variant(r_min)) + ", r_max " + String(Variant(r_max)));
|
||||
|
||||
|
||||
if (r_min > 0.0f)
|
||||
{
|
||||
//LPRINT_RUN(2, "\tout of view");
|
||||
bShow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bShow)
|
||||
{
|
||||
// sob is renderable and visible (not shadow only)
|
||||
//LPRINT_RUN(2, "\tin view");
|
||||
m_pBF_SOBs->SetBit(n, true);
|
||||
m_pVisible_SOBs->push_back(n);
|
||||
}
|
||||
|
||||
} // for through sobs
|
||||
|
||||
}
|
||||
|
||||
void LTrace::CullDOBs(LRoom &room, const LVector<Plane> &planes)
|
||||
{
|
||||
// NYI this isn't efficient, there may be more than 1 portal to the same room
|
||||
|
||||
// cull DOBs
|
||||
int nDOBs = room.m_DOBs.size();
|
||||
|
||||
for (int n=0; n<nDOBs; n++)
|
||||
{
|
||||
LDob &dob = room.m_DOBs[n];
|
||||
|
||||
Spatial * pObj = dob.GetSpatial();
|
||||
|
||||
if (pObj)
|
||||
{
|
||||
bool bShow = true;
|
||||
const Vector3 &pt = pObj->get_global_transform().origin;
|
||||
|
||||
float radius = dob.m_fRadius;
|
||||
|
||||
for (int p=0; p<planes.size(); p++)
|
||||
{
|
||||
float dist = planes[p].distance_to(pt);
|
||||
//print("\t\t\t\t" + itos(p) + " : dist " + String(Variant(dist)));
|
||||
|
||||
if (dist > radius)
|
||||
{
|
||||
bShow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bShow)
|
||||
{
|
||||
LPRINT_RUN(1, "\tDOB " + pObj->get_name() + " visible");
|
||||
dob.m_bVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LPRINT_RUN(1, "\tDOB " + pObj->get_name() + " culled");
|
||||
}
|
||||
}
|
||||
} // for through dobs
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool LTrace::Trace_Light(LRoomManager &manager, const LLight &light, eLightRun eRun)
|
||||
{
|
||||
m_pManager = &manager;
|
||||
|
||||
|
||||
LRoom * pRoom;
|
||||
|
||||
// non area light
|
||||
if (light.m_iArea == -1)
|
||||
{
|
||||
// can only deal with lights in rooms for now
|
||||
if (light.m_Source.m_RoomID == -1)
|
||||
{
|
||||
WARN_PRINT_ONCE("LTrace::Trace_Light can only trace lights in rooms");
|
||||
return true;
|
||||
}
|
||||
|
||||
pRoom = manager.GetRoom(light.m_Source.m_RoomID);
|
||||
if (!pRoom)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// area light
|
||||
pRoom = 0;
|
||||
}
|
||||
|
||||
const LSource &cam = light.m_Source;
|
||||
|
||||
unsigned int pool_member = manager.m_Pool.Request();
|
||||
assert (pool_member != -1);
|
||||
|
||||
LVector<Plane> &planes = manager.m_Pool.Get(pool_member);
|
||||
planes.clear();
|
||||
|
||||
// we now need to trace either just DOBs (in the case of static lights)
|
||||
// or SOBs and DOBs (in the case of dynamic lights)
|
||||
LRoomManager::LLightRender &lr = manager.m_LightRender;
|
||||
lr.m_BF_Temp_SOBs.Blank();
|
||||
lr.m_Temp_Visible_SOBs.clear();
|
||||
lr.m_BF_Temp_Visible_Rooms.Blank();
|
||||
lr.m_Temp_Visible_Rooms.clear();
|
||||
|
||||
bool bLightInView = true;
|
||||
|
||||
switch (eRun)
|
||||
{
|
||||
// finding all shadow casters at runtime
|
||||
case LR_ALL:
|
||||
{
|
||||
//Trace_Prepare(manager, cam, lr.m_BF_Temp_SOBs, manager.m_BF_visible_rooms, lr.m_Temp_Visible_SOBs, *manager.m_pCurr_VisibleRoomList);
|
||||
Trace_Prepare(manager, cam, lr.m_BF_Temp_SOBs, lr.m_BF_Temp_Visible_Rooms, lr.m_Temp_Visible_SOBs, lr.m_Temp_Visible_Rooms);
|
||||
|
||||
Trace_SetFlags(CULL_SOBS | CULL_DOBS | MAKE_ROOM_VISIBLE);
|
||||
|
||||
// create subset planes of light frustum and camera frustum
|
||||
bLightInView = manager.m_MainCamera.AddCameraLightPlanes(manager, cam, planes);
|
||||
}
|
||||
break;
|
||||
// finding only visible rooms at runtime
|
||||
case LR_ROOMS:
|
||||
{
|
||||
Trace_Prepare(manager, cam, lr.m_BF_Temp_SOBs, lr.m_BF_Temp_Visible_Rooms, lr.m_Temp_Visible_SOBs, lr.m_Temp_Visible_Rooms);
|
||||
|
||||
// we ONLY want a list of rooms hit
|
||||
Trace_SetFlags(MAKE_ROOM_VISIBLE);
|
||||
}
|
||||
break;
|
||||
// finding all in preconversion
|
||||
case LR_CONVERT:
|
||||
{
|
||||
Trace_Prepare(manager, cam, lr.m_BF_Temp_SOBs, lr.m_BF_Temp_Visible_Rooms, lr.m_Temp_Visible_SOBs, lr.m_Temp_Visible_Rooms);
|
||||
|
||||
// we want sobs but not to touch rooms
|
||||
m_TraceFlags = CULL_SOBS | MAKE_ROOM_VISIBLE; // | CULL_DOBS | TOUCH_ROOMS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (bLightInView)
|
||||
{
|
||||
// non area light
|
||||
if (pRoom)
|
||||
{
|
||||
Trace_Begin(*pRoom, planes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// area light
|
||||
|
||||
// area lights don't go through portals, e.g. coming from above like sunlight
|
||||
// they instead have a predefined list of rooms governed by the area
|
||||
m_TraceFlags |= DONT_TRACE_PORTALS;
|
||||
|
||||
// new .. trace according to area, not affected rooms, as affected rooms has a limit
|
||||
assert (light.m_iArea != -1);
|
||||
const LArea &area = LMAN->m_Areas[light.m_iArea];
|
||||
|
||||
int last_room = area.m_iFirstRoom + area.m_iNumRooms;
|
||||
|
||||
for (int r=area.m_iFirstRoom; r<last_room; r++)
|
||||
{
|
||||
int room_id = LMAN->m_AreaRooms[r];
|
||||
LRoom * pRoom = manager.GetRoom(room_id);
|
||||
|
||||
// should not happen, assert?
|
||||
assert (pRoom);
|
||||
|
||||
// trace as usual but don't go through the portals
|
||||
Trace_Recursive(0, *pRoom, planes, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
// go through each affected room
|
||||
for (int r=0; r<light.m_NumAffectedRooms; r++)
|
||||
{
|
||||
int room_id = light.m_AffectedRooms[r];
|
||||
LRoom * pRoom = manager.GetRoom(room_id);
|
||||
|
||||
// should not happen, assert?
|
||||
assert (pRoom);
|
||||
|
||||
// trace as usual but don't go through the portals
|
||||
Trace_Recursive(0, *pRoom, planes, 0);
|
||||
}
|
||||
*/
|
||||
} // if area light
|
||||
} // if light in view
|
||||
|
||||
// we no longer need these planes
|
||||
manager.m_Pool.Free(pool_member);
|
||||
|
||||
return bLightInView;
|
||||
}
|
||||
|
||||
|
||||
void LTrace::AddSpotlightPlanes(LVector<Plane> &planes) const
|
||||
{
|
||||
Plane p(m_pCamera->m_ptPos, -m_pCamera->m_ptDir);
|
||||
planes.push_back(p);
|
||||
|
||||
// this is kinda crappy, because ideally we'd want a cone, but instead we'll fake a frustum
|
||||
Vector3 pts[4];
|
||||
|
||||
// assuming here that d is normalized!
|
||||
const Vector3 &d = m_pCamera->m_ptDir;
|
||||
const Vector3 &ptCam = m_pCamera->m_ptPos;
|
||||
|
||||
assert (d.length_squared() < 1.1f);
|
||||
assert (d.length_squared() > 0.9f);
|
||||
|
||||
// spotlight has no 'up' vector, as it is regular shape around direction axis
|
||||
// so we can use anything for side vector
|
||||
|
||||
// this might balls up with a light pointing straight up
|
||||
Vector3 ptSide = Vector3(0, 1, 0).cross(d);
|
||||
|
||||
float l = ptSide.length();
|
||||
if (l < 0.1f)
|
||||
{
|
||||
// special case straight up, lets cross against something else
|
||||
ptSide = d.cross(Vector3(1, 0, 0));
|
||||
l = ptSide.length();
|
||||
assert (l);
|
||||
}
|
||||
|
||||
// unitize side
|
||||
ptSide *= 1.0 / l;
|
||||
|
||||
Vector3 ptUp = ptSide.cross(d);
|
||||
ptUp.normalize();
|
||||
|
||||
// now we've got the vecs, lets create some planes
|
||||
|
||||
// spotlight spread definition (light.cpp, line 146)
|
||||
//float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
|
||||
|
||||
// this is the size at distance 1 .. it would be more efficient to calc distance at which sides were 1, but whatever...
|
||||
float size = Math::tan(Math::deg2rad(m_pCamera->m_fSpread));
|
||||
|
||||
ptSide *= size; // or half size? not sure yet
|
||||
ptUp *= -size;
|
||||
|
||||
// pts will be bot left, top left, top right, bot right
|
||||
Vector3 ptEx = ptCam + d;
|
||||
|
||||
pts[0] = ptEx - ptSide - ptUp;
|
||||
pts[1] = ptEx - ptSide + ptUp;
|
||||
pts[2] = ptEx + ptSide + ptUp;
|
||||
pts[3] = ptEx + ptSide - ptUp;
|
||||
|
||||
Plane left(ptCam, pts[0], pts[1], COUNTERCLOCKWISE);
|
||||
Plane top(ptCam, pts[1], pts[2], COUNTERCLOCKWISE);
|
||||
Plane right(ptCam, pts[2], pts[3], COUNTERCLOCKWISE);
|
||||
Plane bottom(ptCam, pts[3], pts[0], COUNTERCLOCKWISE);
|
||||
|
||||
planes.push_back(left);
|
||||
planes.push_back(top);
|
||||
planes.push_back(right);
|
||||
planes.push_back(bottom);
|
||||
|
||||
// debug
|
||||
if (LMAN->m_bDebugFrustums)
|
||||
{
|
||||
for (int n=0; n<4; n++)
|
||||
{
|
||||
LMAN->m_DebugFrustums.push_back(ptCam);
|
||||
LMAN->m_DebugFrustums.push_back(pts[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LTrace::Trace_Begin(LRoom &room, LVector<Plane> &planes)
|
||||
{
|
||||
int first_plane = 0;
|
||||
|
||||
switch (m_pCamera->m_eType)
|
||||
{
|
||||
case LSource::ST_SPOTLIGHT:
|
||||
{
|
||||
// special cases of spotlight, add some extra planes to define the cone
|
||||
AddSpotlightPlanes(planes);
|
||||
}
|
||||
break;
|
||||
case LSource::ST_CAMERA:
|
||||
first_plane = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
LPRINT_RUN(2, "TRACE BEGIN");
|
||||
LPRINT_RUN(2, m_pCamera->MakeDebugString());
|
||||
|
||||
|
||||
Trace_Recursive(0, room, planes, first_plane);
|
||||
}
|
||||
|
||||
void LTrace::Trace_Recursive(int depth, LRoom &room, const LVector<Plane> &planes, int first_portal_plane)
|
||||
{
|
||||
// prevent too much depth
|
||||
if (depth > 8)
|
||||
{
|
||||
LPRINT_RUN(2, "\t\t\tDEPTH LIMIT REACHED");
|
||||
WARN_PRINT_ONCE("LPortal Depth Limit reached (seeing through > 8 portals)");
|
||||
return;
|
||||
}
|
||||
|
||||
// for debugging
|
||||
Lawn::LDebug::m_iTabDepth = depth;
|
||||
LPRINT_RUN(2, "");
|
||||
|
||||
LPRINT_RUN(2, "ROOM '" + itos(room.m_RoomID) + " : " + room.get_name() + "' planes " + itos(planes.size()) + " portals " + itos(room.m_iNumPortals) );
|
||||
|
||||
// only handle one touch per frame so far (one portal into room)
|
||||
//assert (manager.m_uiFrameCounter > m_uiFrameTouched);
|
||||
|
||||
// first touch
|
||||
DetectFirstTouch(room);
|
||||
|
||||
if (m_TraceFlags & CULL_SOBS)
|
||||
CullSOBs(room, planes);
|
||||
|
||||
if (m_TraceFlags & CULL_DOBS)
|
||||
CullDOBs(room, planes);
|
||||
|
||||
// portals
|
||||
if (m_TraceFlags & DONT_TRACE_PORTALS)
|
||||
return;
|
||||
|
||||
// look through portals
|
||||
int nPortals = room.m_iNumPortals;
|
||||
|
||||
for (int port_num=0; port_num<nPortals; port_num++)
|
||||
{
|
||||
int port_id = room.m_iFirstPortal + port_num;
|
||||
|
||||
const LPortal &port = LMAN->m_Portals[port_id];
|
||||
|
||||
// have we already handled the room on this frame?
|
||||
// get the room pointed to by the portal
|
||||
LRoom * pLinkedRoom = &LMAN->Portal_GetLinkedRoom(port);
|
||||
|
||||
|
||||
|
||||
// cull by portal angle to camera.
|
||||
|
||||
// NEW! I've come up with a much better way of culling portals by direction to camera...
|
||||
// instead of using dot product with a varying view direction, we simply find which side of the portal
|
||||
// plane the camera is on! If it is behind, the portal can be seen through, if in front, it can't! :)
|
||||
float dist_cam = port.m_Plane.distance_to(m_pCamera->m_ptPos);
|
||||
LPRINT_RUN(2, "\tPORTAL " + itos (port_num) + " (" + itos(port_id) + ") " + port.get_name());
|
||||
if (dist_cam > 0.0f)
|
||||
{
|
||||
LPRINT_RUN(2, "\t\tCULLED (back facing)");
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
// Note we need to deal with 'side on' portals, and the camera has a spreading view, so we cannot simply dot
|
||||
// the portal normal with camera direction, we need to take into account angle to the portal itself.
|
||||
const Vector3 &portal_normal = port.m_Plane.normal;
|
||||
LPRINT_RUN(2, "\tPORTAL " + itos (port_num) + " (" + itos(port_id) + ") " + port.get_name() + " normal " + portal_normal);
|
||||
|
||||
// we will dot the portal angle with a ray from the camera to the portal centre
|
||||
// (there might be an even better ray direction but this will do for now)
|
||||
Vector3 dir_portal = port.m_ptCentre - m_pCamera->m_ptPos;
|
||||
|
||||
// doesn't actually need to be normalized?
|
||||
float dot = dir_portal.dot(portal_normal);
|
||||
|
||||
if (dot <= -0.0f) // 0.0
|
||||
{
|
||||
//LPRINT_RUN(2, "\t\tCULLED (wrong direction) dot is " + String(Variant(dot)) + ", dir_portal is " + dir_portal);
|
||||
LPRINT_RUN(2, "\t\tCULLED (wrong direction)");
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
// is it culled by the planes?
|
||||
LPortal::eClipResult overall_res = LPortal::eClipResult::CLIP_INSIDE;
|
||||
|
||||
// while clipping to the planes we maintain a list of partial planes, so we can add them to the
|
||||
// recursive next iteration of planes to check
|
||||
static LVector<int> partial_planes;
|
||||
partial_planes.clear();
|
||||
|
||||
// for portals, we want to ignore the near clipping plane, as we might be right on the edge of a doorway
|
||||
// and still want to look through the portal.
|
||||
// So we are starting this loop from 1, ASSUMING that plane zero is the near clipping plane.
|
||||
// If it isn't we would need a different strategy
|
||||
// Note that now this only occurs for the first portal out of the current room. After that,
|
||||
// 0 is passed as first_portal_plane, because the near plane will probably be irrelevant,
|
||||
// and we are now not necessarily copying the camera planes.
|
||||
for (int l=first_portal_plane; l<planes.size(); l++)
|
||||
{
|
||||
LPortal::eClipResult res = port.ClipWithPlane(planes[l]);
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case LPortal::eClipResult::CLIP_OUTSIDE:
|
||||
overall_res = res;
|
||||
break;
|
||||
case LPortal::eClipResult::CLIP_PARTIAL:
|
||||
overall_res = res;
|
||||
partial_planes.push_back(l);
|
||||
break;
|
||||
default: // suppress warning
|
||||
break;
|
||||
}
|
||||
|
||||
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
||||
break;
|
||||
}
|
||||
|
||||
// this portal is culled
|
||||
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
||||
{
|
||||
LPRINT_RUN(2, "\t\tCULLED (outside planes)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// else recurse into that portal
|
||||
unsigned int uiPoolMem = LMAN->m_Pool.Request();
|
||||
if (uiPoolMem != -1)
|
||||
{
|
||||
// get a vector of planes from the pool
|
||||
LVector<Plane> &new_planes = LMAN->m_Pool.Get(uiPoolMem);
|
||||
new_planes.clear();
|
||||
|
||||
// NEW!! if portal is totally inside the planes, don't copy the old planes
|
||||
if (overall_res != LPortal::eClipResult::CLIP_INSIDE)
|
||||
{
|
||||
// copy the existing planes
|
||||
//new_planes.copy_from(planes);
|
||||
|
||||
// new .. only copy the partial planes that the portal cuts through
|
||||
for (int n=0; n<partial_planes.size(); n++)
|
||||
new_planes.push_back(planes[partial_planes[n]]);
|
||||
}
|
||||
|
||||
// add the planes for the portal
|
||||
// NOTE that we can also optimize by not adding portal planes for edges that
|
||||
// were behind a partial plane. NYI
|
||||
port.AddPlanes(*LMAN, m_pCamera->m_ptPos, new_planes);
|
||||
|
||||
|
||||
if (pLinkedRoom)
|
||||
{
|
||||
Trace_Recursive(depth+1, *pLinkedRoom, new_planes, 0);
|
||||
//pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, 0);
|
||||
// for debugging need to reset tab depth
|
||||
Lawn::LDebug::m_iTabDepth = depth;
|
||||
}
|
||||
|
||||
// we no longer need these planes
|
||||
LMAN->m_Pool.Free(uiPoolMem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// planes pool is empty!
|
||||
// This will happen if the view goes through shedloads of portals
|
||||
// The solution is either to increase the plane pool size, or build levels
|
||||
// with views through multiple portals. Looking through multiple portals is likely to be
|
||||
// slow anyway because of the number of planes to test.
|
||||
WARN_PRINT_ONCE("Planes pool is empty");
|
||||
}
|
||||
|
||||
} // for p through portals
|
||||
|
||||
}
|
||||
|
||||
void LTrace::DetectFirstTouch(LRoom &room)
|
||||
{
|
||||
// mark if not reached yet on this trace
|
||||
if (!m_pBF_Rooms->GetBit(room.m_RoomID))
|
||||
{
|
||||
m_pBF_Rooms->SetBit(room.m_RoomID, true);
|
||||
|
||||
if (m_TraceFlags & MAKE_ROOM_VISIBLE)
|
||||
{
|
||||
// keep track of which rooms are shown this trace
|
||||
m_pVisible_Rooms->push_back(room.m_RoomID);
|
||||
}
|
||||
|
||||
// camera and light traces
|
||||
if (m_TraceFlags & TOUCH_ROOMS)
|
||||
{
|
||||
if (room.m_uiFrameTouched < LMAN->m_uiFrameCounter)
|
||||
FirstTouch(room);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LTrace::FirstTouch(LRoom &room)
|
||||
{
|
||||
// set the frame counter
|
||||
room.m_uiFrameTouched = LMAN->m_uiFrameCounter;
|
||||
|
||||
// show this room and add to visible list of rooms
|
||||
room.Room_MakeVisible(true);
|
||||
|
||||
// m_pBF_Rooms->SetBit(room.m_RoomID, true);
|
||||
|
||||
// keep track of which rooms are shown this frame
|
||||
// m_pVisible_Rooms->push_back(room.m_RoomID);
|
||||
|
||||
// hide all dobs
|
||||
for (int n=0; n<room.m_DOBs.size(); n++)
|
||||
room.m_DOBs[n].m_bVisible = false;
|
||||
}
|
81
ltrace.h
Normal file
81
ltrace.h
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
// Copyright (c) 2019 Lawnjelly
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "lvector.h"
|
||||
|
||||
class LSource;
|
||||
class LRoomManager;
|
||||
class LRoom;
|
||||
class LLight;
|
||||
namespace Lawn {class LBitField_Dynamic;}
|
||||
|
||||
class LTrace
|
||||
{
|
||||
public:
|
||||
enum eTraceFlags
|
||||
{
|
||||
CULL_SOBS = 1 << 0,
|
||||
CULL_DOBS = 1 << 1,
|
||||
TOUCH_ROOMS = 1 << 2,
|
||||
MAKE_ROOM_VISIBLE = 1 << 3,
|
||||
DONT_TRACE_PORTALS = 1 << 4,
|
||||
};
|
||||
|
||||
enum eLightRun
|
||||
{
|
||||
LR_ALL, // runtime find all shadow casters
|
||||
LR_ROOMS, // find affected rooms
|
||||
LR_CONVERT, // initial conversion
|
||||
};
|
||||
|
||||
void Trace_Prepare(LRoomManager &manager, const LSource &cam, Lawn::LBitField_Dynamic &BF_SOBs, Lawn::LBitField_Dynamic &BF_Rooms, LVector<int> &visible_SOBs, LVector<int> &visible_Rooms);
|
||||
// void Trace_Prepare(LRoomManager &manager, const LCamera &cam, Lawn::LBitField_Dynamic &BF_SOBs, Lawn::LBitField_Dynamic &BF_DOBs, Lawn::LBitField_Dynamic &BF_Rooms, LVector<int> &visible_SOBs, LVector<int> &visible_DOBs, LVector<int> &visible_Rooms);
|
||||
|
||||
void Trace_SetFlags(unsigned int flags) {m_TraceFlags = flags;}
|
||||
void Trace_Begin(LRoom &room, LVector<Plane> &planes);
|
||||
|
||||
// simpler method of doing a trace for lights, no need to call prepare and begin
|
||||
bool Trace_Light(LRoomManager &manager, const LLight &light, eLightRun eRun);
|
||||
|
||||
private:
|
||||
void AddSpotlightPlanes(LVector<Plane> &planes) const;
|
||||
void Trace_Recursive(int depth, LRoom &room, const LVector<Plane> &planes, int first_portal_plane);
|
||||
|
||||
void CullSOBs(LRoom &room, const LVector<Plane> &planes);
|
||||
void CullDOBs(LRoom &room, const LVector<Plane> &planes);
|
||||
void FirstTouch(LRoom &room);
|
||||
void DetectFirstTouch(LRoom &room);
|
||||
|
||||
|
||||
LRoomManager * m_pManager;
|
||||
const LSource * m_pCamera;
|
||||
|
||||
Lawn::LBitField_Dynamic * m_pBF_SOBs;
|
||||
//Lawn::LBitField_Dynamic * m_pBF_DOBs;
|
||||
Lawn::LBitField_Dynamic * m_pBF_Rooms;
|
||||
|
||||
LVector<int> * m_pVisible_SOBs;
|
||||
//LVector<int> * m_pVisible_DOBs;
|
||||
LVector<int> * m_pVisible_Rooms;
|
||||
|
||||
unsigned int m_TraceFlags;
|
||||
};
|
Loading…
Reference in New Issue
Block a user