mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +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() {
|
||||
light = new byte[beltLength * 2];
|
||||
if (beltLength > 0) {
|
||||
light = new byte[beltLength * 2];
|
||||
|
||||
Vec3i vec = getBeltFacing().getDirectionVec();
|
||||
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
|
||||
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
|
||||
Vec3i vec = getBeltFacing().getDirectionVec();
|
||||
BeltSlope slope = getBlockState().get(BeltBlock.SLOPE);
|
||||
int verticality = slope == BeltSlope.DOWNWARD ? -1 : slope == BeltSlope.UPWARD ? 1 : 0;
|
||||
|
||||
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
|
||||
for (int i = 0; i < beltLength * 2; i += 2) {
|
||||
light[i] = (byte) world.getLightLevel(LightType.BLOCK, pos);
|
||||
light[i + 1] = (byte) world.getLightLevel(LightType.SKY, pos);
|
||||
BlockPos.Mutable pos = new BlockPos.Mutable(controller);
|
||||
for (int i = 0; i < beltLength * 2; i += 2) {
|
||||
light[i] = (byte) world.getLightLevel(LightType.BLOCK, 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 org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
|
@ -23,82 +24,85 @@ import net.minecraft.util.ResourceLocation;
|
|||
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||
|
||||
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 FloatBuffer MATRIX_BUFFER = MemoryUtil.memAllocFloat(16);
|
||||
public static final Logger log = LogManager.getLogger(Backend.class);
|
||||
public static GLCapabilities capabilities;
|
||||
public static GlFeatureCompat compat;
|
||||
|
||||
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
|
||||
static final Map<ProgramSpec<?>, ProgramGroup<?>> programs = new HashMap<>();
|
||||
private static boolean instancingAvailable;
|
||||
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 static GlFeatureCompat compat;
|
||||
public Backend() {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
|
||||
return (P) programs.get(spec).get(GlFog.getFogMode());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
|
||||
return (P) programs.get(spec).get(GlFog.getFogMode());
|
||||
}
|
||||
public static boolean isFlywheelWorld(World world) {
|
||||
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
|
||||
}
|
||||
|
||||
public static boolean isFlywheelWorld(World world) {
|
||||
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
|
||||
}
|
||||
public static boolean available() {
|
||||
return canUseVBOs();
|
||||
}
|
||||
|
||||
public static boolean available() {
|
||||
return canUseVBOs();
|
||||
}
|
||||
public static boolean canUseInstancing() {
|
||||
return enabled && instancingAvailable;
|
||||
}
|
||||
|
||||
public static boolean canUseInstancing() {
|
||||
return enabled &&
|
||||
compat.vertexArrayObjectsSupported() &&
|
||||
compat.drawInstancedSupported() &&
|
||||
compat.instancedArraysSupported();
|
||||
}
|
||||
public static boolean canUseVBOs() {
|
||||
return enabled && gl20();
|
||||
}
|
||||
|
||||
public static boolean canUseVBOs() {
|
||||
return enabled && gl20();
|
||||
}
|
||||
public static boolean gl33() {
|
||||
return capabilities.OpenGL33;
|
||||
}
|
||||
|
||||
public static boolean gl33() {
|
||||
return capabilities.OpenGL33;
|
||||
}
|
||||
public static boolean gl20() {
|
||||
return capabilities.OpenGL20;
|
||||
}
|
||||
|
||||
public static boolean gl20() {
|
||||
return capabilities.OpenGL20;
|
||||
}
|
||||
public static void init() {
|
||||
// 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() {
|
||||
// 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();
|
||||
|
||||
IResourceManager manager = mc.getResourceManager();
|
||||
if (manager instanceof IReloadableResourceManager) {
|
||||
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
||||
((IReloadableResourceManager) manager).addReloadListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
if (manager instanceof IReloadableResourceManager) {
|
||||
ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload;
|
||||
((IReloadableResourceManager) manager).addReloadListener(listener);
|
||||
}
|
||||
}
|
||||
public static void refresh() {
|
||||
capabilities = GL.createCapabilities();
|
||||
|
||||
public static void refresh() {
|
||||
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
|
||||
}
|
||||
compat = new GlFeatureCompat(capabilities);
|
||||
|
||||
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.Matrix4f;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
|
||||
public class RenderUtil {
|
||||
public static int nextPowerOf2(int a) {
|
||||
|
@ -17,9 +16,12 @@ public class RenderUtil {
|
|||
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[] {
|
||||
model.a00,
|
||||
model.a10,
|
||||
|
@ -48,4 +50,25 @@ public class RenderUtil {
|
|||
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;
|
||||
|
||||
public class ShaderLoader {
|
||||
public static final String SHADER_DIR = "flywheel/shaders/";
|
||||
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
||||
public static final String SHADER_DIR = "flywheel/shaders/";
|
||||
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) {
|
||||
if (predicate.test(VanillaResourceType.SHADERS)) {
|
||||
Backend.capabilities = GL.createCapabilities();
|
||||
Backend.compat = new GlFeatureCompat(Backend.capabilities);
|
||||
static void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
|
||||
if (predicate.test(VanillaResourceType.SHADERS)) {
|
||||
OptifineHandler.refresh();
|
||||
Backend.refresh();
|
||||
|
||||
OptifineHandler.refresh();
|
||||
Backend.refresh();
|
||||
if (Backend.gl20()) {
|
||||
shaderSource.clear();
|
||||
loadShaderSources(manager);
|
||||
|
||||
if (Backend.gl20()) {
|
||||
shaderSource.clear();
|
||||
loadShaderSources(manager);
|
||||
Backend.programs.values().forEach(ProgramGroup::delete);
|
||||
Backend.programs.clear();
|
||||
Backend.registry.values().forEach(ShaderLoader::loadProgram);
|
||||
|
||||
Backend.programs.values().forEach(ProgramGroup::delete);
|
||||
Backend.programs.clear();
|
||||
Backend.registry.values().forEach(ShaderLoader::loadProgram);
|
||||
Backend.log.info("Loaded all shader programs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
|
||||
for (String ext : EXTENSIONS) {
|
||||
if (s.endsWith(ext)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
for (ResourceLocation location : allShaders) {
|
||||
try {
|
||||
IResource resource = manager.getResource(location);
|
||||
|
||||
for (ResourceLocation location : allShaders) {
|
||||
try {
|
||||
IResource resource = manager.getResource(location);
|
||||
String file = readToString(resource.getInputStream());
|
||||
|
||||
String file = readToString(resource.getInputStream());
|
||||
ResourceLocation name = new ResourceLocation(location.getNamespace(),
|
||||
location.getPath().substring(SHADER_DIR.length()));
|
||||
|
||||
ResourceLocation name = new ResourceLocation(location.getNamespace(),
|
||||
location.getPath().substring(SHADER_DIR.length()));
|
||||
shaderSource.put(name, file);
|
||||
} 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) {
|
||||
Map<GlFogMode, P> programGroup = new EnumMap<>(GlFogMode.class);
|
||||
for (GlFogMode fogMode : GlFogMode.values()) {
|
||||
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
||||
}
|
||||
|
||||
for (GlFogMode fogMode : GlFogMode.values()) {
|
||||
programGroup.put(fogMode, loadProgram(programSpec, fogMode));
|
||||
}
|
||||
Backend.programs.put(programSpec, new ProgramGroup<>(programGroup));
|
||||
|
||||
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) {
|
||||
GlShader vert = null;
|
||||
GlShader frag = null;
|
||||
try {
|
||||
ShaderConstants defines = new ShaderConstants(programSpec.defines);
|
||||
defines.defineAll(fogMode.getDefines());
|
||||
|
||||
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);
|
||||
frag = loadShader(programSpec.getFrag(), ShaderType.FRAGMENT, defines);
|
||||
GlProgram.Builder builder = GlProgram.builder(programSpec.name, fogMode).attachShader(vert).attachShader(frag);
|
||||
|
||||
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 {
|
||||
if (vert != null) vert.delete();
|
||||
if (frag != null) frag.delete();
|
||||
}
|
||||
}
|
||||
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
|
||||
|
||||
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) {
|
||||
HashSet<ResourceLocation> seen = new HashSet<>();
|
||||
seen.add(baseName);
|
||||
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
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) {
|
||||
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
|
||||
Matcher matcher = includePattern.matcher(line);
|
||||
|
||||
Matcher matcher = includePattern.matcher(line);
|
||||
if (matcher.find()) {
|
||||
String includeName = matcher.group(1);
|
||||
|
||||
if (matcher.find()) {
|
||||
String includeName = matcher.group(1);
|
||||
ResourceLocation include = new ResourceLocation(includeName);
|
||||
|
||||
ResourceLocation include = new ResourceLocation(includeName);
|
||||
if (seen.add(include)) {
|
||||
String includeSource = shaderSource.get(include);
|
||||
|
||||
if (seen.add(include)) {
|
||||
String includeSource = shaderSource.get(include);
|
||||
if (includeSource != null) {
|
||||
return includeRecursive(includeSource, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (includeSource != null) {
|
||||
return includeRecursive(includeSource, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Stream.of(line);
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
String source = shaderSource.get(name);
|
||||
source = processIncludes(name, source);
|
||||
|
||||
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) {
|
||||
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
|
||||
ByteBuffer bytebuffer = null;
|
||||
public static String readToString(InputStream is) {
|
||||
RenderSystem.assertThread(RenderSystem::isOnRenderThread);
|
||||
ByteBuffer bytebuffer = null;
|
||||
|
||||
try {
|
||||
bytebuffer = readToBuffer(is);
|
||||
int i = bytebuffer.position();
|
||||
((Buffer)bytebuffer).rewind();
|
||||
return MemoryUtil.memASCII(bytebuffer, i);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
bytebuffer = readToBuffer(is);
|
||||
int i = bytebuffer.position();
|
||||
((Buffer)bytebuffer).rewind();
|
||||
return MemoryUtil.memASCII(bytebuffer, i);
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
if (bytebuffer != null) {
|
||||
MemoryUtil.memFree(bytebuffer);
|
||||
}
|
||||
} finally {
|
||||
if (bytebuffer != null) {
|
||||
MemoryUtil.memFree(bytebuffer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||
ByteBuffer bytebuffer;
|
||||
if (is instanceof FileInputStream) {
|
||||
FileInputStream fileinputstream = (FileInputStream)is;
|
||||
FileChannel filechannel = fileinputstream.getChannel();
|
||||
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
|
||||
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||
ByteBuffer bytebuffer;
|
||||
if (is instanceof FileInputStream) {
|
||||
FileInputStream fileinputstream = (FileInputStream)is;
|
||||
FileChannel filechannel = fileinputstream.getChannel();
|
||||
bytebuffer = MemoryUtil.memAlloc((int)filechannel.size() + 1);
|
||||
|
||||
while (filechannel.read(bytebuffer) != -1) { }
|
||||
} else {
|
||||
bytebuffer = MemoryUtil.memAlloc(8192);
|
||||
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
|
||||
while (filechannel.read(bytebuffer) != -1) { }
|
||||
} else {
|
||||
bytebuffer = MemoryUtil.memAlloc(8192);
|
||||
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
|
||||
|
||||
while (readablebytechannel.read(bytebuffer) != -1) {
|
||||
if (bytebuffer.remaining() == 0) {
|
||||
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (readablebytechannel.read(bytebuffer) != -1) {
|
||||
if (bytebuffer.remaining() == 0) {
|
||||
bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytebuffer;
|
||||
}
|
||||
return bytebuffer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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 org.lwjgl.opengl.GL20;
|
||||
|
||||
|
@ -53,9 +54,6 @@ public class BasicProgram extends GlProgram {
|
|||
}
|
||||
|
||||
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
|
||||
Backend.MATRIX_BUFFER.position(0);
|
||||
mat.write(Backend.MATRIX_BUFFER);
|
||||
Backend.MATRIX_BUFFER.rewind();
|
||||
GL20.glUniformMatrix4fv(uniform, false, Backend.MATRIX_BUFFER);
|
||||
GL20.glUniformMatrix4fv(uniform, false, RenderUtil.writeMatrix(mat));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -2,5 +2,9 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -39,14 +39,6 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
|||
public abstract void registerMaterials();
|
||||
|
||||
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)
|
||||
tickableInstances.values().forEach(ITickableInstance::tick);
|
||||
}
|
||||
|
@ -187,16 +179,13 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
|||
return renderer;
|
||||
}
|
||||
|
||||
private void clean() {
|
||||
instances.keySet().removeIf(TileEntity::isRemoved);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
for (RenderMaterial<?, ?> material : materials.values()) {
|
||||
material.delete();
|
||||
}
|
||||
instances.clear();
|
||||
dynamicInstances.clear();
|
||||
tickableInstances.clear();
|
||||
}
|
||||
|
||||
public boolean canCreateInstance(TileEntity tile) {
|
||||
|
|
|
@ -16,7 +16,7 @@ public class ModelData extends BasicData {
|
|||
}
|
||||
|
||||
public ModelData setTransform(MatrixStack stack) {
|
||||
matrices = RenderUtil.bufferMatrices(stack.peek().getModel(), stack.peek().getNormal());
|
||||
matrices = RenderUtil.writeMatrixStack(stack);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,19 @@
|
|||
"package": "com.simibubi.create.foundation.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"refmap": "create.refmap.json",
|
||||
"client": ["AddRemoveTileMixin", "CancelTileEntityRenderMixin", "FogColorTrackerMixin", "LightUpdateMixin", "NetworkLightUpdateMixin", "RenderHooksMixin", "ShaderCloseMixin"],
|
||||
"mixins": ["StepSoundMixin"],
|
||||
"client": [
|
||||
"TileAddMixin",
|
||||
"CancelTileEntityRenderMixin",
|
||||
"FogColorTrackerMixin",
|
||||
"LightUpdateMixin",
|
||||
"NetworkLightUpdateMixin",
|
||||
"RenderHooksMixin",
|
||||
"ShaderCloseMixin",
|
||||
"TileRemoveMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"minVersion": "0.8", "mixins": ["StepSoundMixin"]
|
||||
"minVersion": "0.8"
|
||||
}
|
Loading…
Reference in a new issue