// Copy properties public void CopyProperties(SectorLevel target) { target.sector = this.sector; target.type = this.type; target.plane = this.plane; target.alpha = this.alpha; target.color = this.color; target.brightnessbelow = this.brightnessbelow; target.colorbelow = this.colorbelow; }
// When no geometry has been changed and no effects have been added or removed, // you can call this again to update existing effects. The effects will update // the existing SectorLevels to match with any changes. public void Update() { if (isupdating || updated) { return; } isupdating = true; // Set floor/ceiling to their original setup BasicSetup(); // Update all effects foreach (SectorEffect e in alleffects) { e.Update(); } // Sort the levels (but not the first and the last) SectorLevelComparer comparer = new SectorLevelComparer(sector); lightlevels.Sort(1, lightlevels.Count - 2, comparer); // Now that we know the levels in this sector (and in the right order) we // can determine the lighting in between and on the levels. // Start from the absolute ceiling and go down to 'cast' the lighting for (int i = lightlevels.Count - 2; i >= 0; i--) { SectorLevel l = lightlevels[i]; SectorLevel pl = lightlevels[i + 1]; // Set color when no color is specified, or when a 3D floor is placed above the absolute floor if ((l.color == 0) || ((l == floor) && (lightlevels.Count > 2))) { PixelColor floorbrightness = PixelColor.FromInt(mode.CalculateBrightness(pl.brightnessbelow)); PixelColor floorcolor = PixelColor.Modulate(pl.colorbelow, floorbrightness); l.color = floorcolor.WithAlpha(255).ToInt(); } if (l.colorbelow.a == 0) { l.colorbelow = pl.colorbelow; } if (l.brightnessbelow == -1) { l.brightnessbelow = pl.brightnessbelow; } } floorchanged = false; ceilingchanged = false; updated = true; isupdating = false; }
// This returns the level below the given point public SectorLevel GetLevelBelow(Vector3D pos) { SectorLevel found = null; float dist = float.MaxValue; foreach (SectorLevel l in lightlevels) { float d = pos.z - l.plane.GetZ(pos); if ((d > 0.0f) && (d < dist)) { dist = d; found = l; } } return(found); }
// This returns the level above the given point public SectorLevel GetCeilingAbove(Vector3D pos) { SectorLevel found = null; float dist = float.MaxValue; foreach (SectorLevel l in lightlevels) { if (l.type == SectorLevelType.Ceiling) { float d = l.plane.GetZ(pos) - pos.z; if ((d > 0.0f) && (d < dist)) { dist = d; found = l; } } } return(found); }
// This makes sure we are updated with the source linedef information public override void Update() { SectorData sd = data.Mode.GetSectorData(linedef.Front.Sector); if (!sd.Updated) { sd.Update(); } sd.AddUpdateSector(data.Sector, false); if (level == null) { level = new SectorLevel(sd.Ceiling); data.AddSectorLevel(level); } // Update level sd.Ceiling.CopyProperties(level); level.type = SectorLevelType.Light; }
// Constructor public SectorData(BaseVisualMode mode, Sector s) { // Initialize this.mode = mode; this.sector = s; this.updated = false; this.floorchanged = false; this.ceilingchanged = false; this.lightlevels = new List <SectorLevel>(2); this.extrafloors = new List <Effect3DFloor>(1); this.alleffects = new List <SectorEffect>(1); this.updatesectors = new Dictionary <Sector, bool>(2); this.floor = new SectorLevel(sector, SectorLevelType.Floor); this.ceiling = new SectorLevel(sector, SectorLevelType.Ceiling); BasicSetup(); // Add ceiling and floor lightlevels.Add(floor); lightlevels.Add(ceiling); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup(SectorLevel level, Effect3DFloor extrafloor) { WorldVertex[] verts; Sector s = level.sector; Vector2D texscale; base.Setup(level, extrafloor); // Fetch ZDoom fields float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f)); Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f), s.Fields.GetValue("ypanningceiling", 0.0f)); Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f), s.Fields.GetValue("yscaleceiling", 1.0f)); // Load floor texture base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture); if (base.Texture == null) { base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = s.LongCeilTexture; } else { if (!base.Texture.IsImageLoaded) { setuponloadedtexture = s.LongCeilTexture; } } // Determine texture scale if (base.Texture.IsImageLoaded) { texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight); } else { texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f); } // Make vertices ReadOnlyCollection <Vector2D> triverts = base.Sector.Sector.Triangles.Vertices; verts = new WorldVertex[triverts.Count]; for (int i = 0; i < triverts.Count; i++) { // Color shading PixelColor c = PixelColor.FromInt(level.color); verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); // Vertex coordinates verts[i].x = triverts[i].x; verts[i].y = triverts[i].y; verts[i].z = level.plane.GetZ(triverts[i]); //(float)s.CeilHeight; // Texture coordinates Vector2D pos = triverts[i]; pos = pos.GetRotated(rotate); pos.y = -pos.y; pos = (pos + offset) * scale * texscale; verts[i].u = pos.x; verts[i].v = pos.y; } // The sector triangulation created clockwise triangles that // are right up for the floor. For the ceiling we must flip // the triangles upside down. if ((extrafloor == null) || extrafloor.VavoomType) { SwapTriangleVertices(verts); } // Determine render pass if (extrafloor != null) { if (level.alpha < 255) { this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } } else { this.RenderPass = RenderPass.Solid; } // Apply vertices base.SetVertices(verts); return(verts.Length > 0); }
// This creates vertices from a wall polygon and applies lighting protected List <WorldVertex> CreatePolygonVertices(List <WallPolygon> poly, TexturePlane tp, SectorData sd, int lightvalue, bool lightabsolute) { List <WallPolygon> polygons = new List <WallPolygon>(poly); List <WorldVertex> verts = new List <WorldVertex>(); // Go for all levels to build geometry for (int i = sd.LightLevels.Count - 1; i >= 0; i--) { SectorLevel l = sd.LightLevels[i]; if ((l != sd.Floor) && (l != sd.Ceiling) && (l.type != SectorLevelType.Floor)) { // Go for all polygons int num = polygons.Count; for (int pi = 0; pi < num; pi++) { // Split by plane WallPolygon p = polygons[pi]; WallPolygon np = SplitPoly(ref p, l.plane, false); if (np.Count > 0) { // Determine color int lightlevel = lightabsolute ? lightvalue : l.brightnessbelow + lightvalue; PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel)); PixelColor wallcolor = PixelColor.Modulate(l.colorbelow, wallbrightness); np.color = wallcolor.WithAlpha(255).ToInt(); if (p.Count == 0) { polygons[pi] = np; } else { polygons[pi] = p; polygons.Add(np); } } else { polygons[pi] = p; } } } } // Go for all polygons to make geometry foreach (WallPolygon p in polygons) { // Find texture coordinates for each vertex in the polygon List <Vector2D> texc = new List <Vector2D>(p.Count); foreach (Vector3D v in p) { texc.Add(tp.GetTextureCoordsAt(v)); } // Now we create triangles from the polygon. // The polygon is convex and clockwise, so this is a piece of cake. if (p.Count >= 3) { for (int k = 1; k < (p.Count - 1); k++) { verts.Add(new WorldVertex(p[0], p.color, texc[0])); verts.Add(new WorldVertex(p[k], p.color, texc[k])); verts.Add(new WorldVertex(p[k + 1], p.color, texc[k + 1])); } } } return(verts); }
// This adds a sector level public void AddSectorLevel(SectorLevel level) { // Note: Inserting before the end so that the ceiling stays // at the end and the floor at the beginning lightlevels.Insert(lightlevels.Count - 1, level); }
// Copy constructor public SectorLevel(SectorLevel source) { source.CopyProperties(this); }
// This builds the thing geometry. Returns false when nothing was created. public virtual bool Setup() { PixelColor sectorcolor = new PixelColor(255, 255, 255, 255); // Must have a width and height! if ((info.Radius < 0.1f) || (info.Height < 0.1f)) { return(false); } // Find the sector in which the thing resides Thing.DetermineSector(mode.BlockMap); if (sprite != null) { if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); SectorLevel level = sd.GetLevelAbove(new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + Thing.Sector.FloorHeight)); if (level != null) { // Use sector brightness for color shading PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(level.brightnessbelow)); PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness); sectorcolor = areacolor.WithAlpha(255); } } // Check if the texture is loaded sprite.LoadImage(); isloaded = sprite.IsImageLoaded; if (isloaded) { float offsetx = 0.0f; float offsety = 0.0f; base.Texture = sprite; // Determine sprite size and offset float radius = sprite.ScaledWidth * 0.5f; float height = sprite.ScaledHeight; if (sprite is SpriteImage) { offsetx = (sprite as SpriteImage).OffsetX - radius; offsety = (sprite as SpriteImage).OffsetY - height; } // Scale by thing type/actor scale // We do this after the offset x/y determination above, because that is entirely in sprite pixels space radius *= info.SpriteScale.Width; height *= info.SpriteScale.Height; offsetx *= info.SpriteScale.Width; offsety *= info.SpriteScale.Height; // Make vertices WorldVertex[] verts = new WorldVertex[6]; verts[0] = new WorldVertex(-radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 0.0f, 1.0f); verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 0.0f, 0.0f); verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 1.0f, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 1.0f, 1.0f); SetVertices(verts); } else { base.Texture = General.Map.Data.Hourglass3D; // Determine sprite size float radius = Math.Min(info.Radius, info.Height / 2f); float height = Math.Min(info.Radius * 2f, info.Height); // Make vertices WorldVertex[] verts = new WorldVertex[6]; verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor.ToInt(), 0.0f, 1.0f); verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor.ToInt(), 0.0f, 0.0f); verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor.ToInt(), 1.0f, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor.ToInt(), 1.0f, 1.0f); SetVertices(verts); } } // Determine position Vector3D pos = Thing.Position; if (Thing.Type == 9501) { // This is a special thing that needs special positioning SectorData sd = mode.GetSectorData(Thing.Sector); pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z; } else if (Thing.Type == 9500) { // This is a special thing that needs special positioning SectorData sd = mode.GetSectorData(Thing.Sector); pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z; } else if (info.AbsoluteZ) { // Absolute Z position pos.z = Thing.Position.z; } else if (info.Hangs) { // Hang from ceiling if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); if (Thing.Position.z > 0) { pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; } else { pos.z = Thing.Sector.CeilHeight - info.Height; } } pos.z -= Thing.Position.z; // Check if below floor if ((Thing.Sector != null) && (pos.z < Thing.Sector.FloorHeight)) { // Put thing on the floor SectorData sd = mode.GetSectorData(Thing.Sector); pos.z = sd.Floor.plane.GetZ(Thing.Position); } } else { // Stand on floor if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); if (Thing.Position.z == 0) { pos.z = sd.Floor.plane.GetZ(Thing.Position); } else { pos.z = Thing.Sector.FloorHeight; } } pos.z += Thing.Position.z; // Check if above ceiling if ((Thing.Sector != null) && ((pos.z + info.Height) > Thing.Sector.CeilHeight)) { // Put thing against ceiling SectorData sd = mode.GetSectorData(Thing.Sector); pos.z = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; } } // Apply settings SetPosition(pos); SetCageSize(info.Radius, info.Height); SetCageColor(Thing.Color); // Keep info for object picking cageradius2 = info.Radius * Angle2D.SQRT2; cageradius2 = cageradius2 * cageradius2; pos2d = pos; boxp1 = new Vector3D(pos.x - info.Radius, pos.y - info.Radius, pos.z); boxp2 = new Vector3D(pos.x + info.Radius, pos.y + info.Radius, pos.z + info.Height); // Done changed = false; return(true); }
public virtual bool Setup(SectorLevel level, Effect3DFloor extrafloor) { this.level = level; this.extrafloor = extrafloor; return(false); }
// This makes sure we are updated with the source linedef information public override void Update() { SectorData sd = data.Mode.GetSectorData(linedef.Front.Sector); if (!sd.Updated) { sd.Update(); } sd.AddUpdateSector(data.Sector, true); // Check if this effect still exists int sectortag = linedef.Args[0] + (linedef.Args[4] << 8); if (linedef.IsDisposed || (linedef.Action != 160) || (sectortag != data.Sector.Tag)) { // When the effect is no longer exists, we must remove it and update sectors } if (floor == null) { floor = new SectorLevel(sd.Floor); data.AddSectorLevel(floor); } if (ceiling == null) { ceiling = new SectorLevel(sd.Ceiling); data.AddSectorLevel(ceiling); } // For non-vavoom types, we must switch the level types int argtype = (linedef.Args[1] & 0x03); if (argtype != 0) { vavoomtype = false; alpha = linedef.Args[3]; sd.Ceiling.CopyProperties(floor); sd.Floor.CopyProperties(ceiling); floor.type = SectorLevelType.Floor; floor.plane = sd.Ceiling.plane.GetInverted(); ceiling.type = SectorLevelType.Ceiling; ceiling.plane = sd.Floor.plane.GetInverted(); // A 3D floor's color is always that of the sector it is placed in floor.color = 0; } else { vavoomtype = true; /* * sd.Ceiling.CopyProperties(floor); * sd.Floor.CopyProperties(ceiling); */ floor.type = SectorLevelType.Ceiling; floor.plane = sd.Ceiling.plane; ceiling.type = SectorLevelType.Floor; ceiling.plane = sd.Floor.plane; alpha = 255; // A 3D floor's color is always that of the sector it is placed in ceiling.color = 0; } // Apply alpha floor.alpha = alpha; ceiling.alpha = alpha; // Do not adjust light? (works only for non-vavoom types) if (((linedef.Args[2] & 1) != 0) && !vavoomtype) { floor.brightnessbelow = -1; floor.colorbelow = PixelColor.FromInt(0); ceiling.color = 0; ceiling.brightnessbelow = -1; ceiling.colorbelow = PixelColor.FromInt(0); } }