diff --git a/src/main/java/gregtech/api/entities/particle/GTParticle.java b/src/main/java/gregtech/api/entities/particle/GTParticle.java new file mode 100644 index 00000000000..81f6550bfe7 --- /dev/null +++ b/src/main/java/gregtech/api/entities/particle/GTParticle.java @@ -0,0 +1,116 @@ +package gregtech.api.entities.particle; + +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/08/31 + * @Description: + */ +public abstract class GTParticle extends Particle { + protected float texturesPerRow = 16F; + protected boolean motionless = false; + + public GTParticle(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + } + + public GTParticle(World worldIn, double xCoordIn, double yCoordIn, double zCoordIn, double xSpeedIn, double ySpeedIn, double zSpeedIn) { + super(worldIn, xCoordIn, yCoordIn, zCoordIn, xSpeedIn, ySpeedIn, zSpeedIn); + } + + public void setImmortal() { + this.particleAge = -1; + } + + public void setMotionless(boolean motionless) { + this.motionless = motionless; + } + + public void setColor(int color) { + this.setRBGColorF((color >> 16 & 255) / 255.0F, + (color >> 8 & 255) / 255.0F, + (color & 255) / 255.0F); + this.setAlphaF((color >> 24 & 255) / 255.0F); + } + + public void setScale(float scale) { + this.particleScale = scale; + } + + public void setGravity(float gravity) { + this.particleGravity = gravity; + } + + public void setTexturesIndex(int particleTextureIndexX, int particleTextureIndexY) { + this.particleTextureIndexX = particleTextureIndexX; + this.particleTextureIndexY = particleTextureIndexY; + } + + public void setTexturesPerRow(float texturesPerRow) { + this.texturesPerRow = texturesPerRow; + } + + @Override + public void onUpdate() { + if (this.particleAge >= 0 && this.particleAge++ >= this.particleMaxAge) { + this.setExpired(); + } + + if (!motionless) { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + this.motionY -= 0.04D * (double)this.particleGravity; + this.move(this.motionX, this.motionY, this.motionZ); + this.motionX *= 0.9800000190734863D; + this.motionY *= 0.9800000190734863D; + this.motionZ *= 0.9800000190734863D; + + if (this.onGround) { + this.motionX *= 0.699999988079071D; + this.motionZ *= 0.699999988079071D; + } + } + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + float minU = (float) this.particleTextureIndexX / texturesPerRow; + float maxU = minU + 1F / texturesPerRow;//0.0624375F; + float minV = (float) this.particleTextureIndexY / texturesPerRow; + float maxV = minV + 1F / texturesPerRow;//0.0624375F; + float scale = 0.1F * this.particleScale; + + if (this.particleTexture != null) { + minU = this.particleTexture.getMinU(); + maxU = this.particleTexture.getMaxU(); + minV = this.particleTexture.getMinV(); + maxV = this.particleTexture.getMaxV(); + } + + float renderX = (float) (this.prevPosX + (this.posX - this.prevPosX) * (double) partialTicks - interpPosX); + float renderY = (float) (this.prevPosY + (this.posY - this.prevPosY) * (double) partialTicks - interpPosY); + float renderZ = (float) (this.prevPosZ + (this.posZ - this.prevPosZ) * (double) partialTicks - interpPosZ); + int brightnessForRender = this.getBrightnessForRender(partialTicks); + int j = brightnessForRender >> 16 & 65535; + int k = brightnessForRender & 65535; + buffer.pos(renderX - rotationX * scale - rotationXY * scale, renderY - rotationZ * scale, (renderZ - rotationYZ * scale - rotationXZ * scale)).tex(maxU, maxV).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos(renderX - rotationX * scale + rotationXY * scale, renderY + rotationZ * scale, (renderZ - rotationYZ * scale + rotationXZ * scale)).tex(maxU, minV).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos(renderX + rotationX * scale + rotationXY * scale, (renderY + rotationZ * scale), (renderZ + rotationYZ * scale + rotationXZ * scale)).tex(minU, minV).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + buffer.pos(renderX + rotationX * scale - rotationXY * scale, (renderY - rotationZ * scale), (renderZ + rotationYZ * scale - rotationXZ * scale)).tex(minU, maxV).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex(); + } + + /*** + * Do not create an instance here; use a static instance plz + */ + public IGTParticleHandler getGLHandler() { + return IGTParticleHandler.DEFAULT_FX_HANDLER; + } +} diff --git a/src/main/java/gregtech/api/entities/particle/GTParticleManager.java b/src/main/java/gregtech/api/entities/particle/GTParticleManager.java new file mode 100644 index 00000000000..becfe3ea095 --- /dev/null +++ b/src/main/java/gregtech/api/entities/particle/GTParticleManager.java @@ -0,0 +1,218 @@ +package gregtech.api.entities.particle; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleManager; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.crash.CrashReport; +import net.minecraft.crash.CrashReportCategory; +import net.minecraft.entity.Entity; +import net.minecraft.util.ReportedException; +import net.minecraft.util.Tuple; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.lwjgl.opengl.GL11; + +import java.util.*; +import java.util.concurrent.Callable; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/08/31 + * @Description: ParticleManger register, spawn, efficient rendering, update our custom particles. + */ +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public class GTParticleManager { + public static GTParticleManager instance = new GTParticleManager(); + private static World currentWorld = null; + private static ParticleManager particleManager = Minecraft.getMinecraft().effectRenderer; + + private final Map[]> renderQueue = new HashMap<>(); + private final Queue> newParticleQueue = new ArrayDeque<>(); + + private GTParticleManager() { } + + public void addEffect(Particle... particles) { + if (particleManager == null) { + particleManager = Minecraft.getMinecraft().effectRenderer; + } + for (Particle particle : particles) { + if (particle instanceof GTParticle && ((GTParticle) particle).getGLHandler() != null) { + newParticleQueue.add(new Tuple<>(((GTParticle) particle).getGLHandler(), (GTParticle)particle)); + } else { + particleManager.addEffect(particle); + } + } + } + + public void updateEffects() { + for (int i = 0; i < 4; ++i) { + updateEffectLayer(i); + } + if (!newParticleQueue.isEmpty()) { + for (Tuple handlerParticle = newParticleQueue.poll(); handlerParticle != null; handlerParticle = newParticleQueue.poll()) { + IGTParticleHandler handler = handlerParticle.getFirst(); + GTParticle particle = handlerParticle.getSecond(); + if (!renderQueue.containsKey(handler)) { + renderQueue.put(handler, new ArrayDeque[]{new ArrayDeque(), new ArrayDeque(), new ArrayDeque(), new ArrayDeque()}); + } + ArrayDeque[] arrayDeques = renderQueue.get(handler); + int layer = particle.getFXLayer(); + if (arrayDeques[layer].size() > 6000) { + arrayDeques[layer].removeFirst().setExpired(); + } + arrayDeques[layer].add(particle); + } + } + } + + private void updateEffectLayer(int layer) { + for (ArrayDeque[] array : renderQueue.values()) { + ArrayDeque queue = array[layer]; + if (!queue.isEmpty()) { + Iterator iterator = queue.iterator(); + while (iterator.hasNext()) { + Particle particle = iterator.next(); + tickParticle(particle); + if (!particle.isAlive()) { + iterator.remove(); + } + } + } + } + } + + public void clearAllEffects() { + renderQueue.clear(); + newParticleQueue.clear(); + } + + private void tickParticle(final Particle particle) { + try { + particle.onUpdate(); + } + catch (Throwable throwable) { + CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Ticking Particle"); + CrashReportCategory crashreportcategory = crashreport.makeCategory("Particle being ticked"); + final int i = particle.getFXLayer(); + crashreportcategory.addCrashSection("Particle", new Callable() { + public String call() { + return particle.toString(); + } + }); + crashreportcategory.addCrashSection("Particle Type", new Callable() { + public String call() { + return i == 0 ? "MISC_TEXTURE" : (i == 1 ? "TERRAIN_TEXTURE" : (i == 3 ? "ENTITY_PARTICLE_TEXTURE" : "Unknown - " + i)); + } + }); + throw new ReportedException(crashreport); + } + } + + public void renderParticles(Entity entityIn, float partialTicks) { + float rotationX = ActiveRenderInfo.getRotationX(); + float rotationZ = ActiveRenderInfo.getRotationZ(); + float rotationYZ = ActiveRenderInfo.getRotationYZ(); + float rotationXY = ActiveRenderInfo.getRotationXY(); + float rotationXZ = ActiveRenderInfo.getRotationXZ(); + Particle.interpPosX = entityIn.lastTickPosX + (entityIn.posX - entityIn.lastTickPosX) * (double) partialTicks; + Particle.interpPosY = entityIn.lastTickPosY + (entityIn.posY - entityIn.lastTickPosY) * (double) partialTicks; + Particle.interpPosZ = entityIn.lastTickPosZ + (entityIn.posZ - entityIn.lastTickPosZ) * (double) partialTicks; + Particle.cameraViewDir = entityIn.getLook(partialTicks); + GlStateManager.enableBlend(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0); + + Tessellator tessellator = Tessellator.getInstance(); + GlStateManager.disableLighting(); + + renderGlParticlesInLayer(tessellator, entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + + + + GlStateManager.depthMask(true); + GlStateManager.disableBlend(); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1F); + } + + private void renderGlParticlesInLayer(Tessellator tessellator, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + for (int layer = 0; layer < 4; layer++) { + for (IGTParticleHandler handler : renderQueue.keySet()) { + ArrayDeque particles = renderQueue.get(handler)[layer]; + if (particles.isEmpty()) continue; + BufferBuilder buffer = tessellator.getBuffer(); + handler.preDraw(layer, buffer, entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + for (final Particle particle : particles) { + try { + particle.renderParticle(buffer, entityIn, partialTicks, rotationX, rotationXZ, rotationZ, rotationYZ, rotationXY); + } + catch (Throwable throwable) { + CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Rendering Particle"); + CrashReportCategory crashreportcategory = crashreport.makeCategory("Particle being rendered"); + crashreportcategory.addCrashSection("Particle", new Callable() { + public String call() { + return particle.toString(); + } + }); + throw new ReportedException(crashreport); + } + } + handler.postDraw(layer, buffer, tessellator); + } + } + } + + public String getStatistics() { + int g = 0; + for (ArrayDeque[] array : renderQueue.values()) { + for (ArrayDeque queue : array) { + g += queue.size(); + } + } + return " GLFX: " + g; + } + + @SubscribeEvent + public static void clientTick(TickEvent.ClientTickEvent event) { + Minecraft mc = Minecraft.getMinecraft(); + if (event.phase != TickEvent.Phase.END || mc.isGamePaused()) { + return; + } + + if (currentWorld != mc.world) { + currentWorld = mc.world; + instance.clearAllEffects(); + } + + if (mc.world != null) { + instance.updateEffects(); + } + } + + @SubscribeEvent + public static void renderWorld(RenderWorldLastEvent event) { + instance.renderParticles(Minecraft.getMinecraft().player, event.getPartialTicks()); + } + + @SubscribeEvent + public static void debugOverlay(RenderGameOverlayEvent.Text event) { + if (event.getLeft().size() >= 5 && instance != null) { + String particleTxt = event.getLeft().get(4); + particleTxt += "." + TextFormatting.GOLD + " BC-P: " + instance.getStatistics(); + event.getLeft().set(4, particleTxt); + } + } +} diff --git a/src/main/java/gregtech/api/entities/particle/GTTexturedParticle.java b/src/main/java/gregtech/api/entities/particle/GTTexturedParticle.java new file mode 100644 index 00000000000..74b4be6a1c8 --- /dev/null +++ b/src/main/java/gregtech/api/entities/particle/GTTexturedParticle.java @@ -0,0 +1,86 @@ +package gregtech.api.entities.particle; + +import gregtech.api.gui.resources.ResourceHelper; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/09/01 + * @Description: + */ +public class GTTexturedParticle extends GTParticle { + private static final Map textureMap = new HashMap<>(); + + private ResourceLocation customTexture; + + public GTTexturedParticle(World worldIn, double posXIn, double posYIn, double posZIn, ResourceLocation texture) { + super(worldIn, posXIn, posYIn, posZIn); + setTexture(texture); + } + + public GTTexturedParticle(World worldIn, double xCoordIn, double yCoordIn, double zCoordIn, double xSpeedIn, double ySpeedIn, double zSpeedIn, ResourceLocation texture) { + super(worldIn, xCoordIn, yCoordIn, zCoordIn, xSpeedIn, ySpeedIn, zSpeedIn); + setTexture(texture); + } + + public void setTexture(ResourceLocation texture) { + this.customTexture = texture; + if (!textureMap.containsKey(texture)) { + textureMap.put(texture, new IGTParticleHandler[]{ + new TexturedParticleHandler(true,texture), + new TexturedParticleHandler(false,texture) + }); + } + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + super.renderParticle(buffer, entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + } + + @Override + public final IGTParticleHandler getGLHandler() { + return shouldDisableDepth() ? textureMap.get(customTexture)[0] : textureMap.get(customTexture)[1]; + } + + private static class TexturedParticleHandler implements IGTParticleHandler { + private final boolean depth; + private final ResourceLocation texture; + + public TexturedParticleHandler(boolean depth, ResourceLocation texture) { + this.depth = depth; + this.texture = texture; + } + + @Override + public void preDraw(int layer, BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + if (depth) { + GlStateManager.depthMask(true); + } else { + GlStateManager.depthMask(false); + GlStateManager.alphaFunc(GL11.GL_GREATER, 0F); + } + ResourceHelper.bindTexture(texture); + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + buffer.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + } + + @Override + public void postDraw(int layer, BufferBuilder buffer, Tessellator tessellator) { + tessellator.draw(); + } + } + +} diff --git a/src/main/java/gregtech/api/entities/particle/GTTexturedShaderParticle.java b/src/main/java/gregtech/api/entities/particle/GTTexturedShaderParticle.java new file mode 100644 index 00000000000..de316475903 --- /dev/null +++ b/src/main/java/gregtech/api/entities/particle/GTTexturedShaderParticle.java @@ -0,0 +1,89 @@ +package gregtech.api.entities.particle; + +import codechicken.lib.render.shader.ShaderProgram; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import org.lwjgl.opengl.EXTFramebufferObject; + +import static org.lwjgl.opengl.GL11.glGetInteger; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/09/01 + * @Description: using shader program render the texture in FBO and then bind this texture for particle. + */ +public abstract class GTTexturedShaderParticle extends GTParticle { + public GTTexturedShaderParticle(World worldIn, double posXIn, double posYIn, double posZIn) { + super(worldIn, posXIn, posYIn, posZIn); + this.setTexturesPerRow(1f); + } + + @Override + public abstract FBOShaderHandler getGLHandler(); + + public abstract static class FBOShaderHandler implements IGTParticleHandler, ShaderProgram.IUniformCallback { + protected final ShaderProgram program; + private final Framebuffer fbo; + + public FBOShaderHandler(ShaderProgram program) { + this.program = program; + fbo = new Framebuffer(1000, 1000, false); + } + + public void hookPreDraw(Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + program.useShader(); + } + + @Override + public final void preDraw(int layer, BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + if (program != null) { + int lastID = glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT); + fbo.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F); + fbo.framebufferClear(); + fbo.bindFramebuffer(true); + GlStateManager.pushMatrix(); + GlStateManager.pushAttrib(); + GlStateManager.viewport(0, 0, 1000, 1000); + Tessellator tessellator = Tessellator.getInstance(); + + hookPreDraw(entityIn, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); + + buffer.begin(7, DefaultVertexFormats.POSITION_TEX); + buffer.pos(-1, 1, 0).tex(0, 0).endVertex(); + buffer.pos(-1, -1, 0).tex(0, 1).endVertex(); + buffer.pos(1, -1, 0).tex(1, 1).endVertex(); + buffer.pos(1, 1, 0).tex(1, 0).endVertex(); + + tessellator.draw(); + + program.releaseShader(); + + Minecraft minecraft = Minecraft.getMinecraft(); + GlStateManager.viewport(0, 0, minecraft.displayWidth, minecraft.displayHeight); + GlStateManager.popAttrib(); + GlStateManager.popMatrix(); + fbo.unbindFramebufferTexture(); + OpenGlHelper.glBindFramebuffer(OpenGlHelper.GL_FRAMEBUFFER, lastID); + + GlStateManager.bindTexture(fbo.framebufferTexture); + } + GlStateManager.color(1,1,1,1); + buffer.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + } + + @Override + public final void postDraw(int layer, BufferBuilder buffer, Tessellator tessellator) { + tessellator.draw(); + } + + } +} diff --git a/src/main/java/gregtech/api/entities/particle/IGTParticleHandler.java b/src/main/java/gregtech/api/entities/particle/IGTParticleHandler.java new file mode 100644 index 00000000000..0e8bbab77af --- /dev/null +++ b/src/main/java/gregtech/api/entities/particle/IGTParticleHandler.java @@ -0,0 +1,39 @@ +package gregtech.api.entities.particle; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/08/31 + * @Description: copyright Created by brandon3055 on 30/11/2016. + */ + +public interface IGTParticleHandler { + + /** + * Run any pre render gl code here. + * You can also start drawing quads. + */ + void preDraw(int layer, BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ); + + /** + * Run any post render gl code here. + * This is where you would draw if you started drawing in preDraw + */ + void postDraw(int layer, BufferBuilder buffer, Tessellator tessellator); + + IGTParticleHandler DEFAULT_FX_HANDLER = new IGTParticleHandler() { + @Override + public void preDraw(int layer, BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { + + } + + @Override + public void postDraw(int layer, BufferBuilder buffer, Tessellator tessellator) { + } + }; +} diff --git a/src/main/java/gregtech/api/gui/resources/ResourceHelper.java b/src/main/java/gregtech/api/gui/resources/ResourceHelper.java new file mode 100644 index 00000000000..30b3d21650e --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/ResourceHelper.java @@ -0,0 +1,40 @@ +package gregtech.api.gui.resources; + +import gregtech.api.GTValues; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +import java.util.HashMap; +import java.util.Map; + +/** + * copyright com.brandon3055.draconicevolution.helpers; + */ +public class ResourceHelper { + + private static final Map cachedResources = new HashMap<>(); + public static final String RESOURCE_PREFIX = GTValues.MODID + ":"; + + public static void bindTexture(ResourceLocation texture) { + Minecraft.getMinecraft().renderEngine.bindTexture(texture); + } + + public static ResourceLocation getResource(String rs) { + if (!cachedResources.containsKey(rs)) { + cachedResources.put(rs, new ResourceLocation(RESOURCE_PREFIX + rs)); + } + return cachedResources.get(rs); + } + + public static ResourceLocation getResourceRAW(String rs) { + if (!cachedResources.containsKey(rs)) { + cachedResources.put(rs, new ResourceLocation(rs)); + } + return cachedResources.get(rs); + } + + public static void bindTexture(String rs) { + bindTexture(getResource(rs)); + } + +} diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index 9caf6232641..441a8237e11 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -195,6 +195,19 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, } } + /** + * Renders this meta tile entity (Emissive texture) + * Note that you shouldn't refer to world-related information in this method, because it + * will be called on ItemStacks too + * + * @param renderState render state (either chunk batched or item) + * @param pipeline default set of pipeline transformations + */ + @SideOnly(Side.CLIENT) + public void renderEmissiveMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + + } + @SideOnly(Side.CLIENT) public boolean canRenderInLayer(BlockRenderLayer renderLayer) { return renderLayer == BlockRenderLayer.CUTOUT_MIPPED; diff --git a/src/main/java/gregtech/api/metatileentity/WorkableTieredMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/WorkableTieredMetaTileEntity.java index e72cf5f5726..e18a3c753bf 100644 --- a/src/main/java/gregtech/api/metatileentity/WorkableTieredMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/WorkableTieredMetaTileEntity.java @@ -65,7 +65,17 @@ protected long getMaxInputOutputAmperage() { @Override public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { super.renderMetaTileEntity(renderState, translation, pipeline); - renderer.render(renderState, translation, pipeline, getFrontFacing(), workable.isActive()); + if (!workable.isActive()) { + renderer.render(renderState, translation, pipeline, getFrontFacing(), false); + } + } + + @Override + public void renderEmissiveMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { + super.renderEmissiveMetaTileEntity(renderState, translation, pipeline); + if (workable.isActive()) { + renderer.render(renderState, translation, pipeline, getFrontFacing(), true); + } } @Override diff --git a/src/main/java/gregtech/api/render/LightMapOperation.java b/src/main/java/gregtech/api/render/LightMapOperation.java new file mode 100644 index 00000000000..80d8fa8fb88 --- /dev/null +++ b/src/main/java/gregtech/api/render/LightMapOperation.java @@ -0,0 +1,37 @@ +package gregtech.api.render; + +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/08/31 + * @Description: hack light map in CCL; + */ +public class LightMapOperation implements IVertexOperation { + public static final int operationIndex = CCRenderState.registerOperation(); + int lightmapX; + int lightmapY; + + public LightMapOperation(int lightmapX, int lightmapY) { + this.lightmapX = lightmapX; + this.lightmapY = lightmapY; + } + + @Override + public boolean load(CCRenderState ccRenderState) { + return true; + } + + @Override + public void operate(CCRenderState ccRenderState) { + ccRenderState.brightness = lightmapY << 16 | lightmapX; + } + + @Override + public int operationID() { + return operationIndex; + } +} diff --git a/src/main/java/gregtech/api/render/MetaTileEntityRenderer.java b/src/main/java/gregtech/api/render/MetaTileEntityRenderer.java index f54ffc84fb7..4042286a555 100644 --- a/src/main/java/gregtech/api/render/MetaTileEntityRenderer.java +++ b/src/main/java/gregtech/api/render/MetaTileEntityRenderer.java @@ -114,6 +114,8 @@ public boolean renderBlock(IBlockAccess world, BlockPos pos, IBlockState state, renderState.lightMatrix.locate(world, pos); IVertexOperation[] pipeline = new IVertexOperation[]{renderState.lightMatrix}; metaTileEntity.renderMetaTileEntity(renderState, translation.copy(), pipeline); + pipeline = new IVertexOperation[]{new LightMapOperation(240, 240)}; + metaTileEntity.renderEmissiveMetaTileEntity(renderState, translation.copy(), pipeline); } Matrix4 coverTranslation = new Matrix4().translate(pos.getX(), pos.getY(), pos.getZ()); metaTileEntity.renderCovers(renderState, coverTranslation, renderLayer); diff --git a/src/main/java/gregtech/api/render/shader/Shaders.java b/src/main/java/gregtech/api/render/shader/Shaders.java new file mode 100644 index 00000000000..cfbee94f44a --- /dev/null +++ b/src/main/java/gregtech/api/render/shader/Shaders.java @@ -0,0 +1,54 @@ +package gregtech.api.render.shader; + +import codechicken.lib.render.shader.ShaderObject; +import gregtech.api.GTValues; +import gregtech.api.util.GTLog; +import gregtech.common.ConfigHolder; +import net.minecraft.client.renderer.OpenGlHelper; + +import java.io.IOException; + +import static codechicken.lib.render.shader.ShaderHelper.getStream; +import static codechicken.lib.render.shader.ShaderHelper.readShader; +import static codechicken.lib.render.shader.ShaderObject.ShaderType.FRAGMENT; +import static codechicken.lib.render.shader.ShaderObject.ShaderType.VERTEX; + +/** + * Created with IntelliJ IDEA. + * + * @Author: KilaBash + * @Date: 2021/08/30 + * @Description: Shaders are magic!!! + */ +public class Shaders { + + static { + if (allowedShader()) { + initShaders(); + } + } + + public static void initShaders() { + } + + public static ShaderObject loadShader(ShaderObject.ShaderType shaderType, String location) { + try { + return new ShaderObject(shaderType, readShader(getStream(String.format("/assets/%s/shaders/%s", GTValues.MODID, location)))); + } catch (IOException exception) { + GTLog.logger.error("error while loading shader {}", location, exception); + } + return null; + } + + public static void unloadShader(ShaderObject shaderObject) { + if (shaderObject != null) { + shaderObject.disposeObject(); + } + } + + public static boolean allowedShader() { + return OpenGlHelper.shadersSupported && ConfigHolder.clientConfig.useShader; + } + + +} diff --git a/src/main/java/gregtech/common/ConfigHolder.java b/src/main/java/gregtech/common/ConfigHolder.java index bf3385425e4..eae62c245c8 100644 --- a/src/main/java/gregtech/common/ConfigHolder.java +++ b/src/main/java/gregtech/common/ConfigHolder.java @@ -99,6 +99,16 @@ public class ConfigHolder { @Config.RequiresMcRestart public static int gasTurbineBonusOutput = 6144; + @Config.Comment("Client configs for file path, rendering and so on") + @Config.Name("Client Options") + @Config.RequiresMcRestart + public static ClientConfig clientConfig = new ClientConfig(); + + public static class ClientConfig { + @Config.Comment("Whether to use shader program. Default: true") + public boolean useShader = true; + } + public static class VanillaRecipes { @Config.Comment("Whether to make glass related recipes harder. Default: true")