2019-12-25 01:39:38 -05:00
|
|
|
package mindustry.graphics;
|
2017-12-20 17:05:15 -05:00
|
|
|
|
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.*;
|
|
|
|
import mindustry.ui.*;
|
|
|
|
import mindustry.world.*;
|
2018-04-22 17:40:23 -04:00
|
|
|
|
2019-12-25 01:39:38 -05:00
|
|
|
import static arc.Core.camera;
|
|
|
|
import static mindustry.Vars.*;
|
2018-01-17 17:28:33 -05:00
|
|
|
|
2019-04-23 11:59:07 -04:00
|
|
|
public class BlockRenderer implements Disposable{
|
2018-07-12 20:37:14 -04:00
|
|
|
private final static int initialRequests = 32 * 32;
|
2019-03-02 23:06:14 -05:00
|
|
|
private final static int expandr = 9;
|
2019-03-28 14:38:00 -04:00
|
|
|
private final static 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();
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2018-10-19 12:58:53 -04:00
|
|
|
private Array<BlockRequest> requests = new Array<>(true, initialRequests, BlockRequest.class);
|
2018-07-20 18:41:08 -04:00
|
|
|
private int lastCamX, lastCamY, lastRangeX, lastRangeY;
|
2018-07-12 20:37:14 -04:00
|
|
|
private int requestidx = 0;
|
|
|
|
private int iterateidx = 0;
|
2019-10-14 23:43:13 -04:00
|
|
|
private float brokenFade = 0f;
|
2019-01-09 16:37:14 -05:00
|
|
|
private FrameBuffer shadows = new FrameBuffer(2, 2);
|
2019-01-27 12:09:01 -05:00
|
|
|
private FrameBuffer fog = new FrameBuffer(2, 2);
|
2019-02-21 13:11:28 -05:00
|
|
|
private Array<Tile> outArray = new Array<>();
|
2019-03-28 12:19:54 -04:00
|
|
|
private Array<Tile> shadowEvents = new Array<>();
|
2018-07-12 20:37:14 -04:00
|
|
|
|
|
|
|
public BlockRenderer(){
|
|
|
|
|
|
|
|
for(int i = 0; i < requests.size; i++){
|
|
|
|
requests.set(i, new BlockRequest());
|
|
|
|
}
|
2018-07-20 13:59:00 -04:00
|
|
|
|
2018-12-26 13:22:31 -05:00
|
|
|
Events.on(WorldLoadEvent.class, event -> {
|
2019-03-28 12:19:54 -04:00
|
|
|
shadowEvents.clear();
|
2018-07-20 13:59:00 -04:00
|
|
|
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
|
2019-01-27 12:09:01 -05:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
shadows.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
|
|
|
|
shadows.resize(world.width(), world.height());
|
|
|
|
shadows.begin();
|
2019-09-09 16:22:29 -04:00
|
|
|
Core.graphics.clear(Color.white);
|
2019-03-28 12:19:54 -04:00
|
|
|
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);
|
2019-03-28 12:19:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Draw.flush();
|
|
|
|
Draw.color();
|
|
|
|
shadows.end();
|
|
|
|
|
2019-01-27 12:09:01 -05:00
|
|
|
fog.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
|
|
|
|
fog.resize(world.width(), world.height());
|
|
|
|
fog.begin();
|
2019-09-09 16:22:29 -04:00
|
|
|
Core.graphics.clear(Color.white);
|
2019-01-27 12:09:01 -05:00
|
|
|
Draw.proj().setOrtho(0, 0, fog.getWidth(), fog.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);
|
2019-01-27 12:09:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Draw.flush();
|
|
|
|
Draw.color();
|
|
|
|
fog.end();
|
2018-07-20 13:59:00 -04:00
|
|
|
});
|
|
|
|
|
2018-08-31 16:14:14 -04:00
|
|
|
Events.on(TileChangeEvent.class, event -> {
|
2019-03-28 12:19:54 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-01-27 12:09:01 -05:00
|
|
|
public void drawFog(){
|
|
|
|
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;
|
2019-01-27 12:09:01 -05:00
|
|
|
|
|
|
|
Tmp.tr1.set(fog.getTexture());
|
|
|
|
Tmp.tr1.set(u, v2, u2, v);
|
|
|
|
|
|
|
|
Draw.shader(Shaders.fog);
|
|
|
|
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
|
|
|
|
Draw.shader();
|
|
|
|
}
|
|
|
|
|
2019-11-04 23:47:51 -05:00
|
|
|
public void drawDestroyed(){
|
|
|
|
if(!Core.settings.getBool("destroyedblocks")) return;
|
|
|
|
|
2019-10-14 23:43:13 -04:00
|
|
|
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-02-04 12:14:09 -05:00
|
|
|
for(BrokenBlock block : state.teams.get(player.team()).brokenBlocks){
|
2019-09-30 22:12:02 -04:00
|
|
|
Block b = content.block(block.block);
|
|
|
|
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-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));
|
2019-10-01 23:46:40 -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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-20 18:41:08 -04:00
|
|
|
public void drawShadows(){
|
2019-03-28 12:19:54 -04:00
|
|
|
if(!shadowEvents.isEmpty()){
|
|
|
|
Draw.flush();
|
2019-04-02 17:08:22 -04:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
shadows.begin();
|
|
|
|
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
|
2019-01-27 23:26:07 -05:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
for(Tile tile : shadowEvents){
|
2019-03-29 09:07:46 -04:00
|
|
|
//clear it first
|
2019-09-09 16:22:29 -04:00
|
|
|
Draw.color(Color.white);
|
2019-03-29 09:07:46 -04:00
|
|
|
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
|
|
|
//then draw the shadow
|
2019-09-09 16:22:29 -04:00
|
|
|
Draw.color(!tile.block().hasShadow ? Color.white : shadowColor);
|
2019-03-28 12:19:54 -04:00
|
|
|
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
|
|
|
}
|
2019-01-27 18:09:59 -05:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
Draw.flush();
|
|
|
|
Draw.color();
|
|
|
|
shadows.end();
|
|
|
|
shadowEvents.clear();
|
2019-01-18 09:19:42 -05:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
Draw.proj(camera.projection());
|
2019-01-18 09:19:42 -05:00
|
|
|
}
|
|
|
|
|
2019-03-28 12:19:54 -04: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;
|
2019-03-28 12:19:54 -04:00
|
|
|
|
|
|
|
Tmp.tr1.set(shadows.getTexture());
|
|
|
|
Tmp.tr1.set(u, v2, u2, v);
|
2018-07-20 18:41:08 -04:00
|
|
|
|
2019-03-28 12:19:54 -04:00
|
|
|
Draw.shader(Shaders.fog);
|
|
|
|
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
|
2018-12-29 13:06:17 -05:00
|
|
|
Draw.shader();
|
2018-07-23 20:44:33 -04:00
|
|
|
}
|
|
|
|
|
2019-04-08 09:03:18 -04:00
|
|
|
/** Process all blocks to draw. */
|
2018-07-12 20:37:14 -04:00
|
|
|
public void processBlocks(){
|
2018-07-20 13:59:00 -04:00
|
|
|
iterateidx = 0;
|
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;
|
2018-07-20 18:41:08 -04:00
|
|
|
|
|
|
|
if(avgx == lastCamX && avgy == lastCamY && lastRangeX == rangex && lastRangeY == rangey){
|
2018-07-20 13:59:00 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-20 18:41:08 -04:00
|
|
|
requestidx = 0;
|
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);
|
2018-11-11 11:12:54 -05:00
|
|
|
Tile tile = world.rawTile(x, y);
|
2019-01-15 21:21:28 -05:00
|
|
|
Block block = tile.block();
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2020-03-05 18:05:59 -05:00
|
|
|
if(block != Blocks.air && tile.isCenter() && block.cacheLayer == CacheLayer.normal){
|
2019-01-15 21:21:28 -05:00
|
|
|
if(!expanded){
|
|
|
|
addRequest(tile, Layer.block);
|
2018-11-11 11:12:54 -05:00
|
|
|
}
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2020-03-05 18:05:59 -05:00
|
|
|
if(state.rules.lighting && tile.block().synthetic()){
|
2019-11-16 22:49:36 -05:00
|
|
|
addRequest(tile, Layer.lights);
|
|
|
|
}
|
2019-11-10 16:18:47 -05:00
|
|
|
|
2019-01-15 21:21:28 -05:00
|
|
|
if(block.expanded || !expanded){
|
2019-01-27 18:09:59 -05:00
|
|
|
|
2019-04-25 21:53:17 -04:00
|
|
|
if(block.layer != null){
|
2019-01-15 21:21:28 -05:00
|
|
|
addRequest(tile, block.layer);
|
2018-07-20 18:41:08 -04:00
|
|
|
}
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2019-04-25 21:53:17 -04:00
|
|
|
if(block.layer2 != null){
|
2019-01-15 21:21:28 -05:00
|
|
|
addRequest(tile, block.layer2);
|
2018-07-12 20:37:14 -04:00
|
|
|
}
|
2019-02-21 13:11:28 -05:00
|
|
|
|
2020-02-04 12:14:09 -05:00
|
|
|
if(tile.entity != null && tile.entity.power() != null && tile.entity.power().links.size > 0){
|
2019-02-21 13:11:28 -05:00
|
|
|
for(Tile other : block.getPowerConnections(tile, outArray)){
|
|
|
|
if(other.block().layer == Layer.power){
|
|
|
|
addRequest(other, Layer.power);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 20:37:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Sort.instance().sort(requests.items, 0, requestidx);
|
2018-07-20 13:59:00 -04:00
|
|
|
|
|
|
|
lastCamX = avgx;
|
|
|
|
lastCamY = avgy;
|
2018-07-20 18:41:08 -04:00
|
|
|
lastRangeX = rangex;
|
|
|
|
lastRangeY = rangey;
|
2018-07-12 20:37:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void drawBlocks(Layer stopAt){
|
2019-10-09 01:32:00 +02:00
|
|
|
int startIdx = iterateidx;
|
2018-07-12 20:37:14 -04:00
|
|
|
for(; iterateidx < requestidx; iterateidx++){
|
2019-10-09 01:32:00 +02:00
|
|
|
BlockRequest request = requests.get(iterateidx);
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2019-10-09 01:32:00 +02:00
|
|
|
if(request.layer.ordinal() > stopAt.ordinal()){
|
2018-07-12 20:37:14 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-10-09 01:32:00 +02:00
|
|
|
if(request.layer == Layer.power){
|
|
|
|
if(iterateidx - startIdx > 0 && request.tile.pos() == requests.get(iterateidx - 1).tile.pos()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2018-07-12 20:37:14 -04:00
|
|
|
|
2019-10-09 01:32:00 +02:00
|
|
|
Block block = request.tile.block();
|
|
|
|
|
|
|
|
if(request.layer == Layer.block){
|
|
|
|
block.draw(request.tile);
|
|
|
|
if(request.tile.entity != null && request.tile.entity.damaged()){
|
|
|
|
block.drawCracks(request.tile);
|
2019-04-16 12:15:06 -04:00
|
|
|
}
|
2020-02-05 13:03:22 -05:00
|
|
|
if(block.synthetic() && request.tile.team() != player.team()){
|
2019-10-09 01:32:00 +02:00
|
|
|
block.drawTeam(request.tile);
|
2019-01-22 15:46:22 -05:00
|
|
|
}
|
2019-11-10 16:18:47 -05:00
|
|
|
|
|
|
|
}else if(request.layer == Layer.lights){
|
|
|
|
block.drawLight(request.tile);
|
2019-10-09 01:32:00 +02:00
|
|
|
}else if(request.layer == block.layer){
|
|
|
|
block.drawLayer(request.tile);
|
|
|
|
}else if(request.layer == block.layer2){
|
|
|
|
block.drawLayer2(request.tile);
|
2018-07-12 20:37:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addRequest(Tile tile, Layer layer){
|
|
|
|
if(requestidx >= requests.size){
|
|
|
|
requests.add(new BlockRequest());
|
|
|
|
}
|
|
|
|
BlockRequest r = requests.get(requestidx);
|
|
|
|
if(r == null){
|
|
|
|
requests.set(requestidx, r = new BlockRequest());
|
|
|
|
}
|
|
|
|
r.tile = tile;
|
|
|
|
r.layer = layer;
|
|
|
|
requestidx++;
|
|
|
|
}
|
|
|
|
|
2019-04-23 11:59:07 -04:00
|
|
|
@Override
|
|
|
|
public void dispose(){
|
|
|
|
shadows.dispose();
|
|
|
|
fog.dispose();
|
|
|
|
shadows = fog = null;
|
|
|
|
floor.dispose();
|
|
|
|
}
|
|
|
|
|
2018-07-12 20:37:14 -04:00
|
|
|
private class BlockRequest implements Comparable<BlockRequest>{
|
|
|
|
Tile tile;
|
|
|
|
Layer layer;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int compareTo(BlockRequest other){
|
2019-10-09 01:32:00 +02:00
|
|
|
int compare = layer.compareTo(other.layer);
|
|
|
|
|
|
|
|
return (compare != 0) ? compare : Integer.compare(tile.pos(), other.tile.pos());
|
2018-07-12 20:37:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString(){
|
|
|
|
return tile.block().name + ":" + layer.toString();
|
|
|
|
}
|
|
|
|
}
|
2017-12-20 17:05:15 -05:00
|
|
|
}
|