248 lines
7.9 KiB
Java
248 lines
7.9 KiB
Java
package mindustry.graphics.g3d;
|
|
|
|
import arc.*;
|
|
import arc.graphics.*;
|
|
import arc.graphics.g2d.*;
|
|
import arc.graphics.g3d.*;
|
|
import arc.graphics.gl.*;
|
|
import arc.math.*;
|
|
import arc.math.geom.*;
|
|
import arc.util.*;
|
|
import mindustry.game.EventType.*;
|
|
import mindustry.graphics.*;
|
|
import mindustry.type.*;
|
|
|
|
public class PlanetRenderer implements Disposable{
|
|
public static final float outlineRad = 1.17f, camLength = 4f;
|
|
public static final Color
|
|
outlineColor = Pal.accent.cpy().a(1f),
|
|
hoverColor = Pal.accent.cpy().a(0.5f),
|
|
borderColor = Pal.accent.cpy().a(0.3f),
|
|
shadowColor = new Color(0, 0, 0, 0.7f);
|
|
|
|
/** Camera used for rendering. */
|
|
public final Camera3D cam = new Camera3D();
|
|
/** Raw vertex batch. */
|
|
public final VertexBatch3D batch = new VertexBatch3D(20000, false, true, 0);
|
|
|
|
public final PlaneBatch3D projector = new PlaneBatch3D();
|
|
public final Mat3D mat = new Mat3D();
|
|
public final FrameBuffer buffer = new FrameBuffer(2, 2, true);
|
|
|
|
public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{
|
|
setThreshold(0.8f);
|
|
blurPasses = 6;
|
|
}};
|
|
public final Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f);
|
|
|
|
//seed: 8kmfuix03fw
|
|
public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/"));
|
|
|
|
public PlanetRenderer(){
|
|
projector.setScaling(1f / 150f);
|
|
cam.fov = 60f;
|
|
cam.far = 150f;
|
|
cam.near = 0.01f;
|
|
}
|
|
|
|
/** Render the entire planet scene to the screen. */
|
|
public void render(PlanetParams params){
|
|
Draw.flush();
|
|
Gl.clear(Gl.depthBufferBit);
|
|
Gl.enable(Gl.depthTest);
|
|
Gl.depthMask(true);
|
|
|
|
Gl.enable(Gl.cullFace);
|
|
Gl.cullFace(Gl.back);
|
|
|
|
int w = params.viewW <= 0 ? Core.graphics.getWidth() : params.viewW;
|
|
int h = params.viewH <= 0 ? Core.graphics.getHeight() : params.viewH;
|
|
|
|
bloom.blending = !params.drawSkybox;
|
|
|
|
//lock to up vector so it doesn't get confusing
|
|
cam.up.set(Vec3.Y);
|
|
|
|
cam.resize(w, h);
|
|
params.camPos.setLength((params.planet.radius + params.planet.camRadius) * camLength + (params.zoom-1f) * (params.planet.radius + params.planet.camRadius) * 2);
|
|
|
|
if(params.otherCamPos != null){
|
|
cam.position.set(params.otherCamPos).lerp(params.planet.position, params.otherCamAlpha).add(params.camPos);
|
|
}else{
|
|
cam.position.set(params.planet.position).add(params.camPos);
|
|
}
|
|
//cam.up.set(params.camUp); //TODO broken
|
|
cam.lookAt(params.planet.position);
|
|
cam.update();
|
|
//write back once it changes.
|
|
params.camUp.set(cam.up);
|
|
params.camDir.set(cam.direction);
|
|
|
|
projector.proj(cam.combined);
|
|
batch.proj(cam.combined);
|
|
|
|
Events.fire(Trigger.universeDrawBegin);
|
|
|
|
//begin bloom
|
|
bloom.resize(w, h);
|
|
bloom.capture();
|
|
|
|
if(params.drawSkybox){
|
|
//render skybox at 0,0,0
|
|
Vec3 lastPos = Tmp.v31.set(cam.position);
|
|
cam.position.setZero();
|
|
cam.update();
|
|
|
|
Gl.depthMask(false);
|
|
|
|
skybox.render(cam.combined);
|
|
|
|
Gl.depthMask(true);
|
|
|
|
cam.position.set(lastPos);
|
|
cam.update();
|
|
}
|
|
|
|
Events.fire(Trigger.universeDraw);
|
|
|
|
renderPlanet(params.solarSystem, params);
|
|
renderTransparent(params.solarSystem, params);
|
|
|
|
bloom.render();
|
|
|
|
Events.fire(Trigger.universeDrawEnd);
|
|
|
|
Gl.enable(Gl.blend);
|
|
|
|
if(params.renderer != null){
|
|
params.renderer.renderProjections(params.planet);
|
|
}
|
|
|
|
Gl.disable(Gl.cullFace);
|
|
Gl.disable(Gl.depthTest);
|
|
|
|
cam.update();
|
|
}
|
|
|
|
public void renderPlanet(Planet planet, PlanetParams params){
|
|
if(!planet.visible()) return;
|
|
|
|
cam.update();
|
|
|
|
if(cam.frustum.containsSphere(planet.position, planet.clipRadius)){
|
|
//render planet at offsetted position in the world
|
|
planet.draw(params, cam.combined, planet.getTransform(mat));
|
|
}
|
|
|
|
for(Planet child : planet.children){
|
|
renderPlanet(child, params);
|
|
}
|
|
}
|
|
|
|
public void renderTransparent(Planet planet, PlanetParams params){
|
|
if(!planet.visible()) return;
|
|
|
|
planet.drawClouds(params, cam.combined, planet.getTransform(mat));
|
|
|
|
if(planet.hasGrid() && planet == params.planet && params.drawUi){
|
|
renderSectors(planet, params);
|
|
}
|
|
|
|
if(cam.frustum.containsSphere(planet.position, planet.clipRadius) && planet.parent != null && planet.hasAtmosphere && (params.alwaysDrawAtmosphere || Core.settings.getBool("atmosphere"))){
|
|
planet.drawAtmosphere(atmosphere, cam);
|
|
}
|
|
|
|
for(Planet child : planet.children){
|
|
renderTransparent(child, params);
|
|
}
|
|
|
|
batch.proj(cam.combined);
|
|
|
|
if(params.drawUi){
|
|
renderOrbit(planet, params);
|
|
}
|
|
}
|
|
|
|
public void renderOrbit(Planet planet, PlanetParams params){
|
|
if(planet.parent == null || !planet.visible() || params.uiAlpha <= 0.02f || !planet.drawOrbit) return;
|
|
|
|
Vec3 center = planet.parent.position;
|
|
float radius = planet.orbitRadius;
|
|
int points = (int)(radius * 10);
|
|
Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray.write(Tmp.c1).a(params.uiAlpha)));
|
|
batch.flush(Gl.lineLoop);
|
|
}
|
|
|
|
public void renderSectors(Planet planet, PlanetParams params){
|
|
if(params.uiAlpha <= 0.02f) return;
|
|
planet.renderSectors(batch, cam, params);
|
|
}
|
|
|
|
public void drawArc(Planet planet, Vec3 a, Vec3 b){
|
|
drawArc(planet, a, b, Pal.accent, Color.clear, 1f);
|
|
}
|
|
|
|
public void drawArc(Planet planet, Vec3 a, Vec3 b, Color from, Color to, float length){
|
|
drawArc(planet, a, b, from, to, length, 80f, 25);
|
|
}
|
|
|
|
public void drawArc(Planet planet, Vec3 a, Vec3 b, Color from, Color to, float length, float timeScale, int pointCount){
|
|
planet.drawArc(batch, a, b, from, to, length, timeScale, pointCount);
|
|
}
|
|
|
|
public void drawBorders(Sector sector, Color base, float alpha){
|
|
sector.planet.drawBorders(batch, sector, base, alpha);
|
|
if(batch.getNumVertices() >= batch.getMaxVertices() - 6 * 6){
|
|
batch.flush(Gl.triangles);
|
|
}
|
|
}
|
|
|
|
public void drawPlane(Sector sector, Runnable run){
|
|
Draw.batch(projector, () -> {
|
|
setPlane(sector);
|
|
run.run();
|
|
});
|
|
}
|
|
|
|
public void setPlane(Sector sector){
|
|
float rotation = -sector.planet.getRotation();
|
|
float length = 0.01f;
|
|
|
|
projector.setPlane(
|
|
//origin on sector position
|
|
Tmp.v33.set(sector.tile.v).setLength((outlineRad + length) * sector.planet.radius).rotate(Vec3.Y, rotation).add(sector.planet.position),
|
|
//face up
|
|
sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v, sector.planet.radius).rotate(Vec3.Y, rotation).nor(),
|
|
//right vector
|
|
Tmp.v31.set(Tmp.v32).rotate(Vec3.Y, -rotation).add(sector.tile.v).rotate(sector.tile.v, 90).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor()
|
|
);
|
|
}
|
|
|
|
public void fill(Sector sector, Color color, float offset){
|
|
sector.planet.fill(batch, sector, color, offset);
|
|
}
|
|
|
|
public void drawSelection(Sector sector, float alpha){
|
|
drawSelection(sector, Tmp.c1.set(Pal.accent).a(alpha), 0.04f, 0.001f);
|
|
}
|
|
|
|
public void drawSelection(Sector sector, Color color, float stroke, float length){
|
|
sector.planet.drawSelection(batch, sector, color, stroke, length);
|
|
}
|
|
|
|
@Override
|
|
public void dispose(){
|
|
skybox.dispose();
|
|
batch.dispose();
|
|
projector.dispose();
|
|
atmosphere.dispose();
|
|
buffer.dispose();
|
|
bloom.dispose();
|
|
}
|
|
|
|
public interface PlanetInterfaceRenderer{
|
|
void renderSectors(Planet planet);
|
|
void renderProjections(Planet planet);
|
|
}
|
|
}
|