New unbroken floor rendering system

This commit is contained in:
Anuken
2018-04-18 21:18:12 -04:00
parent 1d8630dd7d
commit b5cba3abfd
9 changed files with 657 additions and 614 deletions

View File

@@ -205,8 +205,8 @@ public class Renderer extends RendererModule{
batch.begin();
//clears shield surface
Graphics.surface(shieldSurface);
Graphics.surface();
//Graphics.surface(shieldSurface);
//Graphics.surface();
drawPadding();
@@ -229,14 +229,10 @@ public class Renderer extends RendererModule{
Entities.draw(airItemGroup);
Entities.draw(effectGroup);
drawShield();
//drawShield();
drawOverlay();
if(Settings.getBool("indicators") && showUI){
drawEnemyMarkers();
}
if(pixelate)
Graphics.flushSurface();
@@ -249,7 +245,7 @@ public class Renderer extends RendererModule{
for(Team team : Team.values()){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(group.count(p -> p.isFlying() == flying) +
playerGroup.count(p -> p.isFlying() == flying && p.team == team) == 0) continue;
playerGroup.count(p -> p.isFlying() == flying && p.team == team) == 0 && flying) continue;
Shaders.outline.color.set(team.color);
@@ -331,31 +327,6 @@ public class Renderer extends RendererModule{
Draw.tscl(fontscale);
}
//TODO implement
void drawEnemyMarkers(){
/*
Graphics.surface(indicatorSurface);
Draw.color(Color.RED);
for(BaseUnit enemy : enemyGroup.all()) {
if (rect.setSize(camera.viewportWidth, camera.viewportHeight).setCenter(camera.position.x, camera.position.y)
.overlaps(enemy.hitbox.getRect(enemy.x, enemy.y))) {
continue;
}
float angle = Angles.angle(camera.position.x, camera.position.y, enemy.x, enemy.y);
float tx = Angles.trnsx(angle, Unit.dp.scl(20f));
float ty = Angles.trnsy(angle, Unit.dp.scl(20f));
Draw.rect("enemyarrow", camera.position.x + tx, camera.position.y + ty, angle);
}
Draw.color();
Draw.alpha(0.4f);
Graphics.flushSurface();
Draw.color();*/
}
void drawShield(){
if(shieldGroup.size() == 0 && shieldDraws.size == 0) return;

View File

@@ -105,7 +105,9 @@ public class BlockRenderer{
Draw.color();
Graphics.end();
//floorRenderer.drawCache(DrawLayer.walls, crangex, crangey);
floorRenderer.beginDraw();
floorRenderer.drawLayer(DrawLayer.walls);
floorRenderer.endDraw();
Graphics.begin();
Arrays.sort(requests.items, 0, requestidx);
@@ -178,6 +180,14 @@ public class BlockRenderer{
floorRenderer.clearTiles();
}
public void beginFloor(){
floorRenderer.beginDraw();
}
public void endFloor(){
floorRenderer.endDraw();
}
public void drawFloor(){
floorRenderer.drawFloor();
}

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.graphics;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.graphics.CacheBatch;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Shader;
@@ -12,78 +11,72 @@ import static io.anuke.mindustry.Vars.renderer;
public enum DrawLayer {
water{
@Override
public void begin(CacheBatch batch){
beginShader(batch);
public void begin(){
beginShader();
}
@Override
public void end(CacheBatch batch){
endShader(batch, Shaders.water);
public void end(){
endShader(Shaders.water);
}
},
lava{
@Override
public void begin(CacheBatch batch){
beginShader(batch);
public void begin(){
beginShader();
}
@Override
public void end(CacheBatch batch){
endShader(batch, Shaders.lava);
public void end(){
endShader(Shaders.lava);
}
},
oil{
@Override
public void begin(CacheBatch batch){
beginShader(batch);
public void begin(){
beginShader();
}
@Override
public void end(CacheBatch batch){
endShader(batch, Shaders.oil);
public void end(){
endShader(Shaders.oil);
}
},
space{
@Override
public void begin(CacheBatch batch){
beginShader(batch);
public void begin(){
beginShader();
}
@Override
public void end(CacheBatch batch){
endShader(batch, Shaders.space);
public void end(){
endShader(Shaders.space);
}
},
normal,
walls;
public void begin(CacheBatch batch){
batch.setProjectionMatrix(Core.camera.combined);
Graphics.useBatch(batch.drawBatch());
Graphics.begin();
public void begin(){
}
public void end(CacheBatch batch){
Graphics.end();
Graphics.popBatch();
public void end(){
}
protected void beginShader(CacheBatch batch){
batch.setProjectionMatrix(Core.camera.combined);
Graphics.useBatch(batch.drawBatch());
Graphics.begin();
Graphics.surface(renderer.waterSurface);
protected void beginShader(){
renderer.getBlocks().endFloor();
renderer.waterSurface.getBuffer().begin();
Graphics.clear(Color.CLEAR);
renderer.getBlocks().beginFloor();
}
public void endShader(CacheBatch batch, Shader shader){
Graphics.surface();
Graphics.end();
public void endShader(Shader shader){
renderer.getBlocks().endFloor();
renderer.waterSurface.getBuffer().end();
renderer.pixelSurface.getBuffer().begin();
Graphics.popBatch();
Graphics.shader(shader);
Graphics.begin();
@@ -91,5 +84,6 @@ public enum DrawLayer {
Core.camera.viewportWidth * Core.camera.zoom, -Core.camera.viewportHeight * Core.camera.zoom);
Graphics.end();
Graphics.shader();
renderer.getBlocks().beginFloor();
}
}

View File

@@ -6,10 +6,13 @@ import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.NumberUtils;
import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.IntSet;
import com.badlogic.gdx.utils.IntSet.IntSetIterator;
import com.badlogic.gdx.utils.async.AsyncExecutor;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
@@ -20,13 +23,29 @@ import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.world;
public class FloorRenderer {
private final static int vsize = 6;
private final static int vsize = 4;
private final static int chunksize = 32;
private AsyncExecutor executor = new AsyncExecutor(4);
private ShaderProgram program = createDefaultShader();
private Chunk[][] cache;
private float z = 0f;
private IntSet drawnLayerSet = new IntSet();
private IntArray drawnLayers = new IntArray();
private short[] indices;
public FloorRenderer(){
int len = chunksize*chunksize*vsize * 6;
indices = new short[len];
short j = 0;
for (int i = 0; i < len; i += 6, j += 4) {
indices[i] = j;
indices[i + 1] = (short)(j + 1);
indices[i + 2] = (short)(j + 2);
indices[i + 3] = (short)(j + 2);
indices[i + 4] = (short)(j + 3);
indices[i + 5] = j;
}
}
public void drawFloor(){
@@ -53,27 +72,21 @@ public class FloorRenderer {
}
}
Graphics.end();
int layers = DrawLayer.values().length;
Graphics.clear(Color.CLEAR);
Gdx.gl.glEnable(GL20.GL_BLEND);
program.begin();
Core.atlas.getTextures().first().bind();
program.setUniformMatrix("u_projTrans", Core.camera.combined);
program.setUniformi("u_texture", 0);
drawnLayers.clear();
drawnLayerSet.clear();
//preliminary layer check:
for(int x = -crangex; x <= crangex; x++){
for(int y = -crangey; y <= crangey; y++){
int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x;
int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y;
if(!Mathf.inBounds(worldx, worldy, cache))
if (!Mathf.inBounds(worldx, worldy, cache))
continue;
if(cache[worldx][worldy] == null){
if (cache[worldx][worldy] == null) {
cache[worldx][worldy] = new Chunk();
executor.submit(() -> cacheChunk(worldx, worldy));
continue;
@@ -81,21 +94,81 @@ public class FloorRenderer {
Chunk chunk = cache[worldx][worldy];
if(!chunk.rendered){
if (!chunk.rendered) {
continue;
}
chunk.mesh.render(program, GL20.GL_TRIANGLES, 0, chunk.length);
//Core.batch.draw(Core.atlas.getTextures().first(), chunk.vertices, 0, chunk.length);
//loop through all layers, and add layer index if it exists
for(int i = 0; i < layers - 1; i ++){
if(chunk.lengths[i] > 0){
drawnLayerSet.add(i);
}
}
}
}
program.end();
IntSetIterator it = drawnLayerSet.iterator();
while(it.hasNext){
drawnLayers.add(it.next());
}
drawnLayers.sort();
Graphics.end();
beginDraw();
for(int i = 0; i < drawnLayers.size; i ++) {
DrawLayer layer = DrawLayer.values()[drawnLayers.get(i)];
drawLayer(layer);
}
endDraw();
Graphics.begin();
}
public void beginDraw(){
Gdx.gl.glEnable(GL20.GL_BLEND);
Core.atlas.getTextures().first().bind();
program.begin();
program.setUniformMatrix("u_projTrans", Core.camera.combined);
program.setUniformi("u_texture", 0);
}
public void endDraw(){
program.end();
}
public void drawLayer(DrawLayer layer){
OrthographicCamera camera = Core.camera;
int crangex = (int)(camera.viewportWidth * camera.zoom / (chunksize * tilesize))+1;
int crangey = (int)(camera.viewportHeight * camera.zoom / (chunksize * tilesize))+1;
layer.begin();
for (int x = -crangex; x <= crangex; x++) {
for (int y = -crangey; y <= crangey; y++) {
int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x;
int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y;
if(!Mathf.inBounds(worldx, worldy, cache) || cache[worldx][worldy] == null || !cache[worldx][worldy].rendered){
continue;
}
Chunk chunk = cache[worldx][worldy];
chunk.mesh.render(program, GL20.GL_TRIANGLES,
chunk.offsets[layer.ordinal()] / vsize,
chunk.lengths[layer.ordinal()] / vsize);
}
}
layer.end();
}
private void fillChunk(float x, float y){
Draw.color(Color.GRAY);
Draw.crect("white", x, y, chunksize * tilesize, chunksize * tilesize);
@@ -104,11 +177,30 @@ public class FloorRenderer {
private Chunk cacheChunk(int cx, int cy){
Chunk chunk = cache[cx][cy];
chunk.vertices = new float[chunksize*chunksize*vsize * 4*6];
int idx = 0;
chunk.vertices = new float[DrawLayer.values().length*chunksize*chunksize*vsize*4*6];
for(DrawLayer layer : DrawLayer.values()){
cacheChunkLayer(cx, cy, chunk, layer);
}
Timers.run(0f, () -> {
chunk.mesh = new Mesh(true, chunk.vertices.length, 0,
new VertexAttribute(Usage.Position, 2, "a_position"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
chunk.mesh.setVertices(chunk.vertices, 0, chunk.idx);
chunk.rendered = true;
});
return chunk;
}
private void cacheChunkLayer(int cx, int cy, Chunk chunk, DrawLayer layer){
float[] vertices = chunk.vertices;
float color = NumberUtils.intToFloatColor(Color.WHITE.toIntBits());
chunk.offsets[layer.ordinal()] = chunk.idx;
int idx = chunk.idx;
TextureRegion region = new TextureRegion(Core.atlas.getTextures().first());
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
@@ -116,98 +208,75 @@ public class FloorRenderer {
Tile tile = world.tile(tilex, tiley);
if(tile == null) continue;
Block block = tile.floor();
if(!Draw.hasRegion(block.name()) || Draw.region(block.name()).getRegionWidth() == 8){
TextureRegion base = Draw.region(block.variants > 0 ? (block.name() + MathUtils.random(1, block.variants)) : block.name());
idx = draw(vertices, idx, base, tile.worldx(), tile.worldy(), color);
if(tile.floor().drawLayer == layer && tile.block().drawLayer != DrawLayer.walls){
idx = drawFloor(tile, idx, region, vertices, false);
}else if(tile.floor().drawLayer.ordinal() < layer.ordinal() && tile.block().drawLayer != DrawLayer.walls){
idx = drawFloor(tile, idx, region, vertices, true);
}
for(int dx = -1; dx <= 1; dx ++){
for(int dy = -1; dy <= 1; dy ++){
if(dx == 0 && dy == 0) continue;
Tile other = world.tile(tile.x+dx, tile.y+dy);
if(other == null) continue;
Block floor = other.floor();
if(floor.id <= block.id) continue;
TextureRegion result = Draw.hasRegion(floor.name() + "edge") ? Draw.region(floor.name() + "edge") :
Draw.region(floor.edge + "edge");
int sx = -dx*8+2, sy = -dy*8+2;
int x = Mathf.clamp(sx, 0, 12);
int y = Mathf.clamp(sy, 0, 12);
int w = Mathf.clamp(sx+8, 0, 12) - x, h = Mathf.clamp(sy+8, 0, 12) - y;
float rx = Mathf.clamp(dx*8, 0, 8-w);
float ry = Mathf.clamp(dy*8, 0, 8-h);
region.setTexture(result.getTexture());
region.setRegion(result.getRegionX()+x, result.getRegionY()+y+h, w, -h);
idx = drawc(vertices, idx, region, tile.worldx()-4 + rx, tile.worldy()-4 + ry, w, h, color);
}
}
}else {
TextureRegion base = Draw.region(block.name());
set(base, region, 1 + Mathf.random(1), 1 + Mathf.random(1));
idx = draw(vertices, idx, region, tile.worldx(), tile.worldy(), color);
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx == 0 && dy == 0) continue;
Tile other = world.tile(tile.x + dx, tile.y + dy);
if (other == null) continue;
Block floor = other.floor();
if (floor.id < block.id) {
float ox = (dx == 0 ? Mathf.range(0.5f) : 0);
float oy = (dy == 0 ? Mathf.range(0.5f) : 0);
set(base, region, (int) (1.5f + 2f * dx + ox), (int) (2f - 2f * dy + oy));
idx = draw(vertices, idx, region,
tile.worldx() + dx * tilesize,
tile.worldy() + dy * tilesize, color);
}
}
}
if(tile.block().drawLayer == layer && layer == DrawLayer.walls){
Block block = tile.block();
idx = draw(vertices,
idx,
Draw.region(block.variants > 0 ? (block.name() + MathUtils.random(1, block.variants)) : block.name()),
tile.worldx(),
tile.worldy());
}
}
}
chunk.length = idx;
Timers.run(0f, () -> {
chunk.mesh = new Mesh(true, vertices.length, 0,
new VertexAttribute(Usage.Position, 3, "a_position"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
chunk.mesh.setVertices(chunk.vertices, 0, chunk.length);
chunk.rendered = true;
});
return chunk;
chunk.lengths[layer.ordinal()] = idx - chunk.offsets[layer.ordinal()];
chunk.idx = idx;
}
private void set(TextureRegion base, TextureRegion region, int x, int y){
x = Mathf.clamp(x, 0, 3);
y = Mathf.clamp(y, 0, 3);
region.setRegion(base.getRegionX() + x *8, base.getRegionY() + y *8, 8, 8);
private int drawFloor(Tile tile, int idx, TextureRegion region, float[] vertices, boolean edgesOnly){
MathUtils.random.setSeed(tile.id());
Block block = tile.floor();
if(!edgesOnly) {
TextureRegion base = Draw.region(block.variants > 0 ? (block.name() + MathUtils.random(1, block.variants)) : block.name());
idx = draw(vertices, idx, base, tile.worldx(), tile.worldy());
}
for(int dx = -1; dx <= 1; dx ++){
for(int dy = -1; dy <= 1; dy ++){
if(dx == 0 && dy == 0) continue;
Tile other = world.tile(tile.x+dx, tile.y+dy);
if(other == null) continue;
Block floor = other.floor();
if(floor.id <= block.id || !((Floor)block).blends.test(floor) || (floor.drawLayer.ordinal() > block.drawLayer.ordinal() && !edgesOnly) ||
(edgesOnly && floor.drawLayer == block.drawLayer)) continue;
TextureRegion result = Draw.hasRegion(floor.name() + "edge") ? Draw.region(floor.name() + "edge") :
Draw.region(floor.edge + "edge");
int sx = -dx*8+2, sy = -dy*8+2;
int x = Mathf.clamp(sx, 0, 12);
int y = Mathf.clamp(sy, 0, 12);
int w = Mathf.clamp(sx+8, 0, 12) - x, h = Mathf.clamp(sy+8, 0, 12) - y;
float rx = Mathf.clamp(dx*8, 0, 8-w);
float ry = Mathf.clamp(dy*8, 0, 8-h);
region.setTexture(result.getTexture());
region.setRegion(result.getRegionX()+x, result.getRegionY()+y+h, w, -h);
idx = drawc(vertices, idx, region, tile.worldx()-4 + rx, tile.worldy()-4 + ry, w, h);
}
}
return idx;
}
private int draw(float[] vertices, int idx, TextureRegion region, float x, float y, float color){
return drawc(vertices, idx, region, x - tilesize/2f, y - tilesize/2f, tilesize, tilesize, color);
private int draw(float[] vertices, int idx, TextureRegion region, float x, float y){
return drawc(vertices, idx, region, x - tilesize/2f, y - tilesize/2f, tilesize, tilesize);
}
private int drawc(float[] vertices, int idx, TextureRegion region, float x, float y, float width, float height, float color){
private int drawc(float[] vertices, int idx, TextureRegion region, float x, float y, float width, float height){
final float fx2 = x + width;
final float fy2 = y + height;
@@ -218,37 +287,31 @@ public class FloorRenderer {
vertices[idx ++] = x;
vertices[idx ++] = y;
vertices[idx ++] = z;
vertices[idx ++] = u;
vertices[idx ++] = v;
vertices[idx ++] = x;
vertices[idx ++] = fy2;
vertices[idx ++] = z;
vertices[idx ++] = u;
vertices[idx ++] = v2;
vertices[idx ++] = fx2;
vertices[idx ++] = fy2;
vertices[idx ++] = z;
vertices[idx ++] = u2;
vertices[idx ++] = v2;
vertices[idx ++] = x;
vertices[idx ++] = y;
vertices[idx ++] = z;
vertices[idx ++] = u;
vertices[idx ++] = v;
vertices[idx ++] = fx2;
vertices[idx ++] = y;
vertices[idx ++] = z;
vertices[idx ++] = u2;
vertices[idx ++] = v;
vertices[idx ++] = fx2;
vertices[idx ++] = fy2;
vertices[idx ++] = z;
vertices[idx ++] = u2;
vertices[idx ++] = v2;
@@ -257,12 +320,24 @@ public class FloorRenderer {
private class Chunk{
float[] vertices;
int[] offsets = new int[DrawLayer.values().length];
int[] lengths = new int[DrawLayer.values().length];
int idx = 0;
boolean rendered;
int length;
Mesh mesh;
}
public void clearTiles(){
if(cache != null){
for(int x = 0; x < cache.length; x ++){
for(int y = 0; y < cache[0].length; y ++){
if(cache[x][y] != null && cache[x][y].mesh != null){
cache[x][y].mesh.dispose();
cache[x][y] = null;
}
}
}
}
cache = null;
}

View File

@@ -17,7 +17,7 @@ import static io.anuke.mindustry.Vars.world;
public class Floor extends Block{
protected TextureRegion tempRegion = new TextureRegion();
protected Predicate<Block> blends = block -> block != this;
public Predicate<Block> blends = block -> block != this;
protected boolean blend = true;
public float speedMultiplier = 1f;