mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-28 16:06:48 +01:00
Little things.
- Quark magnets don't crash (already fixed). - Fix quark magnet leaving behind ghost instances. - Fix crash with belt lighting after being placed by contraptions. - Simplify tile add/remove mixins and avoid conflict with Performant. - Avoid FloatBuffer detour when uploading matrix uniforms. - InstancedTileRenderer no longer has to clean up. - Properly let go of tickable instances.
This commit is contained in:
parent
7eafbe5757
commit
b18993ed26
13 changed files with 300 additions and 290 deletions
|
@ -548,18 +548,20 @@ public class BeltTileEntity extends KineticTileEntity implements LightUpdateList
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeLight() {
|
private void initializeLight() {
|
||||||
light = new byte[beltLength * 2];
|
if (beltLength > 0) {
|
||||||
|
light = new byte[beltLength * 2];
|
||||||
|
|
||||||
Vec3i vec = getBeltFacing().getDirectionVec();
|
Vec3i vec = getBeltFacing().getDirectionVec();
|
||||||
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
|
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
|
||||||
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
|
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
|
||||||
|
|
||||||
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
|
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
|
||||||
for (int i = 0; i < beltLength * 2; i += 2) {
|
for (int i = 0; i < beltLength * 2; i += 2) {
|
||||||
light[i] = (byte) world.getLightLevel(LightType.BLOCK, pos);
|
light[i] = (byte) world.getLightLevel(LightType.BLOCK, pos);
|
||||||
light[i + 1] = (byte) world.getLightLevel(LightType.SKY, pos);
|
light[i + 1] = (byte) world.getLightLevel(LightType.SKY, pos);
|
||||||
|
|
||||||
pos.move(vec.getX(), verticality, vec.getZ());
|
pos.move(vec.getX(), verticality, vec.getZ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
package com.simibubi.create.foundation.mixin;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.render.KineticRenderer;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|
||||||
|
|
||||||
import com.simibubi.create.CreateClient;
|
|
||||||
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
@Mixin(value = World.class, priority = 1042)
|
|
||||||
public class AddRemoveTileMixin {
|
|
||||||
|
|
||||||
@Shadow @Final public boolean isRemote;
|
|
||||||
|
|
||||||
@Shadow @Final protected Set<TileEntity> tileEntitiesToBeRemoved;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JUSTIFICATION: This method is called whenever a tile entity is removed due
|
|
||||||
* to a change in block state, even on the client. By hooking into this method,
|
|
||||||
* we gain easy access to the information while having no impact on performance.
|
|
||||||
*/
|
|
||||||
@Inject(at = @At(
|
|
||||||
value = "INVOKE_ASSIGN",
|
|
||||||
target = "Lnet/minecraft/world/World;getTileEntity(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/tileentity/TileEntity;"
|
|
||||||
),
|
|
||||||
method = "removeTileEntity",
|
|
||||||
locals = LocalCapture.CAPTURE_FAILHARD
|
|
||||||
)
|
|
||||||
private void onRemoveTile(BlockPos pos, CallbackInfo ci, TileEntity te) {
|
|
||||||
if (isRemote) {
|
|
||||||
World thi = (World)(Object) this;
|
|
||||||
CreateClient.kineticRenderer.get(thi).remove(te);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(at = @At("TAIL"), method = "addTileEntity")
|
|
||||||
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) {
|
|
||||||
if (isRemote) {
|
|
||||||
World thi = (World)(Object) this;
|
|
||||||
CreateClient.kineticRenderer.get(thi).queueAdd(te);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Ljava/util/Set;clear()V", ordinal = 0
|
|
||||||
),
|
|
||||||
method = "tickBlockEntities")
|
|
||||||
private void onChunkUnload(CallbackInfo ci) {
|
|
||||||
if (isRemote) {
|
|
||||||
World thi = (World)(Object) this;
|
|
||||||
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(thi);
|
|
||||||
for (TileEntity tile : tileEntitiesToBeRemoved) {
|
|
||||||
kineticRenderer.remove(tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.simibubi.create.foundation.mixin;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
@Mixin(World.class)
|
||||||
|
public class TileAddMixin {
|
||||||
|
|
||||||
|
@Shadow @Final public boolean isRemote;
|
||||||
|
|
||||||
|
@Inject(at = @At("TAIL"), method = "addTileEntity")
|
||||||
|
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
if (isRemote) {
|
||||||
|
CreateClient.kineticRenderer.get((World)(Object) this).queueAdd(te);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.simibubi.create.foundation.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import com.simibubi.create.CreateClient;
|
||||||
|
|
||||||
|
@Mixin(TileEntity.class)
|
||||||
|
public class TileRemoveMixin {
|
||||||
|
|
||||||
|
@Shadow @Nullable protected World world;
|
||||||
|
|
||||||
|
@Inject(at = @At("TAIL"), method = "remove")
|
||||||
|
private void onRemove(CallbackInfo ci) {
|
||||||
|
if (world instanceof ClientWorld)
|
||||||
|
CreateClient.kineticRenderer.get(this.world).remove((TileEntity) (Object) this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
import org.lwjgl.opengl.GLCapabilities;
|
import org.lwjgl.opengl.GLCapabilities;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
@ -23,82 +24,85 @@ import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||||
|
|
||||||
public class Backend {
|
public class Backend {
|
||||||
public static final Boolean SHADER_DEBUG_OUTPUT = true;
|
public static final Boolean SHADER_DEBUG_OUTPUT = true;
|
||||||
|
|
||||||
public static final Logger log = LogManager.getLogger(Backend.class);
|
public static final Logger log = LogManager.getLogger(Backend.class);
|
||||||
public static final FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
|
public static GLCapabilities capabilities;
|
||||||
|
public static GlFeatureCompat compat;
|
||||||
|
|
||||||
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
private static boolean instancingAvailable;
|
||||||
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
private static boolean enabled;
|
||||||
|
|
||||||
private static boolean enabled;
|
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
||||||
|
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
||||||
|
|
||||||
public static GLCapabilities capabilities;
|
public Backend() {
|
||||||
public static GlFeatureCompat compat;
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
public Backend() {
|
/**
|
||||||
throw new IllegalStateException();
|
* Register a shader program. TODO: replace with forge registry?
|
||||||
}
|
*/
|
||||||
|
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
|
||||||
|
ResourceLocation name = spec.name;
|
||||||
|
if (registry.containsKey(name)) {
|
||||||
|
throw new IllegalStateException("Program spec '" + name + "' already registered.");
|
||||||
|
}
|
||||||
|
registry.put(name, spec);
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@SuppressWarnings("unchecked")
|
||||||
* Register a shader program. TODO: replace with forge registry?
|
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
|
||||||
*/
|
return (P) programs.get(spec).get(GlFog.getFogMode());
|
||||||
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
|
}
|
||||||
ResourceLocation name = spec.name;
|
|
||||||
if (registry.containsKey(name)) {
|
|
||||||
throw new IllegalStateException("Program spec '" + name + "' already registered.");
|
|
||||||
}
|
|
||||||
registry.put(name, spec);
|
|
||||||
return spec;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public static boolean isFlywheelWorld(World world) {
|
||||||
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
|
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
|
||||||
return (P) programs.get(spec).get(GlFog.getFogMode());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isFlywheelWorld(World world) {
|
public static boolean available() {
|
||||||
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
|
return canUseVBOs();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean available() {
|
public static boolean canUseInstancing() {
|
||||||
return canUseVBOs();
|
return enabled && instancingAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean canUseInstancing() {
|
public static boolean canUseVBOs() {
|
||||||
return enabled &&
|
return enabled && gl20();
|
||||||
compat.vertexArrayObjectsSupported() &&
|
}
|
||||||
compat.drawInstancedSupported() &&
|
|
||||||
compat.instancedArraysSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean canUseVBOs() {
|
public static boolean gl33() {
|
||||||
return enabled && gl20();
|
return capabilities.OpenGL33;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean gl33() {
|
public static boolean gl20() {
|
||||||
return capabilities.OpenGL33;
|
return capabilities.OpenGL20;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean gl20() {
|
public static void init() {
|
||||||
return capabilities.OpenGL20;
|
// Can be null when running datagenerators due to the unfortunate time we call this
|
||||||
}
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
if (mc == null) return;
|
||||||
|
|
||||||
public static void init() {
|
IResourceManager manager = mc.getResourceManager();
|
||||||
// Can be null when running datagenerators due to the unfortunate time we call this
|
|
||||||
Minecraft mc = Minecraft.getInstance();
|
|
||||||
if (mc == null) return;
|
|
||||||
|
|
||||||
IResourceManager manager = mc.getResourceManager();
|
if (manager instanceof IReloadableResourceManager) {
|
||||||
|
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
||||||
|
((IReloadableResourceManager) manager).addReloadListener(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (manager instanceof IReloadableResourceManager) {
|
public static void refresh() {
|
||||||
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
capabilities = GL.createCapabilities();
|
||||||
((IReloadableResourceManager) manager).addReloadListener(listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void refresh() {
|
compat = new GlFeatureCompat(capabilities);
|
||||||
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
instancingAvailable = compat.vertexArrayObjectsSupported() &&
|
||||||
|
compat.drawInstancedSupported() &&
|
||||||
|
compat.instancedArraysSupported();
|
||||||
|
|
||||||
|
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ package com.simibubi.create.foundation.render.backend;
|
||||||
import net.minecraft.client.renderer.Matrix3f;
|
import net.minecraft.client.renderer.Matrix3f;
|
||||||
import net.minecraft.client.renderer.Matrix4f;
|
import net.minecraft.client.renderer.Matrix4f;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
public class RenderUtil {
|
public class RenderUtil {
|
||||||
public static int nextPowerOf2(int a) {
|
public static int nextPowerOf2(int a) {
|
||||||
|
@ -17,9 +16,12 @@ public class RenderUtil {
|
||||||
return b == 0 && n != 0;
|
return b == 0 && n != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GPUs want matrices in column major order.
|
public static float[] writeMatrixStack(MatrixStack stack) {
|
||||||
|
return writeMatrixStack(stack.peek().getModel(), stack.peek().getNormal());
|
||||||
|
}
|
||||||
|
|
||||||
public static float[] bufferMatrices(Matrix4f model, Matrix3f normal) {
|
// GPUs want matrices in column major order.
|
||||||
|
public static float[] writeMatrixStack(Matrix4f model, Matrix3f normal) {
|
||||||
return new float[] {
|
return new float[] {
|
||||||
model.a00,
|
model.a00,
|
||||||
model.a10,
|
model.a10,
|
||||||
|
@ -48,4 +50,25 @@ public class RenderUtil {
|
||||||
normal.a22,
|
normal.a22,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float[] writeMatrix(Matrix4f model) {
|
||||||
|
return new float[]{
|
||||||
|
model.a00,
|
||||||
|
model.a10,
|
||||||
|
model.a20,
|
||||||
|
model.a30,
|
||||||
|
model.a01,
|
||||||
|
model.a11,
|
||||||
|
model.a21,
|
||||||
|
model.a31,
|
||||||
|
model.a02,
|
||||||
|
model.a12,
|
||||||
|
model.a22,
|
||||||
|
model.a32,
|
||||||
|
model.a03,
|
||||||
|
model.a13,
|
||||||
|
model.a23,
|
||||||
|
model.a33,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,175 +28,172 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ShaderLoader {
|
public class ShaderLoader {
|
||||||
public static final String SHADER_DIR = "flywheel/shaders/";
|
public static final String SHADER_DIR = "flywheel/shaders/";
|
||||||
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
||||||
|
|
||||||
static final Map<ResourceLocation, String> shaderSource = new HashMap<>();
|
static final Map<ResourceLocation, String> shaderSource = new HashMap<>();
|
||||||
|
|
||||||
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
|
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
|
||||||
if (predicate.test(VanillaResourceType.SHADERS)) {
|
if (predicate.test(VanillaResourceType.SHADERS)) {
|
||||||
Backend.capabilities = GL.createCapabilities();
|
OptifineHandler.refresh();
|
||||||
Backend.compat = new GlFeatureCompat(Backend.capabilities);
|
Backend.refresh();
|
||||||
|
|
||||||
OptifineHandler.refresh();
|
if (Backend.gl20()) {
|
||||||
Backend.refresh();
|
shaderSource.clear();
|
||||||
|
loadShaderSources(manager);
|
||||||
|
|
||||||
if (Backend.gl20()) {
|
Backend.programs.values().forEach(ProgramGroup::delete);
|
||||||
shaderSource.clear();
|
Backend.programs.clear();
|
||||||
loadShaderSources(manager);
|
Backend.registry.values().forEach(ShaderLoader::loadProgram);
|
||||||
|
|
||||||
Backend.programs.values().forEach(ProgramGroup::delete);
|
Backend.log.info("Loaded all shader programs.");
|
||||||
Backend.programs.clear();
|
}
|
||||||
Backend.registry.values().forEach(ShaderLoader::loadProgram);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Backend.log.info("Loaded all shader programs.");
|
private static void loadShaderSources(IResourceManager manager){
|
||||||
}
|
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
|
||||||
}
|
for (String ext : EXTENSIONS) {
|
||||||
}
|
if (s.endsWith(ext)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
private static void loadShaderSources(IResourceManager manager){
|
for (ResourceLocation location : allShaders) {
|
||||||
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
|
try {
|
||||||
for (String ext : EXTENSIONS) {
|
IResource resource = manager.getResource(location);
|
||||||
if (s.endsWith(ext)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (ResourceLocation location : allShaders) {
|
String file = readToString(resource.getInputStream());
|
||||||
try {
|
|
||||||
IResource resource = manager.getResource(location);
|
|
||||||
|
|
||||||
String file = readToString(resource.getInputStream());
|
ResourceLocation name = new ResourceLocation(location.getNamespace(),
|
||||||
|
location.getPath().substring(SHADER_DIR.length()));
|
||||||
|
|
||||||
ResourceLocation name = new ResourceLocation(location.getNamespace(),
|
shaderSource.put(name, file);
|
||||||
location.getPath().substring(SHADER_DIR.length()));
|
} catch (IOException e) {
|
||||||
|
|
||||||
shaderSource.put(name, file);
|
}
|
||||||
} catch (IOException e) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
|
||||||
}
|
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
|
||||||
}
|
|
||||||
|
|
||||||
static <P extends GlProgram, S extends ProgramSpec<P>> void loadProgram(S programSpec) {
|
for (GlFogMode fogMode : GlFogMode.values()) {
|
||||||
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
|
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
||||||
|
}
|
||||||
|
|
||||||
for (GlFogMode fogMode : GlFogMode.values()) {
|
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
|
||||||
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
|
Backend.log.debug("Loaded program {}", programSpec.name);
|
||||||
|
}
|
||||||
|
|
||||||
Backend.log.debug("Loaded program {}", programSpec.name);
|
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
|
||||||
}
|
GlShader vert = null;
|
||||||
|
GlShader frag = null;
|
||||||
|
try {
|
||||||
|
ShaderConstants defines = new ShaderConstants(programSpec.defines);
|
||||||
|
|
||||||
private static <P extends GlProgram, S extends ProgramSpec<P>> P loadProgram(S programSpec, GlFogMode fogMode) {
|
defines.defineAll(fogMode.getDefines());
|
||||||
GlShader vert = null;
|
|
||||||
GlShader frag = null;
|
|
||||||
try {
|
|
||||||
ShaderConstants defines = new ShaderConstants(programSpec.defines);
|
|
||||||
|
|
||||||
defines.defineAll(fogMode.getDefines());
|
vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines);
|
||||||
|
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
|
||||||
|
|
||||||
vert = loadShader(programSpec.getVert(), ShaderType.VERTEX, defines);
|
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
|
||||||
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
|
|
||||||
|
|
||||||
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
|
programSpec.attributes.forEach(builder::addAttribute);
|
||||||
|
|
||||||
programSpec.attributes.forEach(builder::addAttribute);
|
return builder.build(programSpec.factory);
|
||||||
|
|
||||||
return builder.build(programSpec.factory);
|
} finally {
|
||||||
|
if (vert != null) vert.delete();
|
||||||
|
if (frag != null) frag.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} finally {
|
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
|
||||||
if (vert != null) vert.delete();
|
|
||||||
if (frag != null) frag.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
|
private static String processIncludes(ResourceLocation baseName, String source) {
|
||||||
|
HashSet<ResourceLocation> seen = new HashSet<>();
|
||||||
|
seen.add(baseName);
|
||||||
|
|
||||||
private static String processIncludes(ResourceLocation baseName, String source) {
|
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
|
||||||
HashSet<ResourceLocation> seen = new HashSet<>();
|
}
|
||||||
seen.add(baseName);
|
|
||||||
|
|
||||||
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
|
private static Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
|
||||||
}
|
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
|
||||||
|
|
||||||
private static Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
|
Matcher matcher = includePattern.matcher(line);
|
||||||
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
|
|
||||||
|
|
||||||
Matcher matcher = includePattern.matcher(line);
|
if (matcher.find()) {
|
||||||
|
String includeName = matcher.group(1);
|
||||||
|
|
||||||
if (matcher.find()) {
|
ResourceLocation include = new ResourceLocation(includeName);
|
||||||
String includeName = matcher.group(1);
|
|
||||||
|
|
||||||
ResourceLocation include = new ResourceLocation(includeName);
|
if (seen.add(include)) {
|
||||||
|
String includeSource = shaderSource.get(include);
|
||||||
|
|
||||||
if (seen.add(include)) {
|
if (includeSource != null) {
|
||||||
String includeSource = shaderSource.get(include);
|
return includeRecursive(includeSource, seen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (includeSource != null) {
|
return Stream.of(line);
|
||||||
return includeRecursive(includeSource, seen);
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Stream.of(line);
|
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
|
||||||
});
|
String source = shaderSource.get(name);
|
||||||
}
|
|
||||||
|
|
||||||
private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
|
source = processIncludes(name, source);
|
||||||
String source = shaderSource.get(name);
|
|
||||||
|
|
||||||
source = processIncludes(name, source);
|
if (defines != null)
|
||||||
|
source = defines.process(source);
|
||||||
if (defines != null)
|
|
||||||
source = defines.process(source);
|
|
||||||
|
|
||||||
|
|
||||||
return new GlShader(type, name, source);
|
return new GlShader(type, name, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readToString(InputStream is) {
|
public static String readToString(InputStream is) {
|
||||||
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
|
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
|
||||||
ByteBuffer bytebuffer = null;
|
ByteBuffer bytebuffer = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bytebuffer = readToBuffer(is);
|
bytebuffer = readToBuffer(is);
|
||||||
int i = bytebuffer.position();
|
int i = bytebuffer.position();
|
||||||
((Buffer)bytebuffer).rewind();
|
((Buffer)bytebuffer).rewind();
|
||||||
return MemoryUtil.memASCII(bytebuffer, i);
|
return MemoryUtil.memASCII(bytebuffer, i);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (bytebuffer != null) {
|
if (bytebuffer != null) {
|
||||||
MemoryUtil.memFree(bytebuffer);
|
MemoryUtil.memFree(bytebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||||
ByteBuffer bytebuffer;
|
ByteBuffer bytebuffer;
|
||||||
if (is instanceof FileInputStream) {
|
if (is instanceof FileInputStream) {
|
||||||
FileInputStream fileinputstream = (FileInputStream)is;
|
FileInputStream fileinputstream = (FileInputStream)is;
|
||||||
FileChannel filechannel = fileinputstream.getChannel();
|
FileChannel filechannel = fileinputstream.getChannel();
|
||||||
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
|
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
|
||||||
|
|
||||||
while (filechannel.read(bytebuffer) != -1) { }
|
while (filechannel.read(bytebuffer) != -1) { }
|
||||||
} else {
|
} else {
|
||||||
bytebuffer = MemoryUtil.memAlloc(8192);
|
bytebuffer = MemoryUtil.memAlloc(8192);
|
||||||
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
|
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
|
||||||
|
|
||||||
while (readablebytechannel.read(bytebuffer) != -1) {
|
while (readablebytechannel.read(bytebuffer) != -1) {
|
||||||
if (bytebuffer.remaining() == 0) {
|
if (bytebuffer.remaining() == 0) {
|
||||||
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
|
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytebuffer;
|
return bytebuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.simibubi.create.foundation.render.backend.gl;
|
package com.simibubi.create.foundation.render.backend.gl;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.backend.RenderUtil;
|
||||||
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode;
|
import com.simibubi.create.foundation.render.backend.gl.shader.ProgramFogMode;
|
||||||
import org.lwjgl.opengl.GL20;
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
|
@ -53,9 +54,6 @@ public class BasicProgram extends GlProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
|
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
|
||||||
Backend.MATRIX_BUFFER.position(0);
|
GL20.glUniformMatrix4fv(uniform, false, RenderUtil.writeMatrix(mat));
|
||||||
mat.write(Backend.MATRIX_BUFFER);
|
|
||||||
Backend.MATRIX_BUFFER.rewind();
|
|
||||||
GL20.glUniformMatrix4fv(uniform, false, Backend.MATRIX_BUFFER);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
||||||
|
|
||||||
public interface IDynamicInstance {
|
public interface IDynamicInstance {
|
||||||
/**
|
/**
|
||||||
* Called every frame, this can be used to make more dynamic animations.
|
* Called every frame. This can be used to smoothly change instance data
|
||||||
|
* to allow for fancy animations that could not be achieved on the GPU alone.
|
||||||
*/
|
*/
|
||||||
void beginFrame();
|
void beginFrame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,9 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
||||||
|
|
||||||
public interface ITickableInstance {
|
public interface ITickableInstance {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called every tick. This is useful for things that don't have to be smooth,
|
||||||
|
* or to recalculate something that would only change after a game tick.
|
||||||
|
*/
|
||||||
void tick();
|
void tick();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,14 +39,6 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
||||||
public abstract void registerMaterials();
|
public abstract void registerMaterials();
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
int ticks = AnimationTickHolder.getTicks();
|
|
||||||
|
|
||||||
// Clean up twice a second. This doesn't have to happen every tick,
|
|
||||||
// but this does need to be run to ensure we don't miss anything.
|
|
||||||
if (ticks % 10 == 0) {
|
|
||||||
clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tickableInstances.size() > 0)
|
if (tickableInstances.size() > 0)
|
||||||
tickableInstances.values().forEach(ITickableInstance::tick);
|
tickableInstances.values().forEach(ITickableInstance::tick);
|
||||||
}
|
}
|
||||||
|
@ -187,16 +179,13 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clean() {
|
|
||||||
instances.keySet().removeIf(TileEntity::isRemoved);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
for (RenderMaterial<?, ?> material : materials.values()) {
|
for (RenderMaterial<?, ?> material : materials.values()) {
|
||||||
material.delete();
|
material.delete();
|
||||||
}
|
}
|
||||||
instances.clear();
|
instances.clear();
|
||||||
dynamicInstances.clear();
|
dynamicInstances.clear();
|
||||||
|
tickableInstances.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canCreateInstance(TileEntity tile) {
|
public boolean canCreateInstance(TileEntity tile) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class ModelData extends BasicData {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModelData setTransform(MatrixStack stack) {
|
public ModelData setTransform(MatrixStack stack) {
|
||||||
matrices = RenderUtil.bufferMatrices(stack.peek().getModel(), stack.peek().getNormal());
|
matrices = RenderUtil.writeMatrixStack(stack);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,19 @@
|
||||||
"package": "com.simibubi.create.foundation.mixin",
|
"package": "com.simibubi.create.foundation.mixin",
|
||||||
"compatibilityLevel": "JAVA_8",
|
"compatibilityLevel": "JAVA_8",
|
||||||
"refmap": "create.refmap.json",
|
"refmap": "create.refmap.json",
|
||||||
"client": ["AddRemoveTileMixin", "CancelTileEntityRenderMixin", "FogColorTrackerMixin", "LightUpdateMixin", "NetworkLightUpdateMixin", "RenderHooksMixin", "ShaderCloseMixin"],
|
"mixins": ["StepSoundMixin"],
|
||||||
|
"client": [
|
||||||
|
"TileAddMixin",
|
||||||
|
"CancelTileEntityRenderMixin",
|
||||||
|
"FogColorTrackerMixin",
|
||||||
|
"LightUpdateMixin",
|
||||||
|
"NetworkLightUpdateMixin",
|
||||||
|
"RenderHooksMixin",
|
||||||
|
"ShaderCloseMixin",
|
||||||
|
"TileRemoveMixin"
|
||||||
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
},
|
},
|
||||||
"minVersion": "0.8", "mixins": ["StepSoundMixin"]
|
"minVersion": "0.8"
|
||||||
}
|
}
|
Loading…
Reference in a new issue