Merge branch 'tiled-logic-displays' of https://github.com/Anuken/Mindustry
This commit is contained in:
@@ -158,7 +158,7 @@ public class Blocks{
|
||||
payloadConveyor, payloadRouter, reinforcedPayloadConveyor, reinforcedPayloadRouter, payloadMassDriver, largePayloadMassDriver, smallDeconstructor, deconstructor, constructor, largeConstructor, payloadLoader, payloadUnloader,
|
||||
|
||||
//logic
|
||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank,
|
||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, logicDisplayTile, memoryCell, memoryBank,
|
||||
canvas, reinforcedMessage,
|
||||
worldProcessor, worldCell, worldMessage, worldSwitch,
|
||||
|
||||
@@ -6596,6 +6596,10 @@ public class Blocks{
|
||||
size = 6;
|
||||
}};
|
||||
|
||||
logicDisplayTile = new TileableLogicDisplay("tile-logic-display"){{
|
||||
requirements(Category.logic, with(Items.lead, 10, Items.silicon, 10, Items.metaglass, 10, Items.phaseFabric, 6));
|
||||
}};
|
||||
|
||||
canvas = new CanvasBlock("canvas"){{
|
||||
requirements(Category.logic, BuildVisibility.shown, with(Items.silicon, 10, Items.beryllium, 10));
|
||||
|
||||
|
||||
@@ -169,7 +169,6 @@ public class SerpuloTechTree{
|
||||
});
|
||||
});
|
||||
|
||||
//logic disabled until further notice
|
||||
node(microProcessor, () -> {
|
||||
node(switchBlock, () -> {
|
||||
node(message, () -> {
|
||||
@@ -177,6 +176,10 @@ public class SerpuloTechTree{
|
||||
node(largeLogicDisplay, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(logicDisplayTile, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(memoryCell, () -> {
|
||||
|
||||
@@ -969,11 +969,7 @@ public class LExecutor{
|
||||
if(Vars.headless) return;
|
||||
|
||||
if(target.building() instanceof LogicDisplayBuild d && (d.team == exec.team || exec.privileged)){
|
||||
if(d.commands.size + exec.graphicsBuffer.size < maxDisplayBuffer){
|
||||
for(int i = 0; i < exec.graphicsBuffer.size; i++){
|
||||
d.commands.addLast(exec.graphicsBuffer.items[i]);
|
||||
}
|
||||
}
|
||||
d.flushCommands(exec.graphicsBuffer);
|
||||
exec.graphicsBuffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import mindustry.annotations.Annotations.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
@@ -65,7 +66,7 @@ public class LogicDisplay extends Block{
|
||||
}
|
||||
|
||||
public class LogicDisplayBuild extends Building{
|
||||
public FrameBuffer buffer;
|
||||
public @Nullable FrameBuffer buffer;
|
||||
public float color = Color.whiteFloatBits;
|
||||
public float stroke = 1f;
|
||||
public LongQueue commands = new LongQueue(256);
|
||||
@@ -87,12 +88,34 @@ public class LogicDisplay extends Block{
|
||||
}
|
||||
});
|
||||
|
||||
processCommands();
|
||||
|
||||
Draw.blend(Blending.disabled);
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
if(buffer != null){
|
||||
Draw.rect(Draw.wrap(buffer.getTexture()), x, y, buffer.getWidth() * scaleFactor * Draw.scl, -buffer.getHeight() * scaleFactor * Draw.scl);
|
||||
}
|
||||
});
|
||||
Draw.blend();
|
||||
}
|
||||
|
||||
public void flushCommands(LongSeq graphicsBuffer){
|
||||
int added = Math.min(graphicsBuffer.size, LExecutor.maxDisplayBuffer - commands.size);
|
||||
|
||||
for(int i = 0; i < added; i++){
|
||||
commands.addLast(graphicsBuffer.items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void processCommands(){
|
||||
//don't bother processing commands if displays are off
|
||||
if(!commands.isEmpty()){
|
||||
if(!commands.isEmpty() && buffer != null){
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
if(buffer == null) return;
|
||||
|
||||
Tmp.m1.set(Draw.proj());
|
||||
Tmp.m2.set(Draw.trans());
|
||||
Draw.proj(0, 0, displaySize, displaySize);
|
||||
Draw.proj(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
if(transform != null){
|
||||
Draw.trans(transform);
|
||||
}
|
||||
@@ -148,14 +171,6 @@ public class LogicDisplay extends Block{
|
||||
Draw.reset();
|
||||
});
|
||||
}
|
||||
|
||||
Draw.blend(Blending.disabled);
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
if(buffer != null){
|
||||
Draw.rect(Draw.wrap(buffer.getTexture()), x, y, buffer.getWidth() * scaleFactor * Draw.scl, -buffer.getHeight() * scaleFactor * Draw.scl);
|
||||
}
|
||||
});
|
||||
Draw.blend();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
287
core/src/mindustry/world/blocks/logic/TileableLogicDisplay.java
Normal file
287
core/src/mindustry/world/blocks/logic/TileableLogicDisplay.java
Normal file
@@ -0,0 +1,287 @@
|
||||
package mindustry.world.blocks.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class TileableLogicDisplay extends LogicDisplay{
|
||||
protected static final Seq<TileableLogicDisplayBuild> queue = new Seq<>();
|
||||
protected static final Seq<TileableLogicDisplayBuild> displays = new Seq<>();
|
||||
protected static final ObjectSet<FrameBuffer> buffers = new ObjectSet<>();
|
||||
protected static final IntSet processed = new IntSet();
|
||||
|
||||
//in tiles
|
||||
public int maxDisplayDimensions = 12;
|
||||
public @Load(value = "@-#", length = 47) TextureRegion[] tileRegion;
|
||||
public @Load("@-back") TextureRegion backRegion;
|
||||
|
||||
static final int[] bitmasks = {
|
||||
39, 36, 39, 36, 27, 16, 27, 24, 39, 36, 39, 36, 27, 16, 27, 24,
|
||||
38, 37, 38, 37, 17, 41, 17, 43, 38, 37, 38, 37, 26, 21, 26, 25,
|
||||
39, 36, 39, 36, 27, 16, 27, 24, 39, 36, 39, 36, 27, 16, 27, 24,
|
||||
38, 37, 38, 37, 17, 41, 17, 43, 38, 37, 38, 37, 26, 21, 26, 25,
|
||||
3, 4, 3, 4, 15, 40, 15, 20, 3, 4, 3, 4, 15, 40, 15, 20,
|
||||
5, 28, 5, 28, 29, 10, 29, 23, 5, 28, 5, 28, 31, 11, 31, 32,
|
||||
3, 4, 3, 4, 15, 40, 15, 20, 3, 4, 3, 4, 15, 40, 15, 20,
|
||||
2, 30, 2, 30, 9, 46, 9, 22, 2, 30, 2, 30, 14, 44, 14, 6,
|
||||
39, 36, 39, 36, 27, 16, 27, 24, 39, 36, 39, 36, 27, 16, 27, 24,
|
||||
38, 37, 38, 37, 17, 41, 17, 43, 38, 37, 38, 37, 26, 21, 26, 25,
|
||||
39, 36, 39, 36, 27, 16, 27, 24, 39, 36, 39, 36, 27, 16, 27, 24,
|
||||
38, 37, 38, 37, 17, 41, 17, 43, 38, 37, 38, 37, 26, 21, 26, 25,
|
||||
3, 0, 3, 0, 15, 42, 15, 12, 3, 0, 3, 0, 15, 42, 15, 12,
|
||||
5, 8, 5, 8, 29, 35, 29, 33, 5, 8, 5, 8, 31, 34, 31, 7,
|
||||
3, 0, 3, 0, 15, 42, 15, 12, 3, 0, 3, 0, 15, 42, 15, 12,
|
||||
2, 1, 2, 1, 9, 45, 9, 19, 2, 1, 2, 1, 14, 18, 14, 13,
|
||||
};
|
||||
|
||||
public TileableLogicDisplay(String name){
|
||||
super(name);
|
||||
|
||||
displaySize = 32;
|
||||
}
|
||||
|
||||
public static void linkDisplays(TileableLogicDisplayBuild start){
|
||||
TileableLogicDisplayBuild root = null;
|
||||
|
||||
int topX = start.tile.x, topY = start.tile.y, botX = start.tile.x, botY = start.tile.y;
|
||||
|
||||
queue.clear();
|
||||
displays.clear();
|
||||
processed.clear();
|
||||
|
||||
queue.add(start);
|
||||
displays.add(start);
|
||||
|
||||
while(!queue.isEmpty()){
|
||||
var next = queue.pop();
|
||||
processed.add(next.id);
|
||||
|
||||
//assign root based on bottom leftmost position
|
||||
if(root == null || next.tile.x < root.tile.x || next.tile.y < root.tile.y){
|
||||
root = next;
|
||||
}
|
||||
|
||||
topX = Math.max(next.tile.x, topX);
|
||||
topY = Math.max(next.tile.y, topY);
|
||||
botX = Math.min(next.tile.x, botX);
|
||||
botY = Math.min(next.tile.y, botY);
|
||||
|
||||
for(var prox : next.proximity){
|
||||
if(prox instanceof TileableLogicDisplayBuild disp && processed.add(disp.id)){
|
||||
queue.add(disp);
|
||||
displays.add(disp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(root.prevBuffers == null){
|
||||
root.prevBuffers = new Seq<>();
|
||||
}
|
||||
|
||||
//add all new buffers
|
||||
buffers.clear();
|
||||
for(var member : displays){
|
||||
if(member.buffer != null && buffers.add(member.buffer)){
|
||||
root.prevBuffers.add(new MergeBuffer(member.buffer, member.originX, member.originY, member.tilesWidth, member.tilesHeight));
|
||||
}
|
||||
}
|
||||
|
||||
int tilesWidth = topX - botX + 1, tilesHeight = topY - botY + 1;
|
||||
|
||||
//the new root display has been assigned
|
||||
for(var member : displays){
|
||||
member.needsUpdate = false;
|
||||
member.rootDisplay = root;
|
||||
member.tilesWidth = tilesWidth;
|
||||
member.tilesHeight = tilesHeight;
|
||||
member.originX = botX;
|
||||
member.originY = botY;
|
||||
member.buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
static class MergeBuffer{
|
||||
FrameBuffer buffer;
|
||||
int x, y, width, height;
|
||||
|
||||
MergeBuffer(FrameBuffer buffer, int x, int y, int width, int height){
|
||||
this.buffer = buffer;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "MergeBuffer{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", width=" + width +
|
||||
", height=" + height +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public class TileableLogicDisplayBuild extends LogicDisplayBuild{
|
||||
//bottom left corner of display
|
||||
public TileableLogicDisplayBuild rootDisplay = this;
|
||||
//size of display area
|
||||
public int tilesWidth = 1, tilesHeight = 1, originX, originY;
|
||||
public @Nullable Seq<MergeBuffer> prevBuffers;
|
||||
|
||||
public int bits = 0;
|
||||
public boolean needsUpdate = false;
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
super.display(table);
|
||||
|
||||
if(tilesWidth > maxDisplayDimensions || tilesHeight > maxDisplayDimensions){
|
||||
table.row().add(Core.bundle.format("bar.displaytoolarge", maxDisplayDimensions, maxDisplayDimensions)).color(Color.scarlet).growX().wrap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProximityUpdate(){
|
||||
super.onProximityUpdate();
|
||||
|
||||
bits = 0;
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
Tile other = tile.nearby(Geometry.d8(i));
|
||||
if(other != null && other.block() == block && other.team() == team){
|
||||
bits |= (1 << i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
//TODO if this is called before draw() on the root display is called, it will wipe it
|
||||
if(needsUpdate){
|
||||
needsUpdate = false;
|
||||
linkDisplays(this);
|
||||
}
|
||||
|
||||
Draw.rect(backRegion, x, y);
|
||||
|
||||
//don't even bother processing anything when displays are off.
|
||||
if(!Vars.renderer.drawDisplays) return;
|
||||
|
||||
if(isRoot()){
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
if(buffer == null && tilesWidth <= maxDisplayDimensions && tilesHeight <= maxDisplayDimensions){
|
||||
buffer = new FrameBuffer(32 * tilesWidth, 32 * tilesHeight);
|
||||
|
||||
Tmp.m1.set(Draw.proj());
|
||||
Tmp.m2.set(Draw.trans());
|
||||
Draw.proj(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
|
||||
//clear the buffer - some OSs leave garbage in it
|
||||
buffer.begin(Pal.darkerMetal);
|
||||
if(prevBuffers != null){
|
||||
for(var other : prevBuffers){
|
||||
Draw.rect(Draw.wrap(other.buffer.getTexture()), (other.x - originX) * 32 + other.buffer.getWidth()/2f, (other.y - originY) * 32 + other.buffer.getHeight()/2f, other.buffer.getWidth(), -other.buffer.getHeight());
|
||||
Draw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
buffer.end();
|
||||
Draw.proj(Tmp.m1);
|
||||
Draw.trans(Tmp.m2);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
if(prevBuffers != null){
|
||||
for(var other : prevBuffers){
|
||||
if(!other.buffer.isDisposed()){
|
||||
other.buffer.dispose();
|
||||
}
|
||||
}
|
||||
prevBuffers.clear();
|
||||
}
|
||||
});
|
||||
|
||||
processCommands();
|
||||
}
|
||||
|
||||
float offset = 0.001f + (rootDisplay.buffer == null ? 0f : (rootDisplay.buffer.hashCode() % 1_000_000) / 1_000_000f * 0.01f);
|
||||
|
||||
Draw.z(Layer.block + offset);
|
||||
|
||||
Draw.blend(Blending.disabled);
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
if(rootDisplay.buffer != null){
|
||||
|
||||
int rtx = (tile.x - originX), rty = (tile.y - originY);
|
||||
|
||||
Tmp.tr1.set(rootDisplay.buffer.getTexture(), rtx * 32, rty * 32, 32, 32);
|
||||
Draw.rect(Tmp.tr1, x, y, tilesize, -tilesize);
|
||||
}
|
||||
});
|
||||
Draw.blend();
|
||||
|
||||
Draw.z(Layer.block + 0.02f);
|
||||
|
||||
Draw.rect(tileRegion[bitmasks[bits]], x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushCommands(LongSeq graphicsBuffer){
|
||||
if(isRoot()){
|
||||
super.flushCommands(graphicsBuffer);
|
||||
}else{
|
||||
rootDisplay.flushCommands(graphicsBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateOthers(){
|
||||
for(int i = 0; i < 4; i++){
|
||||
Tile other = tile.nearby(Geometry.d8edge(i));
|
||||
if(other != null && other.block() == block && other.team() == team){
|
||||
other.build.onProximityUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProximityAdded(){
|
||||
super.onProximityAdded();
|
||||
|
||||
needsUpdate = true;
|
||||
|
||||
updateOthers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProximityRemoved(){
|
||||
super.onProximityRemoved();
|
||||
|
||||
processed.clear();
|
||||
|
||||
for(var other : proximity){
|
||||
if(other instanceof TileableLogicDisplayBuild tl && !processed.contains(tl.id)){
|
||||
tl.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
updateOthers();
|
||||
}
|
||||
|
||||
public boolean isRoot(){
|
||||
return rootDisplay == this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user