Skip to content

Commit

Permalink
- F3 toggle Z level splicing (#87)
Browse files Browse the repository at this point in the history
- ALT + Plus or Minus to go up or down a Z level
- Shift hotkey has been added to decrease Z Level
  • Loading branch information
Vermino authored Oct 23, 2024
1 parent 7f7d872 commit ebfb290
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 19 deletions.
3 changes: 3 additions & 0 deletions ACViewer/Config/MapViewerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace ACViewer.Config
public class MapViewerOptions
{
public MapViewerMode Mode { get; set; }
public bool EnableZSlicing { get; set; } = false;
public int CurrentZLevel { get; set; } = 1;
public float LevelHeight { get; set; } = 10.0f;

public MapViewerOptions()
{
Expand Down
1 change: 1 addition & 0 deletions ACViewer/Extensions/CommandHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Windows.Input;
using ACViewer.Config;

namespace ACViewer.Extensions
{
Expand Down
5 changes: 5 additions & 0 deletions ACViewer/Extensions/Vector3Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
using System;

using Microsoft.Xna.Framework;

using System.Numerics;

using ACE.Server.Physics;

namespace ACViewer
{
public static class Vector3Extensions
{

public static System.Numerics.Vector3 ToNumerics(this Microsoft.Xna.Framework.Vector3 v)
{
return new System.Numerics.Vector3(v.X, v.Y, v.Z);
Expand Down
3 changes: 2 additions & 1 deletion ACViewer/Model/VertexInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ namespace ACViewer.Model
{
public struct VertexInstance : IVertexType
{
public Vector3 Position;
public Vector3 Position { get; set; }
public Vector4 Orientation;
public Vector3 Scale;


public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
(
Expand Down
93 changes: 92 additions & 1 deletion ACViewer/Render/Buffer.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using ACE.DatLoader.Entity;
using ACE.Server.Physics;

using ACViewer.Config;
using ACViewer.Extensions;
using ACViewer.Enum;
using ACViewer.Model;

Expand Down Expand Up @@ -86,6 +88,95 @@ public void Init()

AnimatedTextureAtlasChains = new Dictionary<TextureFormat, TextureAtlasChain>();
}

private bool IsInCurrentZLevel(Vector3 position)
{
if (!ConfigManager.Config.MapViewer.EnableZSlicing)
return true;

var config = ConfigManager.Config.MapViewer;
float levelBottom = (config.CurrentZLevel - 1) * config.LevelHeight;
float levelTop = levelBottom + config.LevelHeight;

return position.Z >= levelBottom && position.Z < levelTop;
}

public void DrawWithZSlicing()
{
Effect.Parameters["xWorld"].SetValue(Matrix.Identity);
Effect.Parameters["xLightDirection"].SetValue(-Vector3.UnitZ);
Effect.Parameters["xAmbient"].SetValue(0.5f);

Effect_Clamp.Parameters["xWorld"].SetValue(Matrix.Identity);
Effect_Clamp.Parameters["xLightDirection"].SetValue(-Vector3.UnitZ);
Effect_Clamp.Parameters["xAmbient"].SetValue(0.5f);

PerfTimer.Start(ProfilerSection.Draw);

if (drawTerrain)
{
SetRasterizerState();
TerrainBatch.DrawWithZFiltering(IsInCurrentZLevel);
}

if (drawEnvCells)
DrawBufferWithZSlicing(RB_EnvCell, true);

if (drawStaticObjs)
DrawBufferWithZSlicing(RB_StaticObjs);

if (drawBuildings)
DrawBufferWithZSlicing(RB_Buildings);

if (drawScenery)
DrawBufferWithZSlicing(RB_Scenery);

if (drawInstances && Server.InstancesLoaded)
DrawBufferWithZSlicing(RB_Instances);

if (drawEncounters && Server.EncountersLoaded)
DrawBufferWithZSlicing(RB_Encounters);

DrawBufferWithZSlicing(RB_Animated);

if (Picker.HitVertices != null)
Picker.DrawHitPoly();

PerfTimer.Stop(ProfilerSection.Draw);
}

private void DrawBufferWithZSlicing(Dictionary<uint, GfxObjInstance_Shared> batches)
{
SetRasterizerState(CullMode.None);

foreach (var batch in batches.Values)
batch.DrawFiltered(IsInCurrentZLevel);
}

private void DrawBufferWithZSlicing(Dictionary<GfxObjTexturePalette, GfxObjInstance_Shared> batches)
{
SetRasterizerState(CullMode.None);

foreach (var batch in batches.Values)
batch.DrawFiltered(IsInCurrentZLevel);
}

private void DrawBufferWithZSlicing(Dictionary<TextureSet, InstanceBatch> batches, bool culling = false)
{
var cullMode = WorldViewer.Instance.DungeonMode || culling ?
CullMode.CullClockwiseFace : CullMode.None;

SetRasterizerState(cullMode);

Effect.CurrentTechnique = Effect.Techniques["TexturedInstanceEnv"];
Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstanceEnv"];

foreach (var batch in batches.Values)
{
batch.DrawFiltered(IsInCurrentZLevel);
}
}


public void ClearBuffer()
{
Expand Down
26 changes: 26 additions & 0 deletions ACViewer/Render/Camera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,31 @@ public void Update(GameTime gameTime)
Position -= Vector3.Cross(Up, Dir) * Speed;
if (keyboardState.IsKeyDown(Keys.Space))
Position += Up * Speed;
// Shift key control for downward movement
if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift))
Position -= Up * Speed;

// Z-level controls
if (keyboardState.IsKeyDown(Keys.F3) && LastKeyboardState != null && !LastKeyboardState.IsKeyDown(Keys.F3))
{
ConfigManager.Config.MapViewer.EnableZSlicing = !ConfigManager.Config.MapViewer.EnableZSlicing;
ConfigManager.Config.MapViewer.CurrentZLevel = 1;
}

// Z-level adjustment
if (ConfigManager.Config.MapViewer.EnableZSlicing)
{
if ((keyboardState.IsKeyDown(Keys.LeftAlt) || keyboardState.IsKeyDown(Keys.RightAlt)))
{
var config = ConfigManager.Config.MapViewer;
if (keyboardState.IsKeyDown(Keys.OemPlus) && !LastKeyboardState.IsKeyDown(Keys.OemPlus))
config.CurrentZLevel = Math.Min(config.CurrentZLevel + 1, 20);
if (keyboardState.IsKeyDown(Keys.OemMinus) && !LastKeyboardState.IsKeyDown(Keys.OemMinus))
config.CurrentZLevel--;
}
}

LastKeyboardState = keyboardState;

// camera speed control
if (mouseState.ScrollWheelValue != PrevMouseState.ScrollWheelValue)
Expand Down Expand Up @@ -368,6 +393,7 @@ public void Update(GameTime gameTime)
//Console.WriteLine("Camera dir: " + GameView.Instance.Render.Camera.Dir);
}

private KeyboardState LastKeyboardState;
public int centerX => GameView.GraphicsDevice.Viewport.Width / 2;
public int centerY => GameView.GraphicsDevice.Viewport.Height / 2;

Expand Down
55 changes: 49 additions & 6 deletions ACViewer/Render/GfxObjInstance_Shared.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Expand All @@ -25,9 +26,8 @@ public class GfxObjInstance_Shared
public Dictionary<TextureFormatChain, GfxObjInstance_TextureFormat> BaseFormats_Alpha { get; set; }

public List<VertexPositionNormalTextures> Vertices { get; set; }

public List<VertexInstance> Instances { get; set; }

public VertexInstance[] Instances_ { get; set; }

public VertexBuffer Shared_VB { get; set; }
Expand All @@ -39,9 +39,7 @@ public class GfxObjInstance_Shared
public GfxObjInstance_Shared(GfxObj gfxObj, Dictionary<TextureFormat, TextureAtlasChain> textureAtlasChains, Dictionary<uint, uint> textureChanges = null, PaletteChanges paletteChanges = null)
{
GfxObj = gfxObj;

BuildStatic(gfxObj, textureAtlasChains, textureChanges, paletteChanges);

Instances = new List<VertexInstance>();
}

Expand Down Expand Up @@ -185,6 +183,51 @@ public void Draw()
foreach (var baseFormat in BaseFormats_Alpha.Values)
baseFormat.Draw(Instances.Count);
}

public void DrawFiltered(Func<Vector3, bool> filter)
{
if (Bindings == null) return;

if (isDirty)
{
Instances_VB.SetData(Instances_);
isDirty = false;
}

// Store original instances
var originalInstances = Instances_.ToArray();

// Filter instances
var filteredInstances = Instances.Where(instance => filter(instance.Position)).ToArray();

if (filteredInstances.Length > 0)
{
// Update vertex buffer with filtered instances
Instances_ = filteredInstances;
Instances_VB.SetData(filteredInstances);

GraphicsDevice.SetVertexBuffers(Bindings);

Effect.CurrentTechnique = Effect.Techniques["TexturedInstance"];
Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstance"];

foreach (var baseFormat in BaseFormats_Solid.Values)
baseFormat.Draw(filteredInstances.Length);

if (Buffer.drawAlpha)
{
Effect.CurrentTechnique = Effect.Techniques["TexturedInstanceAlpha"];
Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstanceAlpha"];
}

foreach (var baseFormat in BaseFormats_Alpha.Values)
baseFormat.Draw(filteredInstances.Length);
}

// Restore original instances
Instances_ = originalInstances;
Instances_VB.SetData(originalInstances);
}

public void Dispose()
{
Expand Down
29 changes: 26 additions & 3 deletions ACViewer/Render/InstanceBatch.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Collections.Generic;

using System;
using System.Collections.Generic;
using System.Linq;
using ACE.Entity.Enum;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ACViewer.Render
Expand All @@ -17,6 +18,28 @@ public class InstanceBatch
public VertexBuffer InstanceBuffer { get; set; }

public R_Environment R_Environment { get; set; }

public void DrawFiltered(Func<Vector3, bool> filter)
{
// Store original instances
var originalInstances = new List<VertexInstanceEnv>(Instances_Env);

// Filter instances based on Z position
Instances_Env = Instances_Env.Where(instance => filter(instance.Position)).ToList();

if (Instances_Env.Count > 0)
{
// Rebuild instance buffer with filtered instances
BuildInstanceBuffer();
BuildBindings();
Draw();
}

// Restore original instances
Instances_Env = originalInstances;
BuildInstanceBuffer();
BuildBindings();
}

public InstanceBatch(R_EnvCell envCell)
{
Expand Down
34 changes: 27 additions & 7 deletions ACViewer/Render/Render.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class Render

// multiple SamplerStates in the same .fx file apparently don't work
public static Effect Effect_Clamp { get; set; }

// Add to existing properties
private MapViewerOptions Config => ConfigManager.Config.MapViewer;

public Camera Camera
{
Expand Down Expand Up @@ -67,21 +70,23 @@ public void SetRasterizerState(bool wireframe = true)

GraphicsDevice.RasterizerState = rs;
}

public void Draw()
{
GraphicsDevice.Clear(ConfigManager.Config.BackgroundColors.WorldViewer);

SetRasterizerState(false);

Effect.Parameters["xView"].SetValue(Camera.ViewMatrix);
Effect_Clamp.Parameters["xView"].SetValue(Camera.ViewMatrix);

//landblock.Draw();
Buffer.Draw();
if (ConfigManager.Config.MapViewer.EnableZSlicing)
Buffer.DrawWithZSlicing();
else
Buffer.Draw();

//DrawEmitters_Naive();
DrawEmitters_Batch();
DrawHUD();
}

public bool ParticlesInitted { get; set; }
Expand Down Expand Up @@ -186,14 +191,29 @@ public void DestroyEmitters()

private static readonly Vector2 TextPos = new Vector2(10, 10);

// DrawHUD to show Z-slice information
public void DrawHUD()
{
var cameraPos = GameView.Camera.GetPosition();
var text = "";

if (ConfigManager.Config.MapViewer.EnableZSlicing)
{
var config = ConfigManager.Config.MapViewer;
string levelPrefix = config.CurrentZLevel < 0 ? "B" : ""; // Add "B" prefix for basement levels
int displayLevel = config.CurrentZLevel < 0 ? -config.CurrentZLevel : config.CurrentZLevel;

text += $"Current Z-Level: {levelPrefix}{displayLevel}\n"; // Shows B1, B2, etc. for basement levels
text += $"Height Range: {(config.CurrentZLevel - 1) * config.LevelHeight:F1}m - {config.CurrentZLevel * config.LevelHeight:F1}m\n";
}

var cameraPos = Camera.GetPosition();
if (cameraPos != null)
text += $"Location: {cameraPos}";

if (!string.IsNullOrEmpty(text))
{
SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearClamp);
SpriteBatch.DrawString(Font, $"Location: {cameraPos}", TextPos, Color.White);
SpriteBatch.DrawString(Font, text, TextPos, Color.White);
SpriteBatch.End();
}
}
Expand Down
Loading

0 comments on commit ebfb290

Please sign in to comment.