// 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 "lportal.h" #include "core/engine.h" #include "lroom.h" bool LPortal::m_bRunning = false; void LPortal::print(String sz) { if (m_bRunning) { } else { print_line(sz); } } bool LPortal::NameStartsWith(Node * pNode, String szSearch) { int sl = szSearch.length(); String name = pNode->get_name(); int l = name.length(); if (l < sl) return false; String szStart = name.substr(0, sl); //print_line("\t\tNameStartsWith szStart is " + szStart); if (szStart == szSearch) return true; return false; } String LPortal::FindNameAfter(Node * pNode, String szStart) { String szRes; String name = pNode->get_name(); szRes = name.substr(szStart.length()); print("\t\tNameAfter is " + szRes); return szRes; } ////////////////////////////////////////////////////////// // add clipping planes to the vector formed by each portal edge and the camera void LPortal::AddPlanes(const Vector3 &ptCam, LVector &planes) const { // short version const Vector &pts = m_ptsWorld; int nPoints = pts.size(); ERR_FAIL_COND(nPoints < 3); Plane p; for (int n=1; n= 0.0f) nOutside++; } if (nOutside == nPoints) { print("LPortal::ClipWithPlane : Outside plane " + p); return CLIP_OUTSIDE; } if (nOutside == 0) return CLIP_INSIDE; return CLIP_PARTIAL; } // use the name of the portal to find a room to link to void LPortal::Link(LRoom * pParentRoom) { // should start with 'portal_' if (!NameStartsWith(this, "lportal_")) { WARN_PRINT("Portal name should begin with lportal_"); return; } String szRoom = FindNameAfter(this, "lportal_"); print("LPortal::Link to room " + szRoom); // find the room group Spatial * pGroup = Object::cast_to(pParentRoom->get_parent()); if (!pGroup) { WARN_PRINT("Room parent is not a spatial"); return; } // attempt to find a child of the group that has the name specified int nChildren = pGroup->get_child_count(); for (int n=0; nget_child(n); String szChildName = pChild->get_name(); // is the name correct for the desired room? if (szRoom != szChildName) continue; LRoom * pTargetRoom = Object::cast_to(pChild); if (!pTargetRoom) { WARN_PRINT("Portal target is not a room"); return; } // found! link pTargetRoom->MakeOppositePortal(this, pParentRoom); return; } } void LPortal::CreateGeometry(PoolVector p_vertices) { int nPoints = p_vertices.size(); ERR_FAIL_COND(nPoints < 3); m_ptsLocal.resize(nPoints); m_ptsWorld.resize(nPoints); print("\tLPortal::CreateGeometry nPoints : " + itos(nPoints)); for (int n=0; n &verts = m_ptsLocal; // find normal Plane plane = Plane(verts[0], verts[1], verts[2]); Vector3 ptNormal = plane.normal; // find centroid int nPoints = verts.size(); Vector3 ptCentre = Vector3(0, 0, 0); for (int n=0; n 0.0f) // if (p.WhichSideNDLCompatible(m_Verts[m], 0.0f) != CoPlane::NEGATIVE_SIDE) { Vector3 b = m_ptsLocal[m] - ptCentre; b.normalize(); double Angle = a.dot(b); if (Angle > SmallestAngle) { SmallestAngle = Angle; Smallest = m; } } // which side } // for m // swap smallest and n+1 vert if (Smallest != -1) { Vector3 temp = verts[Smallest]; verts.set(Smallest, verts[n+1]); verts.set(n+1, temp); } } // for n // the vertices are now sorted, but may be in the opposite order to that wanted. // we detect this by calculating the normal of the poly, then flipping the order if the normal is pointing // the wrong way. plane = Plane(verts[0], verts[1], verts[2]); if (ptNormal.dot(plane.normal) < 0.0f) { // reverse order of verts ReverseWindingOrder(); } } void LPortal::ReverseWindingOrder() { Vector &verts = m_ptsLocal; Vector copy = verts; for (int n=0; n(get_node(path)); if (pNode) { ObjectID id = pNode->get_instance_id(); m_room_path = path; m_room_ID = id; // make the portal name correct and feature the room name int num_names = path.get_name_count(); if (num_names < 1) { WARN_PRINT("LPortal::AddRoom : Path too short"); return false; } String szRoom = path.get_name(num_names-1); String szPortal = "lportal_" + szRoom; set_name(szPortal); return true; } else { WARN_PRINT("not a room"); return false; } } else { WARN_PRINTS("portal link room not found : " + path); } return false; } LPortal::LPortal() { // unset m_room_ID = 0; } LRoom * LPortal::GetLinkedRoom() const { Object *pObj = ObjectDB::get_instance(m_room_ID); if (!pObj) return 0; LRoom * pRoom = Object::cast_to(pObj); if (!pRoom) { WARN_PRINT_ONCE("LRoomManager::FrameUpdate : curr room is not an LRoom"); } return pRoom; } void LPortal::_bind_methods() { }