Skip to content

Instantly share code, notes, and snippets.

@WinterAlexander
Created February 24, 2021 21:55
Show Gist options
  • Select an option

  • Save WinterAlexander/4e9984bef3c5b54888b6c23be27a03a9 to your computer and use it in GitHub Desktop.

Select an option

Save WinterAlexander/4e9984bef3c5b54888b6c23be27a03a9 to your computer and use it in GitHub Desktop.
package net.jumpai.world.objects.background;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import net.jumpai.render.JumpaiAssets;
import net.jumpai.render.RenderScreen;
import net.jumpai.render.assetprovider.texture.background.BackgroundProvider;
import net.jumpai.world.World;
import net.jumpai.world.biome.BiomeMaskGenerator;
import net.jumpai.world.biome.BiomeType;
import net.jumpai.world.camera.WorldCamera;
import net.jumpai.world.component.render.InitRenderer;
import net.jumpai.world.component.render.RenderPriority;
import net.jumpai.world.component.render.WorldRenderPriority;
import static com.badlogic.gdx.graphics.GL20.GL_ONE;
import static com.badlogic.gdx.graphics.GL20.GL_ONE_MINUS_SRC_ALPHA;
import static com.badlogic.gdx.graphics.GL20.GL_SRC_ALPHA;
import static com.badlogic.gdx.graphics.GL20.GL_TEXTURE0;
import static net.jumpai.util.Validation.ensureNotNull;
import static net.jumpai.util.math.MathUtil.negMod;
import static net.jumpai.world.JumpaiWorld.WORLD_WIDTH;
/**
* Renderer for background in world
* <p>
* Created on 2018-03-25.
*
* @author Alexander Winter
*/
public class BackgroundRenderer extends InitRenderer
{
private static final int BG_WIDTH = 4416;
private static final int BG_HEIGHT = 2484;
private static final int BIOME_MASK_UNIT = 5;
protected final World world;
private BackgroundType backgroundType;
private final ObjectMap<BiomeType, Texture> backgrounds = new ObjectMap<>();
private final ObjectMap<BiomeType, TextureRegion> staticBackgrounds = new ObjectMap<>();
private final ObjectMap<BiomeType, Array<TextureRegion>> layers = new ObjectMap<>();
private final ObjectMap<BiomeType, FrameBuffer> fbos = new ObjectMap<>();
private boolean changedBackground;
private ShaderProgram shader;
private Texture white;
private final Vector2 tmpSize = new Vector2();
private int lastWidth = -1;
private OrthographicCamera cam;
public BackgroundRenderer(World world, BackgroundType type)
{
ensureNotNull(world, "world");
ensureNotNull(type, "type");
this.world = world;
this.backgroundType = type;
changedBackground = true;
}
@Override
protected void init(RenderScreen screen)
{
shader = JumpaiAssets.BACKGROUND_BIOME_SHADER.resolve(screen.getAssets());
white = JumpaiAssets.WHITE_PIXEL.resolve(screen.getAssets());
}
@Override
public void prepare(RenderScreen screen)
{
super.prepare(screen);
boolean firstTime = changedBackground;
if(changedBackground)
{
for(BiomeType biome : BiomeType.values())
staticBackgrounds.put(biome, JumpaiAssets.MOUNTAINS_BACKGROUND
.get(biome)
.getStaticLayer()
.resolve(screen.getAssets()));
for(BiomeType biome : BiomeType.values())
{
BackgroundLayerDisposition disposition = backgroundType.getDisposition(biome);
BackgroundProvider provider = disposition.getBackgroundProvider();
Array<TextureRegion> layerArr = new Array<>(disposition.getAssetCount());
if(disposition.hasForeground())
layerArr.add(provider.getForeground().resolve(screen.getAssets()));
for(int i = 0; i < disposition.getMidLayerCount(); i++)
layerArr.add(provider.getMidLayers()[i].resolve(screen.getAssets()));
layerArr.add(provider.getBackground().resolve(screen.getAssets()));
if(disposition.hasClouds())
layerArr.add(provider.getClouds().resolve(screen.getAssets()));
layers.put(biome, layerArr);
}
changedBackground = false;
}
if(screen.useParallax() && firstTime)
{
if(fbos.size == 0 || lastWidth != (int)screen.getScreenSize().x)
{
lastWidth = (int)screen.getScreenSize().x;
for(FrameBuffer fbo : fbos.values())
fbo.dispose();
fbos.clear();
for(BiomeType biomeType : BiomeType.values())
fbos.put(biomeType, new FrameBuffer(Format.RGBA8888, (int)screen.getScreenSize().x, (int)screen.getScreenSize().y, false));
}
if(cam == null)
{
cam = new OrthographicCamera();
cam.setToOrtho(true, BG_WIDTH, BG_HEIGHT);
cam.position.set(BG_WIDTH, BG_HEIGHT, 0f).scl(0.5f);
cam.update();
}
screen.getBatch().setProjectionMatrix(cam.combined);
for(BiomeType biome : BiomeType.values())
{
FrameBuffer fbo = fbos.get(biome);
BackgroundLayerDisposition dispo = backgroundType.getDisposition(biome);
Array<TextureRegion> layerArr = layers.get(biome);
float scale = (float)BG_WIDTH / staticBackgrounds.get(biome).getRegionWidth();
fbo.begin();
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
screen.getBatch().begin();
screen.getBatch().enableBlending();
screen.getBatch().setBlendFunctionSeparate(GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_ONE,
GL_ONE_MINUS_SRC_ALPHA);
screen.getBatch().draw(white,
0f,
0f,
BG_WIDTH,
BG_HEIGHT);
screen.getBatch().flush();
screen.getBatch().draw(white,
0f,
0f,
BG_WIDTH,
BG_HEIGHT);
if(dispo.hasClouds())
{
int position = (int)(world.getFrameId() % BG_WIDTH);
TextureRegion clouds = layerArr.get(dispo.getCloudsIndex());
screen.getBatch().draw(clouds, position, BG_HEIGHT - clouds.getRegionHeight() * scale, BG_WIDTH, clouds.getRegionHeight() * scale);
screen.getBatch().draw(clouds, position - BG_WIDTH, BG_HEIGHT - clouds.getRegionHeight() * scale, BG_WIDTH, clouds.getRegionHeight() * scale);
}
TextureRegion bgRegion = layerArr.get(dispo.getBackgroundIndex());
screen.getBatch().draw(bgRegion,
0f,
BG_HEIGHT - bgRegion.getRegionHeight() * scale,
BG_WIDTH,
bgRegion.getRegionHeight() * scale);
int dragIndex = dispo.hasForeground() ? 1 : 0;
float pos = -world.getCamera().getActualPosition().x / WORLD_WIDTH;
for(int midLayer = dispo.getMidLayerCount() - 1; midLayer >= 0; midLayer--)
{
float layerPos = pos * dispo.getLayerDrag(dragIndex + midLayer);
int position = (int)(negMod(layerPos, 1f) * BG_WIDTH);
boolean flip = negMod(layerPos, 2f) < 1f;
TextureRegion region = layerArr.get(dispo.getMidStartIndex() + midLayer);
screen.getBatch().draw(region,
position, 0,
BG_WIDTH / 2, BG_HEIGHT / 2,
BG_WIDTH, region.getRegionHeight() * scale,
flip ? -1f : 1f, 1f,
0f);
screen.getBatch().draw(layerArr.get(dispo.getMidStartIndex() + midLayer),
position - BG_WIDTH, 0,
BG_WIDTH / 2, BG_HEIGHT / 2,
BG_WIDTH, region.getRegionHeight() * scale,
flip ? 1f : -1f, 1f,
0f);
}
if(dispo.hasForeground())
{
float layerPos = pos * dispo.getLayerDrag(0);
int position = (int)(negMod(layerPos, 1f) * BG_WIDTH);
boolean flip = negMod(layerPos, 2f) < 1f;
TextureRegion region = layerArr.get(dispo.getForegroundIndex());
screen.getBatch().draw(region,
position, 0,
BG_WIDTH / 2, BG_HEIGHT / 2,
BG_WIDTH, region.getRegionHeight() * scale,
flip ? -1f : 1f, 1f,
0f);
screen.getBatch().draw(layerArr.get(dispo.getForegroundIndex()),
position - BG_WIDTH, 0,
BG_WIDTH / 2, BG_HEIGHT / 2,
BG_WIDTH, region.getRegionHeight() * scale,
flip ? 1f : -1f, 1f,
0f);
}
screen.getBatch().end();
fbo.end();
screen.getBatch().setBlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
backgrounds.put(biome, fbo.getColorBufferTexture());
}
}
}
@Override
public void render(RenderScreen screen)
{
WorldCamera cam = world.getCamera();
BiomeMaskGenerator gen = world.getBiomeMaskGenerator();
screen.getBatch().setShader(shader);
shader.setUniformi("u_biomeMask", BIOME_MASK_UNIT);
shader.setUniformf("u_offset", gen.getMaskOffset());
shader.setUniformf("u_scale", gen.getMaskScale());
int dst = screen.getBatch().getBlendDstFunc();
int src = screen.getBatch().getBlendSrcFunc();
screen.getBatch().setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
for(BiomeType biome : BiomeType.values())
{
gen.getMask(biome).bind(BIOME_MASK_UNIT);
Gdx.gl.glActiveTexture(GL_TEXTURE0);
Vector2 pos = cam.getLogicalPosition();
tmpSize.set(cam.getViewSize()).scl(cam.getLogicalZoom());
if(screen.useParallax())
screen.getBatch().draw(backgrounds.get(biome),
pos.x - tmpSize.x / 2,
pos.y - tmpSize.y / 2,
tmpSize.x,
tmpSize.y);
else
screen.getBatch().draw(staticBackgrounds.get(biome),
pos.x - tmpSize.x / 2,
pos.y - tmpSize.y / 2,
tmpSize.x,
tmpSize.y);
screen.getBatch().flush();
}
screen.getBatch().setShader(null);
screen.getBatch().setBlendFunction(src, dst);
}
@Override
public RenderPriority getRenderPriority()
{
return WorldRenderPriority.BACKGROUND;
}
public BackgroundType getBackgroundType()
{
return backgroundType;
}
public void setBackgroundType(BackgroundType backgroundType)
{
if(this.backgroundType == backgroundType)
return;
this.backgroundType = backgroundType;
changedBackground = true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment