//mxd private int GetLevelColor(SectorLevel src) { PixelColor brightness = PixelColor.FromInt(mode.CalculateBrightness(src.brightnessbelow)); PixelColor color = PixelColor.Modulate(src.colorbelow, brightness); return(color.WithAlpha(255).ToInt()); }
private Lights GetLight(int color) { PixelColor c; c = PixelColor.FromInt(color); return(new Lights(c.r, c.g, c.b, 0)); }
//mxd. merged from GZDoomEditing plugin // This applies the given values on the vertices private static void SetupSurfaceVertices(FlatVertex[] vertices, Sector s, ImageData img, Vector2D offset, Vector2D scale, double rotate, int color, int light, bool absolute) { // Prepare for math! rotate = Angle2D.DegToRad(rotate); Vector2D texscale = new Vector2D(1.0f / img.ScaledWidth, 1.0f / img.ScaledHeight); if (!absolute) { light = s.Brightness + light; } PixelColor lightcolor = PixelColor.FromInt(color); PixelColor brightness = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(light)); PixelColor finalcolor = PixelColor.Modulate(lightcolor, brightness); color = finalcolor.WithAlpha(255).ToInt(); // Do the math for all vertices for (int i = 0; i < vertices.Length; i++) { Vector2D pos = new Vector2D(vertices[i].x, vertices[i].y); pos = pos.GetRotated(rotate); pos.y = -pos.y; pos = (pos + offset) * scale * texscale; vertices[i].u = (float)pos.x; vertices[i].v = (float)pos.y; vertices[i].c = color; } }
// When ceiling surface geometry is created for classic modes public override void OnSectorCeilingSurfaceUpdate(Sector s, ref FlatVertex[] vertices) { ImageData img = General.Map.Data.GetFlatImage(s.LongCeilTexture); if ((img != null) && img.IsImageLoaded) { //mxd. Merged from GZDoomEditing plugin if (General.Map.UDMF) { // Fetch ZDoom fields Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0), s.Fields.GetValue("ypanningceiling", 0.0)); Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0), s.Fields.GetValue("yscaleceiling", 1.0)); double rotate = s.Fields.GetValue("rotationceiling", 0.0); int color, light; bool absolute; //mxd. Apply GLDEFS override? if (General.Map.Data.GlowingFlats.ContainsKey(s.LongCeilTexture) && General.Map.Data.GlowingFlats[s.LongCeilTexture].Fullbright) { color = -1; light = 255; absolute = true; } else { color = PixelColor.Modulate(PixelColor.FromInt(s.Fields.GetValue("lightcolor", -1)), PixelColor.FromInt(s.Fields.GetValue("color_ceiling", -1))).ToInt(); light = s.Fields.GetValue("lightceiling", 0); absolute = s.Fields.GetValue("lightceilingabsolute", false); } // Setup the vertices with the given settings SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute); } else { // Make scalars float sw = 1.0f / img.ScaledWidth; float sh = 1.0f / img.ScaledHeight; // Make proper texture coordinates for (int i = 0; i < vertices.Length; i++) { vertices[i].u = vertices[i].u * sw; vertices[i].v = -vertices[i].v * sh; } } } else // [ZZ] proper fallback please. { for (int i = 0; i < vertices.Length; i++) { vertices[i].u = vertices[i].u / 64; vertices[i].v = -vertices[i].v / 64; } } }
// 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 updates the overlay private void UpdateOverlay() { if (renderer.StartOverlay(true)) { // Editing a selection? if (mode == ModifyMode.Adjusting) { // Go for all sectors that are being edited ICollection <Sector> orderedselection = General.Map.Map.GetSelectedSectors(true); foreach (Sector s in orderedselection) { // We use the overlay to dim the brightness of the sectors PixelColor c = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(s.Brightness)); PixelColor brightnesscolor = new PixelColor((byte)(255 - c.r), 0, 0, 0); int brightnessint = brightnesscolor.ToInt(); // Render the geometry FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length]; s.FlatVertices.CopyTo(verts, 0); for (int i = 0; i < verts.Length; i++) { verts[i].c = brightnessint; } renderer.RenderGeometry(verts, null, true); } } if (BuilderPlug.Me.ViewSelectionNumbers) { // Go for all sectors ICollection <Sector> orderedselection = General.Map.Map.GetSelectedSectors(true); foreach (Sector s in orderedselection) { // Render labels TextLabel[] labelarray = labels[s]; for (int i = 0; i < s.Labels.Count; i++) { TextLabel l = labelarray[i]; // Render only when enough space for the label to see float requiredsize = (l.TextSize.Height / 2) / renderer.Scale; if (requiredsize < s.Labels[i].radius) { renderer.RenderText(l); } } } } renderer.Finish(); } }
//mxd. This sets up the association public Association(IRenderer2D renderer) { this.tags = new HashSet <int> { 0 }; this.renderer = renderer; things = new List <Thing>(); sectors = new List <Sector>(); linedefs = new List <Linedef>(); eventlines = new Dictionary <string, List <Line3D> >(); try { font = new Font(new FontFamily(General.Settings.TextLabelFontName), General.Settings.TextLabelFontSize, (General.Settings.TextLabelFontBold ? FontStyle.Bold : FontStyle.Regular)); } catch (Exception) // Fallback if the font couldn't be loaded { font = ((MainForm)General.Interface).Font; } distinctcolors = new List <PixelColor> { General.Colors.InfoLine, PixelColor.FromInt(0x84d5a4).WithAlpha(255), PixelColor.FromInt(0xc059cb).WithAlpha(255), PixelColor.FromInt(0xd0533d).WithAlpha(255), // PixelColor.FromInt(0x415354).WithAlpha(255), // too dark PixelColor.FromInt(0xcea953).WithAlpha(255), PixelColor.FromInt(0x91d44b).WithAlpha(255), PixelColor.FromInt(0xcd5b89).WithAlpha(255), PixelColor.FromInt(0xa8b6c0).WithAlpha(255), PixelColor.FromInt(0x797ecb).WithAlpha(255), // PixelColor.FromInt(0x567539).WithAlpha(255), // too dark // PixelColor.FromInt(0x72422f).WithAlpha(255), // too dark // PixelColor.FromInt(0x5d3762).WithAlpha(255), // too dark PixelColor.FromInt(0xffed6f).WithAlpha(255), PixelColor.FromInt(0xccebc5).WithAlpha(255), PixelColor.FromInt(0xbc80bd).WithAlpha(255), // PixelColor.FromInt(0xd9d9d9).WithAlpha(255), // too gray PixelColor.FromInt(0xfccde5).WithAlpha(255), PixelColor.FromInt(0x80b1d3).WithAlpha(255), PixelColor.FromInt(0xfdb462).WithAlpha(255), PixelColor.FromInt(0xb3de69).WithAlpha(255), PixelColor.FromInt(0xfb8072).WithAlpha(255), PixelColor.FromInt(0xbebada).WithAlpha(255), // too blue/gray? PixelColor.FromInt(0xffffb3).WithAlpha(255), PixelColor.FromInt(0x8dd3c7).WithAlpha(255), }; }
// 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); // Transfer ceiling brightness, keep sector color PixelColor lightcolor = PixelColor.FromInt(data.Sector.Fields.GetValue("lightcolor", -1)); PixelColor brightness = PixelColor.FromInt(General.Map.Renderer3D.CalculateBrightness(sd.Sector.Brightness)); data.Ceiling.color = PixelColor.Modulate(lightcolor, brightness).WithAlpha(255).ToInt(); }
//mxd. This replicates ZDoom's V_GetColorFromString method public static bool GetColorFromString(string name, out PixelColor color) { name = StripQuotes(name.Replace(" ", "")); // Check for HTML-style #RRGGBB or #RGB color string bool ishtmlcolor = false; if (name.StartsWith("#")) { ishtmlcolor = true; name = name.Remove(0, 1); // Expand RGB to RRGGBB if (name.Length == 3) { name = name[0].ToString() + name[0] + name[1] + name[1] + name[2] + name[2]; } else if (name.Length != 6) { // Bad HTML-style; pretend it's black. color = new PixelColor(); return(true); } } // Probably it's a hex color (like FFCC11)? int ci; if (int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ci)) { color = PixelColor.FromInt(ci).WithAlpha(255); return(true); } // Probably it's a color name? if (!ishtmlcolor && General.Map.Data.KnownColors.ContainsKey(name)) { color = General.Map.Data.KnownColors[name]; return(true); } color = new PixelColor(); return(false); }
private void tbColor_TextChanged(object sender, EventArgs e) { if (blockupdate) { return; } int colorval; if (int.TryParse(tbColor.Text, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out colorval)) { colorval = General.Clamp(colorval, 0, 0xFFFFFF); cpColor.Color = PixelColor.FromInt(colorval).WithAlpha(255); } CheckColor(); if (!blockevents && OnValueChanged != null) { OnValueChanged(this, EventArgs.Empty); } }
//mxd private int GetLevelColor(SectorLevel src, SectorLevel target) { PixelColor brightness; if (lightfloorabsolute && target == floor) { brightness = PixelColor.FromInt(mode.CalculateBrightness(lightfloor)); } else if (lightceilingabsolute && target == ceiling) { brightness = PixelColor.FromInt(mode.CalculateBrightness(lightceiling)); } else { brightness = PixelColor.FromInt(mode.CalculateBrightness(src.brightnessbelow)); } PixelColor color = PixelColor.Modulate(src.colorbelow, brightness); return(color.WithAlpha(255).ToInt()); }
public void SetValueFrom(UniFields fields, bool first) { blockevents = true; string colorval = String.Format("{0:X6}", UniFields.GetInteger(fields, field, defaultvalue)); if (first) { tbColor.Text = colorval; } else if (!string.IsNullOrEmpty(tbColor.Text) && colorval != tbColor.Text) { blockupdate = true; tbColor.Text = string.Empty; cpColor.Color = PixelColor.FromInt(defaultvalue).WithAlpha(255); blockupdate = false; CheckColor(); } blockevents = false; }
// This sets up the basic floor and ceiling, as they would be in normal Doom circumstances private void BasicSetup() { // Normal (flat) floor and ceiling planes floor.plane = new Plane(new Vector3D(0, 0, 1), -sector.FloorHeight); ceiling.plane = new Plane(new Vector3D(0, 0, -1), sector.CeilHeight); // Fetch ZDoom fields int color = sector.Fields.GetValue("lightcolor", -1); int flight = sector.Fields.GetValue("lightfloor", 0); bool fabs = sector.Fields.GetValue("lightfloorabsolute", false); int clight = sector.Fields.GetValue("lightceiling", 0); bool cabs = sector.Fields.GetValue("lightceilingabsolute", false); // Determine colors & light levels PixelColor lightcolor = PixelColor.FromInt(color); if (!fabs) { flight = sector.Brightness + flight; } if (!cabs) { clight = sector.Brightness + clight; } PixelColor floorbrightness = PixelColor.FromInt(mode.CalculateBrightness(flight)); PixelColor ceilingbrightness = PixelColor.FromInt(mode.CalculateBrightness(clight)); PixelColor floorcolor = PixelColor.Modulate(lightcolor, floorbrightness); PixelColor ceilingcolor = PixelColor.Modulate(lightcolor, ceilingbrightness); floor.color = floorcolor.WithAlpha(255).ToInt(); floor.brightnessbelow = sector.Brightness; floor.colorbelow = lightcolor.WithAlpha(255); ceiling.color = ceilingcolor.WithAlpha(255).ToInt(); ceiling.brightnessbelow = sector.Brightness; ceiling.colorbelow = lightcolor.WithAlpha(255); }
private GlowingFlatData GetGlowData(bool floor) { // Check UDMF glow properties if (General.Map.UDMF) { int glowcolor = data.Sector.Fields.GetValue((floor ? "floorglowcolor" : "ceilingglowcolor"), 0); // Glow is explicidly disabled? if (glowcolor == -1) { return(null); } // Avoid black glows if (glowcolor > 0) { double glowheight = data.Sector.Fields.GetValue((floor ? "floorglowheight" : "ceilingglowheight"), 0.0); if (glowheight > 0f) { // Create glow data PixelColor c = PixelColor.FromInt(glowcolor); return(new GlowingFlatData { Color = c, Height = glowheight, Brightness = (c.r + c.g + c.b) / 3, }); } } } // Use GLDEFS glow if available long texture = (floor ? data.Sector.LongFloorTexture : data.Sector.LongCeilTexture); return(General.Map.Data.GlowingFlats.ContainsKey(texture) ? General.Map.Data.GlowingFlats[texture] : null); }
// This shows the info public void ShowInfo(Sector s, bool highlightceiling, bool highlightfloor) { int sheight = s.CeilHeight - s.FloorHeight; // Lookup effect description in config string effectinfo = s.Effect + " - " + General.Map.Config.GetSectorEffectInfo(s.Effect).Title; //mxd // Sector info sectorinfo.Text = " Sector " + s.Index + " (" + (s.Sidedefs == null ? "no" : s.Sidedefs.Count.ToString()) + " sidedefs)"; //mxd effect.Text = effectinfo; ceiling.Text = s.CeilHeight.ToString(); floor.Text = s.FloorHeight.ToString(); height.Text = sheight.ToString(); brightness.Text = s.Brightness.ToString(); floorname.Text = (s.FloorTexture.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH ? s.FloorTexture : s.FloorTexture.ToUpperInvariant()); ceilingname.Text = (s.CeilTexture.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH ? s.CeilTexture : s.CeilTexture.ToUpperInvariant()); //mxd. Set tags if (s.Tags.Count > 1) { string[] tags = new string[s.Tags.Count]; for (int i = 0; i < s.Tags.Count; i++) { tags[i] = s.Tags[i].ToString(); } tag.Text = string.Join(", ", tags); tag.Enabled = true; taglabel.Enabled = true; taglabel.Text = "Tags:"; } else { tag.Text = s.Tag + (General.Map.Options.TagLabels.ContainsKey(s.Tag) ? " - " + General.Map.Options.TagLabels[s.Tag] : string.Empty); tag.Enabled = (s.Tag != 0); taglabel.Enabled = (s.Tag != 0); taglabel.Text = "Tag:"; } //mxd effect.Enabled = (s.Effect != 0); effectlabel.Enabled = (s.Effect != 0); //mxd. Texture size if (s.LongFloorTexture == MapSet.EmptyLongName) { labelFloorTextureSize.Visible = false; General.DisplayZoomedImage(floortex, Properties.Resources.MissingTexture); } else { ImageData image = General.Map.Data.GetFlatImage(s.FloorTexture); DisplayTextureSize(labelFloorTextureSize, image); General.DisplayZoomedImage(floortex, image.GetPreview()); } if (s.LongCeilTexture == MapSet.EmptyLongName) { labelCeilTextureSize.Visible = false; General.DisplayZoomedImage(ceilingtex, Properties.Resources.MissingTexture); } else { ImageData image = General.Map.Data.GetFlatImage(s.CeilTexture); DisplayTextureSize(labelCeilTextureSize, image); //mxd General.DisplayZoomedImage(ceilingtex, image.GetPreview()); } //mxd bool showExtededFloorInfo = false; bool showExtededCeilingInfo = false; if (General.Map.UDMF) { if (s.Fields != null) { //sector colors labelLight.Visible = true; labelFade.Visible = true; panelLightColor.Visible = true; panelFadeColor.Visible = true; if (s.Fields.ContainsKey("lightcolor")) { panelLightColor.BackColor = PixelColor.FromInt(s.Fields.GetValue("lightcolor", 0xFFFFFF)).WithAlpha(255).ToColor(); labelLight.Enabled = true; } else { panelLightColor.BackColor = SystemColors.Control; labelLight.Enabled = false; } if (s.Fields.ContainsKey("fadecolor")) { panelFadeColor.BackColor = PixelColor.FromInt(s.Fields.GetValue("fadecolor", 0)).WithAlpha(255).ToColor(); labelFade.Enabled = true; } else { panelFadeColor.BackColor = SystemColors.Control; labelFade.Enabled = false; } //light if (s.Fields.ContainsKey("lightceiling") || s.Fields.ContainsKey("lightceilingabsolute")) { showExtededCeilingInfo = true; ceilingLight.Enabled = true; ceilingLightLabel.Enabled = true; int cl = s.Fields.GetValue("lightceiling", 0); if (s.Fields.GetValue("lightceilingabsolute", false)) { ceilingLight.Text = cl + " (abs.)"; } else { ceilingLight.Text = cl + " (" + Math.Min(255, Math.Max(0, (cl + s.Brightness))) + ")"; } } else { ceilingLight.Text = "--"; ceilingLight.Enabled = false; ceilingLightLabel.Enabled = false; } if (s.Fields.ContainsKey("lightfloor") || s.Fields.ContainsKey("lightfloorabsolute")) { showExtededFloorInfo = true; floorLight.Enabled = true; floorLightLabel.Enabled = true; int fl = s.Fields.GetValue("lightfloor", 0); if (s.Fields.GetValue("lightfloorabsolute", false)) { floorLight.Text = fl + " (abs.)"; } else { floorLight.Text = fl + " (" + Math.Min(255, Math.Max(0, (fl + s.Brightness))) + ")"; } } else { floorLight.Text = "--"; floorLight.Enabled = false; floorLightLabel.Enabled = false; } //ceiling offsets float panX = s.Fields.GetValue("xpanningceiling", 0f); float panY = s.Fields.GetValue("ypanningceiling", 0f); if (panX != 0 || panY != 0) { showExtededCeilingInfo = true; ceilingOffset.Enabled = true; ceilingOffsetLabel.Enabled = true; ceilingOffset.Text = panX.ToString(CultureInfo.InvariantCulture) + ", " + panY.ToString(CultureInfo.InvariantCulture); } else { ceilingOffset.Text = "--, --"; ceilingOffset.Enabled = false; ceilingOffsetLabel.Enabled = false; } //floor offsets panX = s.Fields.GetValue("xpanningfloor", 0f); panY = s.Fields.GetValue("ypanningfloor", 0f); if (panX != 0 || panY != 0) { showExtededFloorInfo = true; floorOffset.Enabled = true; floorOffsetLabel.Enabled = true; floorOffset.Text = panX.ToString(CultureInfo.InvariantCulture) + ", " + panY.ToString(CultureInfo.InvariantCulture); } else { floorOffset.Text = "--, --"; floorOffset.Enabled = false; floorOffsetLabel.Enabled = false; } //ceiling scale float scaleX = s.Fields.GetValue("xscaleceiling", 1.0f); float scaleY = s.Fields.GetValue("yscaleceiling", 1.0f); if (scaleX != 1.0f || scaleY != 1.0f) { showExtededCeilingInfo = true; ceilingScale.Enabled = true; ceilingScaleLabel.Enabled = true; ceilingScale.Text = scaleX.ToString(CultureInfo.InvariantCulture) + ", " + scaleY.ToString(CultureInfo.InvariantCulture); } else { ceilingScale.Text = "--, --"; ceilingScale.Enabled = false; ceilingScaleLabel.Enabled = false; } //floor scale scaleX = s.Fields.GetValue("xscalefloor", 1.0f); scaleY = s.Fields.GetValue("yscalefloor", 1.0f); if (scaleX != 1.0f || scaleY != 1.0f) { showExtededFloorInfo = true; floorScale.Enabled = true; floorScaleLabel.Enabled = true; floorScale.Text = scaleX.ToString(CultureInfo.InvariantCulture) + ", " + scaleY.ToString(CultureInfo.InvariantCulture); } else { floorScale.Text = "--, --"; floorScale.Enabled = false; floorScaleLabel.Enabled = false; } //rotation float ceilangle = s.Fields.GetValue("rotationceiling", 0f); if (ceilangle != 0f) { showExtededCeilingInfo = true; ceilingAngle.Enabled = true; ceilingAngleLabel.Enabled = true; ceilingAngle.Text = ceilangle + "\u00B0"; } else { ceilingAngle.Text = "--"; ceilingAngle.Enabled = false; ceilingAngleLabel.Enabled = false; } float floorangle = s.Fields.GetValue("rotationfloor", 0f); if (floorangle != 0f) { showExtededFloorInfo = true; floorAngle.Enabled = true; floorAngleLabel.Enabled = true; floorAngle.Text = floorangle + "\u00B0"; } else { floorAngle.Text = "--"; floorAngle.Enabled = false; floorAngleLabel.Enabled = false; } } //Flags flags.Items.Clear(); foreach (KeyValuePair <string, string> group in General.Map.Config.SectorFlags) { if (s.Flags.ContainsKey(group.Key) && s.Flags[group.Key]) { flags.Items.Add(new ListViewItem(group.Value) { Checked = true }); } } foreach (KeyValuePair <string, string> group in General.Map.Config.CeilingPortalFlags) { if (s.Flags.ContainsKey(group.Key) && s.Flags[group.Key]) { flags.Items.Add(new ListViewItem(group.Value + " (ceil. portal)") { Checked = true }); } } foreach (KeyValuePair <string, string> group in General.Map.Config.FloorPortalFlags) { if (s.Flags.ContainsKey(group.Key) && s.Flags[group.Key]) { flags.Items.Add(new ListViewItem(group.Value + " (floor portal)") { Checked = true }); } } //mxd. Flags panel visibility and size flagsPanel.Visible = (flags.Items.Count > 0); if (flags.Items.Count > 0) { Rectangle rect = flags.GetItemRect(0); int itemspercolumn = 1; // Check how many items per column we have... for (int i = 1; i < flags.Items.Count; i++) { if (flags.GetItemRect(i).X != rect.X) { break; } itemspercolumn++; } flags.Width = rect.Width * (int)Math.Ceiling(flags.Items.Count / (float)itemspercolumn); flagsPanel.Width = flags.Width + flags.Left * 2; } //mxd. Toggle visibility foreach (Label label in floorinfolabels) { label.Visible = showExtededFloorInfo; } foreach (Label label in floorlabels) { label.Visible = showExtededFloorInfo; } foreach (Label label in ceilinfolabels) { label.Visible = showExtededCeilingInfo; } foreach (Label label in ceillabels) { label.Visible = showExtededCeilingInfo; } } else { panelFadeColor.Visible = false; panelLightColor.Visible = false; labelFade.Visible = false; labelLight.Visible = false; flagsPanel.Visible = false; } //mxd. Resize panels UpdateTexturePanel(ceilingpanel, ceilingname, ceilinfolabels, ceilingtex, ceilingOffsetLabel.Location.X - 1, showExtededCeilingInfo); UpdateTexturePanel(floorpanel, floorname, floorinfolabels, floortex, floorOffsetLabel.Location.X - 1, showExtededFloorInfo); //mxd. Highlight ceiling or floor? Color floorhighlightcolor = (highlightfloor ? SystemColors.HotTrack : SystemColors.WindowText); Color ceilinghighlightcolor = (highlightceiling ? SystemColors.HotTrack : SystemColors.WindowText); floorpanel.ForeColor = floorhighlightcolor; floor.ForeColor = floorhighlightcolor; labelfloor.ForeColor = floorhighlightcolor; ceilingpanel.ForeColor = ceilinghighlightcolor; ceiling.ForeColor = ceilinghighlightcolor; labelceiling.ForeColor = ceilinghighlightcolor; // Show the whole thing this.Show(); this.Update(); }
// 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 builds the thing geometry. Returns false when nothing was created. public bool Setup() { // Find the sector in which the thing resides Thing.DetermineSector(mode.BlockMap); //mxd. If the thing is inside a sector, apply DECORATE/UDMF alpha/renderstyle overrides byte alpha = 255; if (Thing.Sector != null) { string renderstyle = info.RenderStyle; alpha = info.AlphaByte; if (General.Map.UDMF) { if (Thing.IsFlagSet("translucent")) { renderstyle = "translucent"; alpha = 64; } else if (Thing.IsFlagSet("invisible")) { renderstyle = "none"; alpha = 0; } else if (Thing.Fields.ContainsKey("renderstyle")) { renderstyle = Thing.Fields.GetValue("renderstyle", renderstyle); } if ((renderstyle == "add" || renderstyle == "translucent" || renderstyle == "subtract" || renderstyle == "stencil") && Thing.Fields.ContainsKey("alpha")) { alpha = (byte)(General.Clamp(Thing.Fields.GetValue("alpha", info.Alpha), 0f, 1f) * 255); } } else if (General.Map.HEXEN) { if (Thing.IsFlagSet("2048")) { renderstyle = "translucent"; alpha = 64; } else if (Thing.IsFlagSet("4096")) { renderstyle = "none"; alpha = 0; } } // Set appropriate RenderPass switch (renderstyle) { case "translucent": case "subtract": case "stencil": RenderPass = RenderPass.Alpha; break; case "add": RenderPass = RenderPass.Additive; break; case "none": RenderPass = RenderPass.Mask; alpha = 0; break; // Many render styles are not supported yet... default: RenderPass = RenderPass.Mask; alpha = 255; break; } } // Don't bother when alpha is unchanged, unless Additive RenderStyle is used if (RenderPass != RenderPass.Additive && alpha == 255) { RenderPass = RenderPass.Mask; } int sectorcolor = new PixelColor(alpha, 255, 255, 255).ToInt(); fogfactor = 0f; //mxd //mxd. Check thing size float thingradius = Thing.Size; // Thing.Size has ThingRadius arg override applied thingheight = Thing.Height; // Thing.Height has ThingHeight arg override applied if (thingradius < 0.1f || thingheight < 0.1f) { thingradius = FIXED_RADIUS; thingheight = FIXED_RADIUS; sizeless = true; } else { sizeless = false; } Plane floor = new Plane(); //mxd Plane ceiling = new Plane(); //mxd if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); floor = sd.Floor.plane; //mxd ceiling = sd.Ceiling.plane; //mxd if (!info.Bright) { Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); SectorLevel level = sd.GetLevelAboveOrAt(thingpos); //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight; if (nointeraction && level == null && sd.LightLevels.Count > 0) { level = sd.LightLevels[sd.LightLevels.Count - 1]; } //mxd. Use the light level of the highest surface when a thing is above highest sector level. if (level != null) { // TECH: In GZDoom, ceiling glow doesn't affect thing brightness // Use sector brightness for color shading int brightness = level.brightnessbelow; // Level is glowing if (level.affectedbyglow && level.type == SectorLevelType.Floor) { // Extrafloor glow doesn't affect thing brightness if (level.sector == Thing.Sector) { float planez = level.plane.GetZ(thingpos); // Get glow brightness int glowbrightness = sd.FloorGlow.Brightness / 2; SectorLevel nexthigher = sd.GetLevelAbove(new Vector3D(thingpos, planez)); // Interpolate thing brightness between glow and regular ones if (nexthigher != null) { float higherz = nexthigher.plane.GetZ(thingpos); float delta = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f); brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta)); } } } // Level below this one is glowing. Only possible for floor glow(?) else if (level.type == SectorLevelType.Glow) { // Interpolate thing brightness between glow and regular ones if (sd.Floor != null && sd.FloorGlow != null) { // Get glow brightness float glowz = level.plane.GetZ(thingpos); float floorz = floor.GetZ(thingpos); float delta = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f); brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta); } } PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness)); PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness); sectorcolor = areacolor.WithAlpha(alpha).ToInt(); //mxd. Calculate fogfactor fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, brightness); } } //TECH: even Bright Thing frames are affected by custom fade... else { Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); SectorLevel level = sd.GetLevelAboveOrAt(thingpos); if (level != null && level.sector.FogMode > SectorFogMode.CLASSIC) { //mxd. Calculate fogfactor fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, level.brightnessbelow); } } } //mxd. Create verts for all sprite angles WorldVertex[][] allverts = new WorldVertex[info.SpriteFrame.Length][]; Vector2D[] alloffsets = new Vector2D[info.SpriteFrame.Length]; base.textures = new ImageData[info.SpriteFrame.Length]; isloaded = true; for (int i = 0; i < sprites.Length; i++) { Vector2D offsets = new Vector2D(); // Check if the texture is loaded ImageData sprite = sprites[i]; sprite.LoadImage(); if (sprite.IsImageLoaded) { base.textures[i] = sprite; // Determine sprite size and offset float radius = sprite.ScaledWidth * 0.5f; float height = sprite.ScaledHeight; ISpriteImage spriteimg = sprite as ISpriteImage; if (spriteimg != null) { offsets.x = radius - spriteimg.OffsetX; offsets.y = spriteimg.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; offsets.x *= info.SpriteScale.Width; offsets.y *= info.SpriteScale.Height; // Make vertices WorldVertex[] verts = new WorldVertex[6]; //mxd. Sprite mirroring float ul = (info.SpriteFrame[i].Mirror ? 1f : 0f); float ur = (info.SpriteFrame[i].Mirror ? 0f : 1f); if (sizeless) //mxd { float hh = height / 2; verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ul, 1.0f); verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ul, 0.0f); verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ur, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ur, 1.0f); } else { verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y, sectorcolor, ul, 1.0f); verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ul, 0.0f); verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ur, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y, sectorcolor, ur, 1.0f); } allverts[i] = verts; } else { isloaded = false; base.textures[i] = General.Map.Data.Hourglass3D; // Determine sprite size float radius = Math.Min(thingradius, thingheight / 2f); float height = Math.Min(thingradius * 2f, thingheight); //mxd. Determine sprite offsets offsets.x = radius; offsets.y = height / 2; // Make vertices WorldVertex[] verts = new WorldVertex[6]; verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f); verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f); verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f); allverts[i] = verts; } //mxd. Store offsets alloffsets[i] = offsets; } //mxd SetVertices(allverts, alloffsets /*, floor, ceiling*/); // Determine position Vector3D pos = Thing.Position; if (Thing.Type == 9501) { if (Thing.Sector != null) //mxd { // 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) { if (Thing.Sector != null) //mxd { // 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); float maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; pos.z = maxz; if (Thing.Position.z > 0 || nointeraction) { pos.z -= Thing.Position.z; } // Check if below floor if (!nointeraction) { float minz = sd.Floor.plane.GetZ(Thing.Position); if (pos.z < minz) { pos.z = Math.Min(minz, maxz); } } } } else { // Stand on floor if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); float minz = sd.Floor.plane.GetZ(Thing.Position); pos.z = minz; if (Thing.Position.z > 0 || nointeraction) { pos.z += Thing.Position.z; } // Check if above ceiling if (!nointeraction) { float maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; if (pos.z > maxz) { pos.z = Math.Max(minz, maxz); } } } } // Apply settings SetPosition(pos); SetCageColor(Thing.Color); // Keep info for object picking cageradius2 = thingradius * Angle2D.SQRT2; cageradius2 = cageradius2 * cageradius2; pos2d = pos; if (sizeless) //mxd { boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z - thingradius / 2); boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingradius / 2); } else { boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z); boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingheight); } // Done changed = false; return(true); }
public bool Setup(Effect3DFloor extrafloor) { Vector2D vl, vr; Sidedef sourceside = extrafloor.Linedef.Front; this.extrafloor = extrafloor; int lightvalue = Sidedef.Fields.GetValue("light", 0); bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false); Vector2D tscale = new Vector2D(sourceside.Fields.GetValue("scalex_mid", 1.0f), sourceside.Fields.GetValue("scaley_mid", 1.0f)); Vector2D toffset1 = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); Vector2D toffset2 = new Vector2D(sourceside.Fields.GetValue("offsetx_mid", 0.0f), sourceside.Fields.GetValue("offsety_mid", 0.0f)); // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); // Texture given? if ((sourceside.MiddleTexture.Length > 0) && (sourceside.MiddleTexture[0] != '-')) { // Load texture base.Texture = General.Map.Data.GetTextureImage(sourceside.LongMiddleTexture); if (base.Texture == null) { base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = sourceside.LongMiddleTexture; } else { if (!base.Texture.IsImageLoaded) { setuponloadedtexture = sourceside.LongMiddleTexture; } } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset1 + toffset2; tof = tof / tscale; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // For Vavoom type 3D floors the ceiling is lower than floor and they are reversed. // We choose here. float sourcetopheight = extrafloor.VavoomType ? sourceside.Sector.FloorHeight : sourceside.Sector.CeilHeight; float sourcebottomheight = extrafloor.VavoomType ? sourceside.Sector.CeilHeight : sourceside.Sector.FloorHeight; // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (sourcetopheight == sourcebottomheight) ? 1.0f : 0.0f; tp.trb.x = tp.tlt.x + Sidedef.Line.Length; tp.trb.y = tp.tlt.y + (sourcetopheight - sourcebottomheight) + floorbias; // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, sourcetopheight); tp.vrb = new Vector3D(vr.x, vr.y, sourcebottomheight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Get ceiling and floor heights float fl = sd.Floor.plane.GetZ(vl); float fr = sd.Floor.plane.GetZ(vr); float cl = sd.Ceiling.plane.GetZ(vl); float cr = sd.Ceiling.plane.GetZ(vr); // Anything to see? if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f)) { // Keep top and bottom planes for intersection testing top = extrafloor.Floor.plane; bottom = extrafloor.Ceiling.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, fl)); poly.Add(new Vector3D(vl.x, vl.y, cl)); poly.Add(new Vector3D(vr.x, vr.y, cr)); poly.Add(new Vector3D(vr.x, vr.y, fr)); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part above the 3D floor and below the 3D ceiling CropPoly(ref poly, extrafloor.Floor.plane, false); CropPoly(ref poly, extrafloor.Ceiling.plane, false); // Cut out pieces that overlap 3D floors in this sector List <WallPolygon> polygons = new List <WallPolygon>(1); polygons.Add(poly); foreach (Effect3DFloor ef in sd.ExtraFloors) { // Same 3D floor and other floors that are not translucent will clip my walls if ((ef.Alpha == 255) || (ef.Linedef.Front.Sector == extrafloor.Linedef.Front.Sector)) { int num = polygons.Count; for (int pi = 0; pi < num; pi++) { // Split by floor plane of 3D floor WallPolygon p = polygons[pi]; WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true); if (np.Count > 0) { // Split part below floor by the ceiling plane of 3D floor // and keep only the part below the ceiling (front) SplitPoly(ref np, ef.Floor.plane, true); if (p.Count == 0) { polygons[pi] = np; } else { polygons[pi] = p; polygons.Add(np); } } else { polygons[pi] = p; } } } } // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 0) { if (extrafloor.Alpha < 255) { // Apply alpha to vertices byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255); if (alpha < 255) { for (int i = 0; i < verts.Count; i++) { WorldVertex v = verts[i]; PixelColor c = PixelColor.FromInt(v.c); v.c = c.WithAlpha(alpha).ToInt(); verts[i] = v; } } this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } base.SetVertices(verts); return(true); } } return(false); }
public bool Setup(Effect3DFloor extrafloor) { Sidedef sourceside = extrafloor.Linedef.Front; this.extrafloor = extrafloor; //mxd. Extrafloor may've become invalid during undo/redo... if (sourceside == null) { base.SetVertices(null); return(false); } Vector2D vl, vr; //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(sourceside.Fields.GetValue("scalex_mid", 1.0f), sourceside.Fields.GetValue("scaley_mid", 1.0f)); Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset1 = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); Vector2D toffset2 = new Vector2D(sourceside.Fields.GetValue("offsetx_mid", 0.0f), sourceside.Fields.GetValue("offsety_mid", 0.0f)); // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); //mxd. which texture we must use? long texturelong = 0; if ((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0) { if (Sidedef.LongHighTexture != MapSet.EmptyLongName) { texturelong = Sidedef.LongHighTexture; } } else if ((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0) { if (Sidedef.LongLowTexture != MapSet.EmptyLongName) { texturelong = Sidedef.LongLowTexture; } } else if (sourceside.LongMiddleTexture != MapSet.EmptyLongName) { texturelong = sourceside.LongMiddleTexture; } // Texture given? if (texturelong != 0) { // Load texture base.Texture = General.Map.Data.GetTextureImage(texturelong); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = texturelong; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = texturelong; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY) + new Vector2D(sourceside.OffsetX, sourceside.OffsetY); tof = tof + toffset1 + toffset2; tof = tof / tscaleAbs; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // For Vavoom type 3D floors the ceiling is lower than floor and they are reversed. // We choose here. float sourcetopheight = extrafloor.VavoomType ? sourceside.Sector.FloorHeight : sourceside.Sector.CeilHeight; float sourcebottomheight = extrafloor.VavoomType ? sourceside.Sector.CeilHeight : sourceside.Sector.FloorHeight; // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (sourcetopheight == sourcebottomheight) ? 1.0f : 0.0f; tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (sourcetopheight - sourcebottomheight) + floorbias; // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, sourcetopheight); tp.vrb = new Vector3D(vr.x, vr.y, sourcebottomheight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); //mxd. Get ceiling and floor heights. Use our and neighbour sector's data SectorData sdo = mode.GetSectorData(Sidedef.Other.Sector); float flo = sdo.Floor.plane.GetZ(vl); float fro = sdo.Floor.plane.GetZ(vr); float clo = sdo.Ceiling.plane.GetZ(vl); float cro = sdo.Ceiling.plane.GetZ(vr); float fle = sd.Floor.plane.GetZ(vl); float fre = sd.Floor.plane.GetZ(vr); float cle = sd.Ceiling.plane.GetZ(vl); float cre = sd.Ceiling.plane.GetZ(vr); float fl = flo > fle ? flo : fle; float fr = fro > fre ? fro : fre; float cl = clo < cle ? clo : cle; float cr = cro < cre ? cro : cre; // Anything to see? if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f)) { // Keep top and bottom planes for intersection testing top = extrafloor.Floor.plane; bottom = extrafloor.Ceiling.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, fl)); poly.Add(new Vector3D(vl.x, vl.y, cl)); poly.Add(new Vector3D(vr.x, vr.y, cr)); poly.Add(new Vector3D(vr.x, vr.y, fr)); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part above the 3D floor and below the 3D ceiling CropPoly(ref poly, extrafloor.Floor.plane, false); CropPoly(ref poly, extrafloor.Ceiling.plane, false); // Cut out pieces that overlap 3D floors in this sector List <WallPolygon> polygons = new List <WallPolygon> { poly }; bool translucent = (extrafloor.RenderAdditive || extrafloor.Alpha < 255); foreach (Effect3DFloor ef in sd.ExtraFloors) { //mxd. Our poly should be clipped when our ond other extrafloors are both solid or both translucent, // or when only our extrafloor is translucent. // Our poly should not be clipped when our extrafloor is translucent and the other one isn't and both have renderinside setting. bool othertranslucent = (ef.RenderAdditive || ef.Alpha < 255); if (translucent && !othertranslucent && !ef.ClipSidedefs) { continue; } if (ef.ClipSidedefs == extrafloor.ClipSidedefs || ef.ClipSidedefs) { //TODO: find out why ef can be not updated at this point //TODO: [this crashed on me once when performing auto-align on myriad of textures on BoA C1M0] if (ef.Floor == null || ef.Ceiling == null) { ef.Update(); } int num = polygons.Count; for (int pi = 0; pi < num; pi++) { // Split by floor plane of 3D floor WallPolygon p = polygons[pi]; WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true); if (np.Count > 0) { // Split part below floor by the ceiling plane of 3D floor // and keep only the part below the ceiling (front) SplitPoly(ref np, ef.Floor.plane, true); if (p.Count == 0) { polygons[pi] = np; } else { polygons[pi] = p; polygons.Add(np); } } else { polygons[pi] = p; } } } } // Process the polygon and create vertices if (polygons.Count > 0) { List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { if (extrafloor.Sloped3dFloor) { this.RenderPass = RenderPass.Mask; //mxd } else if (extrafloor.RenderAdditive) { this.RenderPass = RenderPass.Additive; //mxd } else if ((extrafloor.Alpha < 255) || Texture.IsTranslucent) { this.RenderPass = RenderPass.Alpha; // [ZZ] translucent texture should trigger Alpha pass } else { this.RenderPass = RenderPass.Mask; } if (extrafloor.Alpha < 255) { // Apply alpha to vertices byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255); if (alpha < 255) { for (int i = 0; i < verts.Count; i++) { WorldVertex v = verts[i]; v.c = PixelColor.FromInt(v.c).WithAlpha(alpha).ToInt(); verts[i] = v; } } } base.SetVertices(verts); return(true); } } } base.SetVertices(null); //mxd return(false); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { Vector2D vl, vr; //mxd. Apply sky hack? UpdateSkyRenderFlag(); //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f), Sidedef.Fields.GetValue("scaley_mid", 1.0f)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); // Texture given? if (Sidedef.LongMiddleTexture != MapSet.EmptyLongName) { // Load texture base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongMiddleTexture; } else { if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongMiddleTexture; } } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; tof = tof / tscale; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f; if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { // When lower unpegged is set, the middle texture is bound to the bottom tp.tlt.y = tsz.y - (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight); } tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Sector.FloorHeight + floorbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Get ceiling and floor heights float fl = sd.Floor.plane.GetZ(vl); float fr = sd.Floor.plane.GetZ(vr); float cl = sd.Ceiling.plane.GetZ(vl); float cr = sd.Ceiling.plane.GetZ(vr); // Anything to see? if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f)) { // Keep top and bottom planes for intersection testing top = sd.Ceiling.plane; bottom = sd.Floor.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, fl)); poly.Add(new Vector3D(vl.x, vl.y, cl)); poly.Add(new Vector3D(vr.x, vr.y, cr)); poly.Add(new Vector3D(vr.x, vr.y, fr)); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut out pieces that overlap 3D floors in this sector List <WallPolygon> polygons = new List <WallPolygon> { poly }; ClipExtraFloors(polygons, sd.ExtraFloors, false); //mxd if (polygons.Count > 0) { // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { base.SetVertices(verts); return(true); } } } base.SetVertices(null); //mxd return(false); }
// This builds the thing geometry. Returns false when nothing was created. public bool Setup() { // Find the sector in which the thing resides Thing.DetermineSector(mode.BlockMap); //mxd. If the thing is inside a sector, apply DECORATE/UDMF alpha/renderstyle overrides byte alpha = 255; if (Thing.Sector != null) { string renderstyle = info.RenderStyle.ToLowerInvariant(); alpha = info.AlphaByte; if (General.Map.UDMF) { if (Thing.IsFlagSet("translucent")) { renderstyle = "translucent"; alpha = 64; } else if (Thing.IsFlagSet("invisible")) { renderstyle = "none"; alpha = 0; } else if (Thing.Fields.ContainsKey("renderstyle")) { renderstyle = Thing.Fields.GetValue("renderstyle", renderstyle).ToLowerInvariant(); } if ((renderstyle == "add" || renderstyle == "translucent" || renderstyle == "subtract" || renderstyle == "translucentstencil") && Thing.Fields.ContainsKey("alpha")) { alpha = (byte)(General.Clamp(Thing.Fields.GetValue("alpha", info.Alpha), 0.0, 1.0) * 255.0); } else if (renderstyle == "soultrans") { // Lost Soul trasparency is controlled by a CVAR (see https://zdoom.org/wiki/CVARs:Display#transsouls), let's use the default 0.75 here alpha = 192; } else if (renderstyle == "shadow") { alpha = 76; // about 0.3 stencilColor = PixelColor.FromInt(PixelColor.INT_BLACK); } if (renderstyle.EndsWith("stencil")) { stencilColor = PixelColor.FromInt(UniFields.GetInteger(Thing.Fields, "fillcolor", 0)); stencilColor.a = 255; // 0xFF alpha means nothing was read. 0x00 alpha means there was a valid fillcolor. } else if (renderstyle != "shadow") { stencilColor.a = 0; } } else if (General.Map.HEXEN) { if (Thing.IsFlagSet("2048")) { renderstyle = "translucent"; alpha = 64; } else if (Thing.IsFlagSet("4096")) { renderstyle = "none"; alpha = 0; } } // Set appropriate RenderPass switch (renderstyle) { case "translucent": case "subtract": case "soultrans": case "translucentstencil": case "shadow": RenderPass = RenderPass.Alpha; break; case "add": case "addstencil": RenderPass = RenderPass.Additive; break; case "none": RenderPass = RenderPass.Mask; alpha = 0; break; // Many render styles are not supported yet... default: RenderPass = RenderPass.Mask; alpha = 255; break; } } int sectorcolor = new PixelColor(alpha, 255, 255, 255).ToInt(); fogfactor = 0f; //mxd //mxd. Check thing size float thingradius = Thing.Size; // Thing.Size has ThingRadius arg override applied thingheight = Thing.Height; // Thing.Height has ThingHeight arg override applied if (thingradius < 0.1f || thingheight < 0.1f) { thingradius = FIXED_RADIUS; thingheight = FIXED_RADIUS; sizeless = true; } else { sizeless = false; } if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); Plane floor = sd.Floor.plane; //mxd if (!info.Bright) { Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); SectorLevel level = sd.GetLevelAboveOrAt(thingpos); //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight; if (nointeraction && level == null && sd.LightLevels.Count > 0) { level = sd.LightLevels[sd.LightLevels.Count - 1]; } //mxd. Use the light level of the highest surface when a thing is above highest sector level. if (level != null) { // TECH: In GZDoom, ceiling glow doesn't affect thing brightness // Use sector brightness for color shading int brightness = level.brightnessbelow; //mxd. Apply lightfloor value // According to Graf, this is incorrect behaviour... // TECH: In (G)ZDoom, this is ignored when ceiling texture is sky or a thing is below a 3D floor // It's probably more involved than this, but for now let's do it only when there are no 3d floors in Thing.Sector... /*if(General.Map.UDMF && sd.LightLevels.Count == 2 && Thing.Sector.CeilTexture != General.Map.Config.SkyFlatName) * { * if(sd.Sector.Fields.GetValue("lightfloorabsolute", false)) * brightness = UniFields.GetInteger(sd.Sector.Fields, "lightfloor"); * else * brightness += UniFields.GetInteger(sd.Sector.Fields, "lightfloor"); * }*/ // Level is glowing if (level.affectedbyglow && level.type == SectorLevelType.Floor) { // Extrafloor glow doesn't affect thing brightness if (level.sector == Thing.Sector) { double planez = level.plane.GetZ(thingpos); // Get glow brightness int glowbrightness = sd.FloorGlow.Brightness / 2; SectorLevel nexthigher = sd.GetLevelAbove(new Vector3D(thingpos, planez)); // Interpolate thing brightness between glow and regular ones if (nexthigher != null) { double higherz = nexthigher.plane.GetZ(thingpos); double delta = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f); brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta)); } } } // Level below this one is glowing. Only possible for floor glow(?) else if (level.type == SectorLevelType.Glow) { // Interpolate thing brightness between glow and regular ones if (sd.Floor != null && sd.FloorGlow != null) { // Get glow brightness double glowz = level.plane.GetZ(thingpos); double floorz = floor.GetZ(thingpos); double delta = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f); brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta); } } PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness)); PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness); // [ZZ] if sector is using Doom64 lighting, apply thing color here. sectorcolor = PixelColor.Modulate(sd.ColorSprites, areacolor).WithAlpha(alpha).ToInt(); //mxd. Calculate fogfactor fogfactor = VisualGeometry.CalculateFogFactor(level.sector, brightness); } } //TECH: even Bright Thing frames are affected by custom fade... else { Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); SectorLevel level = sd.GetLevelAboveOrAt(thingpos); if (level != null && level.sector.FogMode > SectorFogMode.CLASSIC) { //mxd. Calculate fogfactor fogfactor = VisualGeometry.CalculateFogFactor(level.sector, level.brightnessbelow); } } } //mxd. Create verts for all sprite angles WorldVertex[][] allverts = new WorldVertex[info.SpriteFrame.Length][]; Vector2D[] alloffsets = new Vector2D[info.SpriteFrame.Length]; base.textures = new ImageData[info.SpriteFrame.Length]; isloaded = true; for (int i = 0; i < sprites.Length; i++) { Vector2D offsets = new Vector2D(); // Check if the texture is loaded ImageData sprite = sprites[i]; if (!sprite.IsImageLoaded && !sprite.LoadFailed) { sprite.LoadImageNow(); } if (sprite.IsImageLoaded) { base.textures[i] = sprite; // Determine sprite size and offset float radius = sprite.ScaledWidth * 0.5f; float height = sprite.ScaledHeight; ISpriteImage spriteimg = sprite as ISpriteImage; if (spriteimg != null) { offsets.x = radius - spriteimg.OffsetX; offsets.y = spriteimg.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; offsets.x *= info.SpriteScale.Width; offsets.y *= info.SpriteScale.Height; // Make vertices WorldVertex[] verts = new WorldVertex[6]; //mxd. Sprite mirroring float ul = (info.SpriteFrame[i].Mirror ? 1f : 0f); float ur = (info.SpriteFrame[i].Mirror ? 0f : 1f); if (sizeless) //mxd { float hh = height / 2; verts[0] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(offsets.y - hh), sectorcolor, ul, 1.0f); verts[1] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(hh + offsets.y), sectorcolor, ul, 0.0f); verts[2] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(hh + offsets.y), sectorcolor, ur, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(offsets.y - hh), sectorcolor, ur, 1.0f); } else { verts[0] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)offsets.y, sectorcolor, ul, 1.0f); verts[1] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(height + offsets.y), sectorcolor, ul, 0.0f); verts[2] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(height + offsets.y), sectorcolor, ur, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)offsets.y, sectorcolor, ur, 1.0f); } allverts[i] = verts; } else { isloaded = false; base.textures[i] = sprite; // Determine sprite size float radius = Math.Min(thingradius, thingheight / 2f); float height = Math.Min(thingradius * 2f, thingheight); //mxd. Determine sprite offsets offsets.x = radius; offsets.y = height / 2; // Make vertices WorldVertex[] verts = new WorldVertex[6]; verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f); verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f); verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f); verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f); allverts[i] = verts; } //mxd. Store offsets alloffsets[i] = offsets; } //mxd SetVertices(allverts, alloffsets /*, floor, ceiling*/); // Determine position Vector3D pos = Thing.Position; if (Thing.Type == 9501) { if (Thing.Sector != null) //mxd { // 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) { if (Thing.Sector != null) //mxd { // 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); double maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; pos.z = maxz; if (Thing.Position.z > 0 || nointeraction) { pos.z -= Thing.Position.z; } // Check if below floor if (!nointeraction) { double minz = sd.Floor.plane.GetZ(Thing.Position); if (pos.z < minz) { pos.z = Math.Min(minz, maxz); } } } } else { // Stand on floor if (Thing.Sector != null) { SectorData sd = mode.GetSectorData(Thing.Sector); double minz = sd.Floor.plane.GetZ(Thing.Position); pos.z = minz; if (Thing.Position.z > 0 || nointeraction) { pos.z += Thing.Position.z; } // Check if above ceiling if (!nointeraction) { double maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height; if (pos.z > maxz) { pos.z = Math.Max(minz, maxz); } } } } // Apply settings SetPosition(pos); SetCageColor(Thing.Color); // Keep info for object picking cageradius2 = thingradius * Angle2D.SQRT2; cageradius2 = cageradius2 * cageradius2; pos2d = pos; if (sizeless) //mxd { boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z - thingradius / 2); boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingradius / 2); } else { boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z); boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingheight); } // Done changed = false; return(true); }
// Constructor internal ConfigurationInfo(Configuration cfg, string filename) { // Initialize this.filename = filename; this.config = cfg; //mxd this.settingskey = Path.GetFileNameWithoutExtension(filename).ToLower(); // Load settings from game configuration this.name = config.ReadSetting("game", "<unnamed game>"); this.defaultlumpname = config.ReadSetting("defaultlumpname", ""); // Load settings from program configuration this.nodebuildersave = General.Settings.ReadSetting("configurations." + settingskey + ".nodebuildersave", MISSING_NODEBUILDER); this.nodebuildertest = General.Settings.ReadSetting("configurations." + settingskey + ".nodebuildertest", MISSING_NODEBUILDER); this.formatinterface = config.ReadSetting("formatinterface", "").ToLowerInvariant(); //mxd this.defaultscriptcompiler = cfg.ReadSetting("defaultscriptcompiler", ""); //mxd this.resources = new DataLocationList(General.Settings.Config, "configurations." + settingskey + ".resources"); this.startmode = General.Settings.ReadSetting("configurations." + settingskey + ".startmode", "VerticesMode"); this.enabled = General.Settings.ReadSetting("configurations." + settingskey + ".enabled", config.ReadSetting("enabledbydefault", false)); //mxd //mxd. Read test engines testEngines = new List <EngineInfo>(); IDictionary list = General.Settings.ReadSetting("configurations." + settingskey + ".engines", new ListDictionary()); currentEngineIndex = Math.Max(0, General.Settings.ReadSetting("configurations." + settingskey + ".currentengineindex", 0)); // No engine list found? Use old engine properties if (list.Count == 0) { EngineInfo info = new EngineInfo(); info.TestProgram = General.Settings.ReadSetting("configurations." + settingskey + ".testprogram", ""); info.TestProgramName = General.Settings.ReadSetting("configurations." + settingskey + ".testprogramname", EngineInfo.DEFAULT_ENGINE_NAME); info.TestParameters = General.Settings.ReadSetting("configurations." + settingskey + ".testparameters", ""); info.TestShortPaths = General.Settings.ReadSetting("configurations." + settingskey + ".testshortpaths", false); info.CustomParameters = General.Settings.ReadSetting("configurations." + settingskey + ".customparameters", false); info.TestSkill = General.Settings.ReadSetting("configurations." + settingskey + ".testskill", 3); testEngines.Add(info); currentEngineIndex = 0; } else { //read engines settings from config foreach (DictionaryEntry de in list) { string path = "configurations." + settingskey + ".engines." + de.Key; EngineInfo info = new EngineInfo(); info.TestProgram = General.Settings.ReadSetting(path + ".testprogram", ""); info.TestProgramName = General.Settings.ReadSetting(path + ".testprogramname", EngineInfo.DEFAULT_ENGINE_NAME); info.TestParameters = General.Settings.ReadSetting(path + ".testparameters", ""); info.TestShortPaths = General.Settings.ReadSetting(path + ".testshortpaths", false); info.CustomParameters = General.Settings.ReadSetting(path + ".customparameters", false); info.TestSkill = General.Settings.ReadSetting(path + ".testskill", 3); testEngines.Add(info); } if (currentEngineIndex >= testEngines.Count) { currentEngineIndex = 0; } } //mxd. read custom linedef colors List <LinedefColorPreset> colorPresets = new List <LinedefColorPreset>(); list = General.Settings.ReadSetting("configurations." + settingskey + ".linedefcolorpresets", new ListDictionary()); //no presets? add "classic" ones then. if (list.Count == 0) { colorPresets.Add(new LinedefColorPreset("Any action", PixelColor.FromColor(System.Drawing.Color.PaleGreen), -1, 0, new List <string>(), new List <string>(), true)); } else { //read custom linedef colors from config foreach (DictionaryEntry de in list) { string path = "configurations." + settingskey + ".linedefcolorpresets." + de.Key; string presetname = General.Settings.ReadSetting(path + ".name", "Unnamed"); bool presetenabled = General.Settings.ReadSetting(path + ".enabled", true); PixelColor color = PixelColor.FromInt(General.Settings.ReadSetting(path + ".color", -1)); int action = General.Settings.ReadSetting(path + ".action", 0); int activation = General.Settings.ReadSetting(path + ".activation", 0); List <string> flags = new List <string>(); flags.AddRange(General.Settings.ReadSetting(path + ".flags", "").Split(LINEDEF_COLOR_PRESET_FLAGS_SEPARATOR, StringSplitOptions.RemoveEmptyEntries)); List <string> restrictedFlags = new List <string>(); restrictedFlags.AddRange(General.Settings.ReadSetting(path + ".restrictedflags", "").Split(LINEDEF_COLOR_PRESET_FLAGS_SEPARATOR, StringSplitOptions.RemoveEmptyEntries)); LinedefColorPreset preset = new LinedefColorPreset(presetname, color, action, activation, flags, restrictedFlags, presetenabled); colorPresets.Add(preset); } } linedefColorPresets = colorPresets.ToArray(); // Make list of things filters thingsfilters = new List <ThingsFilter>(); IDictionary cfgfilters = General.Settings.ReadSetting("configurations." + settingskey + ".thingsfilters", new Hashtable()); foreach (DictionaryEntry de in cfgfilters) { thingsfilters.Add(new ThingsFilter(General.Settings.Config, "configurations." + settingskey + ".thingsfilters." + de.Key)); } // Make list of texture sets texturesets = new List <DefinedTextureSet>(); IDictionary sets = General.Settings.ReadSetting("configurations." + settingskey + ".texturesets", new Hashtable()); foreach (DictionaryEntry de in sets) { texturesets.Add(new DefinedTextureSet(General.Settings.Config, "configurations." + settingskey + ".texturesets." + de.Key)); } // Make list of edit modes this.editmodes = new Dictionary <string, bool>(StringComparer.Ordinal); IDictionary modes = General.Settings.ReadSetting("configurations." + settingskey + ".editmodes", new Hashtable()); foreach (DictionaryEntry de in modes) { if (de.Key.ToString().StartsWith(MODE_ENABLED_KEY)) { editmodes.Add(de.Value.ToString(), true); } else if (de.Key.ToString().StartsWith(MODE_DISABLED_KEY)) { editmodes.Add(de.Value.ToString(), false); } } }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { //mxd if (Sidedef.LongMiddleTexture == MapSet.EmptyLongName) { base.SetVertices(null); return(false); } Vector2D vl, vr; //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f), Sidedef.Fields.GetValue("scaley_mid", 1.0f)); Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } // Load texture if (Sidedef.LongMiddleTexture != MapSet.EmptyLongName) { base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongMiddleTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongMiddleTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; tof = tof / tscaleAbs; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f; float geotop = Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight); float geobottom = Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight); float zoffset = Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight; //mxd // When lower unpegged is set, the middle texture is bound to the bottom if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { tp.tlt.y = tsz.y - (geotop - geobottom); } if (zoffset > 0) { tp.tlt.y -= zoffset; //mxd } tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Sector.FloorHeight + floorbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Keep top and bottom planes for intersection testing top = sd.Ceiling.plane; bottom = sd.Floor.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl))); poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl))); poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr))); poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr))); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part below the other floor and above the other ceiling CropPoly(ref poly, osd.Ceiling.plane, true); CropPoly(ref poly, osd.Floor.plane, true); // Determine if we should repeat the middle texture repeatmidtex = Sidedef.IsFlagSet("wrapmidtex") || Sidedef.Line.IsFlagSet("wrapmidtex"); //mxd if (!repeatmidtex) { // First determine the visible portion of the texture float textop; // Determine top portion height if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { textop = geobottom + tof.y + Math.Abs(tsz.y); } else { textop = geotop + tof.y; } // Calculate bottom portion height float texbottom = textop - Math.Abs(tsz.y); // Create crop planes (we also need these for intersection testing) topclipplane = new Plane(new Vector3D(0, 0, -1), textop); bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom); // Crop polygon by these heights CropPoly(ref poly, topclipplane, true); CropPoly(ref poly, bottomclipplane, true); } //mxd. In(G)ZDoom, middle sidedef parts are not clipped by extrafloors of any type... List <WallPolygon> polygons = new List <WallPolygon> { poly }; //ClipExtraFloors(polygons, sd.ExtraFloors, true); //mxd //ClipExtraFloors(polygons, osd.ExtraFloors, true); //mxd //if(polygons.Count > 0) //{ // Keep top and bottom planes for intersection testing top = osd.Ceiling.plane; bottom = osd.Floor.plane; // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { // Apply alpha to vertices byte alpha = SetLinedefRenderstyle(true); if (alpha < 255) { for (int i = 0; i < verts.Count; i++) { WorldVertex v = verts[i]; v.c = PixelColor.FromInt(v.c).WithAlpha(alpha).ToInt(); verts[i] = v; } } base.SetVertices(verts); return(true); } //} base.SetVertices(null); //mxd return(false); }
// This sets up the basic floor and ceiling, as they would be in normal Doom circumstances private void BasicSetup() { //mxd if (sector.FloorSlope.GetLengthSq() > 0 && !float.IsNaN(sector.FloorSlopeOffset / sector.FloorSlope.z)) { // Sloped plane floor.plane = new Plane(sector.FloorSlope, sector.FloorSlopeOffset); } else { // Normal (flat) floor plane floor.plane = new Plane(new Vector3D(0, 0, 1), -sector.FloorHeight); } if (sector.CeilSlope.GetLengthSq() > 0 && !float.IsNaN(sector.CeilSlopeOffset / sector.CeilSlope.z)) { // Sloped plane ceiling.plane = new Plane(sector.CeilSlope, sector.CeilSlopeOffset); } else { // Normal (flat) ceiling plane ceiling.plane = new Plane(new Vector3D(0, 0, -1), sector.CeilHeight); } // Fetch ZDoom fields int color = sector.Fields.GetValue("lightcolor", -1); lightfloor = sector.Fields.GetValue("lightfloor", 0); lightfloorabsolute = sector.Fields.GetValue("lightfloorabsolute", false); lightceiling = sector.Fields.GetValue("lightceiling", 0); lightceilingabsolute = sector.Fields.GetValue("lightceilingabsolute", false); if (!lightfloorabsolute) { lightfloor = sector.Brightness + lightfloor; } if (!lightceilingabsolute) { lightceiling = sector.Brightness + lightceiling; } // Determine colors & light levels // [ZZ] Doom64 lighting // // ceiling/floor ColorCeiling = PixelColor.FromInt(sector.Fields.GetValue("color_ceiling", PixelColor.INT_WHITE)); ColorFloor = PixelColor.FromInt(sector.Fields.GetValue("color_floor", PixelColor.INT_WHITE)); ColorSprites = PixelColor.FromInt(sector.Fields.GetValue("color_sprites", PixelColor.INT_WHITE)); ColorWallTop = PixelColor.FromInt(sector.Fields.GetValue("color_walltop", PixelColor.INT_WHITE)); ColorWallBottom = PixelColor.FromInt(sector.Fields.GetValue("color_wallbottom", PixelColor.INT_WHITE)); PixelColor floorbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightfloor)); PixelColor ceilingbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightceiling)); PixelColor lightcolor = PixelColor.FromInt(color); PixelColor floorcolor = PixelColor.Modulate(ColorFloor, PixelColor.Modulate(lightcolor, floorbrightness)); PixelColor ceilingcolor = PixelColor.Modulate(ColorCeiling, PixelColor.Modulate(lightcolor, ceilingbrightness)); floor.color = floorcolor.WithAlpha(255).ToInt(); floor.brightnessbelow = sector.Brightness; floor.colorbelow = lightcolor.WithAlpha(255); ceiling.color = ceilingcolor.WithAlpha(255).ToInt(); ceiling.brightnessbelow = sector.Brightness; ceiling.colorbelow = lightcolor.WithAlpha(255); //mxd. Store a copy of initial settings floor.CopyProperties(floorbase); ceiling.CopyProperties(ceilingbase); //mxd. We need sector brightness here, unaffected by custom ceiling brightness... ceilingbase.brightnessbelow = sector.Brightness; ceilingbase.color = PixelColor.FromInt(mode.CalculateBrightness(sector.Brightness)).WithAlpha(255).ToInt(); //mxd glowingflateffect.Update(); }
private void bReset_Click(object sender, EventArgs e) { cpColor.Focus(); // Otherwise the focus will go to cpColor's textbox, which is not what we want cpColor.Color = PixelColor.FromInt(defaultvalue).WithAlpha(255); cpColor_ColorChanged(this, EventArgs.Empty); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { Vector2D vl, vr; int lightvalue = Sidedef.Fields.GetValue("light", 0); bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f), Sidedef.Fields.GetValue("scaley_mid", 1.0f)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); // Texture given? if ((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-')) { // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } // Texture given? if ((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-')) { // Load texture base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture); if (base.Texture == null) { base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = Sidedef.LongMiddleTexture; } else { if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongMiddleTexture; } } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; tof = tof / tscale; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f; float geotop = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight); float geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight); if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { // When lower unpegged is set, the middle texture is bound to the bottom tp.tlt.y = tsz.y - (float)(geotop - geobottom); } tp.trb.x = tp.tlt.x + Sidedef.Line.Length; tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Keep top and bottom planes for intersection testing top = sd.Ceiling.plane; bottom = sd.Floor.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl))); poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl))); poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr))); poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr))); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part below the other floor and above the other ceiling CropPoly(ref poly, osd.Ceiling.plane, true); CropPoly(ref poly, osd.Floor.plane, true); // Determine if we should repeat the middle texture if (Sidedef.Fields.ContainsKey("wrapmidtex")) { repeatmidtex = Sidedef.Fields.GetValue("wrapmidtex", false); } else { repeatmidtex = Sidedef.Line.IsFlagSet("wrapmidtex"); } if (!repeatmidtex) { // First determine the visible portion of the texture float textop, texbottom; // Determine top portion height if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { textop = geobottom + tof.y + tsz.y; } else { textop = geotop + tof.y; } // Calculate bottom portion height texbottom = textop - tsz.y; // Create crop planes (we also need these for intersection testing) topclipplane = new Plane(new Vector3D(0, 0, -1), textop); bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom); // Crop polygon by these heights CropPoly(ref poly, topclipplane, true); CropPoly(ref poly, bottomclipplane, true); } if (poly.Count > 2) { // Keep top and bottom planes for intersection testing top = osd.Ceiling.plane; bottom = osd.Floor.plane; // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute); if (verts.Count > 0) { // Apply alpha to vertices byte alpha = SetLinedefRenderstyle(true); if (alpha < 255) { for (int i = 0; i < verts.Count; i++) { WorldVertex v = verts[i]; PixelColor c = PixelColor.FromInt(v.c); v.c = c.WithAlpha(alpha).ToInt(); verts[i] = v; } } base.SetVertices(verts); return(true); } } } return(false); }
//mxd public bool Setup(SectorLevel level, Effect3DFloor extrafloor, bool innerside) { Sector s = level.sector; Vector2D texscale; this.innerside = innerside; base.Setup(level, extrafloor); // Fetch ZDoom fields float rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationfloor", 0.0f)); Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f), s.Fields.GetValue("ypanningfloor", 0.0f)); Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f), s.Fields.GetValue("yscalefloor", 1.0f)); //Load floor texture if (s.LongFloorTexture != MapSet.EmptyLongName) { base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = s.LongFloorTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = s.LongFloorTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // 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); } // Determine brightness int color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); //mxd. Top extrafloor level should calculate fogdensity //from the brightness of the level above it int targetbrightness; if (extrafloor != null && extrafloor.VavoomType && !level.disablelighting) { targetbrightness = 0; SectorData sd = mode.GetSectorData(this.Sector.Sector); for (int i = 0; i < sd.LightLevels.Count - 1; i++) { if (sd.LightLevels[i] == level) { targetbrightness = sd.LightLevels[i + 1].brightnessbelow; break; } } } else { targetbrightness = level.brightnessbelow; } //mxd. Determine fog density fogfactor = CalculateFogFactor(targetbrightness); // Make vertices ReadOnlyCollection <Vector2D> triverts = Sector.Sector.Triangles.Vertices; WorldVertex[] verts = new WorldVertex[triverts.Count]; for (int i = 0; i < triverts.Count; i++) { // Color shading verts[i].c = color; //mxd // Vertex coordinates verts[i].x = triverts[i].x; verts[i].y = triverts[i].y; verts[i].z = level.plane.GetZ(triverts[i]); // 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 && !innerside) { SwapTriangleVertices(verts); } // Determine render pass if (extrafloor != null) { if (extrafloor.Sloped3dFloor) //mxd { this.RenderPass = RenderPass.Mask; } else if (extrafloor.RenderAdditive) //mxd { this.RenderPass = RenderPass.Additive; } else if (level.alpha < 255) { this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } } else { this.RenderPass = RenderPass.Solid; } //mxd. Update sky render flag UpdateSkyRenderFlag(); // Apply vertices base.SetVertices(verts); return(verts.Length > 0); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { Vector2D vl, vr; // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = Sector.GetSectorData(); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } //mxd double vlzf = sd.Floor.plane.GetZ(vl); double vrzf = sd.Floor.plane.GetZ(vr); double ovlzf = osd.Floor.plane.GetZ(vl); double ovrzf = osd.Floor.plane.GetZ(vr); //mxd. Side is visible when our sector's floor is lower than the other's at any vertex if (!(vlzf < ovlzf || vrzf < ovrzf)) { base.SetVertices(null); return(false); } // Apply sky hack? UpdateSkyRenderFlag(); //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_bottom", 1.0), Sidedef.Fields.GetValue("scaley_bottom", 1.0)); Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_bottom", 0.0), Sidedef.Fields.GetValue("offsety_bottom", 0.0)); // Texture given? if (Sidedef.LongLowTexture != MapSet.EmptyLongName) { // Load texture base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongLowTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongLowTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongLowTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size. Round up, because that's apparently what GZDoom does Vector2D tsz = new Vector2D(Math.Ceiling(base.Texture.ScaledWidth / tscale.x), Math.Ceiling(base.Texture.ScaledHeight / tscale.y)); // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; // biwa. Also take the ForceWorldPanning MAPINFO entry into account if (General.Map.Config.ScaledTextureOffsets && (!base.Texture.WorldPanning && !General.Map.Data.MapInfo.ForceWorldPanning)) { tof = tof / tscaleAbs; tof = tof * base.Texture.Scale; // If the texture gets replaced with a "hires" texture it adds more fuckery if (base.Texture is HiResImage) { tof *= tscaleAbs; } // Round up, since that's apparently what GZDoom does. Not sure if this is the right place or if it also has to be done earlier tof = new Vector2D(Math.Ceiling(tof.x), Math.Ceiling(tof.y)); } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); double floorbias = (Sidedef.Other.Sector.FloorHeight == Sidedef.Sector.FloorHeight) ? 1.0 : 0.0; if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { if (Sidedef.Sector.CeilTexture == General.Map.Config.SkyFlatName && Sidedef.Other.Sector.CeilTexture == General.Map.Config.SkyFlatName) { // mxd. Replicate Doom texture offset glitch when front and back sector's ceilings are sky tp.tlt.y = (double)Sidedef.Other.Sector.CeilHeight - Sidedef.Other.Sector.FloorHeight; } else { // When lower unpegged is set, the lower texture is bound to the bottom tp.tlt.y = (double)Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.FloorHeight; } } tp.trb.x = tp.tlt.x + Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (Sidedef.Other.Sector.FloorHeight - (Sidedef.Sector.FloorHeight + floorbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Other.Sector.FloorHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, vlzf)); poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl))); poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr))); poly.Add(new Vector3D(vr.x, vr.y, vrzf)); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part above the other floor CropPoly(ref poly, osd.Floor.plane, false); //INFO: Makes sence only when ceiling plane is lower than floor plane. Also ZDoom clips ceiling instead here. if (ovlzf > osd.Ceiling.plane.GetZ(vl) || ovrzf > osd.Ceiling.plane.GetZ(vr)) { CropPoly(ref poly, osd.Ceiling.plane, true); } // Cut out pieces that overlap 3D floors in this sector List <WallPolygon> polygons = new List <WallPolygon> { poly }; ClipExtraFloors(polygons, sd.ExtraFloors, false); //mxd if (polygons.Count > 0) { // Keep top and bottom planes for intersection testing Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's ceiling can be lower than the other sector's floor! top = (osd.Floor.plane.GetZ(linecenter) < sd.Ceiling.plane.GetZ(linecenter) ? osd.Floor.plane : sd.Ceiling.plane); bottom = sd.Floor.plane; // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { base.SetVertices(verts); return(true); } } base.SetVertices(null); //mxd return(false); }
//mxd public bool Setup(SectorLevel level, Effect3DFloor extrafloor, bool innerside) { Sector s = level.sector; Vector2D texscale; this.innerside = innerside; //mxd 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 ceiling texture if (s.LongCeilTexture != MapSet.EmptyLongName) { base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = s.LongCeilTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = s.LongCeilTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // 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); } // Determine brightness byte alpha = (byte)General.Clamp(level.alpha, 0, 255); int color = PixelColor.FromInt(level.color).WithAlpha(alpha).ToInt(); int targetbrightness; if (extrafloor != null && !extrafloor.VavoomType && !level.disablelighting) { //mxd. Top extrafloor level should calculate fogdensity from the brightness of the level above it if (!innerside) { targetbrightness = 0; SectorData sd = mode.GetSectorData(this.Sector.Sector); for (int i = 0; i < sd.LightLevels.Count - 1; i++) { if (sd.LightLevels[i] == level) { targetbrightness = sd.LightLevels[i + 1].brightnessbelow; break; } } } //mxd. Inner extrafloor ceilings must be colored using control sector's color and brightness else { targetbrightness = level.brightnessbelow; SectorData sd = mode.GetSectorData(this.Sector.Sector); for (int i = 0; i < sd.LightLevels.Count; i++) { if (sd.LightLevels[i] == level) { if (i > 0) { color = PixelColor.FromInt(sd.LightLevels[i - 1].color).WithAlpha(alpha).ToInt(); } break; } } } } else { targetbrightness = level.brightnessbelow; } //mxd. Determine fog density fogfactor = CalculateFogFactor(targetbrightness); // Make vertices ReadOnlyCollection <Vector2D> triverts = Sector.Sector.Triangles.Vertices; WorldVertex[] verts = new WorldVertex[triverts.Count]; for (int i = 0; i < triverts.Count; i++) { // Color shading verts[i].c = color; //mxd // Vertex coordinates verts[i].x = triverts[i].x; verts[i].y = triverts[i].y; verts[i].z = level.plane.GetZ(triverts[i]); // 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 || innerside) { SwapTriangleVertices(verts); } // Determine render pass if (extrafloor != null) { if (extrafloor.Sloped3dFloor) //mxd { this.RenderPass = RenderPass.Mask; } else if (extrafloor.RenderAdditive) //mxd { this.RenderPass = RenderPass.Additive; } else if (level.alpha < 255) { this.RenderPass = RenderPass.Alpha; } else { this.RenderPass = RenderPass.Mask; } } else { this.RenderPass = RenderPass.Solid; } //mxd. Update sky render flag bool isrenderedassky = renderassky; renderassky = (level.sector.CeilTexture == General.Map.Config.SkyFlatName); if (isrenderedassky != renderassky && Sector.Sides != null) { // Upper sidedef geometry may need updating... foreach (Sidedef side in level.sector.Sidedefs) { VisualSidedefParts parts = Sector.GetSidedefParts(side); // Upper side can exist in either our, or the neightbouring sector, right? if (parts.upper != null && parts.upper.Triangles > 0) { parts.upper.UpdateSkyRenderFlag(); } else if (side.Other != null && side.Other.Sector != null && side.Other.Sector.CeilTexture == General.Map.Config.SkyFlatName) { // Update upper side of the neightbouring sector BaseVisualSector other = (BaseVisualSector)mode.GetVisualSector(side.Other.Sector); if (other != null && other.Sides != null) { parts = other.GetSidedefParts(side.Other); if (parts.upper != null && parts.upper.Triangles > 0) { parts.upper.UpdateSkyRenderFlag(); } } } } } // 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); }