phase(N.4) Tasks 22+23: WbDrawDispatcher + surface metadata side-table
WbDrawDispatcher draws all entities through WB's ObjectRenderData (VAO/VBO per GfxObj, per-batch IBO) using acdream's TextureCache for texture resolution. Two-pass rendering (opaque+ClipMap, then translucent) matching the existing InstancedMeshRenderer pattern. Per-entity single-instance drawing for N.4 simplicity — true instancing grouping deferred to N.6. Atlas-tier entities: mesh from WB, texture from TextureCache via batch SurfaceId. Per-instance-tier entities: AnimatedEntityState drives part overrides + hidden-parts, palette/surface overrides resolve through TextureCache's composite-key caches. Side-table population (Task 23 folded in): WbMeshAdapter now takes DatCollection and populates AcSurfaceMetadataTable on first IncrementRefCount per GfxObj. The side-table provides TranslucencyKind (critical for ClipMap alpha-test on vegetation) plus Luminosity, Diffuse, SurfOpacity, NeedsUvRepeat, DisableFog for sky-pass and lighting. GameWindow wiring: when WbFoundationFlag is enabled, WbDrawDispatcher draws everything and InstancedMeshRenderer is skipped. Flag-off path is unchanged. Matrix composition: restPose * animOverride * entityWorld, matching the spec. Three MatrixCompositionTests verify the contract. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5b4fd4b61d
commit
01cff4144f
5 changed files with 507 additions and 8 deletions
|
|
@ -1,6 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.Core.Meshing;
|
||||
using Chorizite.OpenGLSDLBackend;
|
||||
using Chorizite.OpenGLSDLBackend.Lib;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Silk.NET.OpenGL;
|
||||
|
|
@ -26,6 +30,9 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
private readonly OpenGLGraphicsDevice? _graphicsDevice;
|
||||
private readonly DefaultDatReaderWriter? _wbDats;
|
||||
private readonly ObjectMeshManager? _meshManager;
|
||||
private readonly DatCollection? _dats;
|
||||
private readonly AcSurfaceMetadataTable _metadataTable = new();
|
||||
private readonly HashSet<ulong> _metadataPopulated = new();
|
||||
|
||||
/// <summary>
|
||||
/// True when this instance was created via <see cref="CreateUninitialized"/>;
|
||||
|
|
@ -43,14 +50,19 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
/// thread (construction runs GL queries; call from OnLoad).</param>
|
||||
/// <param name="datDir">Path to the dat directory (same as the one supplied
|
||||
/// to our DatCollection). DefaultDatReaderWriter opens its own file handles.</param>
|
||||
/// <param name="dats">acdream's DatCollection, used to populate the surface
|
||||
/// metadata side-table via <c>GfxObjMesh.Build</c>. Shares file handles with
|
||||
/// the rest of the client; read-only access from the render thread.</param>
|
||||
/// <param name="logger">Logger for the adapter; ObjectMeshManager uses
|
||||
/// NullLogger internally.</param>
|
||||
public WbMeshAdapter(GL gl, string datDir, ILogger<WbMeshAdapter> logger)
|
||||
public WbMeshAdapter(GL gl, string datDir, DatCollection dats, ILogger<WbMeshAdapter> logger)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(gl);
|
||||
ArgumentNullException.ThrowIfNull(datDir);
|
||||
ArgumentNullException.ThrowIfNull(dats);
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
|
||||
_dats = dats;
|
||||
_graphicsDevice = new OpenGLGraphicsDevice(gl, logger, new DebugRenderSettings());
|
||||
_wbDats = new DefaultDatReaderWriter(datDir);
|
||||
_meshManager = new ObjectMeshManager(
|
||||
|
|
@ -70,9 +82,18 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
/// underlying mesh manager. Public methods are all no-ops.</summary>
|
||||
public static WbMeshAdapter CreateUninitialized() => new();
|
||||
|
||||
/// <summary>
|
||||
/// The surface metadata side-table populated on each first
|
||||
/// <see cref="IncrementRefCount"/>. Queried by the draw dispatcher
|
||||
/// to determine translucency, luminosity, and fog behavior per batch.
|
||||
/// </summary>
|
||||
public AcSurfaceMetadataTable MetadataTable => _metadataTable;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the WB render data for <paramref name="id"/>, or null if not
|
||||
/// yet uploaded or if this adapter is uninitialized.
|
||||
/// yet uploaded or if this adapter is uninitialized. Increments WB's
|
||||
/// internal usage counter — use <see cref="TryGetRenderData"/> for
|
||||
/// render-loop lookups that should not affect lifecycle.
|
||||
/// </summary>
|
||||
public ObjectRenderData? GetRenderData(ulong id)
|
||||
{
|
||||
|
|
@ -80,11 +101,25 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
return _meshManager.GetRenderData(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the WB render data for <paramref name="id"/> without
|
||||
/// modifying reference counts. Returns null if the mesh is not yet
|
||||
/// uploaded. Safe for render-loop lookups.
|
||||
/// </summary>
|
||||
public ObjectRenderData? TryGetRenderData(ulong id)
|
||||
{
|
||||
if (_isUninitialized || _meshManager is null) return null;
|
||||
return _meshManager.TryGetRenderData(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void IncrementRefCount(ulong id)
|
||||
{
|
||||
if (_isUninitialized || _meshManager is null) return;
|
||||
_meshManager.IncrementRefCount(id);
|
||||
|
||||
if (_metadataPopulated.Add(id))
|
||||
PopulateMetadata(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -126,6 +161,21 @@ public sealed class WbMeshAdapter : IDisposable, IWbMeshAdapter
|
|||
}
|
||||
}
|
||||
|
||||
private void PopulateMetadata(ulong id)
|
||||
{
|
||||
if (_dats is null) return;
|
||||
if (!_dats.Portal.TryGet<GfxObj>((uint)id, out var gfxObj)) return;
|
||||
|
||||
var subMeshes = GfxObjMesh.Build(gfxObj, _dats);
|
||||
for (int i = 0; i < subMeshes.Count; i++)
|
||||
{
|
||||
var sm = subMeshes[i];
|
||||
_metadataTable.Add(id, i, new AcSurfaceMetadata(
|
||||
sm.Translucency, sm.Luminosity, sm.Diffuse,
|
||||
sm.SurfOpacity, sm.NeedsUvRepeat, sm.DisableFog));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue