Files
Mindustry/core/src/mindustry/graphics/BlockRenderer.java

313 lines
11 KiB
Java
Raw Normal View History

2019-12-25 01:39:38 -05:00
package mindustry.graphics;
2019-12-25 01:39:38 -05:00
import arc.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.graphics.gl.*;
import arc.math.*;
2020-02-18 19:34:07 -05:00
import arc.struct.*;
2019-12-25 01:39:38 -05:00
import arc.util.*;
import mindustry.content.*;
import mindustry.game.EventType.*;
import mindustry.game.Teams.*;
2020-03-06 15:22:13 -05:00
import mindustry.gen.*;
2019-12-25 01:39:38 -05:00
import mindustry.ui.*;
import mindustry.world.*;
2020-04-22 17:23:30 -04:00
import mindustry.world.blocks.power.*;
2020-10-02 19:51:30 -04:00
import static arc.Core.*;
2019-12-25 01:39:38 -05:00
import static mindustry.Vars.*;
2019-04-23 11:59:07 -04:00
public class BlockRenderer implements Disposable{
2020-10-15 16:33:51 -04:00
public static final int crackRegions = 8, maxCrackSize = 9;
2020-07-17 19:00:39 -04:00
private static final int initialRequests = 32 * 32;
private static final int expandr = 9;
private static final Color shadowColor = new Color(0, 0, 0, 0.71f);
2018-07-12 20:37:14 -04:00
2018-12-28 16:05:49 -05:00
public final FloorRenderer floor = new FloorRenderer();
2020-10-15 16:33:51 -04:00
public TextureRegion[][] cracks;
2018-07-12 20:37:14 -04:00
2020-06-11 15:25:46 -04:00
private Seq<Tile> tileview = new Seq<>(false, initialRequests, Tile.class);
2020-06-15 13:54:02 -04:00
private Seq<Tile> lightview = new Seq<>(false, initialRequests, Tile.class);
2020-04-22 12:47:29 -04:00
private int lastCamX, lastCamY, lastRangeX, lastRangeY;
private float brokenFade = 0f;
2020-04-22 16:06:26 -04:00
private FrameBuffer shadows = new FrameBuffer();
2020-06-15 13:54:02 -04:00
private FrameBuffer dark = new FrameBuffer();
2020-06-26 14:27:26 -04:00
private Seq<Building> outArray2 = new Seq<>();
2020-06-08 17:19:47 -04:00
private Seq<Tile> shadowEvents = new Seq<>();
2020-10-16 20:09:48 -04:00
private IntSet procEntities = new IntSet(), procLinks = new IntSet(), procLights = new IntSet();
2020-03-24 12:02:26 -04:00
private boolean displayStatus = false;
2018-07-12 20:37:14 -04:00
public BlockRenderer(){
2020-10-15 16:33:51 -04:00
Events.on(ClientLoadEvent.class, e -> {
cracks = new TextureRegion[maxCrackSize][crackRegions];
for(int size = 1; size <= maxCrackSize; size++){
for(int i = 0; i < crackRegions; i++){
cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i);
}
}
});
2018-12-26 13:22:31 -05:00
Events.on(WorldLoadEvent.class, event -> {
shadowEvents.clear();
2018-07-20 13:59:00 -04:00
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear);
shadows.resize(world.width(), world.height());
shadows.begin();
Core.graphics.clear(Color.white);
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
Draw.color(shadowColor);
2020-03-03 19:29:41 -05:00
for(Tile tile : world.tiles){
if(tile.block().hasShadow){
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
}
}
Draw.flush();
Draw.color();
shadows.end();
dark.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear);
2020-06-15 13:54:02 -04:00
dark.resize(world.width(), world.height());
dark.begin();
Core.graphics.clear(Color.white);
2020-06-15 13:54:02 -04:00
Draw.proj().setOrtho(0, 0, dark.getWidth(), dark.getHeight());
2020-03-03 19:29:41 -05:00
for(Tile tile : world.tiles){
float darkness = world.getDarkness(tile.x, tile.y);
2020-02-18 19:34:07 -05:00
2020-03-03 19:29:41 -05:00
if(darkness > 0){
Draw.color(0f, 0f, 0f, Math.min((darkness + 0.5f) / 4f, 1f));
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
}
}
Draw.flush();
Draw.color();
2020-06-15 13:54:02 -04:00
dark.end();
2018-07-20 13:59:00 -04:00
});
2020-09-03 14:04:30 -04:00
Events.on(TileChangeEvent.class, event -> {
shadowEvents.add(event.tile);
2018-12-26 13:22:31 -05:00
int avgx = (int)(camera.position.x / tilesize);
2019-04-08 09:03:18 -04:00
int avgy = (int)(camera.position.y / tilesize);
int rangex = (int)(camera.width / tilesize / 2) + 2;
int rangey = (int)(camera.height / tilesize / 2) + 2;
2018-12-26 13:22:31 -05:00
if(Math.abs(avgx - event.tile.x) <= rangex && Math.abs(avgy - event.tile.y) <= rangey){
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
}
2018-07-20 13:59:00 -04:00
});
2018-07-12 20:37:14 -04:00
}
2020-04-23 00:41:18 -04:00
public void drawDarkness(){
2020-06-15 13:54:02 -04:00
Draw.shader(Shaders.darkness);
Draw.fbo(dark, world.width(), world.height(), tilesize);
Draw.shader();
}
2019-11-04 23:47:51 -05:00
public void drawDestroyed(){
if(!Core.settings.getBool("destroyedblocks")) return;
if(control.input.isPlacing() || control.input.isBreaking()){
brokenFade = Mathf.lerpDelta(brokenFade, 1f, 0.1f);
}else{
brokenFade = Mathf.lerpDelta(brokenFade, 0f, 0.1f);
}
if(brokenFade > 0.001f){
2020-06-05 20:59:30 -04:00
for(BlockPlan block : state.teams.get(player.team()).blocks){
2019-09-30 22:12:02 -04:00
Block b = content.block(block.block);
2020-07-19 16:34:06 -04:00
if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset, block.y * tilesize + b.offset))) continue;
2019-09-30 22:12:02 -04:00
2019-12-11 15:13:45 -05:00
Draw.alpha(0.33f * brokenFade);
2019-10-07 17:17:01 -04:00
Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f));
2020-07-19 16:34:06 -04:00
Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset, block.y * tilesize + b.offset, b.rotate ? block.rotation * 90 : 0f);
2019-09-30 22:12:02 -04:00
}
Draw.reset();
}
}
public void drawShadows(){
if(!shadowEvents.isEmpty()){
Draw.flush();
2019-04-02 17:08:22 -04:00
shadows.begin();
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
2019-01-27 23:26:07 -05:00
for(Tile tile : shadowEvents){
//clear it first
Draw.color(Color.white);
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
//then draw the shadow
Draw.color(!tile.block().hasShadow ? Color.white : shadowColor);
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
}
2019-01-27 18:09:59 -05:00
Draw.flush();
Draw.color();
shadows.end();
shadowEvents.clear();
2019-01-18 09:19:42 -05:00
2020-04-14 20:29:59 -04:00
Draw.proj(camera);
2019-01-18 09:19:42 -05:00
}
float ww = world.width() * tilesize, wh = world.height() * tilesize;
2019-04-08 09:03:18 -04:00
float x = camera.position.x + tilesize / 2f, y = camera.position.y + tilesize / 2f;
float u = (x - camera.width / 2f) / ww,
v = (y - camera.height / 2f) / wh,
u2 = (x + camera.width / 2f) / ww,
v2 = (y + camera.height / 2f) / wh;
Tmp.tr1.set(shadows.getTexture());
Tmp.tr1.set(u, v2, u2, v);
2020-06-15 13:54:02 -04:00
Draw.shader(Shaders.darkness);
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
2018-12-29 13:06:17 -05:00
Draw.shader();
}
2019-04-08 09:03:18 -04:00
/** Process all blocks to draw. */
2018-07-12 20:37:14 -04:00
public void processBlocks(){
2020-03-24 12:02:26 -04:00
displayStatus = Core.settings.getBool("blockstatus");
2018-07-12 20:37:14 -04:00
2018-12-26 13:22:31 -05:00
int avgx = (int)(camera.position.x / tilesize);
int avgy = (int)(camera.position.y / tilesize);
2018-07-20 13:59:00 -04:00
2019-04-08 09:03:18 -04:00
int rangex = (int)(camera.width / tilesize / 2) + 3;
int rangey = (int)(camera.height / tilesize / 2) + 3;
if(avgx == lastCamX && avgy == lastCamY && lastRangeX == rangex && lastRangeY == rangey){
2018-07-20 13:59:00 -04:00
return;
}
2020-06-11 15:25:46 -04:00
tileview.clear();
2020-06-15 13:54:02 -04:00
lightview.clear();
2020-10-16 20:09:48 -04:00
procEntities.clear();
procLinks.clear();
procLights.clear();
2020-04-23 10:25:46 -04:00
2018-07-12 20:37:14 -04:00
int minx = Math.max(avgx - rangex - expandr, 0);
int miny = Math.max(avgy - rangey - expandr, 0);
int maxx = Math.min(world.width() - 1, avgx + rangex + expandr);
int maxy = Math.min(world.height() - 1, avgy + rangey + expandr);
for(int x = minx; x <= maxx; x++){
for(int y = miny; y <= maxy; y++){
boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey);
Tile tile = world.rawTile(x, y);
2019-01-15 21:21:28 -05:00
Block block = tile.block();
2020-06-11 15:25:46 -04:00
//link to center
if(tile.build != null){
tile = tile.build.tile;
}
2018-07-12 20:37:14 -04:00
2020-10-16 20:09:48 -04:00
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !procEntities.contains(tile.build.id))){
2019-01-15 21:21:28 -05:00
if(block.expanded || !expanded){
2020-10-16 20:09:48 -04:00
if(tile.build == null || procLinks.add(tile.build.id)){
2020-09-28 11:02:53 -04:00
tileview.add(tile);
if(tile.build != null){
2020-10-16 20:09:48 -04:00
procEntities.add(tile.build.id);
procLinks.add(tile.build.id);
2020-09-28 11:02:53 -04:00
}
}
2020-04-22 15:19:39 -04:00
}
2019-01-27 18:09:59 -05:00
2020-06-15 13:54:02 -04:00
//lights are drawn even in the expanded range
2020-10-16 20:09:48 -04:00
if(((tile.build != null && procLights.add(tile.build.pos())) || tile.block().emitLight)){
2020-06-15 13:54:02 -04:00
lightview.add(tile);
}
2020-06-27 19:16:39 -04:00
if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){
for(Building other : tile.build.getPowerConnections(outArray2)){
2020-10-16 20:09:48 -04:00
if(other.block instanceof PowerNode && procLinks.add(other.id)){ //TODO need a generic way to render connections!
tileview.add(other.tile);
}
}
2018-07-12 20:37:14 -04:00
}
}
2020-07-08 12:40:17 -04:00
//special case for floors
2020-10-16 20:09:48 -04:00
if((block == Blocks.air && tile.floor().emitLight) && procLights.add(tile.pos())){
2020-07-08 12:40:17 -04:00
lightview.add(tile);
}
2018-07-12 20:37:14 -04:00
}
}
2018-07-20 13:59:00 -04:00
lastCamX = avgx;
lastCamY = avgy;
lastRangeX = rangex;
lastRangeY = rangey;
2018-07-12 20:37:14 -04:00
}
2020-04-22 15:19:39 -04:00
public void drawBlocks(){
drawDestroyed();
2020-06-15 13:54:02 -04:00
//draw most tile stuff
2020-06-11 15:25:46 -04:00
for(int i = 0; i < tileview.size; i++){
Tile tile = tileview.items[i];
2020-04-22 15:19:39 -04:00
Block block = tile.block();
2020-06-27 19:16:39 -04:00
Building entity = tile.build;
2020-04-22 15:19:39 -04:00
2020-04-23 00:41:18 -04:00
Draw.z(Layer.block);
2020-04-23 13:58:06 -04:00
if(block != Blocks.air){
block.drawBase(tile);
Draw.reset();
2020-04-24 20:17:24 -04:00
Draw.z(Layer.block);
2020-04-23 00:41:18 -04:00
2020-04-23 13:58:06 -04:00
if(entity != null){
if(entity.damaged()){
entity.drawCracks();
2020-04-24 20:17:24 -04:00
Draw.z(Layer.block);
2020-04-23 13:58:06 -04:00
}
2018-07-12 20:37:14 -04:00
if(entity.team != player.team()){
2020-04-23 13:58:06 -04:00
entity.drawTeam();
2020-04-24 20:17:24 -04:00
Draw.z(Layer.block);
2020-04-23 13:58:06 -04:00
}
2018-07-12 20:37:14 -04:00
2020-04-23 13:58:06 -04:00
if(displayStatus && block.consumes.any()){
entity.drawStatus();
}
}
2020-04-23 17:45:12 -04:00
Draw.reset();
2020-03-24 12:02:26 -04:00
}
2018-07-12 20:37:14 -04:00
}
2020-06-15 13:54:02 -04:00
2020-07-08 12:40:17 -04:00
if(renderer.lights.enabled()){
//draw lights
for(int i = 0; i < lightview.size; i++){
Tile tile = lightview.items[i];
Building entity = tile.build;
2020-06-15 13:54:02 -04:00
2020-07-08 12:40:17 -04:00
if(entity != null){
entity.drawLight();
}else if(tile.block().emitLight){
tile.block().drawEnvironmentLight(tile);
2020-10-22 11:54:27 -04:00
}else if(tile.floor().emitLight && !tile.block().solid && world.getDarkness(tile.x, tile.y) < 3){ //only draw floor light under non-solid blocks
2020-07-08 12:40:17 -04:00
tile.floor().drawEnvironmentLight(tile);
}
2020-06-15 13:54:02 -04:00
}
}
2020-07-08 12:40:17 -04:00
2018-07-12 20:37:14 -04:00
}
2019-04-23 11:59:07 -04:00
@Override
public void dispose(){
shadows.dispose();
2020-06-15 13:54:02 -04:00
dark.dispose();
shadows = dark = null;
2019-04-23 11:59:07 -04:00
floor.dispose();
}
}