diff --git a/core/src/com/etheller/warsmash/viewer5/Scene.java b/core/src/com/etheller/warsmash/viewer5/Scene.java index fda3f6f..f4c3a4a 100644 --- a/core/src/com/etheller/warsmash/viewer5/Scene.java +++ b/core/src/com/etheller/warsmash/viewer5/Scene.java @@ -317,4 +317,8 @@ public abstract class Scene { return -Float.compare(o2.depth, o1.depth); } } + + public SceneLightManager getLightManager() { + return this.lightManager; + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/BatchGroup.java b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/BatchGroup.java index 72f23a1..17aaea3 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/BatchGroup.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/BatchGroup.java @@ -12,6 +12,7 @@ import com.etheller.warsmash.viewer5.Texture; import com.etheller.warsmash.viewer5.gl.DataTexture; import com.etheller.warsmash.viewer5.gl.WebGL; import com.etheller.warsmash.viewer5.handlers.w3x.DynamicShadowManager; +import com.etheller.warsmash.viewer5.handlers.w3x.W3xSceneLightManager; public class BatchGroup extends GenericGroup { @@ -36,6 +37,7 @@ public class BatchGroup extends GenericGroup { final WebGL webGL = viewer.webGL; final boolean isExtended = this.isExtended; final ShaderProgram shader; + final W3xSceneLightManager lightManager = (W3xSceneLightManager) scene.getLightManager(); if (isExtended) { if (DynamicShadowManager.IS_SHADOW_MAPPING) { @@ -59,6 +61,11 @@ public class BatchGroup extends GenericGroup { shader.setUniformMatrix("u_mvp", mvp); final DataTexture boneTexture = instance.boneTexture; + final DataTexture unitLightsTexture = lightManager.getUnitLightsTexture(); + + unitLightsTexture.bind(16); + shader.setUniformi("u_lightTexture", 16); + shader.setUniformf("u_lightCount", unitLightsTexture.getHeight()); // Instances of models with no bones don't have a bone texture. if (boneTexture != null) { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/LightInstance.java b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/LightInstance.java index c7c5b59..ca95984 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/mdx/LightInstance.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/mdx/LightInstance.java @@ -13,14 +13,18 @@ public class LightInstance implements UpdatableObject, SceneLightInstance { protected final Light light; private boolean visible; private boolean loadedInScene; + private final MdxComplexInstance instance; public LightInstance(final MdxComplexInstance instance, final Light light) { + this.instance = instance; this.node = instance.nodes[light.index]; this.light = light; } - public void bind(final int offset, final FloatBuffer floatBuffer, final int sequence, final int frame, - final int counter) { + public void bind(final int offset, final FloatBuffer floatBuffer) { + final int sequence = this.instance.sequence; + final int frame = this.instance.frame; + final int counter = this.instance.counter; this.light.getAttenuationStart(scalarHeap, sequence, frame, counter); final float attenuationStart = scalarHeap[0]; this.light.getAttenuationEnd(scalarHeap, sequence, frame, counter); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/W3xSceneLightManager.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/W3xSceneLightManager.java index a46c9a3..e5512cf 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/W3xSceneLightManager.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/W3xSceneLightManager.java @@ -1,5 +1,8 @@ package com.etheller.warsmash.viewer5.handlers.w3x; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.List; @@ -10,13 +13,19 @@ import com.etheller.warsmash.viewer5.handlers.mdx.LightInstance; public class W3xSceneLightManager implements SceneLightManager { public final List lights; + private FloatBuffer lightDataCopyHeap; private final DataTexture unitLightsTexture; private final DataTexture terrainLightsTexture; + private final War3MapViewer viewer; + private int terrainLightCount; + private int unitLightCount; public W3xSceneLightManager(final War3MapViewer viewer) { + this.viewer = viewer; this.lights = new ArrayList<>(); this.unitLightsTexture = new DataTexture(viewer.gl, 4, 4, 1); this.terrainLightsTexture = new DataTexture(viewer.gl, 4, 4, 1); + this.lightDataCopyHeap = ByteBuffer.allocateDirect(16 * 1 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); } @Override @@ -24,6 +33,7 @@ public class W3xSceneLightManager implements SceneLightManager { // TODO redesign to avoid cast final LightInstance mdxLight = (LightInstance) lightInstance; this.lights.add(mdxLight); + rebind(); } @Override @@ -31,5 +41,67 @@ public class W3xSceneLightManager implements SceneLightManager { // TODO redesign to avoid cast final LightInstance mdxLight = (LightInstance) lightInstance; this.lights.remove(mdxLight); + rebind(); + } + + private void rebind() { + final int numberOfLights = this.lights.size() + 1; + final int bytesNeeded = numberOfLights * 4 * 16; + if (bytesNeeded > (this.lightDataCopyHeap.capacity() * 4)) { + this.lightDataCopyHeap = ByteBuffer.allocateDirect(bytesNeeded).order(ByteOrder.nativeOrder()) + .asFloatBuffer(); + } + + this.unitLightCount = 0; + this.lightDataCopyHeap.clear(); + int offset = 0; + if (this.viewer.dncUnit != null) { + if (!this.viewer.dncUnit.lights.isEmpty()) { + this.viewer.dncUnit.lights.get(0).bind(0, this.lightDataCopyHeap); + offset += 16; + this.unitLightCount++; + } + } + for (final LightInstance light : this.lights) { + light.bind(offset, this.lightDataCopyHeap); + offset += 16; + this.unitLightCount++; + } + this.lightDataCopyHeap.flip(); + this.unitLightsTexture.bindAndUpdate(this.lightDataCopyHeap, 16, this.unitLightCount); + + this.terrainLightCount = 0; + this.lightDataCopyHeap.clear(); + offset = 0; + if (this.viewer.dncTerrain != null) { + if (!this.viewer.dncTerrain.lights.isEmpty()) { + this.viewer.dncTerrain.lights.get(0).bind(0, this.lightDataCopyHeap); + offset += 16; + this.terrainLightCount++; + } + } + for (final LightInstance light : this.lights) { + light.bind(offset, this.lightDataCopyHeap); + offset += 16; + this.terrainLightCount++; + } + this.lightDataCopyHeap.flip(); + this.terrainLightsTexture.bindAndUpdate(this.lightDataCopyHeap, 16, this.terrainLightCount); + } + + public DataTexture getUnitLightsTexture() { + return this.unitLightsTexture; + } + + public int getUnitLightCount() { + return this.unitLightCount; + } + + public DataTexture getTerrainLightsTexture() { + return this.terrainLightsTexture; + } + + public int getTerrainLightCount() { + return this.terrainLightCount; } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java index a49b942..eca9dff 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/War3MapViewer.java @@ -156,8 +156,8 @@ public class War3MapViewer extends ModelViewer { public DataTable miscData; private DataTable unitGlobalStrings; private MdxComplexInstance confirmationInstance; - private MdxComplexInstance dncUnit; - private MdxComplexInstance dncTerrain; + public MdxComplexInstance dncUnit; + public MdxComplexInstance dncTerrain; public CSimulation simulation; private float updateTime;