it is done
This commit is contained in:
329
core/src/mindustry/graphics/BlockRenderer.java
Normal file
329
core/src/mindustry/graphics/BlockRenderer.java
Normal file
@@ -0,0 +1,329 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import static arc.Core.camera;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BlockRenderer implements Disposable{
|
||||
private final static int initialRequests = 32 * 32;
|
||||
private final static int expandr = 9;
|
||||
private final static Color shadowColor = new Color(0, 0, 0, 0.71f);
|
||||
|
||||
public final FloorRenderer floor = new FloorRenderer();
|
||||
|
||||
private Array<BlockRequest> requests = new Array<>(true, initialRequests, BlockRequest.class);
|
||||
private int lastCamX, lastCamY, lastRangeX, lastRangeY;
|
||||
private int requestidx = 0;
|
||||
private int iterateidx = 0;
|
||||
private float brokenFade = 0f;
|
||||
private FrameBuffer shadows = new FrameBuffer(2, 2);
|
||||
private FrameBuffer fog = new FrameBuffer(2, 2);
|
||||
private Array<Tile> outArray = new Array<>();
|
||||
private Array<Tile> shadowEvents = new Array<>();
|
||||
|
||||
public BlockRenderer(){
|
||||
|
||||
for(int i = 0; i < requests.size; i++){
|
||||
requests.set(i, new BlockRequest());
|
||||
}
|
||||
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
shadowEvents.clear();
|
||||
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);
|
||||
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
if(tile.block().hasShadow){
|
||||
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
Draw.color();
|
||||
shadows.end();
|
||||
|
||||
fog.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
|
||||
fog.resize(world.width(), world.height());
|
||||
fog.begin();
|
||||
Core.graphics.clear(Color.white);
|
||||
Draw.proj().setOrtho(0, 0, fog.getWidth(), fog.getHeight());
|
||||
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
int edgeBlend = 2;
|
||||
float rot = tile.rotation();
|
||||
boolean fillable = (tile.block().solid && tile.block().fillsTile && !tile.block().synthetic());
|
||||
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (world.width() - 1)), Math.abs(y - (world.height() - 1)))));
|
||||
if(edgeDst <= edgeBlend){
|
||||
rot = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), fillable ? rot : 0);
|
||||
}
|
||||
if(rot > 0 && (fillable || edgeDst <= edgeBlend)){
|
||||
Draw.color(0f, 0f, 0f, Math.min((rot + 0.5f) / 4f, 1f));
|
||||
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
Draw.color();
|
||||
fog.end();
|
||||
});
|
||||
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
shadowEvents.add(event.tile);
|
||||
|
||||
int avgx = (int)(camera.position.x / tilesize);
|
||||
int avgy = (int)(camera.position.y / tilesize);
|
||||
int rangex = (int)(camera.width / tilesize / 2) + 2;
|
||||
int rangey = (int)(camera.height / tilesize / 2) + 2;
|
||||
|
||||
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
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void drawFog(){
|
||||
float ww = world.width() * tilesize, wh = world.height() * tilesize;
|
||||
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(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();
|
||||
}
|
||||
|
||||
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){
|
||||
for(BrokenBlock block : state.teams.get(player.getTeam()).brokenBlocks){
|
||||
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;
|
||||
|
||||
Draw.alpha(0.33f * brokenFade);
|
||||
Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f));
|
||||
Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f);
|
||||
}
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawShadows(){
|
||||
if(!shadowEvents.isEmpty()){
|
||||
Draw.flush();
|
||||
|
||||
shadows.begin();
|
||||
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
Draw.color();
|
||||
shadows.end();
|
||||
shadowEvents.clear();
|
||||
|
||||
Draw.proj(camera.projection());
|
||||
renderer.pixelator.rebind();
|
||||
}
|
||||
|
||||
float ww = world.width() * tilesize, wh = world.height() * tilesize;
|
||||
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);
|
||||
|
||||
Draw.shader(Shaders.fog);
|
||||
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
|
||||
Draw.shader();
|
||||
}
|
||||
|
||||
/** Process all blocks to draw. */
|
||||
public void processBlocks(){
|
||||
iterateidx = 0;
|
||||
|
||||
int avgx = (int)(camera.position.x / tilesize);
|
||||
int avgy = (int)(camera.position.y / tilesize);
|
||||
|
||||
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){
|
||||
return;
|
||||
}
|
||||
|
||||
requestidx = 0;
|
||||
|
||||
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);
|
||||
if(tile == null) continue; //how is this possible?
|
||||
Block block = tile.block();
|
||||
|
||||
if(block != Blocks.air && block.cacheLayer == CacheLayer.normal){
|
||||
if(!expanded){
|
||||
addRequest(tile, Layer.block);
|
||||
}
|
||||
|
||||
if(state.rules.lighting && tile.block().synthetic() && !(tile.block() instanceof BlockPart)){
|
||||
addRequest(tile, Layer.lights);
|
||||
}
|
||||
|
||||
if(block.expanded || !expanded){
|
||||
|
||||
if(block.layer != null){
|
||||
addRequest(tile, block.layer);
|
||||
}
|
||||
|
||||
if(block.layer2 != null){
|
||||
addRequest(tile, block.layer2);
|
||||
}
|
||||
|
||||
if(tile.entity != null && tile.entity.power != null && tile.entity.power.links.size > 0){
|
||||
for(Tile other : block.getPowerConnections(tile, outArray)){
|
||||
if(other.block().layer == Layer.power){
|
||||
addRequest(other, Layer.power);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sort.instance().sort(requests.items, 0, requestidx);
|
||||
|
||||
lastCamX = avgx;
|
||||
lastCamY = avgy;
|
||||
lastRangeX = rangex;
|
||||
lastRangeY = rangey;
|
||||
}
|
||||
|
||||
public void drawBlocks(Layer stopAt){
|
||||
int startIdx = iterateidx;
|
||||
for(; iterateidx < requestidx; iterateidx++){
|
||||
BlockRequest request = requests.get(iterateidx);
|
||||
|
||||
if(request.layer.ordinal() > stopAt.ordinal()){
|
||||
break;
|
||||
}
|
||||
|
||||
if(request.layer == Layer.power){
|
||||
if(iterateidx - startIdx > 0 && request.tile.pos() == requests.get(iterateidx - 1).tile.pos()){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if(block.synthetic() && request.tile.getTeam() != player.getTeam()){
|
||||
block.drawTeam(request.tile);
|
||||
}
|
||||
|
||||
}else if(request.layer == Layer.lights){
|
||||
block.drawLight(request.tile);
|
||||
}else if(request.layer == block.layer){
|
||||
block.drawLayer(request.tile);
|
||||
}else if(request.layer == block.layer2){
|
||||
block.drawLayer2(request.tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
shadows.dispose();
|
||||
fog.dispose();
|
||||
shadows = fog = null;
|
||||
floor.dispose();
|
||||
}
|
||||
|
||||
private class BlockRequest implements Comparable<BlockRequest>{
|
||||
Tile tile;
|
||||
Layer layer;
|
||||
|
||||
@Override
|
||||
public int compareTo(BlockRequest other){
|
||||
int compare = layer.compareTo(other.layer);
|
||||
|
||||
return (compare != 0) ? compare : Integer.compare(tile.pos(), other.tile.pos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return tile.block().name + ":" + layer.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
420
core/src/mindustry/graphics/Bloom.java
Normal file
420
core/src/mindustry/graphics/Bloom.java
Normal file
@@ -0,0 +1,420 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Pixmap.Format;
|
||||
import arc.graphics.VertexAttributes.Usage;
|
||||
import arc.graphics.gl.FrameBuffer;
|
||||
import arc.graphics.gl.Shader;
|
||||
|
||||
/**
|
||||
* Bloomlib allow easy but efficient way to add bloom effect as post process
|
||||
* effect
|
||||
*
|
||||
* @author kalle_h
|
||||
*/
|
||||
public class Bloom{
|
||||
|
||||
/**
|
||||
* To use implement bloom more like a glow. Texture alpha channel can be
|
||||
* used as mask which part are glowing and which are not. see more info at:
|
||||
* http://www.gamasutra.com/view/feature/2107/realtime_glow.php
|
||||
* <p>
|
||||
* NOTE: need to be set before bloom instance is created. After that this
|
||||
* does nothing.
|
||||
*/
|
||||
public static boolean useAlphaChannelAsMask = false;
|
||||
|
||||
/** how many blur pass */
|
||||
public int blurPasses = 1;
|
||||
|
||||
private Shader tresholdShader;
|
||||
private Shader bloomShader;
|
||||
|
||||
private Mesh fullScreenQuad;
|
||||
|
||||
private Texture pingPongTex1;
|
||||
private Texture pingPongTex2;
|
||||
private Texture original;
|
||||
|
||||
private FrameBuffer frameBuffer;
|
||||
private FrameBuffer pingPongBuffer1;
|
||||
private FrameBuffer pingPongBuffer2;
|
||||
|
||||
private Shader blurShader;
|
||||
|
||||
private float bloomIntensity;
|
||||
private float originalIntensity;
|
||||
private float threshold;
|
||||
private int w;
|
||||
private int h;
|
||||
private boolean blending = false;
|
||||
private boolean capturing = false;
|
||||
private float r = 0f;
|
||||
private float g = 0f;
|
||||
private float b = 0f;
|
||||
private float a = 1f;
|
||||
private boolean disposeFBO = true;
|
||||
|
||||
/**
|
||||
* IMPORTANT NOTE CALL THIS WHEN RESUMING
|
||||
*/
|
||||
public void resume(){
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
}
|
||||
bloomShader.end();
|
||||
|
||||
setSize(w, h);
|
||||
setThreshold(threshold);
|
||||
setBloomIntesity(bloomIntensity);
|
||||
setOriginalIntesity(originalIntensity);
|
||||
|
||||
original = frameBuffer.getTexture();
|
||||
pingPongTex1 = pingPongBuffer1.getTexture();
|
||||
pingPongTex2 = pingPongBuffer2.getTexture();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bloom class that capsulate original scene capturate,
|
||||
* tresholding, gaussian blurring and blending. Default values: depth = true
|
||||
* blending = false 32bits = true
|
||||
*/
|
||||
public Bloom(){
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4,
|
||||
null, false, false, true);
|
||||
}
|
||||
|
||||
public Bloom(boolean useBlending){
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4,
|
||||
null, false, useBlending, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bloom class that capsulate original scene capturate,
|
||||
* tresholding, gaussian blurring and blending.
|
||||
*
|
||||
* @param FBO_W
|
||||
* @param FBO_H how big fbo is used for bloom texture, smaller = more blur and
|
||||
* lot faster but aliasing can be problem
|
||||
* @param hasDepth do rendering need depth buffer
|
||||
* @param useBlending does fbo need alpha channel and is blending enabled when final
|
||||
* image is rendered. This allow to combine background graphics
|
||||
* and only do blooming on certain objects param use32bitFBO does
|
||||
* fbo use higher precision than 16bits.
|
||||
*/
|
||||
public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending,
|
||||
boolean use32bitFBO){
|
||||
initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERT FUNCTIONALITY. no error checking. Use this only if you know what
|
||||
* you are doing. Remember that bloom.capture() clear the screen so use
|
||||
* continue instead if that is a problem.
|
||||
* <p>
|
||||
* Initialize bloom class that capsulate original scene capturate,
|
||||
* tresholding, gaussian blurring and blending.
|
||||
* <p>
|
||||
* * @param sceneIsCapturedHere diposing is user responsibility.
|
||||
*
|
||||
* @param FBO_W
|
||||
* @param FBO_H how big fbo is used for bloom texture, smaller = more blur and
|
||||
* lot faster but aliasing can be problem
|
||||
* @param useBlending does fbo need alpha channel and is blending enabled when final
|
||||
* image is rendered. This allow to combine background graphics
|
||||
* and only do blooming on certain objects param use32bitFBO does
|
||||
* fbo use higher precision than 16bits.
|
||||
*/
|
||||
public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere,
|
||||
boolean useBlending, boolean use32bitFBO){
|
||||
|
||||
initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending,
|
||||
use32bitFBO);
|
||||
disposeFBO = false;
|
||||
}
|
||||
|
||||
private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo,
|
||||
boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
||||
blending = useBlending;
|
||||
Format format = null;
|
||||
|
||||
if(use32bitFBO){
|
||||
if(useBlending){
|
||||
format = Format.RGBA8888;
|
||||
}else{
|
||||
format = Format.RGB888;
|
||||
}
|
||||
|
||||
}else{
|
||||
if(useBlending){
|
||||
format = Format.RGBA4444;
|
||||
}else{
|
||||
format = Format.RGB565;
|
||||
}
|
||||
}
|
||||
if(fbo == null){
|
||||
frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(),
|
||||
Core.graphics.getHeight(), hasDepth);
|
||||
}else{
|
||||
frameBuffer = fbo;
|
||||
}
|
||||
|
||||
pingPongBuffer1 = new FrameBuffer(format, FBO_W, FBO_H, false);
|
||||
|
||||
pingPongBuffer2 = new FrameBuffer(format, FBO_W, FBO_H, false);
|
||||
|
||||
original = frameBuffer.getTexture();
|
||||
pingPongTex1 = pingPongBuffer1.getTexture();
|
||||
pingPongTex2 = pingPongBuffer2.getTexture();
|
||||
|
||||
fullScreenQuad = createFullScreenQuad();
|
||||
final String alpha = useBlending ? "alpha_" : "";
|
||||
|
||||
bloomShader = createShader("screenspace", alpha + "bloom");
|
||||
|
||||
if(useAlphaChannelAsMask){
|
||||
tresholdShader = createShader("screenspace", "maskedtreshold");
|
||||
}else{
|
||||
tresholdShader = createShader("screenspace", alpha + "threshold");
|
||||
}
|
||||
|
||||
blurShader = createShader("blurspace", alpha + "gaussian");
|
||||
|
||||
setSize(FBO_W, FBO_H);
|
||||
setBloomIntesity(2.5f);
|
||||
setOriginalIntesity(0.8f);
|
||||
setThreshold(0.5f);
|
||||
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
}
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clearing color for capturing buffer
|
||||
*
|
||||
* @param r
|
||||
* @param g
|
||||
* @param b
|
||||
* @param a
|
||||
*/
|
||||
public void setClearColor(float r, float g, float b, float a){
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this before rendering scene.
|
||||
*/
|
||||
public void capture(){
|
||||
if(!capturing){
|
||||
capturing = true;
|
||||
frameBuffer.begin();
|
||||
Core.gl.glClearColor(r, g, b, a);
|
||||
Core.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause capturing to fbo.
|
||||
*/
|
||||
public void capturePause(){
|
||||
if(capturing){
|
||||
capturing = false;
|
||||
frameBuffer.end();
|
||||
}
|
||||
}
|
||||
|
||||
/** Start capturing again after pause, no clearing is done to framebuffer */
|
||||
public void captureContinue(){
|
||||
if(!capturing){
|
||||
capturing = true;
|
||||
frameBuffer.begin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after scene. Renders the bloomed scene.
|
||||
*/
|
||||
public void render(){
|
||||
if(capturing){
|
||||
capturing = false;
|
||||
frameBuffer.end();
|
||||
}
|
||||
|
||||
Core.gl.glDisable(GL20.GL_BLEND);
|
||||
Core.gl.glDisable(GL20.GL_DEPTH_TEST);
|
||||
Core.gl.glDepthMask(false);
|
||||
|
||||
gaussianBlur();
|
||||
|
||||
if(blending){
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
Core.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
pingPongTex1.bind(1);
|
||||
original.bind(0);
|
||||
bloomShader.begin();
|
||||
{
|
||||
fullScreenQuad.render(bloomShader, GL20.GL_TRIANGLE_FAN);
|
||||
}
|
||||
bloomShader.end();
|
||||
|
||||
}
|
||||
|
||||
private void gaussianBlur(){
|
||||
|
||||
// cut bright areas of the picture and blit to smaller fbo
|
||||
|
||||
original.bind(0);
|
||||
pingPongBuffer1.begin();
|
||||
{
|
||||
tresholdShader.begin();
|
||||
{
|
||||
// tresholdShader.setUniformi("u_texture0", 0);
|
||||
fullScreenQuad.render(tresholdShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
tresholdShader.end();
|
||||
}
|
||||
pingPongBuffer1.end();
|
||||
|
||||
for(int i = 0; i < blurPasses; i++){
|
||||
|
||||
pingPongTex1.bind(0);
|
||||
|
||||
// horizontal
|
||||
pingPongBuffer2.begin();
|
||||
{
|
||||
blurShader.begin();
|
||||
{
|
||||
blurShader.setUniformf("dir", 1f, 0f);
|
||||
fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
blurShader.end();
|
||||
}
|
||||
pingPongBuffer2.end();
|
||||
|
||||
pingPongTex2.bind(0);
|
||||
// vertical
|
||||
pingPongBuffer1.begin();
|
||||
{
|
||||
blurShader.begin();
|
||||
{
|
||||
blurShader.setUniformf("dir", 0f, 1f);
|
||||
|
||||
fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
blurShader.end();
|
||||
}
|
||||
pingPongBuffer1.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set intensity for bloom. higher mean more brightening for spots that are
|
||||
* over threshold
|
||||
*
|
||||
* @param intensity multiplier for blurred texture in combining phase. must be
|
||||
* positive.
|
||||
*/
|
||||
public void setBloomIntesity(float intensity){
|
||||
bloomIntensity = intensity;
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformf("BloomIntensity", intensity);
|
||||
}
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* set intensity for original scene. under 1 mean darkening and over 1 means
|
||||
* lightening
|
||||
*
|
||||
* @param intensity multiplier for captured texture in combining phase. must be
|
||||
* positive.
|
||||
*/
|
||||
public void setOriginalIntesity(float intensity){
|
||||
originalIntensity = intensity;
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformf("OriginalIntensity", intensity);
|
||||
}
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Treshold for bright parts. everything under threshold is clamped to 0
|
||||
*
|
||||
* @param threshold must be in range 0..1
|
||||
*/
|
||||
public void setThreshold(float threshold){
|
||||
this.threshold = threshold;
|
||||
tresholdShader.begin();
|
||||
{
|
||||
tresholdShader.setUniformf("threshold", threshold,
|
||||
1f / (1 - threshold));
|
||||
}
|
||||
tresholdShader.end();
|
||||
}
|
||||
|
||||
private void setSize(int FBO_W, int FBO_H){
|
||||
w = FBO_W;
|
||||
h = FBO_H;
|
||||
blurShader.begin();
|
||||
blurShader.setUniformf("size", FBO_W, FBO_H);
|
||||
blurShader.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when application is exiting.
|
||||
*/
|
||||
public void dispose(){
|
||||
try{
|
||||
if(disposeFBO)
|
||||
frameBuffer.dispose();
|
||||
|
||||
fullScreenQuad.dispose();
|
||||
|
||||
pingPongBuffer1.dispose();
|
||||
pingPongBuffer2.dispose();
|
||||
|
||||
blurShader.dispose();
|
||||
bloomShader.dispose();
|
||||
tresholdShader.dispose();
|
||||
}catch(Exception ignored){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static Mesh createFullScreenQuad(){
|
||||
float[] verts = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1};
|
||||
Mesh tmpMesh = new Mesh(true, 4, 0, new VertexAttribute(
|
||||
Usage.Position, 2, "a_position"), new VertexAttribute(
|
||||
Usage.TextureCoordinates, 2, "a_texCoord0"));
|
||||
|
||||
tmpMesh.setVertices(verts);
|
||||
return tmpMesh;
|
||||
|
||||
}
|
||||
|
||||
private static Shader createShader(String vertexName, String fragmentName){
|
||||
String vertexShader = Core.files.internal("bloomshaders/" + vertexName + ".vertex.glsl").readString();
|
||||
String fragmentShader = Core.files.internal("bloomshaders/" + fragmentName + ".fragment.glsl").readString();
|
||||
return new Shader(vertexShader, fragmentShader);
|
||||
}
|
||||
|
||||
}
|
||||
66
core/src/mindustry/graphics/CacheLayer.java
Normal file
66
core/src/mindustry/graphics/CacheLayer.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.g2d.Draw;
|
||||
import arc.graphics.gl.Shader;
|
||||
|
||||
import static arc.Core.camera;
|
||||
import static mindustry.Vars.renderer;
|
||||
|
||||
public enum CacheLayer{
|
||||
water{
|
||||
@Override
|
||||
public void begin(){
|
||||
beginShader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(){
|
||||
endShader(Shaders.water);
|
||||
}
|
||||
},
|
||||
tar{
|
||||
@Override
|
||||
public void begin(){
|
||||
beginShader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(){
|
||||
endShader(Shaders.tar);
|
||||
}
|
||||
},
|
||||
normal,
|
||||
walls;
|
||||
|
||||
public void begin(){
|
||||
|
||||
}
|
||||
|
||||
public void end(){
|
||||
|
||||
}
|
||||
|
||||
void beginShader(){
|
||||
if(!Core.settings.getBool("animatedwater")) return;
|
||||
|
||||
renderer.blocks.floor.endc();
|
||||
renderer.shieldBuffer.begin();
|
||||
Core.graphics.clear(Color.clear);
|
||||
renderer.blocks.floor.beginc();
|
||||
}
|
||||
|
||||
void endShader(Shader shader){
|
||||
if(!Core.settings.getBool("animatedwater")) return;
|
||||
|
||||
renderer.blocks.floor.endc();
|
||||
renderer.shieldBuffer.end();
|
||||
|
||||
Draw.shader(shader);
|
||||
Draw.rect(Draw.wrap(renderer.shieldBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height);
|
||||
Draw.shader();
|
||||
|
||||
renderer.blocks.floor.beginc();
|
||||
}
|
||||
}
|
||||
87
core/src/mindustry/graphics/Drawf.java
Normal file
87
core/src/mindustry/graphics/Drawf.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
|
||||
import static mindustry.Vars.renderer;
|
||||
|
||||
public class Drawf{
|
||||
|
||||
public static void dashCircle(float x, float y, float rad, Color color){
|
||||
Lines.stroke(3f, Pal.gray);
|
||||
Lines.dashCircle(x, y, rad);
|
||||
Lines.stroke(1f, color);
|
||||
Lines.dashCircle(x, y, rad);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public static void circles(float x, float y, float rad){
|
||||
circles(x, y, rad, Pal.accent);
|
||||
}
|
||||
|
||||
public static void circles(float x, float y, float rad, Color color){
|
||||
Lines.stroke(3f, Pal.gray);
|
||||
Lines.circle(x, y, rad);
|
||||
Lines.stroke(1f, color);
|
||||
Lines.circle(x, y, rad);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public static void square(float x, float y, float radius, Color color){
|
||||
Lines.stroke(3f, Pal.gray);
|
||||
Lines.square(x, y, radius + 1f, 45);
|
||||
Lines.stroke(1f, color);
|
||||
Lines.square(x, y, radius + 1f, 45);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public static void square(float x, float y, float radius){
|
||||
square(x, y, radius, Pal.accent);
|
||||
}
|
||||
|
||||
public static void arrow(float x, float y, float x2, float y2, float length, float radius){
|
||||
float angle = Angles.angle(x, y, x2, y2);
|
||||
float space = 2f;
|
||||
Tmp.v1.set(x2, y2).sub(x, y).limit(length);
|
||||
float vx = Tmp.v1.x + x, vy = Tmp.v1.y + y;
|
||||
|
||||
Draw.color(Pal.gray);
|
||||
Fill.poly(vx, vy, 3, radius + space, angle);
|
||||
Draw.color(Pal.accent);
|
||||
Fill.poly(vx, vy, 3, radius, angle);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public static void laser(TextureRegion line, TextureRegion edge, float x, float y, float x2, float y2, float scale){
|
||||
laser(line, edge, x, y, x2, y2, Mathf.angle(x2 - x, y2 - y), scale);
|
||||
}
|
||||
|
||||
public static void laser(TextureRegion line, TextureRegion edge, float x, float y, float x2, float y2){
|
||||
laser(line, edge, x, y, x2, y2, Mathf.angle(x2 - x, y2 - y), 1f);
|
||||
}
|
||||
|
||||
public static void laser(TextureRegion line, TextureRegion edge, float x, float y, float x2, float y2, float rotation, float scale){
|
||||
Tmp.v1.trns(rotation, 8f * scale * Draw.scl);
|
||||
|
||||
Draw.rect(edge, x, y, edge.getWidth() * scale * Draw.scl, edge.getHeight() * scale * Draw.scl, rotation + 180);
|
||||
Draw.rect(edge, x2, y2, edge.getWidth() * scale * Draw.scl, edge.getHeight() * scale * Draw.scl, rotation);
|
||||
|
||||
Lines.stroke(12f * scale);
|
||||
Lines.precise(true);
|
||||
Lines.line(line, x + Tmp.v1.x, y + Tmp.v1.y, x2 - Tmp.v1.x, y2 - Tmp.v1.y, CapStyle.none, 0f);
|
||||
Lines.precise(false);
|
||||
Lines.stroke(1f);
|
||||
|
||||
renderer.lights.line(x, y, x2, y2);
|
||||
}
|
||||
|
||||
public static void tri(float x, float y, float width, float length, float rotation){
|
||||
float oy = 17f / 63f * length;
|
||||
Draw.rect(Core.atlas.find("shape-3"), x, y - oy + length / 2f, width, length, width / 2f, oy, rotation - 90);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
234
core/src/mindustry/graphics/FloorRenderer.java
Normal file
234
core/src/mindustry/graphics/FloorRenderer.java
Normal file
@@ -0,0 +1,234 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.Events;
|
||||
import arc.struct.*;
|
||||
import arc.struct.IntSet.IntSetIterator;
|
||||
import arc.graphics.Camera;
|
||||
import arc.graphics.GL20;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.Mathf;
|
||||
import arc.util.*;
|
||||
import mindustry.game.EventType.WorldLoadEvent;
|
||||
import mindustry.world.Tile;
|
||||
import mindustry.world.blocks.Floor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static mindustry.Vars.tilesize;
|
||||
import static mindustry.Vars.world;
|
||||
|
||||
public class FloorRenderer implements Disposable{
|
||||
private final static int chunksize = 64;
|
||||
|
||||
private Chunk[][] cache;
|
||||
private MultiCacheBatch cbatch;
|
||||
private IntSet drawnLayerSet = new IntSet();
|
||||
private IntArray drawnLayers = new IntArray();
|
||||
private ObjectSet<CacheLayer> used = new ObjectSet<>();
|
||||
|
||||
public FloorRenderer(){
|
||||
Events.on(WorldLoadEvent.class, event -> clearTiles());
|
||||
}
|
||||
|
||||
public void drawFloor(){
|
||||
if(cache == null){
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = Core.camera;
|
||||
|
||||
int crangex = (int)(camera.width / (chunksize * tilesize)) + 1;
|
||||
int crangey = (int)(camera.height / (chunksize * tilesize)) + 1;
|
||||
|
||||
int camx = (int)(camera.position.x / (chunksize * tilesize));
|
||||
int camy = (int)(camera.position.y / (chunksize * tilesize));
|
||||
|
||||
int layers = CacheLayer.values().length;
|
||||
|
||||
drawnLayers.clear();
|
||||
drawnLayerSet.clear();
|
||||
|
||||
//preliminary layer check
|
||||
for(int x = -crangex; x <= crangex; x++){
|
||||
for(int y = -crangey; y <= crangey; y++){
|
||||
int worldx = camx + x;
|
||||
int worldy = camy + y;
|
||||
|
||||
if(!Structs.inBounds(worldx, worldy, cache))
|
||||
continue;
|
||||
|
||||
Chunk chunk = cache[worldx][worldy];
|
||||
|
||||
//loop through all layers, and add layer index if it exists
|
||||
for(int i = 0; i < layers; i++){
|
||||
if(chunk.caches[i] != -1 && i != CacheLayer.walls.ordinal()){
|
||||
drawnLayerSet.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IntSetIterator it = drawnLayerSet.iterator();
|
||||
while(it.hasNext){
|
||||
drawnLayers.add(it.next());
|
||||
}
|
||||
|
||||
drawnLayers.sort();
|
||||
|
||||
Draw.flush();
|
||||
beginDraw();
|
||||
|
||||
for(int i = 0; i < drawnLayers.size; i++){
|
||||
CacheLayer layer = CacheLayer.values()[drawnLayers.get(i)];
|
||||
|
||||
drawLayer(layer);
|
||||
}
|
||||
|
||||
endDraw();
|
||||
}
|
||||
|
||||
public void beginc(){
|
||||
cbatch.beginDraw();
|
||||
}
|
||||
|
||||
public void endc(){
|
||||
cbatch.endDraw();
|
||||
}
|
||||
|
||||
public void beginDraw(){
|
||||
if(cache == null){
|
||||
return;
|
||||
}
|
||||
|
||||
cbatch.setProjection(Core.camera.projection());
|
||||
cbatch.beginDraw();
|
||||
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
}
|
||||
|
||||
public void endDraw(){
|
||||
if(cache == null){
|
||||
return;
|
||||
}
|
||||
|
||||
cbatch.endDraw();
|
||||
}
|
||||
|
||||
public void drawLayer(CacheLayer layer){
|
||||
if(cache == null){
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = Core.camera;
|
||||
|
||||
int crangex = (int)(camera.width / (chunksize * tilesize)) + 1;
|
||||
int crangey = (int)(camera.height / (chunksize * tilesize)) + 1;
|
||||
|
||||
layer.begin();
|
||||
|
||||
for(int x = -crangex; x <= crangex; x++){
|
||||
for(int y = -crangey; y <= crangey; y++){
|
||||
int worldx = (int)(camera.position.x / (chunksize * tilesize)) + x;
|
||||
int worldy = (int)(camera.position.y / (chunksize * tilesize)) + y;
|
||||
|
||||
if(!Structs.inBounds(worldx, worldy, cache)){
|
||||
continue;
|
||||
}
|
||||
|
||||
Chunk chunk = cache[worldx][worldy];
|
||||
if(chunk.caches[layer.ordinal()] == -1) continue;
|
||||
cbatch.drawCache(chunk.caches[layer.ordinal()]);
|
||||
}
|
||||
}
|
||||
|
||||
layer.end();
|
||||
}
|
||||
|
||||
private void cacheChunk(int cx, int cy){
|
||||
used.clear();
|
||||
Chunk chunk = cache[cx][cy];
|
||||
|
||||
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
|
||||
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){
|
||||
Tile tile = world.tile(tilex, tiley);
|
||||
|
||||
if(tile != null){
|
||||
if(tile.block().cacheLayer != CacheLayer.normal){
|
||||
used.add(tile.block().cacheLayer);
|
||||
}else{
|
||||
used.add(tile.floor().cacheLayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(CacheLayer layer : used){
|
||||
cacheChunkLayer(cx, cy, chunk, layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void cacheChunkLayer(int cx, int cy, Chunk chunk, CacheLayer layer){
|
||||
SpriteBatch current = Core.batch;
|
||||
Core.batch = cbatch;
|
||||
|
||||
cbatch.beginCache();
|
||||
|
||||
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
|
||||
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){
|
||||
Tile tile = world.tile(tilex, tiley);
|
||||
Floor floor;
|
||||
|
||||
if(tile == null){
|
||||
continue;
|
||||
}else{
|
||||
floor = tile.floor();
|
||||
}
|
||||
|
||||
if(tile.block().cacheLayer == layer && layer == CacheLayer.walls && !(tile.isDarkened() && tile.rotation() >= 5)){
|
||||
tile.block().draw(tile);
|
||||
}else if(floor.cacheLayer == layer && (world.isAccessible(tile.x, tile.y) || tile.block().cacheLayer != CacheLayer.walls || !tile.block().fillsTile)){
|
||||
floor.draw(tile);
|
||||
}else if(floor.cacheLayer.ordinal() < layer.ordinal() && layer != CacheLayer.walls){
|
||||
floor.drawNonLayer(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
Core.batch = current;
|
||||
chunk.caches[layer.ordinal()] = cbatch.endCache();
|
||||
}
|
||||
|
||||
public void clearTiles(){
|
||||
if(cbatch != null) cbatch.dispose();
|
||||
|
||||
int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
|
||||
chunksy = Mathf.ceil((float)(world.height()) / chunksize);
|
||||
cache = new Chunk[chunksx][chunksy];
|
||||
cbatch = new MultiCacheBatch(chunksize * chunksize * 4);
|
||||
|
||||
Time.mark();
|
||||
|
||||
for(int x = 0; x < chunksx; x++){
|
||||
for(int y = 0; y < chunksy; y++){
|
||||
cache[x][y] = new Chunk();
|
||||
Arrays.fill(cache[x][y].caches, -1);
|
||||
|
||||
cacheChunk(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Time to cache: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
if(cbatch != null){
|
||||
cbatch.dispose();
|
||||
cbatch = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class Chunk{
|
||||
int[] caches = new int[CacheLayer.values().length];
|
||||
}
|
||||
}
|
||||
245
core/src/mindustry/graphics/IndexedRenderer.java
Normal file
245
core/src/mindustry/graphics/IndexedRenderer.java
Normal file
@@ -0,0 +1,245 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.VertexAttributes.Usage;
|
||||
import arc.graphics.g2d.BatchShader;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.graphics.gl.Shader;
|
||||
import arc.math.Mathf;
|
||||
import arc.math.Matrix3;
|
||||
import arc.util.Disposable;
|
||||
import arc.util.Strings;
|
||||
|
||||
//TODO this class is a trainwreck, remove it
|
||||
public class IndexedRenderer implements Disposable{
|
||||
private final static int vsize = 5;
|
||||
|
||||
private Shader program = new Shader(
|
||||
Strings.join("\n",
|
||||
"attribute vec4 " + Shader.POSITION_ATTRIBUTE + ";",
|
||||
"attribute vec4 " + Shader.COLOR_ATTRIBUTE + ";",
|
||||
"attribute vec2 " + Shader.TEXCOORD_ATTRIBUTE + "0;",
|
||||
"uniform mat4 u_projTrans;",
|
||||
"varying vec4 v_color;",
|
||||
"varying vec2 v_texCoords;",
|
||||
"",
|
||||
"void main(){",
|
||||
" v_color = " + Shader.COLOR_ATTRIBUTE + ";",
|
||||
" v_color.a = v_color.a * (255.0/254.0);",
|
||||
" v_texCoords = " + Shader.TEXCOORD_ATTRIBUTE + "0;",
|
||||
" gl_Position = u_projTrans * " + Shader.POSITION_ATTRIBUTE + ";",
|
||||
"}"),
|
||||
Strings.join("\n",
|
||||
"#ifdef GL_ES",
|
||||
"#define LOWP lowp",
|
||||
"precision mediump float;",
|
||||
"#else",
|
||||
"#define LOWP ",
|
||||
"#endif",
|
||||
"",
|
||||
"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 Mesh mesh;
|
||||
private float[] tmpVerts = new float[vsize * 6];
|
||||
private float[] vertices;
|
||||
|
||||
private Matrix3 projMatrix = new Matrix3();
|
||||
private Matrix3 transMatrix = new Matrix3();
|
||||
private Matrix3 combined = new Matrix3();
|
||||
private float color = Color.white.toFloatBits();
|
||||
|
||||
public IndexedRenderer(int sprites){
|
||||
resize(sprites);
|
||||
}
|
||||
|
||||
public void render(Texture texture){
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
|
||||
updateMatrix();
|
||||
|
||||
program.begin();
|
||||
|
||||
texture.bind();
|
||||
|
||||
program.setUniformMatrix4("u_projTrans", BatchShader.copyTransform(combined));
|
||||
program.setUniformi("u_texture", 0);
|
||||
|
||||
mesh.render(program, GL20.GL_TRIANGLES, 0, vertices.length / vsize);
|
||||
|
||||
program.end();
|
||||
}
|
||||
|
||||
public void setColor(Color color){
|
||||
this.color = color.toFloatBits();
|
||||
}
|
||||
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h){
|
||||
final float fx2 = x + w;
|
||||
final float fy2 = y + h;
|
||||
final float u = region.getU();
|
||||
final float v = region.getV2();
|
||||
final float u2 = region.getU2();
|
||||
final float v2 = region.getV();
|
||||
|
||||
float[] vertices = tmpVerts;
|
||||
|
||||
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;
|
||||
|
||||
//tri2
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = fy2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
mesh.updateVertices(index * vsize * 6, vertices);
|
||||
}
|
||||
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){
|
||||
final float u = region.getU();
|
||||
final float v = region.getV2();
|
||||
final float u2 = region.getU2();
|
||||
final float v2 = region.getV();
|
||||
|
||||
final float originX = w / 2, originY = h / 2;
|
||||
|
||||
final float cos = Mathf.cosDeg(rotation);
|
||||
final float sin = Mathf.sinDeg(rotation);
|
||||
|
||||
float fx = -originX;
|
||||
float fy = -originY;
|
||||
float fx2 = w - originX;
|
||||
float fy2 = h - originY;
|
||||
|
||||
final float worldOriginX = x + originX;
|
||||
final float worldOriginY = y + originY;
|
||||
|
||||
float x1 = cos * fx - sin * fy;
|
||||
float y1 = sin * fx + cos * fy;
|
||||
|
||||
float x2 = cos * fx - sin * fy2;
|
||||
float y2 = sin * fx + cos * fy2;
|
||||
|
||||
float x3 = cos * fx2 - sin * fy2;
|
||||
float y3 = sin * fx2 + cos * fy2;
|
||||
|
||||
float x4 = x1 + (x3 - x2);
|
||||
float y4 = y3 - (y2 - y1);
|
||||
|
||||
x1 += worldOriginX;
|
||||
y1 += worldOriginY;
|
||||
x2 += worldOriginX;
|
||||
y2 += worldOriginY;
|
||||
x3 += worldOriginX;
|
||||
y3 += worldOriginY;
|
||||
x4 += worldOriginX;
|
||||
y4 += worldOriginY;
|
||||
|
||||
float[] vertices = tmpVerts;
|
||||
|
||||
int idx = 0;
|
||||
vertices[idx++] = x1;
|
||||
vertices[idx++] = y1;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
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++] = u;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
//tri2
|
||||
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++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x3;
|
||||
vertices[idx++] = y3;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
mesh.updateVertices(index * vsize * 6, vertices);
|
||||
}
|
||||
|
||||
public Matrix3 getTransformMatrix(){
|
||||
return transMatrix;
|
||||
}
|
||||
|
||||
public void setProjectionMatrix(Matrix3 matrix){
|
||||
projMatrix = matrix;
|
||||
}
|
||||
|
||||
public void resize(int sprites){
|
||||
if(mesh != null) mesh.dispose();
|
||||
|
||||
mesh = new Mesh(true, 6 * sprites, 0,
|
||||
new VertexAttribute(Usage.Position, 2, "a_position"),
|
||||
new VertexAttribute(Usage.ColorPacked, 4, "a_color"),
|
||||
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
|
||||
vertices = new float[6 * sprites * vsize];
|
||||
mesh.setVertices(vertices);
|
||||
}
|
||||
|
||||
private void updateMatrix(){
|
||||
combined.set(projMatrix).mul(transMatrix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
mesh.dispose();
|
||||
program.dispose();
|
||||
}
|
||||
}
|
||||
16
core/src/mindustry/graphics/Layer.java
Normal file
16
core/src/mindustry/graphics/Layer.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
public enum Layer{
|
||||
/** Base block layer. */
|
||||
block,
|
||||
/** for placement */
|
||||
placement,
|
||||
/** First overlay. Stuff like conveyor items. */
|
||||
overlay,
|
||||
/** "High" blocks, like turrets. */
|
||||
turret,
|
||||
/** Power lasers. */
|
||||
power,
|
||||
/** Extra layer that's always on top.*/
|
||||
lights
|
||||
}
|
||||
199
core/src/mindustry/graphics/LightRenderer.java
Normal file
199
core/src/mindustry/graphics/LightRenderer.java
Normal file
@@ -0,0 +1,199 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
|
||||
import static mindustry.Vars.state;
|
||||
|
||||
/** Renders overlay lights. Client only. */
|
||||
public class LightRenderer{
|
||||
private static final int scaling = 4;
|
||||
private float[] vertices = new float[24];
|
||||
private FrameBuffer buffer = new FrameBuffer(2, 2);
|
||||
private Array<Runnable> lights = new Array<>();
|
||||
|
||||
public void add(Runnable run){
|
||||
if(!enabled()) return;
|
||||
|
||||
lights.add(run);
|
||||
}
|
||||
|
||||
public void add(float x, float y, float radius, Color color, float opacity){
|
||||
if(!enabled()) return;
|
||||
|
||||
float res = color.toFloatBits();
|
||||
add(() -> {
|
||||
Draw.color(res);
|
||||
Draw.alpha(opacity);
|
||||
Draw.rect("circle-shadow", x, y, radius * 2, radius * 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void add(float x, float y, TextureRegion region, Color color, float opacity){
|
||||
if(!enabled()) return;
|
||||
|
||||
float res = color.toFloatBits();
|
||||
add(() -> {
|
||||
Draw.color(res);
|
||||
Draw.alpha(opacity);
|
||||
Draw.rect(region, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
public void line(float x, float y, float x2, float y2){
|
||||
if(!enabled()) return;
|
||||
|
||||
add(() -> {
|
||||
Draw.color(Color.orange, 0.3f);
|
||||
|
||||
float stroke = 30f;
|
||||
float rot = Mathf.angleExact(x2 - x, y2 - y);
|
||||
TextureRegion ledge = Core.atlas.find("circle-end"), lmid = Core.atlas.find("circle-mid");
|
||||
|
||||
float color = Draw.getColor().toFloatBits();
|
||||
float u = lmid.getU();
|
||||
float v = lmid.getV2();
|
||||
float u2 = lmid.getU2();
|
||||
float v2 = lmid.getV();
|
||||
|
||||
|
||||
Vector2 v1 = Tmp.v1.trnsExact(rot + 90f, stroke);
|
||||
float lx1 = x - v1.x, ly1 = y - v1.y,
|
||||
lx2 = x + v1.x, ly2 = y + v1.y,
|
||||
lx3 = x2 + v1.x, ly3 = y2 + v1.y,
|
||||
lx4 = x2 - v1.x, ly4 = y2 - v1.y;
|
||||
|
||||
vertices[0] = lx1;
|
||||
vertices[1] = ly1;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx2;
|
||||
vertices[7] = ly2;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx3;
|
||||
vertices[13] = ly3;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx4;
|
||||
vertices[19] = ly4;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
|
||||
|
||||
Vector2 v3 = Tmp.v2.trnsExact(rot, stroke);
|
||||
|
||||
u = ledge.getU();
|
||||
v = ledge.getV2();
|
||||
u2 = ledge.getU2();
|
||||
v2 = ledge.getV();
|
||||
|
||||
vertices[0] = lx4;
|
||||
vertices[1] = ly4;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx3;
|
||||
vertices[7] = ly3;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx3 + v3.x;
|
||||
vertices[13] = ly3 + v3.y;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx4 + v3.x;
|
||||
vertices[19] = ly4 + v3.y;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
|
||||
vertices[0] = lx2;
|
||||
vertices[1] = ly2;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx1;
|
||||
vertices[7] = ly1;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx1 - v3.x;
|
||||
vertices[13] = ly1 - v3.y;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx2 - v3.x;
|
||||
vertices[19] = ly2 - v3.y;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean enabled(){
|
||||
return state.rules.lighting;
|
||||
}
|
||||
|
||||
public void draw(){
|
||||
if(buffer.getWidth() != Core.graphics.getWidth()/scaling || buffer.getHeight() != Core.graphics.getHeight()/scaling){
|
||||
buffer.resize(Core.graphics.getWidth()/scaling, Core.graphics.getHeight()/scaling);
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
buffer.beginDraw(Color.clear);
|
||||
Draw.blend(Blending.normal);
|
||||
for(Runnable run : lights){
|
||||
run.run();
|
||||
}
|
||||
Draw.reset();
|
||||
Draw.blend();
|
||||
buffer.endDraw();
|
||||
|
||||
Draw.color();
|
||||
Shaders.light.ambient.set(state.rules.ambientLight);
|
||||
Draw.shader(Shaders.light);
|
||||
Draw.rect(Draw.wrap(buffer.getTexture()), Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
Draw.shader();
|
||||
|
||||
lights.clear();
|
||||
}
|
||||
}
|
||||
304
core/src/mindustry/graphics/MenuRenderer.java
Normal file
304
core/src/mindustry/graphics/MenuRenderer.java
Normal file
@@ -0,0 +1,304 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.struct.Array;
|
||||
import arc.func.Floatc2;
|
||||
import arc.graphics.Camera;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.FrameBuffer;
|
||||
import arc.math.*;
|
||||
import arc.scene.ui.layout.Scl;
|
||||
import arc.util.*;
|
||||
import arc.util.noise.RidgedPerlin;
|
||||
import arc.util.noise.Simplex;
|
||||
import mindustry.content.Blocks;
|
||||
import mindustry.content.UnitTypes;
|
||||
import mindustry.type.UnitType;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.Floor;
|
||||
import mindustry.world.blocks.OreBlock;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class MenuRenderer implements Disposable{
|
||||
private static final float darkness = 0.3f;
|
||||
private final int width = !mobile ? 100 : 60, height = !mobile ? 50 : 40;
|
||||
|
||||
private int cacheFloor, cacheWall;
|
||||
private Camera camera = new Camera();
|
||||
private Matrix3 mat = new Matrix3();
|
||||
private FrameBuffer shadows;
|
||||
private CacheBatch batch;
|
||||
private float time = 0f;
|
||||
private float flyerRot = 45f;
|
||||
private int flyers = Mathf.chance(0.2) ? Mathf.random(35) : Mathf.random(15);
|
||||
private UnitType flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant);
|
||||
|
||||
public MenuRenderer(){
|
||||
Time.mark();
|
||||
generate();
|
||||
cache();
|
||||
Log.info("Time to generate menu: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
private void generate(){
|
||||
Tile[][] tiles = world.createTiles(width, height);
|
||||
Array<Block> ores = content.blocks().select(b -> b instanceof OreBlock);
|
||||
shadows = new FrameBuffer(width, height);
|
||||
int offset = Mathf.random(100000);
|
||||
Simplex s1 = new Simplex(offset);
|
||||
Simplex s2 = new Simplex(offset + 1);
|
||||
Simplex s3 = new Simplex(offset + 2);
|
||||
RidgedPerlin rid = new RidgedPerlin(1 + offset, 1);
|
||||
Block[] selected = Structs.select(
|
||||
new Block[]{Blocks.sand, Blocks.sandRocks},
|
||||
new Block[]{Blocks.shale, Blocks.shaleRocks},
|
||||
new Block[]{Blocks.ice, Blocks.icerocks},
|
||||
new Block[]{Blocks.sand, Blocks.sandRocks},
|
||||
new Block[]{Blocks.shale, Blocks.shaleRocks},
|
||||
new Block[]{Blocks.ice, Blocks.icerocks},
|
||||
new Block[]{Blocks.moss, Blocks.sporePine}
|
||||
);
|
||||
Block[] selected2 = Structs.select(
|
||||
new Block[]{Blocks.ignarock, Blocks.duneRocks},
|
||||
new Block[]{Blocks.ignarock, Blocks.duneRocks},
|
||||
new Block[]{Blocks.stone, Blocks.rocks},
|
||||
new Block[]{Blocks.stone, Blocks.rocks},
|
||||
new Block[]{Blocks.moss, Blocks.sporerocks},
|
||||
new Block[]{Blocks.salt, Blocks.saltRocks}
|
||||
);
|
||||
|
||||
Block ore1 = ores.random();
|
||||
ores.remove(ore1);
|
||||
Block ore2 = ores.random();
|
||||
|
||||
double tr1 = Mathf.random(0.65f, 0.85f);
|
||||
double tr2 = Mathf.random(0.65f, 0.85f);
|
||||
boolean doheat = Mathf.chance(0.25);
|
||||
boolean tendrils = Mathf.chance(0.25);
|
||||
boolean tech = Mathf.chance(0.25);
|
||||
int secSize = 10;
|
||||
|
||||
Block floord = selected[0], walld = selected[1];
|
||||
Block floord2 = selected2[0], walld2 = selected2[1];
|
||||
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
Block floor = floord;
|
||||
Block ore = Blocks.air;
|
||||
Block wall = Blocks.air;
|
||||
|
||||
if(s1.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){
|
||||
wall = walld;
|
||||
}
|
||||
|
||||
if(s3.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){
|
||||
floor = floord2;
|
||||
if(wall != Blocks.air){
|
||||
wall = walld2;
|
||||
}
|
||||
}
|
||||
|
||||
if(s2.octaveNoise2D(3, 0.3, 1/30.0, x, y) > tr1){
|
||||
ore = ore1;
|
||||
}
|
||||
|
||||
if(s2.octaveNoise2D(2, 0.2, 1/15.0, x, y+99999) > tr2){
|
||||
ore = ore2;
|
||||
}
|
||||
|
||||
if(doheat){
|
||||
double heat = s3.octaveNoise2D(4, 0.6, 1 / 50.0, x, y + 9999);
|
||||
double base = 0.65;
|
||||
|
||||
if(heat > base){
|
||||
ore = Blocks.air;
|
||||
wall = Blocks.air;
|
||||
floor = Blocks.ignarock;
|
||||
|
||||
if(heat > base + 0.1){
|
||||
floor = Blocks.hotrock;
|
||||
|
||||
if(heat > base + 0.15){
|
||||
floor = Blocks.magmarock;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(tech){
|
||||
int mx = x % secSize, my = y % secSize;
|
||||
int sclx = x / secSize, scly = y / secSize;
|
||||
if(s1.octaveNoise2D(2, 1f / 10f, 0.5f, sclx, scly) > 0.4f && (mx == 0 || my == 0 || mx == secSize - 1 || my == secSize - 1)){
|
||||
floor = Blocks.darkPanel3;
|
||||
if(Mathf.dst(mx, my, secSize/2, secSize/2) > secSize/2f + 1){
|
||||
floor = Blocks.darkPanel4;
|
||||
}
|
||||
|
||||
|
||||
if(wall != Blocks.air && Mathf.chance(0.7)){
|
||||
wall = Blocks.darkMetal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(tendrils){
|
||||
if(rid.getValue(x, y, 1f / 17f) > 0f){
|
||||
floor = Mathf.chance(0.2) ? Blocks.sporeMoss : Blocks.moss;
|
||||
|
||||
if(wall != Blocks.air){
|
||||
wall = Blocks.sporerocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tile tile;
|
||||
tiles[x][y] = (tile = new CachedTile());
|
||||
tile.x = (short)x;
|
||||
tile.y = (short)y;
|
||||
tile.setFloor((Floor) floor);
|
||||
tile.setBlock(wall);
|
||||
tile.setOverlay(ore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cache(){
|
||||
|
||||
//draw shadows
|
||||
Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight());
|
||||
shadows.beginDraw(Color.clear);
|
||||
Draw.color(Color.black);
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
if(world.rawTile(x, y).block() != Blocks.air){
|
||||
Fill.rect(x + 0.5f, y + 0.5f, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Draw.color();
|
||||
shadows.endDraw();
|
||||
|
||||
SpriteBatch prev = Core.batch;
|
||||
|
||||
Core.batch = batch = new CacheBatch(new SpriteCache(width * height * 6, false));
|
||||
batch.beginCache();
|
||||
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
tile.floor().draw(tile);
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
if(tile.overlay() != Blocks.air){
|
||||
tile.overlay().draw(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheFloor = batch.endCache();
|
||||
batch.beginCache();
|
||||
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
if(tile.block() != Blocks.air){
|
||||
tile.block().draw(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheWall = batch.endCache();
|
||||
|
||||
Core.batch = prev;
|
||||
}
|
||||
|
||||
public void render(){
|
||||
time += Time.delta();
|
||||
float scaling = Math.max(Scl.scl(4f), Math.max(Core.graphics.getWidth() / ((width - 1f) * tilesize), Core.graphics.getHeight() / ((height - 1f) * tilesize)));
|
||||
camera.position.set(width * tilesize / 2f, height * tilesize / 2f);
|
||||
camera.resize(Core.graphics.getWidth() / scaling,
|
||||
Core.graphics.getHeight() / scaling);
|
||||
|
||||
mat.set(Draw.proj());
|
||||
Draw.flush();
|
||||
Draw.proj(camera.projection());
|
||||
batch.setProjection(camera.projection());
|
||||
batch.beginDraw();
|
||||
batch.drawCache(cacheFloor);
|
||||
batch.endDraw();
|
||||
Draw.color();
|
||||
Draw.rect(Draw.wrap(shadows.getTexture()),
|
||||
width * tilesize / 2f - 4f, height * tilesize / 2f - 4f,
|
||||
width * tilesize, -height * tilesize);
|
||||
Draw.flush();
|
||||
batch.beginDraw();
|
||||
batch.drawCache(cacheWall);
|
||||
batch.endDraw();
|
||||
|
||||
drawFlyers();
|
||||
|
||||
Draw.proj(mat);
|
||||
Draw.color(0f, 0f, 0f, darkness);
|
||||
Fill.crect(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
private void drawFlyers(){
|
||||
Draw.color(0f, 0f, 0f, 0.4f);
|
||||
|
||||
TextureRegion icon = flyerType.icon(Cicon.full);
|
||||
|
||||
float size = Math.max(icon.getWidth(), icon.getHeight()) * Draw.scl * 1.6f;
|
||||
|
||||
flyers((x, y) -> {
|
||||
Draw.rect(flyerType.region, x - 12f, y - 13f, flyerRot - 90);
|
||||
});
|
||||
|
||||
flyers((x, y) -> {
|
||||
Draw.rect("circle-shadow", x, y, size, size);
|
||||
});
|
||||
Draw.color();
|
||||
|
||||
flyers((x, y) -> {
|
||||
float engineOffset = flyerType.engineOffset, engineSize = flyerType.engineSize, rotation = flyerRot;
|
||||
|
||||
Draw.color(Pal.engine);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset), y + Angles.trnsy(rotation + 180, engineOffset),
|
||||
engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f));
|
||||
|
||||
Draw.color(Color.white);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset - 1f), y + Angles.trnsy(rotation + 180, engineOffset - 1f),
|
||||
(engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f)) / 2f);
|
||||
Draw.color();
|
||||
|
||||
Draw.rect(flyerType.region, x, y, flyerRot - 90);
|
||||
});
|
||||
}
|
||||
|
||||
private void flyers(Floatc2 cons){
|
||||
float tw = width * tilesize * 1f + tilesize;
|
||||
float th = height * tilesize * 1f + tilesize;
|
||||
float range = 500f;
|
||||
float offset = -100f;
|
||||
|
||||
for(int i = 0; i < flyers; i++){
|
||||
Tmp.v1.trns(flyerRot, time * (2f + flyerType.speed));
|
||||
|
||||
cons.get((Mathf.randomSeedRange(i, range) + Tmp.v1.x + Mathf.absin(time + Mathf.randomSeedRange(i + 2, 500), 10f, 3.4f) + offset) % (tw + Mathf.randomSeed(i + 5, 0, 500)),
|
||||
(Mathf.randomSeedRange(i + 1, range) + Tmp.v1.y + Mathf.absin(time + Mathf.randomSeedRange(i + 3, 500), 10f, 3.4f) + offset) % th);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
batch.dispose();
|
||||
shadows.dispose();
|
||||
}
|
||||
}
|
||||
191
core/src/mindustry/graphics/MinimapRenderer.java
Normal file
191
core/src/mindustry/graphics/MinimapRenderer.java
Normal file
@@ -0,0 +1,191 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Pixmap.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.io.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class MinimapRenderer implements Disposable{
|
||||
private static final float baseSize = 16f;
|
||||
private final Array<Unit> units = new Array<>();
|
||||
private Pixmap pixmap;
|
||||
private Texture texture;
|
||||
private TextureRegion region;
|
||||
private Rectangle rect = new Rectangle();
|
||||
private float zoom = 4;
|
||||
|
||||
public MinimapRenderer(){
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
reset();
|
||||
updateAll();
|
||||
});
|
||||
|
||||
//make sure to call on the graphics thread
|
||||
Events.on(TileChangeEvent.class, event -> Core.app.post(() -> update(event.tile)));
|
||||
}
|
||||
|
||||
public Pixmap getPixmap(){
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
public Texture getTexture(){
|
||||
return texture;
|
||||
}
|
||||
|
||||
public void zoomBy(float amount){
|
||||
zoom += amount;
|
||||
setZoom(zoom);
|
||||
}
|
||||
|
||||
public void setZoom(float amount){
|
||||
zoom = Mathf.clamp(amount, 1f, Math.min(world.width(), world.height()) / baseSize / 2f);
|
||||
}
|
||||
|
||||
public float getZoom(){
|
||||
return zoom;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
if(pixmap != null){
|
||||
pixmap.dispose();
|
||||
texture.dispose();
|
||||
}
|
||||
setZoom(4f);
|
||||
pixmap = new Pixmap(world.width(), world.height(), Format.RGBA8888);
|
||||
texture = new Texture(pixmap);
|
||||
region = new TextureRegion(texture);
|
||||
}
|
||||
|
||||
public void drawEntities(float x, float y, float w, float h, boolean withLabels){
|
||||
updateUnitArray();
|
||||
|
||||
float sz = baseSize * zoom;
|
||||
float dx = (Core.camera.position.x / tilesize);
|
||||
float dy = (Core.camera.position.y / tilesize);
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
|
||||
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
|
||||
|
||||
for(Unit unit : units){
|
||||
float rx = (unit.x - rect.x) / rect.width * w;
|
||||
float ry = (unit.y - rect.y) / rect.width * h;
|
||||
|
||||
if(withLabels && unit instanceof Player){
|
||||
Player pl = (Player) unit;
|
||||
if(!pl.isLocal){
|
||||
// Only display names for other players.
|
||||
drawLabel(x + rx, y + ry, pl.name, unit.getTeam().color);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color(unit.getTeam().color);
|
||||
Fill.rect(x + rx, y + ry, Scl.scl(baseSize / 2f), Scl.scl(baseSize / 2f));
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public void drawEntities(float x, float y, float w, float h){
|
||||
drawEntities(x, y, w, h, true);
|
||||
}
|
||||
|
||||
public TextureRegion getRegion(){
|
||||
if(texture == null) return null;
|
||||
|
||||
float sz = Mathf.clamp(baseSize * zoom, baseSize, Math.min(world.width(), world.height()));
|
||||
float dx = (Core.camera.position.x / tilesize);
|
||||
float dy = (Core.camera.position.y / tilesize);
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
float invTexWidth = 1f / texture.getWidth();
|
||||
float invTexHeight = 1f / texture.getHeight();
|
||||
float x = dx - sz, y = world.height() - dy - sz, width = sz * 2, height = sz * 2;
|
||||
region.set(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
|
||||
return region;
|
||||
}
|
||||
|
||||
public void updateAll(){
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(world.tile(x, y)));
|
||||
}
|
||||
}
|
||||
texture.draw(pixmap, 0, 0);
|
||||
}
|
||||
|
||||
public void update(Tile tile){
|
||||
int color = colorFor(world.tile(tile.x, tile.y));
|
||||
pixmap.draw(tile.x, pixmap.getHeight() - 1 - tile.y, color);
|
||||
|
||||
Pixmaps.drawPixel(texture, tile.x, pixmap.getHeight() - 1 - tile.y, color);
|
||||
}
|
||||
|
||||
public void updateUnitArray(){
|
||||
float sz = baseSize * zoom;
|
||||
float dx = (Core.camera.position.x / tilesize);
|
||||
float dy = (Core.camera.position.y / tilesize);
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
|
||||
units.clear();
|
||||
Units.nearby((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize, units::add);
|
||||
}
|
||||
|
||||
private int colorFor(Tile tile){
|
||||
if(tile == null) return 0;
|
||||
tile = tile.link();
|
||||
int bc = tile.block().minimapColor(tile);
|
||||
if(bc != 0){
|
||||
return bc;
|
||||
}
|
||||
return Tmp.c1.set(MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam())).mul(tile.block().cacheLayer == CacheLayer.walls ? 1f - tile.rotation() / 4f : 1f).rgba();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
if(pixmap != null && texture != null){
|
||||
pixmap.dispose();
|
||||
texture.dispose();
|
||||
texture = null;
|
||||
pixmap = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void drawLabel(float x, float y, String text, Color color){
|
||||
BitmapFont font = Fonts.outline;
|
||||
GlyphLayout l = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
boolean ints = font.usesIntegerPositions();
|
||||
font.getData().setScale(1 / 1.5f / Scl.scl(1f));
|
||||
font.setUseIntegerPositions(false);
|
||||
|
||||
l.setText(font, text, color, 90f, Align.left, true);
|
||||
float yOffset = 20f;
|
||||
float margin = 3f;
|
||||
|
||||
Draw.color(0f, 0f, 0f, 0.2f);
|
||||
Fill.rect(x, y + yOffset - l.height/2f, l.width + margin, l.height + margin);
|
||||
Draw.color();
|
||||
font.setColor(color);
|
||||
font.draw(text, x - l.width/2f, y + yOffset, 90f, Align.left, true);
|
||||
font.setUseIntegerPositions(ints);
|
||||
|
||||
font.getData().setScale(1f);
|
||||
|
||||
Pools.free(l);
|
||||
}
|
||||
}
|
||||
61
core/src/mindustry/graphics/MultiPacker.java
Normal file
61
core/src/mindustry/graphics/MultiPacker.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Pixmap.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.util.*;
|
||||
|
||||
public class MultiPacker implements Disposable{
|
||||
private PixmapPacker[] packers = new PixmapPacker[PageType.all.length];
|
||||
|
||||
public MultiPacker(){
|
||||
for(int i = 0; i < packers.length; i++){
|
||||
int pageSize = 2048;
|
||||
packers[i] = new PixmapPacker(pageSize, pageSize, Format.RGBA8888, 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has(PageType type, String name){
|
||||
return packers[type.ordinal()].getRect(name) != null;
|
||||
}
|
||||
|
||||
public void add(PageType type, String name, PixmapRegion region){
|
||||
packers[type.ordinal()].pack(name, region);
|
||||
}
|
||||
|
||||
public void add(PageType type, String name, Pixmap pix){
|
||||
packers[type.ordinal()].pack(name, pix);
|
||||
}
|
||||
|
||||
public TextureAtlas flush(TextureFilter filter, TextureAtlas atlas){
|
||||
for(PixmapPacker p : packers){
|
||||
p.updateTextureAtlas(atlas, filter, filter, false, false);
|
||||
}
|
||||
return atlas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
for(PixmapPacker packer : packers){
|
||||
packer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//There are several pages for sprites.
|
||||
//main page (sprites.png) - all sprites for units, weapons, placeable blocks, effects, bullets, etc
|
||||
//environment page (sprites2.png) - all sprites for things in the environmental cache layer
|
||||
//editor page (sprites3.png) - all sprites needed for rendering in the editor, including block icons and a few minor sprites
|
||||
//zone page (sprites4.png) - zone previews
|
||||
//ui page (sprites5.png) - content icons, white icons and UI elements
|
||||
public enum PageType{
|
||||
main,
|
||||
environment,
|
||||
editor,
|
||||
zone,
|
||||
ui;
|
||||
|
||||
public static final PageType[] all = values();
|
||||
}
|
||||
}
|
||||
160
core/src/mindustry/graphics/OverlayRenderer.java
Normal file
160
core/src/mindustry/graphics/OverlayRenderer.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.type.Category;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.units.MechPad;
|
||||
import mindustry.world.meta.BlockFlag;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class OverlayRenderer{
|
||||
private static final float indicatorLength = 14f;
|
||||
private static final float spawnerMargin = tilesize*11f;
|
||||
private static final Rectangle rect = new Rectangle();
|
||||
private float buildFadeTime;
|
||||
|
||||
public void drawBottom(){
|
||||
InputHandler input = control.input;
|
||||
|
||||
if(player.isDead()) return;
|
||||
|
||||
input.drawBottom();
|
||||
}
|
||||
|
||||
public void drawTop(){
|
||||
|
||||
if(Core.settings.getBool("indicators")){
|
||||
for(Player player : playerGroup.all()){
|
||||
if(Vars.player != player && Vars.player.getTeam() == player.getTeam()){
|
||||
if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f)
|
||||
.setCenter(Core.camera.position.x, Core.camera.position.y).contains(player.x, player.y)){
|
||||
|
||||
Tmp.v1.set(player.x, player.y).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);
|
||||
|
||||
Lines.stroke(2f, player.getTeam().color);
|
||||
Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 4f);
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Units.all(unit -> {
|
||||
if(unit != player && unit.getTeam() != player.getTeam() && !rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f).setCenter(Core.camera.position.x, Core.camera.position.y).contains(unit.x, unit.y)){
|
||||
Tmp.v1.set(unit.x, unit.y).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);
|
||||
|
||||
Lines.stroke(1f, unit.getTeam().color);
|
||||
Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 3f);
|
||||
Draw.reset();
|
||||
}
|
||||
});
|
||||
|
||||
if(ui.hudfrag.blockfrag.currentCategory == Category.upgrade){
|
||||
for(Tile mechpad : indexer.getAllied(player.getTeam(), BlockFlag.mechPad)){
|
||||
if(!(mechpad.block() instanceof MechPad)) continue;
|
||||
if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f)
|
||||
.setCenter(Core.camera.position.x, Core.camera.position.y).contains(mechpad.x, mechpad.y)){
|
||||
|
||||
Tmp.v1.set(mechpad.drawx(), mechpad.drawy()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);
|
||||
|
||||
Lines.stroke(2f, ((MechPad) mechpad.block()).mech.engineColor);
|
||||
Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 0.5f);
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(player.isDead()) return; //dead players don't draw
|
||||
|
||||
InputHandler input = control.input;
|
||||
|
||||
//draw config selected block
|
||||
if(input.frag.config.isShown()){
|
||||
Tile tile = input.frag.config.getSelectedTile();
|
||||
tile.block().drawConfigure(tile);
|
||||
}
|
||||
|
||||
input.drawTop();
|
||||
|
||||
buildFadeTime = Mathf.lerpDelta(buildFadeTime, input.isPlacing() ? 1f : 0f, 0.06f);
|
||||
|
||||
Draw.reset();
|
||||
Lines.stroke(buildFadeTime * 2f);
|
||||
|
||||
if(buildFadeTime > 0.005f){
|
||||
for(Team enemy : state.teams.enemiesOf(player.getTeam())){
|
||||
for(Tile core : state.teams.get(enemy).cores){
|
||||
float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy());
|
||||
if(dst < state.rules.enemyCoreBuildRadius * 1.5f){
|
||||
Draw.color(Color.darkGray);
|
||||
Lines.circle(core.drawx(), core.drawy() - 2, state.rules.enemyCoreBuildRadius);
|
||||
Draw.color(Pal.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f));
|
||||
Lines.circle(core.drawx(), core.drawy(), state.rules.enemyCoreBuildRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Lines.stroke(2f);
|
||||
Draw.color(Color.gray, Color.lightGray, Mathf.absin(Time.time(), 8f, 1f));
|
||||
|
||||
for(Tile tile : spawner.getGroundSpawns()){
|
||||
if(tile.withinDst(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){
|
||||
Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin));
|
||||
Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
|
||||
//draw selected block
|
||||
if(input.block == null && !Core.scene.hasMouse()){
|
||||
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||
Tile tile = world.ltileWorld(vec.x, vec.y);
|
||||
|
||||
if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){
|
||||
tile.block().drawSelect(tile);
|
||||
|
||||
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate){
|
||||
control.input.drawArrow(tile.block(), tile.x, tile.y, tile.rotation(), true);
|
||||
Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f));
|
||||
Fill.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f);
|
||||
Draw.color();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//draw selection overlay when dropping item
|
||||
if(input.isDroppingItem()){
|
||||
Vector2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||
float size = 8;
|
||||
Draw.rect(player.item().item.icon(Cicon.medium), v.x, v.y, size, size);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time(), 5f, 1f));
|
||||
Draw.reset();
|
||||
|
||||
Tile tile = world.ltileWorld(v.x, v.y);
|
||||
if(tile != null && tile.interactable(player.getTeam()) && tile.block().acceptStack(player.item().item, player.item().amount, tile, player) > 0){
|
||||
Lines.stroke(3f, Pal.gray);
|
||||
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 3 + Mathf.absin(Time.time(), 5f, 1f));
|
||||
Lines.stroke(1f, Pal.place);
|
||||
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 2 + Mathf.absin(Time.time(), 5f, 1f));
|
||||
Draw.reset();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
87
core/src/mindustry/graphics/Pal.java
Normal file
87
core/src/mindustry/graphics/Pal.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.graphics.Color;
|
||||
|
||||
public class Pal{
|
||||
public static final Color
|
||||
|
||||
items = Color.valueOf("2ea756"),
|
||||
command = Color.valueOf("eab678"),
|
||||
|
||||
bulletYellow = Color.valueOf("ffeec9"),
|
||||
bulletYellowBack = Color.valueOf("f9c87a"),
|
||||
|
||||
darkMetal = Color.valueOf("6e7080"),
|
||||
|
||||
missileYellow = Color.valueOf("ffd2ae"),
|
||||
missileYellowBack = Color.valueOf("e58956"),
|
||||
|
||||
meltdownHit = Color.valueOf("ffb98b"),
|
||||
|
||||
plastaniumBack = Color.valueOf("d8d97f"),
|
||||
plastaniumFront = Color.valueOf("fffac6"),
|
||||
|
||||
lightFlame = Color.valueOf("ffdd55"),
|
||||
darkFlame = Color.valueOf("db401c"),
|
||||
|
||||
power2 = Color.valueOf("ff9f6c"),
|
||||
|
||||
lightPyraFlame = Color.valueOf("ffb855"),
|
||||
darkPyraFlame = Color.valueOf("db661c"),
|
||||
|
||||
turretHeat = Color.valueOf("ab3400"),
|
||||
|
||||
lightOrange = Color.valueOf("f68021"),
|
||||
lightishOrange = Color.valueOf("f8ad42"),
|
||||
lighterOrange = Color.valueOf("f6e096"),
|
||||
|
||||
lightishGray = Color.valueOf("a2a2a2"),
|
||||
darkishGray = new Color(0.3f, 0.3f, 0.3f, 1f),
|
||||
darkerGray = new Color(0.2f, 0.2f, 0.2f, 1f),
|
||||
ammo = Color.valueOf("ff8947"),
|
||||
rubble = Color.valueOf("1c1817"),
|
||||
|
||||
boostTo = Color.valueOf("ffad4d"),
|
||||
boostFrom = Color.valueOf("ff7f57"),
|
||||
|
||||
lancerLaser = Color.valueOf("a9d8ff"),
|
||||
|
||||
stoneGray = Color.valueOf("8f8f8f"),
|
||||
engine = Color.valueOf("ffbb64"),
|
||||
|
||||
health = Color.valueOf("ff341c"),
|
||||
heal = Color.valueOf("98ffa9"),
|
||||
bar = Color.slate,
|
||||
accent = Color.valueOf("ffd37f"),
|
||||
stat = Color.valueOf("ffd37f"),
|
||||
gray = Color.valueOf("454545"),
|
||||
accentBack = Color.valueOf("d4816b"),
|
||||
place = Color.valueOf("6335f8"),
|
||||
remove = Color.valueOf("e55454"),
|
||||
noplace = Color.valueOf("ffa697"),
|
||||
removeBack = Color.valueOf("a73e3e"),
|
||||
placeRotate = accent,
|
||||
breakInvalid = Color.valueOf("d44b3d"),
|
||||
range = Color.valueOf("f4ba6e"),
|
||||
power = Color.valueOf("fbad67"),
|
||||
powerBar = Color.valueOf("ec7b4c"),
|
||||
powerLight = Color.valueOf("fbd367"),
|
||||
placing = accent,
|
||||
|
||||
unitFront = Color.valueOf("ffa665"),
|
||||
unitBack = Color.valueOf("d06b53"),
|
||||
|
||||
lightTrail = Color.valueOf("ffe2a9"),
|
||||
|
||||
surge = Color.valueOf("f3e979"),
|
||||
|
||||
plastanium = Color.valueOf("a1b46e"),
|
||||
|
||||
redSpark = Color.valueOf("fbb97f"),
|
||||
orangeSpark = Color.valueOf("d2b29c"),
|
||||
|
||||
redDust = Color.valueOf("ffa480"),
|
||||
redderDust = Color.valueOf("ff7b69"),
|
||||
|
||||
plasticSmoke = Color.valueOf("f1e479");
|
||||
}
|
||||
80
core/src/mindustry/graphics/Pixelator.java
Normal file
80
core/src/mindustry/graphics/Pixelator.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.Blending;
|
||||
import arc.graphics.Texture.TextureFilter;
|
||||
import arc.graphics.g2d.Draw;
|
||||
import arc.graphics.gl.FrameBuffer;
|
||||
import arc.util.Disposable;
|
||||
import mindustry.entities.type.Player;
|
||||
|
||||
import static arc.Core.camera;
|
||||
import static arc.Core.graphics;
|
||||
import static mindustry.Vars.playerGroup;
|
||||
import static mindustry.Vars.renderer;
|
||||
|
||||
public class Pixelator implements Disposable{
|
||||
private FrameBuffer buffer = new FrameBuffer(2, 2);
|
||||
|
||||
{
|
||||
buffer.getTexture().setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
|
||||
}
|
||||
|
||||
public void drawPixelate(){
|
||||
float pre = renderer.getScale();
|
||||
float scale = renderer.getScale();
|
||||
scale = (int)scale;
|
||||
renderer.setScale(scale);
|
||||
camera.width = (int)camera.width;
|
||||
camera.height = (int)camera.height;
|
||||
|
||||
boolean hadShields = Core.settings.getBool("animatedshields");
|
||||
boolean hadWater = Core.settings.getBool("animatedwater");
|
||||
Core.settings.put("animatedwater", false);
|
||||
Core.settings.put("animatedshields", false);
|
||||
graphics.clear(0f, 0f, 0f, 1f);
|
||||
|
||||
float px = Core.camera.position.x, py = Core.camera.position.y;
|
||||
Core.camera.position.set((int)px + ((int)(camera.width) % 2 == 0 ? 0 : 0.5f), (int)py + ((int)(camera.height) % 2 == 0 ? 0 : 0.5f));
|
||||
|
||||
int w = (int)(Core.camera.width * renderer.landScale());
|
||||
int h = (int)(Core.camera.height * renderer.landScale());
|
||||
|
||||
if(!graphics.isHidden() && (buffer.getWidth() != w || buffer.getHeight() != h)){
|
||||
buffer.resize(w, h);
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
buffer.begin();
|
||||
renderer.draw();
|
||||
|
||||
Draw.flush();
|
||||
buffer.end();
|
||||
|
||||
Draw.blend(Blending.disabled);
|
||||
Draw.rect(Draw.wrap(buffer.getTexture()), Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
Draw.blend();
|
||||
|
||||
playerGroup.draw(p -> !p.isDead(), Player::drawName);
|
||||
|
||||
Core.camera.position.set(px, py);
|
||||
Core.settings.put("animatedwater", hadWater);
|
||||
Core.settings.put("animatedshields", hadShields);
|
||||
renderer.setScale(pre);
|
||||
}
|
||||
|
||||
public void rebind(){
|
||||
if(enabled()){
|
||||
buffer.begin();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean enabled(){
|
||||
return Core.settings.getBool("pixelate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
buffer.dispose();
|
||||
}
|
||||
}
|
||||
173
core/src/mindustry/graphics/Shaders.java
Normal file
173
core/src/mindustry/graphics/Shaders.java
Normal file
@@ -0,0 +1,173 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.graphics.gl.Shader;
|
||||
import arc.scene.ui.layout.Scl;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.Time;
|
||||
|
||||
public class Shaders{
|
||||
public static Shadow shadow;
|
||||
public static BlockBuild blockbuild;
|
||||
public static @Nullable
|
||||
Shield shield;
|
||||
public static UnitBuild build;
|
||||
public static FogShader fog;
|
||||
public static MenuShader menu;
|
||||
public static LightShader light;
|
||||
public static SurfaceShader water, tar;
|
||||
|
||||
public static void init(){
|
||||
shadow = new Shadow();
|
||||
blockbuild = new BlockBuild();
|
||||
try{
|
||||
shield = new Shield();
|
||||
}catch(Throwable t){
|
||||
//don't load shield shader
|
||||
shield = null;
|
||||
t.printStackTrace();
|
||||
}
|
||||
build = new UnitBuild();
|
||||
fog = new FogShader();
|
||||
menu = new MenuShader();
|
||||
light = new LightShader();
|
||||
water = new SurfaceShader("water");
|
||||
tar = new SurfaceShader("tar");
|
||||
}
|
||||
|
||||
public static class LightShader extends LoadShader{
|
||||
public Color ambient = new Color(0.01f, 0.01f, 0.04f, 0.99f);
|
||||
|
||||
public LightShader(){
|
||||
super("light", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_ambient", ambient);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MenuShader extends LoadShader{
|
||||
float time = 0f;
|
||||
|
||||
public MenuShader(){
|
||||
super("menu", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
time = time % 158;
|
||||
|
||||
setUniformf("u_resolution", Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
setUniformi("u_time", (int)(time += Core.graphics.getDeltaTime() * 60f));
|
||||
setUniformf("u_uv", Core.atlas.white().getU(), Core.atlas.white().getV());
|
||||
setUniformf("u_scl", Scl.scl(1f));
|
||||
setUniformf("u_uv2", Core.atlas.white().getU2(), Core.atlas.white().getV2());
|
||||
}
|
||||
}
|
||||
|
||||
public static class FogShader extends LoadShader{
|
||||
public FogShader(){
|
||||
super("fog", "default");
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnitBuild extends LoadShader{
|
||||
public float progress, time;
|
||||
public Color color = new Color();
|
||||
public TextureRegion region;
|
||||
|
||||
public UnitBuild(){
|
||||
super("unitbuild", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_time", time);
|
||||
setUniformf("u_color", color);
|
||||
setUniformf("u_progress", progress);
|
||||
setUniformf("u_uv", region.getU(), region.getV());
|
||||
setUniformf("u_uv2", region.getU2(), region.getV2());
|
||||
setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Shadow extends LoadShader{
|
||||
public Color color = new Color();
|
||||
public TextureRegion region = new TextureRegion();
|
||||
public float scl;
|
||||
|
||||
public Shadow(){
|
||||
super("shadow", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_color", color);
|
||||
setUniformf("u_scl", scl);
|
||||
setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockBuild extends LoadShader{
|
||||
public Color color = new Color();
|
||||
public float progress;
|
||||
public TextureRegion region = new TextureRegion();
|
||||
|
||||
public BlockBuild(){
|
||||
super("blockbuild", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_progress", progress);
|
||||
setUniformf("u_color", color);
|
||||
setUniformf("u_uv", region.getU(), region.getV());
|
||||
setUniformf("u_uv2", region.getU2(), region.getV2());
|
||||
setUniformf("u_time", Time.time());
|
||||
setUniformf("u_texsize", region.getTexture().getWidth(), region.getTexture().getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Shield extends LoadShader{
|
||||
|
||||
public Shield(){
|
||||
super("shield", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_dp", Scl.scl(1f));
|
||||
setUniformf("u_time", Time.time() / Scl.scl(1f));
|
||||
setUniformf("u_offset",
|
||||
Core.camera.position.x - Core.camera.width / 2,
|
||||
Core.camera.position.y - Core.camera.height / 2);
|
||||
setUniformf("u_texsize", Core.camera.width,
|
||||
Core.camera.height);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SurfaceShader extends LoadShader{
|
||||
|
||||
public SurfaceShader(String frag){
|
||||
super(frag, "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("camerapos", Core.camera.position.x - Core.camera.width / 2, Core.camera.position.y - Core.camera.height / 2);
|
||||
setUniformf("screensize", Core.camera.width, Core.camera.height);
|
||||
setUniformf("time", Time.time());
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoadShader extends Shader{
|
||||
public LoadShader(String frag, String vert){
|
||||
super(Core.files.internal("shaders/" + vert + ".vertex.glsl"), Core.files.internal("shaders/" + frag + ".fragment.glsl"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user