package net.fourbytes.shadow.utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectMap;
import net.fourbytes.shadow.*;
public class ChunkRenderer {
public OrthographicCamera cam = new OrthographicCamera();
public int width = 1024;
public int height = 1024;
public int ppb = 16;
public FrameBuffer fbo;
public Texture tex;
protected Array<Chunk> render = new Array<Chunk>(Chunk.class);
protected Array<TextureRegion> regions = new Array<TextureRegion>(TextureRegion.class);
protected ObjectMap<Chunk, TextureRegion> mapChunkRegion = new ObjectMap<Chunk, TextureRegion>();
protected ObjectMap<TextureRegion, Chunk> mapRegionChunk = new ObjectMap<TextureRegion, Chunk>();
protected ObjectIntMap<Chunk> mapChunkId = new ObjectIntMap<Chunk>();
public ChunkRenderer() {
setup();
}
public void setup() {
setup(width, height);
}
public void setup(int width, int height) {
this.width = width;
this.height = height;
if (fbo != null) {
fbo.dispose();
}
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, width, height, false);
tex = fbo.getColorBufferTexture();
tex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
}
public void render(Layer l) {
Shadow.spriteBatch.end();
render.clear();
for (int i = 0; i < l.inView.size; i++) {
GameObject go = l.inView.items[i];
if (go instanceof Block && !((Block)go).dynamic) {
Chunk c = go.chunk;
if (!render.contains(c, true)) {
preRender(c);
if (Camera.shadows) {
renderShadow(c);
}
render.add(c);
}
}
}
for (int i = 0; i < render.size; i++) {
Chunk c = render.items[i];
render(c);
}
Shadow.spriteBatch.begin();
}
public void preRender(Chunk c) {
TextureRegion reg = mapChunkRegion.get(c);
if (reg == null) {
int x = 1;
int y = 0;
int w = c.size * ppb;
int h = c.size * ppb;
TextureRegion regLast = regions.size > 0 ? regions.peek() : null;
if (regLast != null) {
x += regLast.getRegionX() / w;
y += regLast.getRegionY() / h;
}
if (x >= width / w) {
x = 0;
y++;
}
if (y >= height / h) {
y = 0;
TextureRegion regFirst = regions.size > 0 ? regions.first() : null;
Chunk cFirst = mapRegionChunk.get(regFirst);
mapRegionChunk.remove(regFirst);
mapChunkRegion.remove(cFirst);
mapChunkId.remove(cFirst, 0);
reg = regFirst;
}
if (reg == null) {
reg = new TextureRegion(tex, x * w, y * h, w, h);
}
mapChunkRegion.put(c, reg);
mapRegionChunk.put(reg, c);
regions.add(reg);
}
if (c.rerender) {
int x = reg.getRegionX();
int y = reg.getRegionY();
int w = reg.getRegionWidth();
int h = reg.getRegionHeight();
Shadow.spriteBatch.flush();
fbo.begin();
cam.viewportWidth = c.size * (float) width / (float) w;
cam.viewportHeight = c.size * (float) height / (float) h;
cam.position.set(c.x * c.size + cam.viewportWidth / 2f - c.size * x / w,
c.y * c.size + cam.viewportHeight / 2f - c.size * y / h,
0f);
cam.update();
Shadow.spriteBatch.setProjectionMatrix(cam.combined);
Gdx.gl.glScissor(x, y, w, h);
Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST);
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
for (int i = 0; i < c.blocks.size; i++) {
Block b = c.blocks.items[i];
if (!b.dynamic) {
Shadow.spriteBatch.begin();
b.preRender();
b.render();
Shadow.spriteBatch.end();
}
}
Shadow.spriteBatch.flush();
fbo.end();
Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST);
Shadow.spriteBatch.setProjectionMatrix(Shadow.cam.cam.combined);
Shadow.spriteCache.beginCache();
Shadow.spriteCache.add(reg, c.x * c.size, c.y * c.size + c.size, c.size, -c.size);
mapChunkId.put(c, Shadow.spriteCache.endCache());
c.rerender = false;
}
}
public void renderShadow(Chunk c) {
int id = mapChunkId.get(c, 0);
Shadow.cam.cam.translate(0.125f, 0.125f);
Shadow.cam.cam.update();
Shadow.spriteCache.setProjectionMatrix(Shadow.cam.cam.combined);
Shadow.spriteCache.begin();
Gdx.gl.glEnable(GL20.GL_BLEND);
ShaderHelper.set("s_colorOverride", 0f, 0f, 0f, 0.5f);
Shadow.spriteCache.draw(id);
ShaderHelper.set("s_colorOverride", 1f, 1f, 1f, 1f);
Shadow.spriteCache.end();
Shadow.cam.cam.translate(-0.125f, -0.125f);
Shadow.cam.cam.update();
}
public void render(Chunk c) {
int id = mapChunkId.get(c, 0);
Shadow.spriteCache.setProjectionMatrix(Shadow.cam.cam.combined);
Shadow.spriteCache.begin();
Gdx.gl.glEnable(GL20.GL_BLEND);
Shadow.spriteCache.draw(id);
Shadow.spriteCache.end();
}
}