-- file: scene.ms -- file with helpers for scene objects -- author; GunnarD filein "pipeline/ui/GuidComparison_ui.ms" fn RsMouseclickBoundsIntersect viewPoint:mouse.screenpos = ( local theObjs = objects as array -- local viewPoint = mouse.screenpos -- if undefined!=worldRay then -- viewPoint = local foundObjs = #() for o in theObjs do in coordsys screen ( if o.isHiddenInVpt then o.isHidden = true local colour = random (color 0 0 0) (color 255 255 255) local thecoodsys = (inverse (getViewTM())) local bb = nodeGetBoundingBox o thecoodsys local viewSpacePoint = mapScreenToView viewPoint (bb[1].z+((bb[2].z-bb[1].z)/2)) -- in coordsys thecoodsys point pos:bb[1] color:colour -- in coordsys thecoodsys point pos:bb[2] color:colour -- print o -- print bb[1] -- print bb[2] -- print viewSpacePoint -- print "++++" if viewSpacePoint.x < bb[2].x and viewSpacePoint.y < bb[2].y and viewSpacePoint.x > bb[1].x and viewSpacePoint.y > bb[1].y then ( local depthindex = foundObjs.count while depthindex>1 and foundObjs[depthindex].pos.z < o.pos.z do ( depthindex = depthindex-1 ) if depthindex<=0 then depthindex =1 insertItem o foundObjs depthindex ) ) -- print foundObjs return foundObjs ) fn RsMousePosGridIntersect = ( -- http://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm: -- Ray: P = P0 + tV -- Plane: P . N + d = 0 -- subst for P: -- (P0 + tV) . N + d = 0 -- t = -(P0 . N + d) / (V . N) -- P(intersection) = P0 + tV local mouseRay = mapScreenToWorldRay mouse.pos local N = [0,0,1] local d = 0 local P0 = mouseRay.pos local V = mouseRay.dir local t = -(dot P0 N) / (dot V N) local gridPoint = P0 + (V * t) return gridPoint ) -- nicked from http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection -- -- bool SpherePrimitive::intersect(const Ray& ray, float* t) -- { -- //Compute A, B and C coefficients -- float a = dot(ray.d, ray.d); -- float b = 2 * dot(ray.d, ray.o); -- float c = dot(ray.o, ray.o) - (r * r); -- //Find discriminant -- float disc = b * b - 4 * a * c; -- -- // if discriminant is negative there are no real roots, so return -- // false as ray misses sphere -- if (disc < 0) -- return false; -- // compute q as described above -- float distSqrt = sqrtf(disc); -- float q; -- if (b < 0) -- q = (-b - distSqrt)/2.0; -- else -- q = (-b + distSqrt)/2.0; -- // compute t0 and t1 -- float t0 = q / a; -- float t1 = c / q; -- // make sure t0 is smaller than t1 -- if (t0 > t1) -- { -- // if t0 is bigger than t1 swap them around -- float temp = t0; -- t0 = t1; -- t1 = temp; -- } -- // if t1 is less than zero, the object is in the ray's negative direction -- // and consequently the ray misses the sphere -- if (t1 < 0) -- return false; -- // if t0 is less than zero, the intersection point is at t1 -- if (t0 < 0) -- { -- t = t1; -- return true; -- } -- // else the intersection point is at t0 -- else -- { -- t = t0; -- return true; -- } -- } fn RsSphereRayIntersect sphereRadius theRay clipToRadius:true = ( --Compute A, B and C coefficients local a = (dot theRay.dir theRay.dir); local b = 2 * (dot theRay.dir theRay.pos); local c = (dot theRay.pos theRay.pos) - (sphereRadius * sphereRadius); --Find discriminant local disc = b * b - 4 * a * c; -- if discriminant is negative there are no real roots, so return -- false as ray misses sphere if (disc < 0) then ( if clipToRadius then disc = 0 else return undefined ) -- compute q as described above local distSqrt = (sqrt disc) local q if (b < 0) then q = (-b - distSqrt)/2.0; else q = (-b + distSqrt)/2.0; -- compute t0 and t1 local t0 = q / a; local t1 = c / q; -- make sure t0 is smaller than t1 if (t0 > t1) then ( -- if t0 is bigger than t1 swap them around local temp = t0; t0 = t1; t1 = temp; ) -- if t1 is less than zero, the object is in the ray's negative direction -- and consequently the ray misses the sphere if (t1 < 0) then return undefined; -- if t0 is less than zero, the intersection point is at t1 if (t0 < 0) then ( return theRay.pos + (theRay.dir * t1) ) -- else the intersection point is at t0 else ( return theRay.pos + (theRay.dir * t0) ) ) -- CheckSceneForLightIDProbs -- -- Description: Used for lights to find unique attribute Guids fn RecCheckGuid root usedIds objectPairs = ( local objGuid = getattrguid root if usedIds.containsKey objGuid then ( if (getNodeByName root.name all:true).count>1 then gRsUlog.LogError ("Name "+root.name+" found on more than one object!") context:root.name else if (root.name!=(usedIds.item objGuid)) then ( append objectPairs (DataPair root.name (usedIds.item objGuid)) gRsUlog.LogError ("Object's "+root.name+" global ID is already used. Please \"Rs Utils -> Rs Organisational -> GUID Tools -> Reset Object GUID\". https://devstar.rockstargames.com/wiki/index.php/Map_Export_Errors#Duplicate_Attribute_GUID") context:root ) ) else usedIds.add objGuid root.name for c in root.children where "Gta Object"==(getattrclass c) and not isrsref c do ( RecCheckGuid c usedIds objectPairs ) ) fn CheckSceneForLightIDProbs feedback:false map: showComparisonDialog:false = ( local objs if (map != unsupplied) then ( if (map.name != undefined) do ( local contentNode = RsContentTree.GetContentNode map.filename if ( contentNode == undefined ) then ( gRsUlog.LogError ("No map node found for " + map.filename) return false ) if RsContentTree.GetMapType( contentNode ) != "props" then ( gRsUlog.LogMessage ("non prop map "+map.name+". No light check needed.") return true ) ) objs = map.objects ) else ( objs = objects ) local usedIds = dotnetobject "RSG.MaxUtils.MaxDictionary" local objpairs = #() pushPrompt "Checking object GUIDs..." for o in objs where "Gta Object"==(getattrclass o) and not isrsref o do ( RecCheckGuid o usedIds objpairs ) popPrompt() if not showComparisonDialog then ( return gRsUlog.Validate() ) else if objpairs.count>0 then ( CreateGuidCompareDialog objpairs return false ) if feedback then messagebox "No problems found in scene.\nThis is only a local scene check though and other problems might occur globally if guid is reused." return true ) fn RsGenericRec root func = ( func root for c in root.children do RsGenericRec c func ) fn RsCollectChildren root kids = ( appendIfUnique kids root for c in root.children do RsCollectChildren c kids ) fn HasVisTrack obj = (undefined != (getVisController obj)) fn RsHasVisTrackRec obj = ( if HasVisTrack obj then return true for c in obj.children do if RsHasVisTrackRec c then return true return false ) -------------------------------------------------------------- -- Find out if this node is supposed to be exported -------------------------------------------------------------- fn IsExportRootNode obj = ( local childLinks = RsSceneLink.GetNodeChildLinkTypes obj local parentLinks= RsSceneLink.GetNodeParentLinkTypes obj return (getattrclass obj == "Gta Object") and 0 == findItem childLinks LinkType_DRAWLOD and 0 == findItem childLinks LinkType_ShadowMesh ) fn GetExportRootNode obj = ( if undefined==obj then return undefined -- foudn one!! if IsExportRootNode obj and IsExportRootParent obj.parent then return obj -- checking max hierarchy local foundNode = GetExportRootNode obj.parent if undefined!=foundNode then return foundNode local linkChildren = #() -- checking custom link hierarchy RsSceneLink.GetChildren LinkType_DRAWLOD obj &linkChildren RsSceneLink.GetChildren LinkType_ShadowMesh obj &linkChildren for child in linkChildren do ( local foundNode = GetExportRootNode child if undefined!=foundNode then return foundNode ) --nae luck return undefined ) -- Find out whether this is an object that serves as a root to link drawables to. fn IsExportRootParent obj = ( (undefined == obj) or (rootnode == obj) or (undefined!=Containers.IsContainerNode obj) or (classof obj==GtaMloRoom) ) fn GetContainer obj = ( if IsExportRootParent obj then obj else if undefined!=obj.parent then (GetContainer obj.parent) else undefined ) fn RsLinkDepth obj = ( local lodDepthCheck = obj local depth = 0 local children = #() RsSceneLink.GetChildren LinkType_LOD lodDepthCheck &children lodDepthCheck = children[1] while (lodDepthCheck!=undefined) do ( local children = #() RsSceneLink.GetChildren LinkType_LOD lodDepthCheck &children lodDepthCheck = children[1] depth += 1 ) return depth ) fn GetRootNodes nodes = ( local roots = #() for n in nodes do ( local parent = n while undefined!=parent and not IsExportRootParent parent.parent do ( parent = parent.parent ) appendIfUnique roots parent ) roots ) fn CheckForCirclularDependeciesRec root parents:#() = ( for p in parents where 0!=(finditem (refs.dependents root) p) do ( local err = stringstream "" format "Circular dependency: % dependent on % while the latter being a child of the former." p root to:err gRsUlog.LogError err context:#(p,root) ) newParents = copy parents #noMap append newParents root for c in root.children do CheckForCirclularDependeciesRec c parents:newParents ) fn CheckForCirclularDependecies = ( for o in rootNode.children do CheckForCirclularDependeciesRec o ) fn GetClothChildren root clothChildren:#() = ( if RsCloth.IsCloth root then appendIfUnique clothChildren root for child in root.children do GetClothChildren child clothChildren:clothChildren ) -- Gets the first dependent of a specified class fn RsGetDependent obj class = ( (for Dependant in Refs.Dependents obj where (isValidNode Dependant and ClassOf Dependant == class) collect Dependant)[1] )