Partially implemented new building rendering
This commit is contained in:
@@ -70,7 +70,7 @@ public class DrawOperation{
|
||||
}
|
||||
}
|
||||
case opBlock -> {
|
||||
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
|
||||
tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y));
|
||||
|
||||
Block block = content.block(to);
|
||||
tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation);
|
||||
@@ -78,7 +78,7 @@ public class DrawOperation{
|
||||
tile.build.enabled = true;
|
||||
}
|
||||
|
||||
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
|
||||
tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y));
|
||||
}
|
||||
case opRotation -> {
|
||||
if(tile.build != null) tile.build.rotation = to;
|
||||
@@ -86,7 +86,7 @@ public class DrawOperation{
|
||||
case opTeam -> tile.setTeam(Team.get(to));
|
||||
}
|
||||
});
|
||||
editor.renderer.updatePoint(tile.x, tile.y);
|
||||
editor.renderer.updateStatic(tile.x, tile.y);
|
||||
}
|
||||
|
||||
@Struct
|
||||
|
||||
171
core/src/mindustry/editor/EditorSpriteCache.java
Normal file
171
core/src/mindustry/editor/EditorSpriteCache.java
Normal file
@@ -0,0 +1,171 @@
|
||||
package mindustry.editor;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
|
||||
public class EditorSpriteCache implements Disposable{
|
||||
//xy + color + uv
|
||||
static final int vertexSize = 2 + 1 + 2;
|
||||
|
||||
private @Nullable Mesh mesh;
|
||||
private final Seq<Texture> textures = new Seq<>(8);
|
||||
private final IntSeq counts = new IntSeq(8);
|
||||
|
||||
private float[] tmpVertices;
|
||||
|
||||
/** Index in tmpVertices of current vertex data. */
|
||||
private int index;
|
||||
|
||||
/** @param tmpVertices Temporary buffer to hold vertices while building up sprites. Should be large enough to hold all sprite data this cache will contain. */
|
||||
public EditorSpriteCache(float[] tmpVertices){
|
||||
this.tmpVertices = tmpVertices;
|
||||
}
|
||||
|
||||
/** @return whether anything was added to the cache. */
|
||||
public boolean isEmpty(){
|
||||
return index == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds this cache into a mesh that can be used for rendering. Use after calling {@link #draw(TextureRegion, float, float, float, float, float, float, float, float)}.
|
||||
* Until this method is called, no mesh is created.
|
||||
*
|
||||
* @param indices The shared index data in standard quad format, as seen in SpriteBatch.
|
||||
* Since this data is static, it should be the same across all caches, and be large enough to accommodate all sprites.
|
||||
* */
|
||||
public void build(IndexData indices){
|
||||
if(mesh != null) mesh.dispose();
|
||||
|
||||
mesh = new Mesh(true, index / vertexSize, 0,
|
||||
VertexAttribute.position,
|
||||
VertexAttribute.color,
|
||||
VertexAttribute.texCoords
|
||||
);
|
||||
mesh.indices = indices;
|
||||
mesh.setVertices(tmpVertices, 0, index);
|
||||
}
|
||||
|
||||
/** Adds the specified region to the cache. */
|
||||
public void draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float rotation, float colorPacked){
|
||||
if(mesh != null) throw new IllegalStateException("This cache is already built. Call #clear() before drawing new sprites.");
|
||||
|
||||
// bottom left and top right corner points relative to origin
|
||||
final float worldOriginX = x + originX;
|
||||
final float worldOriginY = y + originY;
|
||||
float fx = -originX;
|
||||
float fy = -originY;
|
||||
float fx2 = width - originX;
|
||||
float fy2 = height - originY;
|
||||
|
||||
float x1, y1, x2, y2, x3, y3, x4, y4;
|
||||
|
||||
// rotate
|
||||
if(rotation != 0){
|
||||
final float cos = Mathf.cosDeg(rotation);
|
||||
final float sin = Mathf.sinDeg(rotation);
|
||||
|
||||
x1 = cos * fx - sin * fy;
|
||||
y1 = sin * fx + cos * fy;
|
||||
|
||||
x2 = cos * fx - sin * fy2;
|
||||
y2 = sin * fx + cos * fy2;
|
||||
|
||||
x3 = cos * fx2 - sin * fy2;
|
||||
y3 = sin * fx2 + cos * fy2;
|
||||
|
||||
x4 = x1 + (x3 - x2);
|
||||
y4 = y3 - (y2 - y1);
|
||||
}else{
|
||||
x1 = fx;
|
||||
y1 = fy;
|
||||
|
||||
x2 = fx;
|
||||
y2 = fy2;
|
||||
|
||||
x3 = fx2;
|
||||
y3 = fy2;
|
||||
|
||||
x4 = fx2;
|
||||
y4 = fy;
|
||||
}
|
||||
|
||||
x1 += worldOriginX;
|
||||
y1 += worldOriginY;
|
||||
x2 += worldOriginX;
|
||||
y2 += worldOriginY;
|
||||
x3 += worldOriginX;
|
||||
y3 += worldOriginY;
|
||||
x4 += worldOriginX;
|
||||
y4 += worldOriginY;
|
||||
|
||||
final float u = region.u;
|
||||
final float v = region.v2;
|
||||
final float u2 = region.u2;
|
||||
final float v2 = region.v;
|
||||
|
||||
int idx = index;
|
||||
float[] verts = tmpVertices;
|
||||
Texture texture = region.texture;
|
||||
|
||||
verts[idx + 0] = x1;
|
||||
verts[idx + 1] = y1;
|
||||
verts[idx + 2] = colorPacked;
|
||||
verts[idx + 3] = u;
|
||||
verts[idx + 4] = v;
|
||||
|
||||
verts[idx + 5] = x2;
|
||||
verts[idx + 6] = y2;
|
||||
verts[idx + 7] = colorPacked;
|
||||
verts[idx + 8] = u;
|
||||
verts[idx + 9] = v2;
|
||||
|
||||
verts[idx + 10] = x3;
|
||||
verts[idx + 11] = y3;
|
||||
verts[idx + 12] = colorPacked;
|
||||
verts[idx + 13] = u2;
|
||||
verts[idx + 14] = v2;
|
||||
|
||||
verts[idx + 15] = x4;
|
||||
verts[idx + 16] = y4;
|
||||
verts[idx + 17] = colorPacked;
|
||||
verts[idx + 18] = u2;
|
||||
verts[idx + 19] = v;
|
||||
|
||||
int lastIndex = textures.size - 1;
|
||||
if(lastIndex < 0 || textures.get(lastIndex) != texture){
|
||||
textures.add(texture);
|
||||
counts.add(6);
|
||||
}else{
|
||||
counts.incr(lastIndex, 6);
|
||||
}
|
||||
|
||||
index += vertexSize * 4;
|
||||
}
|
||||
|
||||
/** Renders the cached mesh. The shader must already have the correct view matrix (usually u_projectionViewMatrix) set as a uniform. */
|
||||
public void render(Shader shader){
|
||||
if(mesh == null) throw new IllegalStateException("Cache is empty, call build() first.");
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for(int i = 0; i < textures.size; i++){
|
||||
int count = counts.items[i];
|
||||
textures.get(i).bind();
|
||||
|
||||
mesh.render(shader, Gl.triangles, offset, count);
|
||||
offset += count;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
if(mesh != null){
|
||||
mesh.dispose();
|
||||
mesh = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import arc.func.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.modules.*;
|
||||
@@ -46,13 +47,16 @@ public class EditorTile extends Tile{
|
||||
|
||||
@Override
|
||||
public void setBlock(Block type, Team team, int rotation, Prov<Building> entityprov){
|
||||
Block prev = this.block;
|
||||
Tile prevCenter = (build == null ? this : build.tile);
|
||||
|
||||
if(skip()){
|
||||
super.setBlock(type, team, rotation, entityprov);
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.block == type && (build == null || build.rotation == rotation)){
|
||||
update();
|
||||
updateStatic();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -61,7 +65,7 @@ public class EditorTile extends Tile{
|
||||
cen.op(DrawOperation.opRotation, (byte)build.rotation);
|
||||
cen.op(DrawOperation.opTeam, (byte)build.team.id);
|
||||
cen.op(DrawOperation.opBlock, block.id);
|
||||
update();
|
||||
updateStatic();
|
||||
}else{
|
||||
if(build != null) op(DrawOperation.opRotation, (byte)build.rotation);
|
||||
if(build != null) op(DrawOperation.opTeam, (byte)build.team.id);
|
||||
@@ -70,7 +74,20 @@ public class EditorTile extends Tile{
|
||||
|
||||
super.setBlock(type, team, rotation, entityprov);
|
||||
|
||||
renderer.blocks.updateShadowTile(this);
|
||||
if(requiresBlockUpdate(type) || requiresBlockUpdate(prev)){
|
||||
if(prev.size > 1){
|
||||
prevCenter.getLinkedTilesAs(prev, tile -> {
|
||||
editor.renderer.updateBlock(tile.x, tile.y);
|
||||
renderer.blocks.updateShadowTile(tile);
|
||||
});
|
||||
}
|
||||
getLinkedTiles(tile -> {
|
||||
editor.renderer.updateBlock(tile.x, tile.y);
|
||||
renderer.blocks.updateShadowTile(tile);
|
||||
});
|
||||
}else{
|
||||
renderer.blocks.updateShadowTile(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +101,7 @@ public class EditorTile extends Tile{
|
||||
op(DrawOperation.opTeam, (byte)getTeamID());
|
||||
super.setTeam(team);
|
||||
|
||||
getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
|
||||
getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +122,7 @@ public class EditorTile extends Tile{
|
||||
if(skip()){
|
||||
super.fireChanged();
|
||||
}else{
|
||||
update();
|
||||
updateStatic();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +131,7 @@ public class EditorTile extends Tile{
|
||||
if(skip()){
|
||||
super.firePreChanged();
|
||||
}else{
|
||||
update();
|
||||
updateStatic();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,8 +176,12 @@ public class EditorTile extends Tile{
|
||||
return skip() && super.isDarkened();
|
||||
}
|
||||
|
||||
private void update(){
|
||||
editor.renderer.updatePoint(x, y);
|
||||
private boolean requiresBlockUpdate(Block block){
|
||||
return block != Blocks.air && block.cacheLayer == CacheLayer.normal;
|
||||
}
|
||||
|
||||
private void updateStatic(){
|
||||
editor.renderer.updateStatic(x, y);
|
||||
}
|
||||
|
||||
private boolean skip(){
|
||||
|
||||
@@ -374,7 +374,7 @@ public class MapEditor{
|
||||
if(currentOp == null) currentOp = new DrawOperation();
|
||||
currentOp.addOperation(data);
|
||||
|
||||
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
||||
renderer.updateStatic(TileOp.x(data), TileOp.y(data));
|
||||
}
|
||||
|
||||
class Context implements WorldContext{
|
||||
|
||||
@@ -303,7 +303,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules);
|
||||
lastSavedRules = null;
|
||||
saved = false;
|
||||
editor.renderer.updateAll();
|
||||
editor.renderer.recache();
|
||||
}
|
||||
|
||||
private void editInGame(){
|
||||
|
||||
@@ -185,7 +185,7 @@ public class MapGenerateDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
//reset undo stack as generation... messes things up
|
||||
editor.renderer.updateAll();
|
||||
editor.renderer.recache();
|
||||
editor.clearOp();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class MapProcessorsDialog extends BaseDialog{
|
||||
foundAny = true;
|
||||
tile.setNet(Blocks.worldProcessor, Team.sharded, 0);
|
||||
if(ui.editor.isShown()){
|
||||
Vars.editor.renderer.updatePoint(x, y);
|
||||
Vars.editor.renderer.updateStatic(x, y);
|
||||
}
|
||||
break outer;
|
||||
}
|
||||
|
||||
@@ -3,228 +3,178 @@ package mindustry.editor;
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class MapRenderer implements Disposable{
|
||||
private static final int chunkSize = 62;
|
||||
private IndexedRenderer[][] chunks;
|
||||
private IntSet updates = new IntSet();
|
||||
private IntSet delayedUpdates = new IntSet();
|
||||
private TextureRegion clearEditor;
|
||||
private static final int chunkSize = 60;
|
||||
private EditorSpriteCache[][] chunks;
|
||||
private IntSet recacheChunks = new IntSet();
|
||||
private int width, height;
|
||||
|
||||
private Shader shader;
|
||||
|
||||
public void resize(int width, int height){
|
||||
updates.clear();
|
||||
delayedUpdates.clear();
|
||||
if(chunks != null){
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
chunks[x][y].dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
dispose();
|
||||
|
||||
chunks = new IndexedRenderer[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)];
|
||||
recacheChunks.clear();
|
||||
chunks = new EditorSpriteCache[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)];
|
||||
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
chunks[x][y] = new IndexedRenderer(chunkSize * chunkSize * 2);
|
||||
}
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
updateAll();
|
||||
|
||||
renderer.blocks.floor.clearTiles();
|
||||
renderer.blocks.reload();
|
||||
recache();
|
||||
}
|
||||
|
||||
public void draw(float tx, float ty, float tw, float th, float zoom){
|
||||
public void draw(float tx, float ty, float tw, float th){
|
||||
if(shader == null){
|
||||
shader = new Shader(
|
||||
"""
|
||||
attribute vec4 a_position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec2 a_texCoord0;
|
||||
uniform mat4 u_projTrans;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
void main(){
|
||||
v_color = a_color;
|
||||
v_color.a = v_color.a * (255.0/254.0);
|
||||
v_texCoords = a_texCoord0;
|
||||
gl_Position = u_projTrans * a_position;
|
||||
}
|
||||
""",
|
||||
|
||||
"""
|
||||
varying lowp vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
void main(){
|
||||
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
|
||||
}
|
||||
"""
|
||||
);
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
|
||||
//TODO properly integrate this later
|
||||
if(true){
|
||||
updates.each(i -> renderer.blocks.floor.recacheTile(i % width, i / width));
|
||||
updates.clear();
|
||||
renderer.blocks.floor.checkChanges();
|
||||
|
||||
updates.addAll(delayedUpdates);
|
||||
delayedUpdates.clear();
|
||||
boolean prev = renderer.animateWater;
|
||||
renderer.animateWater = false;
|
||||
|
||||
renderer.blocks.floor.checkChanges();
|
||||
Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize);
|
||||
Core.camera.width = 999999f;
|
||||
Core.camera.height = 999999f;
|
||||
Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f));
|
||||
renderer.blocks.floor.drawFloor();
|
||||
|
||||
boolean prev = renderer.animateWater;
|
||||
renderer.animateWater = false;
|
||||
Tmp.m2.set(Draw.proj());
|
||||
|
||||
Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize);
|
||||
Core.camera.width = 999999f;
|
||||
Core.camera.height = 999999f;
|
||||
Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f));
|
||||
renderer.blocks.floor.drawFloor();
|
||||
//scissors are always enabled because this is drawn clipped in UI, make sure they don't interfere with drawing shadow events
|
||||
Gl.disable(Gl.scissorTest);
|
||||
|
||||
Tmp.m2.set(Draw.proj());
|
||||
renderer.blocks.processShadows();
|
||||
|
||||
//this sure is awful!
|
||||
Gl.disable(Gl.scissorTest);
|
||||
Gl.enable(Gl.scissorTest);
|
||||
|
||||
renderer.blocks.processShadows();
|
||||
Draw.proj(Core.camera.mat);
|
||||
|
||||
Gl.enable(Gl.scissorTest);
|
||||
Draw.shader(Shaders.darkness);
|
||||
Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize);
|
||||
Draw.shader();
|
||||
|
||||
Draw.proj(Core.camera.mat);
|
||||
Draw.proj(Tmp.m2);
|
||||
|
||||
Draw.shader(Shaders.darkness);
|
||||
Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize);
|
||||
Draw.shader();
|
||||
renderer.blocks.floor.beginDraw();
|
||||
renderer.blocks.floor.drawLayer(CacheLayer.walls);
|
||||
renderer.animateWater = prev;
|
||||
|
||||
Draw.proj(Tmp.m2);
|
||||
if(chunks == null) return;
|
||||
|
||||
renderer.blocks.floor.beginDraw();
|
||||
renderer.blocks.floor.drawLayer(CacheLayer.walls);
|
||||
renderer.animateWater = prev;
|
||||
return;
|
||||
}
|
||||
recacheChunks.each(i -> recacheChunk(Point2.x(i), Point2.y(i)));
|
||||
recacheChunks.clear();
|
||||
|
||||
clearEditor = Core.atlas.find("clear-editor");
|
||||
|
||||
updates.each(i -> render(i % width, i / width));
|
||||
updates.clear();
|
||||
|
||||
updates.addAll(delayedUpdates);
|
||||
delayedUpdates.clear();
|
||||
|
||||
//????
|
||||
if(chunks == null){
|
||||
return;
|
||||
}
|
||||
|
||||
var texture = clearEditor.texture;
|
||||
shader.bind();
|
||||
shader.setUniformMatrix4("u_projTrans", Core.camera.mat);
|
||||
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
IndexedRenderer mesh = chunks[x][y];
|
||||
EditorSpriteCache mesh = chunks[x][y];
|
||||
|
||||
if(mesh == null){
|
||||
continue;
|
||||
if(mesh == null) continue;
|
||||
|
||||
mesh.render(shader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateStatic(int x, int y){
|
||||
renderer.blocks.floor.recacheTile(x, y);
|
||||
}
|
||||
|
||||
void updateBlock(int x, int y){
|
||||
recacheChunks.add(Point2.pack(x / chunkSize, y / chunkSize));
|
||||
}
|
||||
|
||||
void recache(){
|
||||
renderer.blocks.floor.clearTiles();
|
||||
renderer.blocks.reload();
|
||||
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
recacheChunk(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recacheChunk(int cx, int cy){
|
||||
if(chunks[cx][cy] != null){
|
||||
chunks[cx][cy].dispose();
|
||||
chunks[cx][cy] = null;
|
||||
}
|
||||
|
||||
EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer());
|
||||
|
||||
for(int x = cx * chunkSize; x < (cx + 1) * chunkSize; x++){
|
||||
for(int y = cy * chunkSize; y < (cy + 1) * chunkSize; y++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
if(tile != null && tile.block() != Blocks.air && tile.block().cacheLayer == CacheLayer.normal && tile.isCenter()){
|
||||
Block block = tile.block();
|
||||
|
||||
TextureRegion region = block.fullIcon;
|
||||
|
||||
float width = region.width * region.scl(), height = region.height * region.scl();
|
||||
|
||||
cache.draw(block.fullIcon,
|
||||
x * tilesize + block.offset - width / 2f,
|
||||
y * tilesize + block.offset - height / 2f,
|
||||
width/2f, height/2f,
|
||||
width, height,
|
||||
tile.build == null || !block.rotate ? 0 : tile.build.rotdeg(),
|
||||
Color.whiteFloatBits);
|
||||
}
|
||||
|
||||
mesh.getTransformMatrix().setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize));
|
||||
mesh.setProjectionMatrix(Draw.proj());
|
||||
|
||||
mesh.render(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePoint(int x, int y){
|
||||
updates.add(x + y * width);
|
||||
}
|
||||
|
||||
public void updateAll(){
|
||||
clearEditor = Core.atlas.find("clear-editor");
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
render(x, y);
|
||||
}
|
||||
if(!cache.isEmpty()){
|
||||
cache.build(renderer.blocks.floor.getIndexData());
|
||||
chunks[cx][cy] = cache;
|
||||
}
|
||||
}
|
||||
|
||||
private TextureRegion getIcon(Block wall, int index){
|
||||
return !wall.fullIcon.found() ?
|
||||
clearEditor : wall.variants > 0 ?
|
||||
wall.variantRegions()[Mathf.randomSeed(index, 0, wall.variantRegions().length - 1)] :
|
||||
wall.fullIcon;
|
||||
}
|
||||
|
||||
private void render(int wx, int wy){
|
||||
int x = wx / chunkSize, y = wy / chunkSize;
|
||||
if(x >= chunks.length || y >= chunks[0].length) return;
|
||||
IndexedRenderer mesh = chunks[x][y];
|
||||
Tile tile = editor.tiles().getn(wx, wy);
|
||||
|
||||
Floor floor = tile.floor();
|
||||
Floor overlay = tile.overlay();
|
||||
Block wall = tile.block();
|
||||
|
||||
TextureRegion region;
|
||||
|
||||
int idxWall = (wx % chunkSize) + (wy % chunkSize) * chunkSize;
|
||||
int idxDecal = (wx % chunkSize) + (wy % chunkSize) * chunkSize + chunkSize * chunkSize;
|
||||
boolean useSyntheticWall = overlay.wallOre;
|
||||
|
||||
//draw synthetic wall or floor OR standard wall if wall ore
|
||||
if(wall != Blocks.air && useSyntheticWall){
|
||||
region = getIcon(wall, idxWall);
|
||||
|
||||
float width = region.width * region.scl(), height = region.height * region.scl(), ox = wall.offset + (tilesize - width) / 2f, oy = wall.offset + (tilesize - height) / 2f;
|
||||
|
||||
//force fit to tile
|
||||
if(overlay.wallOre && !wall.synthetic()){
|
||||
width = height = tilesize;
|
||||
ox = oy = 0f;
|
||||
}
|
||||
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + ox,
|
||||
wy * tilesize + oy,
|
||||
width, height,
|
||||
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg());
|
||||
}else{
|
||||
if(floor instanceof ColoredFloor){
|
||||
mesh.setColor(Tmp.c1.set(tile.extraData | 0xff));
|
||||
}
|
||||
|
||||
region = floor.variantRegions()[Mathf.randomSeed(idxWall, 0, floor.variantRegions().length - 1)];
|
||||
|
||||
mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
}
|
||||
|
||||
float offsetX = -((wall.size + 1) / 3) * tilesize, offsetY = -((wall.size + 1) / 3) * tilesize;
|
||||
|
||||
//draw non-synthetic wall or ore
|
||||
if(!(wall.update || wall.destructible) && !useSyntheticWall && wall != Blocks.air){
|
||||
region = getIcon(wall, idxWall);
|
||||
|
||||
if(wall == Blocks.cliff){
|
||||
mesh.setColor(Tmp.c1.set(floor.mapColor).mul(1.6f));
|
||||
region = ((Cliff)Blocks.cliff).editorCliffs[tile.data & 0xff];
|
||||
}else if(wall instanceof ColoredWall){
|
||||
mesh.setColor(Tmp.c1.set(tile.extraData | 0xff));
|
||||
}
|
||||
|
||||
offsetX = tilesize / 2f - region.width * region.scl() / 2f;
|
||||
offsetY = tilesize / 2f - region.height * region.scl() / 2f;
|
||||
}else if((wall == Blocks.air || overlay.wallOre) && !overlay.isAir()){
|
||||
if(floor.isLiquid){
|
||||
mesh.setColor(Tmp.c1.set(1f, 1f, 1f, floor.overlayAlpha));
|
||||
}
|
||||
region = overlay.variantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().variantRegions().length - 1)];
|
||||
}else{
|
||||
region = clearEditor;
|
||||
}
|
||||
|
||||
float width = region.width * region.scl(), height = region.height * region.scl();
|
||||
if(!wall.synthetic() && wall != Blocks.air && !wall.isMultiblock()){
|
||||
offsetX = offsetY = 0f;
|
||||
width = height = tilesize;
|
||||
}
|
||||
|
||||
mesh.draw(idxDecal, region, wx * tilesize + offsetX, wy * tilesize + offsetY, width, height);
|
||||
mesh.setColor(Color.white);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
if(chunks == null){
|
||||
return;
|
||||
}
|
||||
if(chunks == null) return;
|
||||
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
if(chunks[x][y] != null){
|
||||
|
||||
@@ -248,7 +248,7 @@ public class MapView extends Element implements GestureListener{
|
||||
Draw.color(Pal.remove);
|
||||
Lines.stroke(2f);
|
||||
Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2);
|
||||
editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight, zoom);
|
||||
editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight);
|
||||
Draw.reset();
|
||||
|
||||
if(grid){
|
||||
|
||||
@@ -101,7 +101,7 @@ public class CacheLayer{
|
||||
|
||||
renderer.effectBuffer.begin();
|
||||
Core.graphics.clear(Color.clear);
|
||||
renderer.blocks.floor.beginc();
|
||||
renderer.blocks.floor.beginDraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,7 +110,7 @@ public class CacheLayer{
|
||||
|
||||
renderer.effectBuffer.end();
|
||||
renderer.effectBuffer.blit(shader);
|
||||
renderer.blocks.floor.beginc();
|
||||
renderer.blocks.floor.beginDraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,10 @@ public class FloorRenderer{
|
||||
return indexData;
|
||||
}
|
||||
|
||||
public float[] getVertexBuffer(){
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/** Queues up a cache change for a tile. Only runs in render loop. */
|
||||
public void recacheTile(Tile tile){
|
||||
recacheTile(tile.x, tile.y);
|
||||
@@ -183,14 +187,6 @@ public class FloorRenderer{
|
||||
underwaterDraw.clear();
|
||||
}
|
||||
|
||||
public void beginc(){
|
||||
shader.bind();
|
||||
shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat);
|
||||
|
||||
//only ever use the base environment texture
|
||||
texture.bind(0);
|
||||
}
|
||||
|
||||
public void checkChanges(){
|
||||
if(recacheSet.size > 0){
|
||||
//recache one chunk at a time
|
||||
@@ -215,7 +211,11 @@ public class FloorRenderer{
|
||||
|
||||
Draw.flush();
|
||||
|
||||
beginc();
|
||||
shader.bind();
|
||||
shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat);
|
||||
|
||||
//only ever use the base environment texture
|
||||
texture.bind(0);
|
||||
|
||||
Gl.enable(Gl.blend);
|
||||
}
|
||||
@@ -343,7 +343,7 @@ public class FloorRenderer{
|
||||
(cx+1) * tilesize * chunksize + tilesize/2f, (cy+1) * tilesize * chunksize + tilesize/2f);
|
||||
|
||||
mesh.setVertices(vertices, 0, vidx);
|
||||
//all vertices are shared
|
||||
//all indices are shared and identical
|
||||
mesh.indices = indexData;
|
||||
|
||||
return mesh;
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class IndexedRenderer implements Disposable{
|
||||
private static final int vsize = 5;
|
||||
|
||||
private final static Shader program = new Shader(
|
||||
"""
|
||||
attribute vec4 a_position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec2 a_texCoord0;
|
||||
uniform mat4 u_projTrans;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
void main(){
|
||||
v_color = a_color;
|
||||
v_color.a = v_color.a * (255.0/254.0);
|
||||
v_texCoords = a_texCoord0;
|
||||
gl_Position = u_projTrans * a_position;
|
||||
}
|
||||
""",
|
||||
|
||||
"""
|
||||
varying lowp vec4 v_color;
|
||||
varying vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
void main(){
|
||||
gl_FragColor = v_color * texture2D(u_texture, v_texCoords);
|
||||
}
|
||||
"""
|
||||
);
|
||||
private static final float[] tmpVerts = new float[vsize * 4];
|
||||
|
||||
private Mesh mesh;
|
||||
private FloatBuffer buffer;
|
||||
|
||||
private Mat projMatrix = new Mat();
|
||||
private Mat transMatrix = new Mat();
|
||||
private Mat combined = new Mat();
|
||||
private float color = Color.white.toFloatBits();
|
||||
|
||||
public IndexedRenderer(int sprites){
|
||||
resize(sprites);
|
||||
}
|
||||
|
||||
public void render(Texture texture){
|
||||
Gl.enable(Gl.blend);
|
||||
|
||||
updateMatrix();
|
||||
|
||||
program.bind();
|
||||
texture.bind();
|
||||
|
||||
program.setUniformMatrix4("u_projTrans", combined);
|
||||
|
||||
mesh.render(program, Gl.triangles, 0, mesh.getMaxVertices() * 6 / 4);
|
||||
}
|
||||
|
||||
public void setColor(Color color){
|
||||
this.color = color.toFloatBits();
|
||||
}
|
||||
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h){
|
||||
float fx2 = x + w;
|
||||
float fy2 = y + h;
|
||||
float u = region.u;
|
||||
float v = region.v2;
|
||||
float u2 = region.u2;
|
||||
float v2 = region.v;
|
||||
|
||||
float[] vertices = tmpVerts;
|
||||
float color = this.color;
|
||||
|
||||
int idx = 0;
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = fy2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = fy2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
int dest = index * vsize * 4;
|
||||
|
||||
buffer.position(dest);
|
||||
buffer.put(vertices);
|
||||
|
||||
//mark dirty
|
||||
mesh.getVerticesBuffer();
|
||||
}
|
||||
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){
|
||||
float u = region.u;
|
||||
float v = region.v2;
|
||||
float u2 = region.u2;
|
||||
float v2 = region.v;
|
||||
|
||||
float originX = w / 2, originY = h / 2;
|
||||
|
||||
float cos = Mathf.cosDeg(rotation);
|
||||
float sin = Mathf.sinDeg(rotation);
|
||||
|
||||
float fx = -originX;
|
||||
float fy = -originY;
|
||||
float fx2 = w - originX;
|
||||
float fy2 = h - originY;
|
||||
|
||||
float worldOriginX = x + originX;
|
||||
float worldOriginY = y + originY;
|
||||
|
||||
float x1 = cos * fx - sin * fy + worldOriginX;
|
||||
float y1 = sin * fx + cos * fy + worldOriginY;
|
||||
float x2 = cos * fx - sin * fy2 + worldOriginX;
|
||||
float y2 = sin * fx + cos * fy2 + worldOriginY;
|
||||
float x3 = cos * fx2 - sin * fy2 + worldOriginX;
|
||||
float y3 = sin * fx2 + cos * fy2 + worldOriginY;
|
||||
float x4 = x1 + (x3 - x2);
|
||||
float y4 = y3 - (y2 - y1);
|
||||
|
||||
float[] vertices = tmpVerts;
|
||||
float color = this.color;
|
||||
|
||||
int idx = 0;
|
||||
vertices[idx++] = x1;
|
||||
vertices[idx++] = y1;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x2;
|
||||
vertices[idx++] = y2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = x3;
|
||||
vertices[idx++] = y3;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = x4;
|
||||
vertices[idx++] = y4;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
int dest = index * vsize * 4;
|
||||
|
||||
buffer.position(dest);
|
||||
buffer.put(vertices);
|
||||
|
||||
//mark dirty
|
||||
mesh.getVerticesBuffer();
|
||||
}
|
||||
|
||||
public Mat getTransformMatrix(){
|
||||
return transMatrix;
|
||||
}
|
||||
|
||||
public void setProjectionMatrix(Mat matrix){
|
||||
projMatrix = matrix;
|
||||
}
|
||||
|
||||
public void resize(int sprites){
|
||||
if(mesh != null) mesh.dispose();
|
||||
|
||||
mesh = new Mesh(true, 4 * sprites, 0,
|
||||
VertexAttribute.position,
|
||||
VertexAttribute.color,
|
||||
VertexAttribute.texCoords);
|
||||
|
||||
buffer = mesh.getVerticesBuffer();
|
||||
buffer.limit(buffer.capacity());
|
||||
|
||||
mesh.indices = Vars.renderer.blocks.floor.getIndexData();
|
||||
}
|
||||
|
||||
private void updateMatrix(){
|
||||
combined.set(projMatrix).mul(transMatrix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
mesh.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user