2019-09-11 09:09:36 +02:00
|
|
|
// 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 "lroom.h"
|
|
|
|
#include "core/engine.h"
|
|
|
|
#include "scene/3d/mesh_instance.h"
|
|
|
|
#include "lportal.h"
|
2019-09-13 20:15:25 +02:00
|
|
|
#include "lbitfield_dynamic.h"
|
2019-09-12 20:53:24 +02:00
|
|
|
#include "lroom_manager.h"
|
2019-09-18 12:04:02 +02:00
|
|
|
#include "ldebug.h"
|
2019-09-11 09:09:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
LRoom::LRoom() {
|
2019-09-15 16:39:01 +02:00
|
|
|
m_RoomID = -1;
|
2019-09-13 20:15:25 +02:00
|
|
|
m_uiFrameTouched = 0;
|
2019-09-15 16:39:01 +02:00
|
|
|
m_iFirstPortal = 0;
|
|
|
|
m_iNumPortals = 0;
|
2019-09-24 16:37:38 +02:00
|
|
|
m_bVisible = true;
|
2019-09-24 19:33:55 +02:00
|
|
|
|
|
|
|
m_iFirstSOB = 0;
|
|
|
|
m_iNumSOBs = 0;
|
2019-09-26 09:53:15 +02:00
|
|
|
|
|
|
|
m_iFirstShadowCaster_SOB = 0;
|
|
|
|
m_iNumShadowCasters_SOB = 0;
|
2019-09-15 16:39:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Spatial * LRoom::GetGodotRoom() const
|
|
|
|
{
|
|
|
|
Object *pObj = ObjectDB::get_instance(m_GodotID);
|
|
|
|
|
|
|
|
// assuming is a portal
|
|
|
|
Spatial * pSpat = Object::cast_to<Spatial>(pObj);
|
|
|
|
|
|
|
|
return pSpat;
|
2019-09-11 09:09:36 +02:00
|
|
|
}
|
|
|
|
|
2019-09-13 20:15:25 +02:00
|
|
|
|
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
void LRoom::DOB_Add(const LDob &dob)
|
2019-09-13 20:15:25 +02:00
|
|
|
{
|
2019-09-16 15:23:10 +02:00
|
|
|
// LDob dob;
|
|
|
|
// dob.m_ID = pDOB->get_instance_id();
|
2019-09-13 20:15:25 +02:00
|
|
|
|
|
|
|
m_DOBs.push_back(dob);
|
|
|
|
}
|
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
unsigned int LRoom::DOB_Find(Node * pDOB) const
|
2019-09-13 20:15:25 +02:00
|
|
|
{
|
|
|
|
ObjectID id = pDOB->get_instance_id();
|
|
|
|
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
{
|
2019-09-24 16:37:38 +02:00
|
|
|
if (m_DOBs[n].m_ID_Spatial == id)
|
2019-09-13 20:15:25 +02:00
|
|
|
{
|
2019-09-16 15:23:10 +02:00
|
|
|
return n;
|
2019-09-13 20:15:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LRoom::DOB_Remove(unsigned int ui)
|
|
|
|
{
|
|
|
|
if (ui < m_DOBs.size())
|
|
|
|
{
|
|
|
|
m_DOBs.remove_unsorted(ui);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-13 20:15:25 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-15 16:39:01 +02:00
|
|
|
// returns -1 if no change, or the linked room we are moving into
|
2019-09-15 20:26:18 +02:00
|
|
|
LRoom * LRoom::DOB_Update(LRoomManager &manager, Spatial * pDOB)
|
2019-09-13 20:15:25 +02:00
|
|
|
{
|
|
|
|
const Vector3 &pt = pDOB->get_global_transform().origin;
|
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
// is it the camera?
|
2019-09-23 12:14:41 +02:00
|
|
|
bool bCamera = pDOB->get_instance_id() == manager.m_ID_camera;
|
2019-09-15 20:26:18 +02:00
|
|
|
float slop = 0.2f;
|
|
|
|
if (bCamera)
|
|
|
|
slop = 0.0f;
|
2019-09-13 20:15:25 +02:00
|
|
|
|
|
|
|
// the camera can't have slop because we might end up front side of a door without entering the room,
|
|
|
|
// hence can't see into the room through the portal!
|
|
|
|
// if (bCamera)
|
|
|
|
// slop = 0.0f;
|
|
|
|
|
|
|
|
// check each portal - has the object crossed it into the neighbouring room?
|
2019-09-15 16:39:01 +02:00
|
|
|
for (int p=0; p<m_iNumPortals; p++)
|
2019-09-13 20:15:25 +02:00
|
|
|
{
|
2019-09-15 16:39:01 +02:00
|
|
|
const LPortal &port = manager.m_Portals[m_iFirstPortal + p];
|
2019-09-13 20:15:25 +02:00
|
|
|
|
2019-09-15 16:39:01 +02:00
|
|
|
float dist = port.m_Plane.distance_to(pt);
|
2019-09-13 20:15:25 +02:00
|
|
|
|
|
|
|
if (dist > slop)
|
|
|
|
{
|
2019-09-18 12:04:02 +02:00
|
|
|
LPRINT(0, "DOB at pos " + pt + " ahead of portal " + port.get_name() + " by " + String(Variant(dist)));
|
2019-09-15 16:39:01 +02:00
|
|
|
|
|
|
|
// we want to move into the adjoining room
|
|
|
|
return &manager.Portal_GetLinkedRoom(port);
|
2019-09-13 20:15:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
|
|
|
|
// instead of directly showing and hiding objects we now set their layer,
|
|
|
|
// 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.
|
|
|
|
// All objects in view (that are set to cast shadows) should cast shadows, so the actual
|
|
|
|
// shown objects are a superset of the softshown.
|
2019-10-01 16:27:32 +02:00
|
|
|
void LRoom::SoftShow(VisualInstance * pVI, uint32_t show_flags)
|
2019-09-24 16:37:38 +02:00
|
|
|
{
|
2019-10-01 16:27:32 +02:00
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
// hijack this layer number
|
|
|
|
uint32_t mask = pVI->get_layer_mask();
|
|
|
|
uint32_t orig_mask = mask;
|
|
|
|
|
|
|
|
|
2019-10-01 16:27:32 +02:00
|
|
|
// debug, to check shadow casters are correct for different light types
|
|
|
|
//#define DEBUG_SHOW_CASTERS_ONLY
|
|
|
|
#ifdef DEBUG_SHOW_CASTERS_ONLY
|
|
|
|
bShow = true;
|
2019-09-24 16:37:38 +02:00
|
|
|
if (bShow)
|
|
|
|
{
|
2019-10-01 16:27:32 +02:00
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
}
|
2019-10-01 16:27:32 +02:00
|
|
|
#else
|
|
|
|
if (show_flags & LAYER_MASK_CAMERA)
|
|
|
|
mask |= LAYER_MASK_CAMERA; // set
|
2019-09-24 16:37:38 +02:00
|
|
|
else
|
2019-10-01 16:27:32 +02:00
|
|
|
mask &= ~LAYER_MASK_CAMERA; // clear
|
|
|
|
|
|
|
|
if (show_flags & LAYER_MASK_LIGHT)
|
|
|
|
mask |= LAYER_MASK_LIGHT;
|
|
|
|
else
|
|
|
|
mask &= ~LAYER_MASK_LIGHT;
|
|
|
|
|
|
|
|
// if (bShow)
|
|
|
|
// {
|
|
|
|
// // set
|
|
|
|
// mask |= SOFT_SHOW_MASK;
|
|
|
|
// // clear
|
|
|
|
// mask &= ~(1 | SOFT_HIDE_MASK);
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// {
|
|
|
|
// // set
|
|
|
|
// mask |= SOFT_HIDE_MASK;
|
|
|
|
// // clear
|
|
|
|
// mask &= ~(1 | SOFT_SHOW_MASK);
|
|
|
|
// }
|
|
|
|
#endif
|
2019-09-24 16:37:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
// noop? don't touch the visual server if no change to mask
|
|
|
|
if (mask == orig_mask)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pVI->set_layer_mask(mask);
|
|
|
|
|
2019-10-01 16:27:32 +02:00
|
|
|
// test the visual server - NOT A BOTTLENECK. set_layer_mask is cheap
|
2019-09-24 16:37:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-25 17:35:14 +02:00
|
|
|
// naive version, adds all the non visible objects in visible rooms as shadow casters
|
|
|
|
void LRoom::AddShadowCasters(LRoomManager &manager)
|
|
|
|
{
|
2019-09-26 19:33:40 +02:00
|
|
|
LPRINT(2, "ADDSHADOWCASTERS room " + get_name() + ", " + itos(m_iNumShadowCasters_SOB) + " shadow casters");
|
2019-09-26 09:53:15 +02:00
|
|
|
|
2019-10-01 16:27:32 +02:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-26 19:33:40 +02:00
|
|
|
// new!! use precalced list of shadow casters
|
|
|
|
int last = m_iFirstShadowCaster_SOB + m_iNumShadowCasters_SOB;
|
|
|
|
for (int n=m_iFirstShadowCaster_SOB; n<last; n++)
|
|
|
|
{
|
|
|
|
int sobID = manager.m_ShadowCasters_SOB[n];
|
|
|
|
|
|
|
|
// only add to the caster list if not in it already
|
|
|
|
if (!manager.m_BF_caster_SOBs.GetBit(sobID))
|
|
|
|
{
|
|
|
|
LPRINT(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
|
|
|
|
{
|
2019-10-01 16:27:32 +02:00
|
|
|
//LPRINT(2, "\t" + itos(sobID) + ", ALREADY CASTER " + manager.m_SOBs[sobID].GetSpatial()->get_name());
|
2019-09-26 19:33:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-09-25 17:35:14 +02:00
|
|
|
int last_sob = m_iFirstSOB + m_iNumSOBs;
|
|
|
|
for (int n=m_iFirstSOB; n<last_sob; n++)
|
|
|
|
{
|
2019-09-26 09:53:15 +02:00
|
|
|
// bool bVisible = manager.m_BF_visible_SOBs.GetBit(n) != 0;
|
2019-09-25 17:35:14 +02:00
|
|
|
|
2019-09-26 09:53:15 +02:00
|
|
|
// // already in list
|
|
|
|
// if (bVisible)
|
|
|
|
// continue;
|
2019-09-25 17:35:14 +02:00
|
|
|
|
2019-09-26 09:53:15 +02:00
|
|
|
manager.m_BF_caster_SOBs.SetBit(n, true);
|
|
|
|
manager.m_CasterList_SOBs.push_back(n);
|
2019-09-25 17:35:14 +02:00
|
|
|
}
|
2019-09-26 19:33:40 +02:00
|
|
|
*/
|
2019-09-25 17:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
// hide all the objects not hit on this frame .. instead of calling godot hide without need
|
|
|
|
// (it might be expensive)
|
|
|
|
void LRoom::FinalizeVisibility(LRoomManager &manager)
|
|
|
|
{
|
2019-10-01 16:27:32 +02:00
|
|
|
// make sure all lights needed are turned on
|
|
|
|
|
2019-09-26 19:33:40 +02:00
|
|
|
// int last_sob = m_iFirstSOB + m_iNumSOBs;
|
|
|
|
// for (int n=m_iFirstSOB; n<last_sob; n++)
|
|
|
|
// {
|
|
|
|
// LSob &sob = manager.m_SOBs[n];
|
|
|
|
// Spatial * pS = sob.GetSpatial();
|
|
|
|
// if (!pS)
|
|
|
|
// continue;
|
2019-09-16 15:23:10 +02:00
|
|
|
|
2019-09-26 19:33:40 +02:00
|
|
|
// if (manager.m_BF_master_SOBs.GetBit(n))
|
|
|
|
// pS->show();
|
|
|
|
// else
|
|
|
|
// pS->hide();
|
|
|
|
// }
|
2019-09-25 17:45:09 +02:00
|
|
|
|
2019-09-26 09:53:15 +02:00
|
|
|
|
|
|
|
//print_line("FinalizeVisibility room " + get_name() + " NumSOBs " + itos(m_SOBs.size()) + ", NumDOBs " + itos(m_DOBs.size()));
|
2019-09-16 15:23:10 +02:00
|
|
|
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
{
|
|
|
|
const LDob &dob = m_DOBs[n];
|
|
|
|
|
|
|
|
// don't cull the main camera
|
2019-09-24 16:37:38 +02:00
|
|
|
if (dob.m_ID_Spatial == manager.m_ID_camera)
|
2019-09-16 15:23:10 +02:00
|
|
|
continue;
|
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
// Spatial * pSpat = dob.GetSpatial();
|
|
|
|
// if (pSpat)
|
|
|
|
// {
|
|
|
|
// // all should be showing .. this is mostly a no op
|
|
|
|
// pSpat->show();
|
|
|
|
// }
|
|
|
|
|
|
|
|
VisualInstance * pVI = dob.GetVI();
|
|
|
|
if (pVI)
|
2019-09-16 15:23:10 +02:00
|
|
|
{
|
2019-09-24 16:37:38 +02:00
|
|
|
SoftShow(pVI, dob.m_bVisible);
|
|
|
|
// if (dob.m_bVisible)
|
|
|
|
// {
|
|
|
|
// //print("LRoom::FinalizeVisibility making visible dob " + pS->get_name());
|
|
|
|
// pS->show();
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// pS->hide();
|
2019-09-16 15:23:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
// allows us to show / hide all dobs as the room visibility changes
|
|
|
|
void LRoom::Room_MakeVisible(bool bVisible)
|
2019-09-16 15:23:10 +02:00
|
|
|
{
|
2019-09-24 16:37:38 +02:00
|
|
|
// noop
|
|
|
|
if (bVisible == m_bVisible)
|
|
|
|
return;
|
2019-09-16 15:23:10 +02:00
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
m_bVisible = bVisible;
|
|
|
|
|
|
|
|
if (m_bVisible)
|
|
|
|
{
|
|
|
|
// show room
|
2019-09-26 19:33:40 +02:00
|
|
|
// GetGodotRoom()->show();
|
2019-09-24 16:37:38 +02:00
|
|
|
|
|
|
|
// show all dobs
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
{
|
|
|
|
LDob &dob = m_DOBs[n];
|
|
|
|
Spatial * pS = dob.GetSpatial();
|
|
|
|
if (pS)
|
|
|
|
pS->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-09-16 15:23:10 +02:00
|
|
|
{
|
2019-09-24 16:37:38 +02:00
|
|
|
// hide room
|
2019-09-26 19:33:40 +02:00
|
|
|
// GetGodotRoom()->hide();
|
2019-09-24 16:37:38 +02:00
|
|
|
|
|
|
|
// hide all dobs
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
{
|
|
|
|
LDob &dob = m_DOBs[n];
|
|
|
|
Spatial * p = dob.GetSpatial();
|
|
|
|
if (p)
|
|
|
|
p->hide();
|
|
|
|
}
|
2019-09-16 15:23:10 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-13 20:15:25 +02:00
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
|
|
|
|
// hide godot room and all linked dobs
|
|
|
|
//void LRoom::Hide_All()
|
|
|
|
//{
|
|
|
|
// GetGodotRoom()->hide();
|
|
|
|
|
|
|
|
// for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
// {
|
|
|
|
// LDob &dob = m_DOBs[n];
|
|
|
|
// Spatial * p = dob.GetSpatial();
|
|
|
|
// if (p)
|
|
|
|
// p->hide();
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
2019-09-18 12:04:02 +02:00
|
|
|
// show godot room and all linked dobs and all sobs
|
2019-09-24 16:37:38 +02:00
|
|
|
void LRoom::Debug_ShowAll()
|
2019-09-18 12:04:02 +02:00
|
|
|
{
|
2019-09-24 16:37:38 +02:00
|
|
|
Room_MakeVisible(true);
|
2019-09-18 12:04:02 +02:00
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
// NYI .. change layers to all be visible
|
|
|
|
// for (int n=0; n<m_SOBs.size(); n++)
|
|
|
|
// {
|
|
|
|
// LSob &sob = m_SOBs[n];
|
|
|
|
// Spatial * pS = sob.GetSpatial();
|
|
|
|
// if (pS)
|
|
|
|
// pS->show();
|
|
|
|
// }
|
2019-09-18 12:04:02 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
void LRoom::FirstTouch(LRoomManager &manager)
|
|
|
|
{
|
|
|
|
// set the frame counter
|
|
|
|
m_uiFrameTouched = manager.m_uiFrameCounter;
|
|
|
|
|
2019-09-24 16:37:38 +02:00
|
|
|
// show this room and add to visible list of rooms
|
|
|
|
Room_MakeVisible(true);
|
|
|
|
|
|
|
|
manager.m_BF_visible_rooms.SetBit(m_RoomID, true);
|
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
// keep track of which rooms are shown this frame
|
|
|
|
manager.m_pCurr_VisibleRoomList->push_back(m_RoomID);
|
|
|
|
|
|
|
|
// hide all objects
|
2019-09-24 20:05:33 +02:00
|
|
|
// int last_sob = m_iFirstSOB + m_iNumSOBs;
|
|
|
|
// for (int n=m_iFirstSOB; n<last_sob; n++)
|
|
|
|
// {
|
|
|
|
// LSob &sob = manager.m_SOBs[n];
|
|
|
|
// sob.m_bSOBVisible = false;
|
|
|
|
// }
|
2019-09-15 20:26:18 +02:00
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
// hide all dobs
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
m_DOBs[n].m_bVisible = false;
|
2019-09-15 20:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-15 16:39:01 +02:00
|
|
|
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, int portalID_from)
|
2019-09-11 09:09:36 +02:00
|
|
|
{
|
2019-09-12 12:07:43 +02:00
|
|
|
// prevent too much depth
|
2019-09-18 12:04:02 +02:00
|
|
|
if (depth > 8)
|
2019-09-12 12:07:43 +02:00
|
|
|
{
|
2019-09-18 12:04:02 +02:00
|
|
|
LPRINT_RUN(2, "\t\t\tDEPTH LIMIT REACHED");
|
|
|
|
WARN_PRINT_ONCE("LPortal Depth Limit reached (seeing through > 8 portals)");
|
2019-09-12 12:07:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:04:02 +02:00
|
|
|
// for debugging
|
|
|
|
Lawn::LDebug::m_iTabDepth = depth;
|
|
|
|
LPRINT_RUN(2, "");
|
|
|
|
LPRINT_RUN(2, "ROOM '" + get_name() + "' planes " + itos(planes.size()) + " portals " + itos(m_iNumPortals) );
|
2019-09-12 16:51:33 +02:00
|
|
|
|
2019-09-15 17:16:09 +02:00
|
|
|
// only handle one touch per frame so far (one portal into room)
|
2019-09-16 15:23:10 +02:00
|
|
|
//assert (manager.m_uiFrameCounter > m_uiFrameTouched);
|
2019-09-15 17:16:09 +02:00
|
|
|
|
|
|
|
// first touch
|
|
|
|
if (m_uiFrameTouched < manager.m_uiFrameCounter)
|
2019-09-15 20:26:18 +02:00
|
|
|
FirstTouch(manager);
|
2019-09-13 20:15:25 +02:00
|
|
|
|
2019-09-12 12:07:43 +02:00
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
|
|
|
|
// clip all objects in this room to the clipping planes
|
2019-09-24 19:33:55 +02:00
|
|
|
int last_sob = m_iFirstSOB + m_iNumSOBs;
|
|
|
|
for (int n=m_iFirstSOB; n<last_sob; n++)
|
2019-09-16 15:23:10 +02:00
|
|
|
{
|
2019-09-24 19:33:55 +02:00
|
|
|
LSob &sob = manager.m_SOBs[n];
|
2019-09-16 15:23:10 +02:00
|
|
|
|
2019-09-24 19:56:46 +02:00
|
|
|
//LPRINT_RUN(2, "sob " + itos(n) + " " + sob.GetSpatial()->get_name());
|
|
|
|
// already determined to be visible through another portal
|
|
|
|
if (manager.m_BF_visible_SOBs.GetBit(n))
|
|
|
|
{
|
|
|
|
//LPRINT_RUN(2, "\talready visible");
|
2019-09-16 15:23:10 +02:00
|
|
|
continue;
|
2019-09-24 19:56:46 +02:00
|
|
|
}
|
2019-09-16 15:23:10 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
bShow = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bShow)
|
2019-09-24 19:56:46 +02:00
|
|
|
{
|
|
|
|
// sob is renderable and visible (not shadow only)
|
|
|
|
manager.m_BF_visible_SOBs.SetBit(n, true);
|
2019-09-26 09:53:15 +02:00
|
|
|
//manager.m_BF_render_SOBs.SetBit(n, true);
|
|
|
|
manager.m_VisibleList_SOBs.push_back(n);
|
2019-09-24 19:56:46 +02:00
|
|
|
}
|
2019-09-16 15:23:10 +02:00
|
|
|
|
2019-09-18 12:04:02 +02:00
|
|
|
} // for through sobs
|
2019-09-16 15:23:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
// cull DOBs
|
|
|
|
for (int n=0; n<m_DOBs.size(); n++)
|
|
|
|
{
|
|
|
|
LDob &dob = 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)
|
2019-09-18 12:04:02 +02:00
|
|
|
{
|
|
|
|
LPRINT_RUN(1, "\tDOB " + pObj->get_name() + " visible");
|
2019-09-16 15:23:10 +02:00
|
|
|
dob.m_bVisible = true;
|
2019-09-18 12:04:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LPRINT_RUN(1, "\tDOB " + pObj->get_name() + " culled");
|
|
|
|
}
|
2019-09-16 15:23:10 +02:00
|
|
|
}
|
2019-09-18 12:04:02 +02:00
|
|
|
} // for through dobs
|
2019-09-12 16:51:33 +02:00
|
|
|
|
|
|
|
|
2019-09-16 15:23:10 +02:00
|
|
|
|
|
|
|
// look through portals
|
2019-09-18 12:04:02 +02:00
|
|
|
for (int port_num=0; port_num<m_iNumPortals; port_num++)
|
2019-09-11 09:09:36 +02:00
|
|
|
{
|
2019-09-18 12:04:02 +02:00
|
|
|
int port_id = m_iFirstPortal + port_num;
|
2019-09-11 09:09:36 +02:00
|
|
|
|
2019-09-15 16:39:01 +02:00
|
|
|
const LPortal &port = manager.m_Portals[port_id];
|
2019-09-11 09:09:36 +02:00
|
|
|
|
2019-09-13 20:15:25 +02:00
|
|
|
// have we already handled the room on this frame?
|
|
|
|
// get the room pointed to by the portal
|
2019-09-15 16:39:01 +02:00
|
|
|
LRoom * pLinkedRoom = &manager.Portal_GetLinkedRoom(port);
|
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
// cull by portal angle to camera.
|
|
|
|
// 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;
|
2019-09-18 12:04:02 +02:00
|
|
|
LPRINT_RUN(2, "\tPORTAL " + itos (port_num) + " (" + itos(port_id) + ") " + port.get_name() + " normal " + portal_normal);
|
2019-09-15 20:26:18 +02:00
|
|
|
|
|
|
|
// 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 - cam.m_ptPos;
|
|
|
|
|
|
|
|
// doesn't actually need to be normalized?
|
|
|
|
float dot = dir_portal.dot(portal_normal);
|
2019-09-11 09:09:36 +02:00
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
if (dot <= -0.0f) // 0.0
|
|
|
|
{
|
2019-09-18 12:04:02 +02:00
|
|
|
//LPRINT_RUN(2, "\t\tCULLED (wrong direction) dot is " + String(Variant(dot)) + ", dir_portal is " + dir_portal);
|
|
|
|
LPRINT_RUN(2, "\t\tCULLED (wrong direction)");
|
2019-09-15 20:26:18 +02:00
|
|
|
continue;
|
|
|
|
}
|
2019-09-11 09:09:36 +02:00
|
|
|
|
|
|
|
// is it culled by the planes?
|
|
|
|
LPortal::eClipResult overall_res = LPortal::eClipResult::CLIP_INSIDE;
|
|
|
|
|
2019-09-13 20:15:25 +02:00
|
|
|
// 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
|
2019-09-18 12:04:02 +02:00
|
|
|
|
2019-09-13 20:15:25 +02:00
|
|
|
for (int l=1; l<planes.size(); l++)
|
2019-09-11 09:09:36 +02:00
|
|
|
{
|
2019-09-15 16:39:01 +02:00
|
|
|
LPortal::eClipResult res = port.ClipWithPlane(planes[l]);
|
2019-09-11 09:09:36 +02:00
|
|
|
|
|
|
|
switch (res)
|
|
|
|
{
|
|
|
|
case LPortal::eClipResult::CLIP_OUTSIDE:
|
|
|
|
overall_res = res;
|
|
|
|
break;
|
|
|
|
case LPortal::eClipResult::CLIP_PARTIAL:
|
|
|
|
overall_res = res;
|
|
|
|
break;
|
2019-09-17 15:30:31 +02:00
|
|
|
default: // suppress warning
|
|
|
|
break;
|
2019-09-11 09:09:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this portal is culled
|
|
|
|
if (overall_res == LPortal::eClipResult::CLIP_OUTSIDE)
|
2019-09-12 12:07:43 +02:00
|
|
|
{
|
2019-09-18 12:04:02 +02:00
|
|
|
LPRINT_RUN(2, "\t\tCULLED (outside planes)");
|
2019-09-11 09:09:36 +02:00
|
|
|
continue;
|
2019-09-12 12:07:43 +02:00
|
|
|
}
|
2019-09-11 09:09:36 +02:00
|
|
|
|
|
|
|
// else recurse into that portal
|
2019-09-12 20:53:24 +02:00
|
|
|
unsigned int uiPoolMem = manager.m_Pool.Request();
|
|
|
|
if (uiPoolMem != -1)
|
|
|
|
{
|
|
|
|
// get a vector of planes from the pool
|
|
|
|
LVector<Plane> &new_planes = manager.m_Pool.Get(uiPoolMem);
|
|
|
|
|
|
|
|
// copy the existing planes
|
|
|
|
new_planes.copy_from(planes);
|
|
|
|
|
|
|
|
// add the planes for the portal
|
2019-09-23 12:14:41 +02:00
|
|
|
port.AddPlanes(manager, cam.m_ptPos, new_planes);
|
2019-09-11 09:09:36 +02:00
|
|
|
|
2019-09-15 20:26:18 +02:00
|
|
|
|
2019-09-12 20:53:24 +02:00
|
|
|
if (pLinkedRoom)
|
2019-09-18 12:04:02 +02:00
|
|
|
{
|
2019-09-15 16:39:01 +02:00
|
|
|
pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, port_id);
|
2019-09-18 12:04:02 +02:00
|
|
|
// for debugging need to reset tab depth
|
|
|
|
Lawn::LDebug::m_iTabDepth = depth;
|
|
|
|
}
|
2019-09-11 09:09:36 +02:00
|
|
|
|
2019-09-15 16:39:01 +02:00
|
|
|
// we no longer need these planes
|
2019-09-12 20:53:24 +02:00
|
|
|
manager.m_Pool.Free(uiPoolMem);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// planes pool is empty!
|
2019-09-15 16:39:01 +02:00
|
|
|
// 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.
|
2019-09-12 20:53:24 +02:00
|
|
|
WARN_PRINT_ONCE("Planes pool is empty");
|
|
|
|
}
|
2019-09-18 12:04:02 +02:00
|
|
|
|
|
|
|
} // for p through portals
|
2019-09-11 09:09:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|