public void RenderObject(IGameViewport viewport, GameObject obj, bool showInvisible) { mTotalLastFrame++; var type = obj.type; var flags = obj.GetFlags(); // Dont render destroyed or disabled objects const ObjectFlag dontDrawFlags = ObjectFlag.OFF | ObjectFlag.DESTROYED | ObjectFlag.DONTDRAW; if ((flags & dontDrawFlags) != 0) { return; } // Hide invisible objects we're supposed to show them if ((flags & ObjectFlag.INVISIBLE) != 0 && !showInvisible) { return; } // Dont draw secret doors that haven't been found yet var secretDoorFlags = obj.GetSecretDoorFlags(); if (secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR)) { var found = secretDoorFlags.HasFlag(SecretDoorFlag.SECRET_DOOR_FOUND); if (!found && type != ObjectType.portal) { return; } } var animatedModel = obj.GetOrCreateAnimHandle(); var animParams = obj.GetAnimParams(); locXY worldLoc; GameObject parent = null; if (type.IsEquipment()) { parent = GameSystems.Item.GetParent(obj); } var alpha = GetAlpha(obj); if (parent != null) { var parentAlpha = GetAlpha(parent); alpha = (alpha + parentAlpha) / 2; worldLoc = parent.GetLocation(); } else { worldLoc = obj.GetLocation(); } if (alpha == 0) { return; } // Handle fog occlusion of the world position if (type != ObjectType.container && (type == ObjectType.projectile || type.IsCritter() || type.IsEquipment()) && (GameSystems.MapFogging.GetFogStatus(worldLoc, animParams.offsetX, animParams.offsetY) & 1) == 0) { return; } LocAndOffsets worldPosFull; worldPosFull.off_x = animParams.offsetX; worldPosFull.off_y = animParams.offsetY; worldPosFull.location = worldLoc; var radius = obj.GetRadius(); var renderHeight = obj.GetRenderHeight(true); if (!IsObjectOnScreen(viewport.Camera, worldPosFull, animParams.offsetZ, radius, renderHeight)) { return; } if (Globals.Config.drawObjCylinders) { Tig.ShapeRenderer3d.DrawCylinder( viewport, worldPosFull.ToInches3D(animParams.offsetZ), radius, renderHeight ); } var lightSearchRadius = 0.0f; if (!flags.HasFlag(ObjectFlag.DONTLIGHT)) { lightSearchRadius = radius; } LocAndOffsets locAndOffsets; locAndOffsets.location = worldLoc; locAndOffsets.off_x = animParams.offsetX; locAndOffsets.off_y = animParams.offsetY; var lights = FindLights(locAndOffsets, lightSearchRadius); if (type == ObjectType.weapon) { int glowType; if (flags.HasFlag(ObjectFlag.INVENTORY) && parent != null) { glowType = GameSystems.D20.GetWeaponGlowType(parent, obj); } else { glowType = GameSystems.D20.GetWeaponGlowType(null, obj); } if (glowType != 0 && glowType <= mGlowMaterials.Length) { var glowMaterial = mGlowMaterials[glowType - 1]; if (glowMaterial.IsValid) { RenderObjectHighlight(viewport, obj, glowMaterial); } } } if (GameSystems.ItemHighlight.ShowHighlights && (type.IsEquipment() && !(flags.HasFlag(ObjectFlag.INVENTORY) || flags.HasFlag(ObjectFlag.CLICK_THROUGH)) || GameSystems.Critter.IsLootableCorpse(obj) || type == ObjectType.portal)) { RenderObjectHighlight(viewport, obj, mHighlightMaterial); // Add a single light with full ambient color to make the object appear fully lit lights.Clear(); Light3d fullBrightLight = new Light3d(); fullBrightLight.ambient = LinearColor.White; fullBrightLight.color = new LinearColor(0, 0, 0); fullBrightLight.dir = Vector4.UnitZ; fullBrightLight.type = Light3dType.Directional; lights.Add(fullBrightLight); } mRenderedLastFrame++; MdfRenderOverrides overrides = new MdfRenderOverrides(); overrides.alpha = alpha / 255.0f; mAasRenderer.Render(viewport, animatedModel, animParams, lights, overrides); Light3d globalLight = new Light3d(); if (lights.Count > 0) { globalLight = lights[0]; } if (type.IsCritter()) { if (alpha > 16) { if (mShadowType == ShadowType.ShadowMap) { RenderShadowMapShadow(viewport, obj, animParams, animatedModel, globalLight, alpha); } else if (mShadowType == ShadowType.Geometry) { mAasRenderer.RenderGeometryShadow( viewport.Camera, animatedModel, animParams, globalLight, alpha / 255.0f); } else if (mShadowType == ShadowType.Blob) { RenderBlobShadow(viewport, obj, animatedModel, ref animParams, alpha); } } /* * This renders the equipment in a critter's hand separately, but * I am not certain *why* exactly. I thought this would have been * handled by addmeshes, but it might be that there's a distinct * difference between addmeshes that are skinned onto the mobile's * skeleton and equipment that is unskinned and just positioned * in the player's hands. */ var weaponPrim = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponPrimary); if (weaponPrim != null) { RenderObject(viewport, weaponPrim, showInvisible); } var weaponSec = GameSystems.Critter.GetWornItem(obj, EquipSlot.WeaponSecondary); if (weaponSec != null) { RenderObject(viewport, weaponSec, showInvisible); } var shield = GameSystems.Critter.GetWornItem(obj, EquipSlot.Shield); if (shield != null) { RenderObject(viewport, shield, showInvisible); } } else if (type.IsEquipment() && mShadowType == ShadowType.Geometry) { mAasRenderer.RenderGeometryShadow( viewport.Camera, animatedModel, animParams, globalLight, alpha / 255.0f); } RenderMirrorImages( viewport, obj, animParams, animatedModel, lights); if (mGrappleController.IsGiantFrog(obj)) { mGrappleController.AdvanceAndRender( viewport, obj, animParams, animatedModel, lights, alpha / 255.0f); } }
public List <Light3d> FindLights(LocAndOffsets atLocation, float radius) { List <Light3d> lights = new List <Light3d>(); if (GameSystems.Light.IsGlobalLightEnabled) { Light3d light = new Light3d(); var legacyLight = GameSystems.Light.GlobalLight; light.type = (Light3dType)legacyLight.type; light.color = legacyLight.Color; light.dir.X = legacyLight.dir.X; light.dir.Y = legacyLight.dir.Y; light.dir.Z = legacyLight.dir.Z; light.pos.X = legacyLight.pos.X; light.pos.Y = legacyLight.pos.Y; light.pos.Z = legacyLight.pos.Z; light.range = legacyLight.range; light.phi = legacyLight.phi; lights.Add(light); } if (radius == 0) { return(lights); } // Build a box that has twice the radius convert to tiles as it's width/height // For some reason, ToEE will add one more INCH_PER_TILE here, which translates to // roughly 28 tiles more search radius than is needed var boxDimensions = (int)(radius / locXY.INCH_PER_TILE + locXY.INCH_PER_TILE); var tileX1 = atLocation.location.locx - 1 - boxDimensions; var tileX2 = atLocation.location.locx + 1 + boxDimensions; var tileY1 = atLocation.location.locy - 1 - boxDimensions; var tileY2 = atLocation.location.locy + 1 + boxDimensions; using var sectorIterator = new SectorIterator(tileX1, tileX2, tileY1, tileY2); var atPos = atLocation.ToInches2D(); while (sectorIterator.HasNext) { using var sector = sectorIterator.Next(); foreach (ref var light in sector.Lights) { int type; LinearColor color; Vector3 direction; float range, phi; var lightPos = light.position.ToInches2D(); if ((light.flags & 0x40) != 0) { if (GameSystems.Light.IsNight) { type = light.light2.type; color = light.light2.color; direction = light.light2.direction; range = light.range; // Notice how it's using light 1's range phi = light.light2.phi; /* * Kill the daytime particle system if it's night and the * daytime particle system is still alive. */ if (light.partSys.handle != null) { GameSystems.ParticleSys.Remove(light.partSys.handle); light.partSys.handle = null; } /* * If the nighttime particle system has not yet been started, * do it here. */ ref var nightPartSys = ref light.light2.partSys; if (nightPartSys.handle == null && nightPartSys.hashCode != 0) { var centerOfTile = light.position.ToInches3D(light.offsetZ); nightPartSys.handle = GameSystems.ParticleSys.CreateAt( nightPartSys.hashCode, centerOfTile ); } } else { type = light.type; color = light.color; direction = light.direction; range = light.range; phi = light.phi; // This is just the inverse of what we're doing at night (see above) ref var nightPartSys = ref light.light2.partSys; if (nightPartSys.handle != null) { GameSystems.ParticleSys.Remove(nightPartSys.handle); nightPartSys.handle = null; } ref var dayPartSys = ref light.partSys; if (dayPartSys.handle == null && dayPartSys.hashCode != 0) { var centerOfTile = light.position.ToInches3D(light.offsetZ); dayPartSys.handle = GameSystems.ParticleSys.CreateAt( dayPartSys.hashCode, centerOfTile ); } } }