Render screen texture on block

This commit is contained in:
2026-04-22 22:30:23 +02:00
parent faa1be7175
commit 55f30283c3
10 changed files with 166 additions and 28 deletions

View File

@@ -0,0 +1,13 @@
package org.neoflock.neocomputers.platforms.fabric.client;
import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import org.neoflock.neocomputers.entity.BlockEntities;
import org.neoflock.neocomputers.gui.render.ScreenEntityRenderer;
public class NeoComputersFabricClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
BlockEntityRenderers.register(BlockEntities.INSTANCE.getSCREEN_ENTITY().get(), ScreenEntityRenderer::new);
}
}

View File

@@ -1,5 +1,7 @@
package org.neoflock.neocomputers package org.neoflock.neocomputers
import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.VertexFormat
import dev.architectury.event.events.client.ClientLifecycleEvent import dev.architectury.event.events.client.ClientLifecycleEvent
import dev.architectury.event.events.common.PlayerEvent import dev.architectury.event.events.common.PlayerEvent
import dev.architectury.event.events.common.TickEvent import dev.architectury.event.events.common.TickEvent
@@ -11,11 +13,15 @@ import org.neoflock.neocomputers.gui.menu.Menus
import dev.architectury.utils.Env import dev.architectury.utils.Env
import dev.architectury.utils.EnvExecutor import dev.architectury.utils.EnvExecutor
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.RenderStateShard
import net.minecraft.client.renderer.RenderType
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.block.NodeSynchronizer import org.neoflock.neocomputers.block.NodeSynchronizer
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.gui.render.ScreenRenderer import org.neoflock.neocomputers.gui.render.ScreenRenderer
import org.neoflock.neocomputers.gui.widget.ComponentRoles import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.item.GPUCard
import org.neoflock.neocomputers.item.Items import org.neoflock.neocomputers.item.Items
import org.neoflock.neocomputers.item.Tabs import org.neoflock.neocomputers.item.Tabs
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
@@ -24,12 +30,19 @@ import org.neoflock.neocomputers.utils.FontProvider
import org.neoflock.neocomputers.utils.GenericContainerScreen import org.neoflock.neocomputers.utils.GenericContainerScreen
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.nio.Buffer
object NeoComputers { object NeoComputers {
const val MODID: String = "neocomputers" const val MODID: String = "neocomputers"
val LOGGER: Logger = LoggerFactory.getLogger("NeoComputers") val LOGGER: Logger = LoggerFactory.getLogger("NeoComputers")
var PLATFORM: ModPlatform? = null var PLATFORM: ModPlatform? = null
val BlockEntityRenderType: RenderType = RenderType.create(
"nc_blockentities",
DefaultVertexFormat.POSITION_TEX,
VertexFormat.Mode.QUADS,
0xc000, RenderType.CompositeState.builder().setShaderState(RenderStateShard.POSITION_TEX_SHADER).createCompositeState(false)) // TODO: figure out correct buffer size and composite state
fun entrypoint(platform: ModPlatform?) { fun entrypoint(platform: ModPlatform?) {
PLATFORM = platform PLATFORM = platform
@@ -51,6 +64,14 @@ object NeoComputers {
ClientLifecycleEvent.CLIENT_STARTED.register { ClientLifecycleEvent.CLIENT_STARTED.register {
FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex")) FontProvider.load(ResourceLocation.fromNamespaceAndPath(MODID, "font/unscii.hex"))
ScreenRenderer.genUnboundTex(); ScreenRenderer.genUnboundTex();
var buffer: MutableList<BufferRenderer.GPUChar> = mutableListOf(BufferRenderer.GPUChar('h'), BufferRenderer.GPUChar('i'))
for (i in 0..398) {
buffer.add(BufferRenderer.GPUChar(' '))
}
var renderer: BufferRenderer = BufferRenderer(20, 20, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen/test"), buffer)
renderer.drawBuffer()
} }
ClientLifecycleEvent.CLIENT_STOPPING.register { ClientLifecycleEvent.CLIENT_STOPPING.register {

View File

@@ -1,8 +1,10 @@
package org.neoflock.neocomputers.block; package org.neoflock.neocomputers.block;
import dev.architectury.registry.menu.ExtendedMenuProvider
import dev.architectury.registry.menu.MenuRegistry import dev.architectury.registry.menu.MenuRegistry
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionHand
@@ -35,6 +37,7 @@ import kotlin.math.max
class ScreenBlock() : NodeBlock() { class ScreenBlock() : NodeBlock() {
companion object { companion object {
val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java) val FACING: EnumProperty<Direction> = EnumProperty.create<Direction>("facing", Direction::class.java)
val ENERGY: Long = 5
} }
init { init {
@@ -56,14 +59,19 @@ class ScreenBlock() : NodeBlock() {
): InteractionResult { ): InteractionResult {
if(!level.isClientSide) { if(!level.isClientSide) {
val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get() val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
if(!screenState.node.consumeEnergy(5)) { if(!screenState.node.consumeEnergy(ENERGY)) {
player.sendSystemMessage(Component.literal("Not enough power.")) player.sendSystemMessage(Component.literal("Not enough power."))
return InteractionResult.SUCCESS return InteractionResult.SUCCESS
}; };
MenuRegistry.openMenu(player as ServerPlayer, object : MenuProvider { MenuRegistry.openExtendedMenu(player as ServerPlayer, object : ExtendedMenuProvider {
override fun getDisplayName(): Component = Component.literal("SCREEEEEN!") override fun getDisplayName(): Component = Component.literal("SCREEEEEN!")
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu { override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
return Menus.SCREEN_MENU.get().create(i, inventory); // return Menus.SCREEN_MENU.get().create(i, inventory);
return ScreenMenu(i, inventory, level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get())
}
override fun saveExtraData(buf: FriendlyByteBuf?) {
buf!!.writeBlockPos(blockPos)
} }
}) })
} }

View File

@@ -1,8 +1,12 @@
package org.neoflock.neocomputers.entity; package org.neoflock.neocomputers.entity;
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.NodeBlockEntity import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.network.Networking import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole import org.neoflock.neocomputers.network.PowerRole
@@ -10,4 +14,38 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) { NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
override val node = Networking.Node() override val node = Networking.Node()
var bound = "screen/unbound"
var render_on_block = false
private var cleanrenderer: () -> Unit = { }; // TODO: THIS SUCKS, FIND A BETTER WAY
override fun setChanged() {
super.setChanged()
if (bound == "screen/unbound") {
createscreenstuffs()
}
}
override fun setRemoved() {
super.setRemoved()
cleanrenderer()
}
private fun createscreenstuffs() {
bound = "screen/"+node.address.toString().replace("-", "_")
NeoComputers.LOGGER.info(bound)
if (level!!.isClientSide) {
var buffer: MutableList<BufferRenderer.GPUChar> = mutableListOf()
for(char in node.address.toString()) {
buffer.add(BufferRenderer.GPUChar(char, 0xFFFF00, 0x0000FF))
}
for (i in 0..((40*20)-36)) {
buffer.add(BufferRenderer.GPUChar(' '))
}
var renderer: BufferRenderer = BufferRenderer(40, 20, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), buffer)
renderer.drawBuffer()
cleanrenderer = { renderer.clean() }
}
}
} }

View File

@@ -17,7 +17,8 @@ import org.neoflock.neocomputers.gui.screen.ScreenScreen
object Menus { object Menus {
val MENUS: DeferredRegister<MenuType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.MENU) val MENUS: DeferredRegister<MenuType<*>> = DeferredRegister.create(NeoComputers.MODID, Registries.MENU)
val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuType(::ScreenMenu, FeatureFlagSet.of()) } // val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuType(::ScreenMenu, FeatureFlagSet.of()) }
val SCREEN_MENU: RegistrySupplier<MenuType<ScreenMenu>> = MENUS.register("screen_menu") { MenuRegistry.ofExtended<ScreenMenu>(::ScreenMenu) }
val COMBUSTGEN_MENU: RegistrySupplier<MenuType<CombustionGeneratorMenu>> = MENUS.register("combustgen_menu") { MenuType(::CombustionGeneratorMenu, FeatureFlagSet.of() ) } val COMBUSTGEN_MENU: RegistrySupplier<MenuType<CombustionGeneratorMenu>> = MENUS.register("combustgen_menu") { MenuType(::CombustionGeneratorMenu, FeatureFlagSet.of() ) }
val CASE_MENU: RegistrySupplier<MenuType<CaseMenu>> = MENUS.register("case_menu") { MenuType(::CaseMenu, FeatureFlagSet.of() )} val CASE_MENU: RegistrySupplier<MenuType<CaseMenu>> = MENUS.register("case_menu") { MenuType(::CaseMenu, FeatureFlagSet.of() )}

View File

@@ -1,5 +1,6 @@
package org.neoflock.neocomputers.gui.menu; package org.neoflock.neocomputers.gui.menu;
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import org.neoflock.neocomputers.gui.menu.Menus; import org.neoflock.neocomputers.gui.menu.Menus;
@@ -7,7 +8,16 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.MenuType
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntity
import org.neoflock.neocomputers.entity.ScreenEntity
import org.neoflock.neocomputers.utils.GenericContainerMenu import org.neoflock.neocomputers.utils.GenericContainerMenu
class ScreenMenu(i: Int, inv: Inventory) : GenericContainerMenu(Menus.SCREEN_MENU.get(), i, SimpleContainer(0)) { class ScreenMenu : GenericContainerMenu {
var entity: ScreenEntity? = null
constructor(i: Int, inv: Inventory, buf: FriendlyByteBuf) : this(i, inv, inv.player.level().getBlockEntity(buf.readBlockPos()))
constructor(i: Int, inv: Inventory, entity: BlockEntity?) : super(Menus.SCREEN_MENU.get(), i, SimpleContainer(0)) {
this.entity = entity as ScreenEntity
}
} }

View File

@@ -20,14 +20,18 @@ class BufferRenderer(private var width: Int, private var height: Int, private va
private var image: NativeImage = NativeImage(texwidth, texheight, true); // idk what the boolean is private var image: NativeImage = NativeImage(texwidth, texheight, true); // idk what the boolean is
private var tex: DynamicTexture = DynamicTexture(image) private var tex: DynamicTexture = DynamicTexture(image)
init {
Minecraft.getInstance().textureManager.register(this.id, tex)
}
fun dump(path: String) { fun dump(path: String) {
image.writeToFile(File(path)) image.writeToFile(File(path))
NeoComputers.LOGGER.info("DUMPED!!!") NeoComputers.LOGGER.info("DUMPED!!!")
} }
fun toRGBA(color: Int): Int { // fun toRGBA(color: Int): Int {
return color.shl(8).or(0xFF) // return color.shl(8).or(0xFF)
} // }
fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) { fun drawGlyph(x: Int, y: Int, c: Char, fg: Int) {
var glyph: ArrayList<Byte> = FontProvider.map[c]!! var glyph: ArrayList<Byte> = FontProvider.map[c]!!
@@ -36,7 +40,7 @@ class BufferRenderer(private var width: Int, private var height: Int, private va
for (i in 0..<CHARW) { for (i in 0..<CHARW) {
// var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation // var pixel = ((glyph[j] and ((1 shl (CHARW - i - 1)).toByte())).toInt()) ushr (CHARW - i - 1) // retardation
var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt() var pixel = (glyph[j] and (0b10000000 ushr i).toByte()).toInt()
if (pixel > 0) image.setPixelRGBA(x+i, y+j, toRGBA(fg)) if (pixel > 0) image.setPixelRGBA(x+i, y+j, 0xFF000000.toInt()+fg)
} }
} }
} }
@@ -59,15 +63,11 @@ class BufferRenderer(private var width: Int, private var height: Int, private va
buffer[y*width+x] = c buffer[y*width+x] = c
} }
fun register() {
Minecraft.getInstance().textureManager.register(this.id, tex) // also idk how to unregister this
}
fun clean() { fun clean() {
Minecraft.getInstance().textureManager.release(this.id) Minecraft.getInstance().textureManager.release(this.id)
image.close() image.close()
tex.close() tex.close()
} }
data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) data class GPUChar(val c: Char, val fg: Int =0xFFFFFF, val bg: Int = 0) // all is bgr
} }

View File

@@ -0,0 +1,51 @@
package org.neoflock.neocomputers.gui.render
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
import net.minecraft.core.Direction
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.level.block.state.properties.EnumProperty
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.NeoComputers.BlockEntityRenderType
import org.neoflock.neocomputers.block.ScreenBlock
import org.neoflock.neocomputers.entity.ScreenEntity
class ScreenEntityRenderer(val context: BlockEntityRendererProvider.Context?) : BlockEntityRenderer<ScreenEntity> {
override fun render(entity: ScreenEntity, partialTick: Float, mat: PoseStack, bufferSource: MultiBufferSource, packedLight: Int, packedOverlay: Int) {
mat.pushPose()
handleDirection(entity, mat)
mat.translate(2 / 16f, 2 / 16f, 0.0001f) // am i epstein or am i just retarded
// mat.mulPose(Axis.YP.rotationDegrees(180f))
// handleDirection(entity, mat)
// RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderTexture(0, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, entity.bound))
val buffer = bufferSource.getBuffer(BlockEntityRenderType) // idk the correct rendertype for ts
buffer.addVertex(mat.last(), 3 / 4f, 0f, 0f).setUv(1f, 1f)
buffer.addVertex(mat.last(), 3 / 4f, 3 / 4f, 0f).setUv(1f, 0f)
buffer.addVertex(mat.last(), 0f, 3 / 4f, 0f).setUv(0f, 0f)
buffer.addVertex(mat.last(), 0f, 0f, 0f).setUv(0f, 1f)
mat.popPose()
}
private fun handleDirection(ent: ScreenEntity, mat: PoseStack) { // TODO: separate up and down from cardinal directions
when (ent.blockState.getValue(ScreenBlock.FACING)) {
Direction.SOUTH -> { mat.translate(0F, 0F, 1F) }
Direction.EAST -> { mat.mulPose(Axis.YP.rotationDegrees(90F)); mat.translate(-1F, 0F, 1F) }
Direction.WEST -> { mat.mulPose(Axis.YN.rotationDegrees(90F)); }
Direction.NORTH -> {mat.mulPose(Axis.YP.rotationDegrees(180F)); mat.translate(-1F, 0F, 0F) }
Direction.UP -> { mat.mulPose(Axis.XN.rotationDegrees(90F)); mat.mulPose(Axis.ZP.rotationDegrees(180F)); mat.translate(-1.0001F, 0F, 1F) } // idek
Direction.DOWN -> { mat.mulPose(Axis.XP.rotationDegrees(90F)); mat.mulPose(Axis.ZN.rotationDegrees(180F)); mat.translate(-1F, -1F, 0F) }
else -> return
}
}
// private fun handleDirection(ent: ScreenEntity, mat: PoseStack?) {
// `when`(ent.getBlockState().get)
// }
}

View File

@@ -10,6 +10,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.ScreenEntity
import org.neoflock.neocomputers.gui.buffer.BufferRenderer import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.gui.menu.ScreenMenu import org.neoflock.neocomputers.gui.menu.ScreenMenu
import org.neoflock.neocomputers.gui.render.ScreenRenderer import org.neoflock.neocomputers.gui.render.ScreenRenderer
@@ -17,17 +18,9 @@ import org.neoflock.neocomputers.gui.render.ScreenRenderer
class ScreenScreen : AbstractContainerScreen<ScreenMenu>{ class ScreenScreen : AbstractContainerScreen<ScreenMenu>{
private var renderer: ScreenRenderer = ScreenRenderer(); private var renderer: ScreenRenderer = ScreenRenderer();
private var bufferRenderer: BufferRenderer? = null;
constructor(abstractContainerMenu: ScreenMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) { constructor(abstractContainerMenu: ScreenMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) {
val buffer: ArrayList<BufferRenderer.GPUChar> = arrayListOf(BufferRenderer.GPUChar('h'), BufferRenderer.GPUChar('a'), BufferRenderer.GPUChar('i')) var ent: ScreenEntity = abstractContainerMenu.entity!!;
for (i in 0..<(400-3)) { renderer.bind(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, ent.bound))
buffer.add(BufferRenderer.GPUChar(' '))
}
bufferRenderer = BufferRenderer(20, 20, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen/test"), buffer)
bufferRenderer!!.register()
bufferRenderer!!.drawBuffer()
renderer.bind(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen/test"))
} }
override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {} override fun renderBg(guiGraphics: GuiGraphics, f: Float, i: Int, j: Int) {}
override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) { override fun render(graphics: GuiGraphics, mouseX: Int, mouseY: Int, something: Float) {
@@ -35,8 +28,8 @@ class ScreenScreen : AbstractContainerScreen<ScreenMenu>{
renderer.render(graphics, 50, 50, 100, 200) renderer.render(graphics, 50, 50, 100, 200)
} }
override fun onClose() { // override fun onClose() {
super.onClose() // super.onClose()
bufferRenderer!!.clean() // renderer.
} // }
} }

View File

@@ -21,6 +21,9 @@
], ],
"main": [ "main": [
"org.neoflock.neocomputers.platforms.fabric.NeoComputersFabric" "org.neoflock.neocomputers.platforms.fabric.NeoComputersFabric"
],
"client": [
"org.neoflock.neocomputers.platforms.fabric.client.NeoComputersFabricClient"
] ]
}, },
"mixins": [ "mixins": [