Class MdiGeometryAtlas
MdiBatchCoordinator.
Holds:
- One vertex VBO (
GL_ARRAY_BUFFER) containing the concatenated per-part vertex bytes (pos vec3 / normal vec3 / uv vec2 / int bone_id, stride 36). - One index EBO (
GL_ELEMENT_ARRAY_BUFFER) with the concatenated per-partGL_UNSIGNED_INTindices. Per-part draw commands usebaseVertex(added to each element index) and a byte offset into the EBO forglDrawElementsInstancedBaseVertexBaseInstance; дляDrawElementsIndirectCommand.firstIndexв буфере indirect нужно то же смещение в элементах (байты / 4). Локальные индексы частей — как есть (0..N-1 на часть). - One instance VBO with the unsliced 30-float instance layout (loc 4..12
with divisor 1), large enough to hold the sum of all per-renderer
MAX_INSTANCESbudgets for a single frame. - One indirect buffer for the
MdiBatchCoordinatorto stream commands into. - One VAO with all of the above pre-bound.
Geometry registration is lazy and growable: each
InstancedStaticPartRenderer that first becomes MDI-eligible calls
registerGeometryIfAbsent(com.hbm_m.client.render.InstancedStaticPartRenderer, java.nio.ByteBuffer, java.nio.IntBuffer, int) with a copy of its vertex bytes + index
stream. When the existing vertex/index buffers don't have room, we
reallocate at double capacity and re-upload all known parts. This is rare
(happens only on first-frame growth) and amortised across the session.
Sliced renderers (useSlicedLight=true) are NOT supported here today —
they use a different attribute layout and a different shader. Adding a
second atlas + a second MDI dispatch later is mechanical, but out of scope
for the initial integration.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classSlot record returned to the coordinator. -
Method Summary
Modifier and TypeMethodDescriptionbooleanacceptsInstanceDataSize(int floatsPerInstance) Acceptance gate forMdiBatchCoordinator.submit(com.hbm_m.client.render.InstancedStaticPartRenderer, int, int, int, java.nio.FloatBuffer, int[], long[], java.nio.ByteBuffer, java.nio.IntBuffer, int): only the unsliced 30-float layout is wired into this atlas.voidВключает vertex attrib arrays 0..11 на уже привязанномvaoId.voidensureIndirectCommandByteCapacity(int needBytes) Расширяет GL_DRAW_INDIRECT_BUFFER при необходимости (редко).booleanensureInstanceCapacity(int instances) Ensure the instance VBO can holdinstancescontiguous instance records.static voidУдаляет геометрию рендерера из атласа при егоInstancedStaticPartRenderer.cleanup()до полногоresetForResourceLifecycle().getCurrentSlot(InstancedStaticPartRenderer renderer) ТекущийMdiGeometryAtlas.Slotдля уже зарегистрированного рендерера после любогоrepackGeometryAndRefreshSlots()(рост VBO/EBO).intlongЁмкостьGL40.GL_DRAW_INDIRECT_BUFFER(байты); для orphan перед записью команд.intintstatic MdiGeometryAtlasintТолько для диагностики MDI: число зарегистрированных частей в атласе.intgetVaoId()booleanisReady()voidorphanInstanceBuffer(int instances) Orphan the instance VBO at the start of a frame (driver-friendly streaming).registerGeometryIfAbsent(InstancedStaticPartRenderer renderer, ByteBuffer vertexBytes, IntBuffer indices, int indexCount) Lazy-register a renderer's geometry.static voidПолный сброс атласа при F3+T / disconnect.voiduploadInstanceWindow(int floatOffset, FloatBuffer src, int floatCount) Upload one window of instance floats at the given instance-float offset.
-
Method Details
-
getOrCreate
-
resetForResourceLifecycle
public static void resetForResourceLifecycle()Полный сброс атласа при F3+T / disconnect. Только render-thread.Без этого
geometryByRendererбессрочно держит старыеInstancedStaticPartRendererкак ключи: послеclearCaches()на них больше нет ссылок из BER, но Map не даёт их собрать GC и накапливает вторую/третью копию той же геометрии для новых инстансов рендерера — отсюда «cog рисуется как base химзавода», дыры в полигонах и полный отказ MDI до перезахода (слоты/порядок repack расходятся с ожиданиями). -
isReady
public boolean isReady() -
getVaoId
public int getVaoId() -
getIndirectBufferId
public int getIndirectBufferId() -
getIndirectCommandBufferCapBytes
public long getIndirectCommandBufferCapBytes()ЁмкостьGL40.GL_DRAW_INDIRECT_BUFFER(байты); для orphan перед записью команд. -
getInstanceFloatsPerInstance
public int getInstanceFloatsPerInstance() -
getInstanceFadeFloatOffset
public int getInstanceFadeFloatOffset() -
getRegisteredGeometryCount
public int getRegisteredGeometryCount()Только для диагностики MDI: число зарегистрированных частей в атласе. -
enableVertexAttribArraysOnBoundVao
public void enableVertexAttribArraysOnBoundVao()Включает vertex attrib arrays 0..11 на уже привязанномvaoId. ПослеShaderInstance#apply()/ Embeddium chunk-батчей часть массивов может оказаться отключённой; без этого MDI рисует только подмножество атрибутов (типично «видна только base», створки/cogs — нет). -
acceptsInstanceDataSize
public boolean acceptsInstanceDataSize(int floatsPerInstance) Acceptance gate forMdiBatchCoordinator.submit(com.hbm_m.client.render.InstancedStaticPartRenderer, int, int, int, java.nio.FloatBuffer, int[], long[], java.nio.ByteBuffer, java.nio.IntBuffer, int): only the unsliced 30-float layout is wired into this atlas. -
getCurrentSlot
ТекущийMdiGeometryAtlas.Slotдля уже зарегистрированного рендерера после любогоrepackGeometryAndRefreshSlots()(рост VBO/EBO). ПодMdiBatchCoordinator.dispatch()нужен именно он:submitкопирует смещения вPendingв порядкеflushInstancedBatches, а между двумяflushсоседних типов машин одинregisterGeometryIfAbsentможет вызвать repack и пересчитатьGeoRecord#slotу всех записей — старые значения вPendingтогда указывают в пустоту/чужую геометрию (невидимые двери/сборка, «дырявая» хим установка). -
evictRendererIfRegistered
Удаляет геометрию рендерера из атласа при егоInstancedStaticPartRenderer.cleanup()до полногоresetForResourceLifecycle(). Иначе вgeometryByRendererостаются «зомби»-ключи (cleanup уже освободил retained-буферы, а GeoRecord продолжает участвовать в repack), что ломает порядок/смещения MDI без срабатывания дрейфа слотов в Pending. -
registerGeometryIfAbsent
public MdiGeometryAtlas.Slot registerGeometryIfAbsent(InstancedStaticPartRenderer renderer, ByteBuffer vertexBytes, IntBuffer indices, int indexCount) Lazy-register a renderer's geometry. The first call uploads vertex+index bytes into the atlas; subsequent calls return the cached slot.Atlas growth: if the new geometry doesn't fit in the current VBO/EBO capacity, both buffers are reallocated at next-power-of-two size and ALL known parts are re-uploaded. This is rare (once per part per session); not on the hot path.
-
ensureInstanceCapacity
public boolean ensureInstanceCapacity(int instances) Ensure the instance VBO can holdinstancescontiguous instance records. -
orphanInstanceBuffer
public void orphanInstanceBuffer(int instances) Orphan the instance VBO at the start of a frame (driver-friendly streaming). -
ensureIndirectCommandByteCapacity
public void ensureIndirectCommandByteCapacity(int needBytes) Расширяет GL_DRAW_INDIRECT_BUFFER при необходимости (редко). Обновление команд — только SubData на стороне координатора. -
uploadInstanceWindow
Upload one window of instance floats at the given instance-float offset.
-