Handle arbitrary numbers of GameStateProviders

- Use bitset instead of long.
 - We only ever iterate over the GameStateProviders, so use a list instead of a map.
 - GameStateProviders don't need IDs.
This commit is contained in:
Jozufozu 2022-01-13 15:58:51 -08:00
parent 29d4ec03c2
commit c4d6ec706e
6 changed files with 54 additions and 62 deletions

View File

@ -1,61 +1,58 @@
package com.jozufozu.flywheel.core;
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import com.jozufozu.flywheel.core.shader.GameStateProvider;
import com.jozufozu.flywheel.core.shader.ShaderConstants;
import com.jozufozu.flywheel.core.shader.StateSnapshot;
import net.minecraft.resources.ResourceLocation;
public class GameStateRegistry {
private static final Map<ResourceLocation, GameStateProvider> registeredStateProviders = new HashMap<>();
private static final List<GameStateProvider> PROVIDERS = new ArrayList<>();
public static void _clear() {
registeredStateProviders.clear();
}
public static GameStateProvider getStateProvider(ResourceLocation location) {
GameStateProvider out = registeredStateProviders.get(location);
if (out == null) {
throw new IllegalArgumentException("State provider '" + location + "' does not exist.");
}
return out;
}
public static void register(GameStateProvider context) {
if (registeredStateProviders.containsKey(context.getID())) {
throw new IllegalStateException("Duplicate game state provider: " + context.getID());
}
registeredStateProviders.put(context.getID(), context);
/**
* Registers a game state provider.
* @param provider The provider to register.
*/
public static void register(GameStateProvider provider) {
PROVIDERS.add(provider);
}
/**
* Takes a snapshot of the current game state, storing it in a bit set.
* @return An object that represents the current game state.
*/
public static StateSnapshot takeSnapshot() {
long ctx = 0;
for (GameStateProvider state : registeredStateProviders.values()) {
if (state.isTrue()) {
ctx |= 1;
BitSet bitSet = new BitSet(PROVIDERS.size());
for (int i = 0, listSize = PROVIDERS.size(); i < listSize; i++) {
if (PROVIDERS.get(i).isTrue()) {
bitSet.set(i);
}
ctx <<= 1;
}
return new StateSnapshot(ctx);
return new StateSnapshot(bitSet);
}
public static ShaderConstants getDefines(long ctx) {
long stateID = ctx;
/**
* Based on the given snapshot, gathers shader constants to be injected during shader compilation.
* @param snapshot The snapshot to use.
* @return A list of shader constants.
*/
public static ShaderConstants getShaderConstants(StateSnapshot snapshot) {
BitSet ctx = snapshot.ctx();
ShaderConstants shaderConstants = new ShaderConstants();
for (GameStateProvider state : registeredStateProviders.values()) {
if ((stateID & 1) == 1) {
state.alterConstants(shaderConstants);
for (int i = 0, listSize = PROVIDERS.size(); i < listSize; i++) {
if (ctx.get(i)) {
PROVIDERS.get(i).alterConstants(shaderConstants);
}
stateID >>= 1;
}
return shaderConstants;
}
public static void _clear() {
PROVIDERS.clear();
}
}

View File

@ -71,7 +71,7 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
}
public ShaderConstants getShaderConstants() {
ShaderConstants shaderConstants = ctx.getDefines();
ShaderConstants shaderConstants = ctx.getShaderConstants();
if (alphaDiscard > 0) {
shaderConstants.define("ALPHA_DISCARD", alphaDiscard);

View File

@ -25,7 +25,7 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX));
key.ctx.getDefines().writeInto(finalSource);
key.ctx.getShaderConstants().writeInto(finalSource);
finalSource.append("""
struct Vertex {

View File

@ -1,12 +1,19 @@
package com.jozufozu.flywheel.core.shader;
import net.minecraft.resources.ResourceLocation;
/**
* An object that provides a view of the current game state for shader compilation.
*/
public interface GameStateProvider {
ResourceLocation getID();
/**
* Get the status of this game state provider.
* @return Returning {@code true} will cause #alterConstants to be called before compiling a shader.
*/
boolean isTrue();
/**
* Alter the constants for shader compilation.
* @param constants The shader constants.
*/
void alterConstants(ShaderConstants constants);
}

View File

@ -1,18 +1,9 @@
package com.jozufozu.flywheel.core.shader;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.config.FlwConfig;
import net.minecraft.resources.ResourceLocation;
public class NormalDebugStateProvider implements GameStateProvider {
public static final NormalDebugStateProvider INSTANCE = new NormalDebugStateProvider();
public static final ResourceLocation NAME = Flywheel.rl("normal_debug");
protected NormalDebugStateProvider() {
}
public enum NormalDebugStateProvider implements GameStateProvider {
INSTANCE;
@Override
public boolean isTrue() {
@ -20,11 +11,6 @@ public class NormalDebugStateProvider implements GameStateProvider {
.debugNormals();
}
@Override
public ResourceLocation getID() {
return NAME;
}
@Override
public void alterConstants(ShaderConstants constants) {
constants.define("DEBUG_NORMAL");

View File

@ -1,11 +1,13 @@
package com.jozufozu.flywheel.core.shader;
import java.util.BitSet;
import com.jozufozu.flywheel.core.GameStateRegistry;
public record StateSnapshot(long ctx) {
public record StateSnapshot(BitSet ctx) {
// TODO: is this needed?
public ShaderConstants getDefines() {
return GameStateRegistry.getDefines(ctx);
public ShaderConstants getShaderConstants() {
return GameStateRegistry.getShaderConstants(this);
}
}