// 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" #include "ldebug.h" #include "lroom_manager.h" ///////////////////////////////////////////////////////////////////// bool LPortal::NameStartsWith(const 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()); // because godot doesn't support multiple nodes with the same name, we will strip e.g. a number // after an @ on the end of the name... // e.g. portal_kitchen@2 for (int c=0; c &planes, bool bReverse) const { const Vector &pts = m_ptsWorld; int nPoints = pts.size(); ERR_FAIL_COND(nPoints < 3); if (light.m_Source.m_eType == LSource::ST_DIRECTIONAL) { // assuming ortho light const int max_points = 32; Vector3 pushed_pts[max_points]; if (nPoints > max_points) nPoints = max_points; // transform pushed points Vector3 ptPush = light.m_Source.m_ptDir * 2.0; for (int n=0; n &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) { LPRINT_RUN(2, "\t\tOutside plane " + p); return CLIP_OUTSIDE; } if (nOutside == 0) return CLIP_INSIDE; return CLIP_PARTIAL; } void LPortal::CreateGeometry(PoolVector p_vertices, const Transform &trans, bool bPortalPlane_Convention) { int nPoints = p_vertices.size(); ERR_FAIL_COND(nPoints < 3); m_ptsWorld.clear(); //print("\t\t\tLPortal::CreateGeometry nPoints : " + itos(nPoints)); //Vector3 ptFirstThree[3]; for (int n=0; n &verts = m_ptsWorld; // We first assumed first 3 determine the desired normal // find normal Plane plane; if (bPortalPlane_Convention) plane = Plane(verts[0], verts[2], verts[1]); else 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) { Vector3 b = verts[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_ptsWorld; Vector copy = verts; for (int n=0; n