Add cloud rendering
This commit is contained in:
+11
@@ -1,8 +1,10 @@
|
||||
package com.seibel.distanthorizons.api.interfaces.render;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@@ -27,6 +29,11 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
|
||||
/** @return if active this group will render. */
|
||||
boolean isActive();
|
||||
|
||||
/** Sets whether this group should render with Screen Space Ambient Occlusioning. */
|
||||
void setSsaoEnabled(boolean ssaoEnabled);
|
||||
/** @return if active this group will render with Screen Space Ambient Occlusioning. */
|
||||
boolean isSsaoEnabled();
|
||||
|
||||
/** Sets where this group will render in the level. */
|
||||
void setOriginBlockPos(DhApiVec3f pos);
|
||||
/** @return the block position in the level that all {@see DhApiRenderableBox} will render relative to. */
|
||||
@@ -37,6 +44,7 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
|
||||
* This is a good place to change the origin or notify of any box changes.
|
||||
*/
|
||||
void setPreRenderFunc(Consumer<DhApiRenderParam> renderEventParam);
|
||||
void setPostRenderFunc(Consumer<DhApiRenderParam> renderEventParam); // TODO name?
|
||||
|
||||
/**
|
||||
* If a cube's color, position, or other property is changed this method
|
||||
@@ -55,4 +63,7 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
|
||||
void setBlockLight(int blockLight);
|
||||
int getBlockLight();
|
||||
|
||||
void setShading(DhApiRenderableBoxGroupShading shading);
|
||||
DhApiRenderableBoxGroupShading getShading();
|
||||
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.seibel.distanthorizons.api.objects.render;
|
||||
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @see IDhApiRenderableBoxGroup
|
||||
*
|
||||
* Shading values are multiplied against the color for each direction,
|
||||
* for example: <br>
|
||||
* A shading value of 1.0 indicates the color is unchanged. <br>
|
||||
* A shading value of 0.0 changes the color to black. <br>
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2024-7-7
|
||||
* @since API 3.0.0
|
||||
*/
|
||||
public class DhApiRenderableBoxGroupShading
|
||||
{
|
||||
/** negative X */
|
||||
public float north = 1.0f;
|
||||
/** positive X */
|
||||
public float south = 1.0f;
|
||||
|
||||
/** positive X */
|
||||
public float east = 1.0f;
|
||||
/** negative X */
|
||||
public float west = 1.0f;
|
||||
|
||||
/** positive Y */
|
||||
public float top = 1.0f;
|
||||
/** negative Y */
|
||||
public float bottom = 1.0f;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public static DhApiRenderableBoxGroupShading getDefaultShaded()
|
||||
{
|
||||
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
|
||||
shading.setDefaultShaded();
|
||||
return shading;
|
||||
}
|
||||
|
||||
public static DhApiRenderableBoxGroupShading getUnshaded()
|
||||
{
|
||||
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
|
||||
shading.setUnshaded();
|
||||
return shading;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
/**
|
||||
* Directions will have different brightness similar to Minecraft blocks. <br>
|
||||
* This is a good default for un-lit objects.
|
||||
*/
|
||||
public void setDefaultShaded()
|
||||
{
|
||||
this.north = 0.8f;
|
||||
this.south = 0.8f;
|
||||
this.east = 0.6f;
|
||||
this.west = 0.6f;
|
||||
this.top = 1.0f;
|
||||
this.bottom = 0.5f;
|
||||
}
|
||||
|
||||
/**
|
||||
* All directions render with the same brightness. <br>
|
||||
* This is best used for glowing objects like beacons.
|
||||
*/
|
||||
public void setUnshaded()
|
||||
{
|
||||
this.north = 1.0f;
|
||||
this.south = 1.0f;
|
||||
this.east = 1.0f;
|
||||
this.west = 1.0f;
|
||||
this.top = 1.0f;
|
||||
this.bottom = 1.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkModifiedEvent;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||
import com.seibel.distanthorizons.core.dataObjects.transformers.ChunkToLodBuilder;
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.DelayedFullDataSourceSaveCache;
|
||||
@@ -30,6 +32,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.render.renderer.generic.CloudRenderHandler;
|
||||
import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory;
|
||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||
@@ -72,6 +75,8 @@ public abstract class AbstractDhLevel implements IDhLevel
|
||||
|
||||
protected boolean beaconGroupBound = false;
|
||||
|
||||
protected CloudRenderHandler cloudRenderHandler;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
@@ -85,6 +90,8 @@ public abstract class AbstractDhLevel implements IDhLevel
|
||||
this.beaconBoxGroup = GenericRenderObjectFactory.INSTANCE.createAbsolutePositionedGroup(new ArrayList<>(0));
|
||||
this.beaconBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.beaconBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.beaconBoxGroup.setShading(DhApiRenderableBoxGroupShading.getUnshaded());
|
||||
this.beaconBoxGroup.setPreRenderFunc((renderEventParam) -> this.beaconBoxGroup.setActive(Config.Client.Advanced.Graphics.GenericRendering.enableBeaconRendering.get()));
|
||||
}
|
||||
|
||||
protected void createAndSetSupportingRepos(File databaseFile)
|
||||
@@ -221,12 +228,13 @@ public abstract class AbstractDhLevel implements IDhLevel
|
||||
|
||||
// should always be non-null, but just in case
|
||||
if (this.beaconBeamRepo != null
|
||||
&& genericObjectRenderer != null)
|
||||
&& genericObjectRenderer != null)
|
||||
{
|
||||
if (!this.beaconGroupBound)
|
||||
{
|
||||
this.beaconGroupBound = true;
|
||||
genericObjectRenderer.add(this.beaconBoxGroup);
|
||||
this.cloudRenderHandler = new CloudRenderHandler(this, genericObjectRenderer);
|
||||
}
|
||||
|
||||
|
||||
@@ -319,6 +327,7 @@ public abstract class AbstractDhLevel implements IDhLevel
|
||||
{
|
||||
this.beaconGroupBound = true;
|
||||
genericObjectRenderer.add(this.beaconBoxGroup);
|
||||
this.cloudRenderHandler = new CloudRenderHandler(this, genericObjectRenderer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+14
-3
@@ -303,9 +303,12 @@ public class LodRenderer
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
|
||||
this.bufferHandler.renderOpaque(this, renderEventParam);
|
||||
|
||||
// custom objects
|
||||
profiler.popPush("Custom Objects");
|
||||
this.genericObjectRenderer.render(renderEventParam, profiler);
|
||||
// custom objects with SSAO
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.enableRendering.get())
|
||||
{
|
||||
profiler.popPush("Custom Objects");
|
||||
this.genericObjectRenderer.render(renderEventParam, profiler, true);
|
||||
}
|
||||
|
||||
|
||||
// SSAO
|
||||
@@ -316,6 +319,14 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
|
||||
// custom objects without SSAO
|
||||
if (Config.Client.Advanced.Graphics.GenericRendering.enableRendering.get())
|
||||
{
|
||||
profiler.popPush("Custom Objects");
|
||||
this.genericObjectRenderer.render(renderEventParam, profiler, false);
|
||||
}
|
||||
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Fog.drawMode.get() != EDhApiFogDrawMode.FOG_DISABLED)
|
||||
{
|
||||
profiler.popPush("LOD Fog");
|
||||
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2023 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.render.renderer.generic;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public class CloudRenderHandler
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
private static final String CLOUD_RESOURCE_TEXTURE_PATH = "assets/distanthorizons/textures/clouds.png";
|
||||
// FIXME transparency sorting makes having transparent clouds impossible
|
||||
private static final Color CLOUD_COLOR = new Color(255,255,255,255);
|
||||
|
||||
private static final boolean DEBUG_BORDER_COLORS = false;
|
||||
|
||||
/**
|
||||
* How wide an individual box is. <br>
|
||||
* Measured in blocks.
|
||||
*/
|
||||
private static final int CLOUD_BOX_WIDTH = 128;
|
||||
/** measured in blocks */
|
||||
private static final int CLOUD_BOX_THICKNESS = 32;
|
||||
|
||||
private final IDhApiRenderableBoxGroup[][] boxGroupByOffset;
|
||||
private final IDhLevel level;
|
||||
|
||||
private float moveSpeedInBlocksPerSecond = 3.0f;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public CloudRenderHandler(IDhLevel level, GenericObjectRenderer renderer)
|
||||
{
|
||||
this.level = level;
|
||||
|
||||
|
||||
// default to a single empty slot in case the texture is broken
|
||||
boolean[][] cloudLocations = new boolean[1][1];
|
||||
try
|
||||
{
|
||||
cloudLocations = getCloudsFromTexture();
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error("Unexpected issue getting cloud texture, error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
if (cloudLocations.length != 0 &&
|
||||
cloudLocations.length != cloudLocations[0].length)
|
||||
{
|
||||
LOGGER.warn("Non-square cloud texture found, some parts of the texture will be clipped off.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int textureWidth = cloudLocations.length;
|
||||
ArrayList<DhApiRenderableBox> boxList = new ArrayList<>(512);
|
||||
for (int x = 0; x < textureWidth; x ++)
|
||||
{
|
||||
for (int z = 0; z < textureWidth; z ++)
|
||||
{
|
||||
if (cloudLocations[x][z])
|
||||
{
|
||||
int minX = x * CLOUD_BOX_WIDTH;
|
||||
int minZ = z * CLOUD_BOX_WIDTH;
|
||||
int maxX = minX + CLOUD_BOX_WIDTH;
|
||||
int maxZ = minZ + CLOUD_BOX_WIDTH;
|
||||
|
||||
Color color = CLOUD_COLOR;
|
||||
if (DEBUG_BORDER_COLORS)
|
||||
{
|
||||
// equals is included so the board is 2 blocks wide, it makes it easier to see
|
||||
if (x <= 1) { color = Color.RED; }
|
||||
else if (x >= textureWidth-2) { color = Color.GREEN; }
|
||||
if (z <= 1) { color = Color.BLUE; }
|
||||
else if (z >= textureWidth-2) { color = Color.BLACK; }
|
||||
}
|
||||
|
||||
DhApiRenderableBox box = new DhApiRenderableBox(
|
||||
new DhApiVec3f(minX, 0, minZ),
|
||||
new DhApiVec3f(maxX, CLOUD_BOX_THICKNESS, maxZ),
|
||||
color
|
||||
);
|
||||
boxList.add(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// slightly lighter shading than the default
|
||||
DhApiRenderableBoxGroupShading cloudShading = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||
cloudShading.north = cloudShading.south = 0.9f;
|
||||
cloudShading.east = cloudShading.west = 0.8f;
|
||||
cloudShading.top = 1.0f;
|
||||
cloudShading.bottom = 0.7f;
|
||||
|
||||
this.boxGroupByOffset = new IDhApiRenderableBoxGroup[3][3];
|
||||
for (int x = -1; x <= 1; x++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
IDhApiRenderableBoxGroup boxGroup = GenericRenderObjectFactory.INSTANCE.createRelativePositionedGroup(
|
||||
new DhApiVec3f(0, 0, 0), // the offset will be set during rendering
|
||||
boxList);
|
||||
boxGroup.setBlockLight(LodUtil.MIN_MC_LIGHT);
|
||||
boxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
boxGroup.setSsaoEnabled(false);
|
||||
boxGroup.setShading(cloudShading);
|
||||
|
||||
CloudParams offset = new CloudParams(textureWidth, x, z);
|
||||
boxGroup.setPreRenderFunc((renderParam) -> this.preRender(offset));
|
||||
|
||||
renderer.add(boxGroup);
|
||||
this.boxGroupByOffset[x+1][z+1] = boxGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void preRender(CloudParams clouds)
|
||||
{
|
||||
IDhApiRenderableBoxGroup boxGroup = this.boxGroupByOffset[clouds.instanceOffsetX+1][clouds.instanceOffsetZ+1];
|
||||
|
||||
boolean renderClouds = Config.Client.Advanced.Graphics.GenericRendering.enableCloudRendering.get();
|
||||
boxGroup.setActive(renderClouds);
|
||||
if(!renderClouds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// cloud movement //
|
||||
//================//
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
float deltaTime = (currentTime - clouds.lastFrameTime) / 1000.0f; // Delta time in seconds
|
||||
clouds.lastFrameTime = currentTime;
|
||||
|
||||
float deltaX = this.moveSpeedInBlocksPerSecond * deltaTime;
|
||||
// negative delta is to match vanilla's cloud movement
|
||||
clouds.xOffset -= deltaX;
|
||||
// wrap the cloud around after reaching the edge
|
||||
clouds.xOffset %= clouds.widthInBlocks;
|
||||
|
||||
|
||||
|
||||
//============================//
|
||||
// camera movement and offset //
|
||||
//============================//
|
||||
|
||||
// camera position
|
||||
int cameraPosX = (int)MC_RENDER.getCameraExactPosition().x;
|
||||
int cameraPosZ = (int)MC_RENDER.getCameraExactPosition().z;
|
||||
// offset the camera position by negative 1 width when below zero to fix off-by-one errors in the negative direction
|
||||
if (cameraPosX < 0) { cameraPosX -= clouds.widthInBlocks; }
|
||||
if (cameraPosZ < 0) { cameraPosZ -= clouds.widthInBlocks; }
|
||||
|
||||
// determine how many cloud instances away from the origin we are
|
||||
int cloudInstanceOffsetX = cameraPosX / (int)clouds.widthInBlocks;
|
||||
int cloudInstanceOffsetZ = cameraPosZ / (int)clouds.widthInBlocks;
|
||||
|
||||
// calculate the new offset
|
||||
float xOffset = (cloudInstanceOffsetX * clouds.widthInBlocks);
|
||||
float zOffset = (cloudInstanceOffsetZ * clouds.widthInBlocks);
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// update group //
|
||||
//==============//
|
||||
|
||||
boxGroup.setOriginBlockPos(
|
||||
new DhApiVec3f(
|
||||
clouds.xOffset + (clouds.instanceOffsetX * clouds.widthInBlocks) + xOffset + clouds.halfWidthInBlocks,
|
||||
this.level.getLevelWrapper().getHeight() + 200,
|
||||
clouds.zOffset + (clouds.instanceOffsetZ * clouds.widthInBlocks) + zOffset + clouds.halfWidthInBlocks
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// texture handling //
|
||||
//==================//
|
||||
|
||||
public static boolean[][] getCloudsFromTexture() throws FileNotFoundException, IOException
|
||||
{
|
||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
boolean[][] whitePixels = null;
|
||||
try(InputStream imageInputStream = loader.getResourceAsStream(CLOUD_RESOURCE_TEXTURE_PATH))
|
||||
{
|
||||
if (imageInputStream == null)
|
||||
{
|
||||
throw new FileNotFoundException("Unable to find cloud texture at resource path: ["+CLOUD_RESOURCE_TEXTURE_PATH+"].");
|
||||
}
|
||||
|
||||
BufferedImage image = ImageIO.read(imageInputStream);
|
||||
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
whitePixels = new boolean[width][height];
|
||||
|
||||
for (int x = 0; x < width; x ++)
|
||||
{
|
||||
for (int z = 0; z < width; z ++)
|
||||
{
|
||||
Color color = new Color(image.getRGB(x,z));
|
||||
whitePixels[x][z] = color.equals(Color.WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return whitePixels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
private static class CloudParams
|
||||
{
|
||||
public final float textureWidth;
|
||||
public final float widthInBlocks;
|
||||
public final float halfWidthInBlocks;
|
||||
|
||||
public final int instanceOffsetX;
|
||||
public final int instanceOffsetZ;
|
||||
|
||||
|
||||
public float xOffset = 0;
|
||||
public float zOffset = 0;
|
||||
|
||||
public long lastFrameTime = System.currentTimeMillis();
|
||||
|
||||
|
||||
|
||||
// constructor //
|
||||
|
||||
public CloudParams(float textureWidth, int instanceOffsetX, int instanceOffsetZ)
|
||||
{
|
||||
this.textureWidth = textureWidth;
|
||||
this.widthInBlocks = (this.textureWidth * CLOUD_BOX_WIDTH);
|
||||
this.halfWidthInBlocks = this.widthInBlocks / 2;
|
||||
|
||||
this.instanceOffsetX = instanceOffsetX;
|
||||
this.instanceOffsetZ = instanceOffsetZ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+111
-47
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
@@ -79,8 +80,8 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
private boolean init = false;
|
||||
|
||||
private ShaderProgram shader;
|
||||
private GLVertexBuffer vertexBuffer;
|
||||
private GLElementBuffer solidIndexBuffer;
|
||||
private GLVertexBuffer boxVertexBuffer;
|
||||
private GLElementBuffer boxIndexBuffer;
|
||||
private AbstractVertexAttribute va;
|
||||
|
||||
private boolean useInstancedRendering;
|
||||
@@ -100,6 +101,13 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
private int skyLightUniform;
|
||||
private int blockLightUniform;
|
||||
|
||||
private int northShadingUniform;
|
||||
private int southShadingUniform;
|
||||
private int eastShadingUniform;
|
||||
private int westShadingUniform;
|
||||
private int topShadingUniform;
|
||||
private int bottomShadingUniform;
|
||||
|
||||
|
||||
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -108,37 +116,62 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
/** A box from 0,0,0 to 1,1,1 */
|
||||
private static final float[] BOX_VERTICES = {
|
||||
// Pos x y z
|
||||
|
||||
// min X, vertical face
|
||||
0, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
// max X, vertical face
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 1,
|
||||
|
||||
// min Z, vertical face
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
// max Z, vertical face
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 1,
|
||||
};
|
||||
|
||||
private static final int[] SOLID_BOX_INDICES = {
|
||||
// min Z, vertical face
|
||||
0, 3, 2,
|
||||
2, 1, 0,
|
||||
// max Z, vertical face
|
||||
4, 5, 6,
|
||||
6, 7, 4,
|
||||
|
||||
// min X, vertical face
|
||||
7, 3, 0,
|
||||
0, 4, 7,
|
||||
// max X, vertical face
|
||||
2, 6, 5,
|
||||
5, 1, 2,
|
||||
1, 1, 0,
|
||||
1, 0, 0,
|
||||
|
||||
// min Y, horizontal face
|
||||
1, 5, 4,
|
||||
4, 0, 1,
|
||||
0, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
// max Y, horizontal face
|
||||
3, 7, 6,
|
||||
6, 2, 3,
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
};
|
||||
|
||||
private static final int[] BOX_INDICES = {
|
||||
// min X, vertical face
|
||||
2, 1, 0,
|
||||
0, 3, 2,
|
||||
// max X, vertical face
|
||||
6, 5, 4,
|
||||
4, 7, 6,
|
||||
|
||||
// min Z, vertical face
|
||||
10, 9, 8,
|
||||
8, 11, 10,
|
||||
// max Z, vertical face
|
||||
14, 13, 12,
|
||||
12, 15, 14,
|
||||
|
||||
// min Y, horizontal face
|
||||
18, 17, 16,
|
||||
16, 19, 18,
|
||||
// max Y, horizontal face
|
||||
20, 21, 22,
|
||||
22, 23, 20,
|
||||
};
|
||||
|
||||
|
||||
@@ -187,6 +220,14 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
this.lightMapUniform = this.shader.getUniformLocation("uLightMap");
|
||||
this.skyLightUniform = this.shader.getUniformLocation("uSkyLight");
|
||||
this.blockLightUniform = this.shader.getUniformLocation("uBlockLight");
|
||||
//this.shadingModeUniform = this.shader.getUniformLocation("uShadingMode");
|
||||
this.northShadingUniform = this.shader.getUniformLocation("uNorthShading");
|
||||
this.southShadingUniform = this.shader.getUniformLocation("uSouthShading");
|
||||
this.eastShadingUniform = this.shader.getUniformLocation("uEastShading");
|
||||
this.westShadingUniform = this.shader.getUniformLocation("uWestShading");
|
||||
this.topShadingUniform = this.shader.getUniformLocation("uTopShading");
|
||||
this.bottomShadingUniform = this.shader.getUniformLocation("uBottomShading");
|
||||
|
||||
|
||||
this.createBuffers();
|
||||
|
||||
@@ -202,19 +243,19 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
boxVerticesBuffer.order(ByteOrder.nativeOrder());
|
||||
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||
boxVerticesBuffer.rewind();
|
||||
this.vertexBuffer = new GLVertexBuffer(false);
|
||||
this.vertexBuffer.bind();
|
||||
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||
this.boxVertexBuffer = new GLVertexBuffer(false);
|
||||
this.boxVertexBuffer.bind();
|
||||
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||
|
||||
|
||||
// box vertex indexes
|
||||
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(SOLID_BOX_INDICES.length * Integer.BYTES);
|
||||
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(BOX_INDICES.length * Integer.BYTES);
|
||||
solidIndexBuffer.order(ByteOrder.nativeOrder());
|
||||
solidIndexBuffer.asIntBuffer().put(SOLID_BOX_INDICES);
|
||||
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
|
||||
solidIndexBuffer.rewind();
|
||||
this.solidIndexBuffer = new GLElementBuffer(false);
|
||||
this.solidIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, SOLID_BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
this.solidIndexBuffer.bind();
|
||||
this.boxIndexBuffer = new GLElementBuffer(false);
|
||||
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
this.boxIndexBuffer.bind();
|
||||
|
||||
}
|
||||
private void addGenericDebugObjects()
|
||||
@@ -345,7 +386,12 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
// rendering //
|
||||
//===========//
|
||||
|
||||
public void render(DhApiRenderParam renderEventParam, IProfilerWrapper profiler)
|
||||
/**
|
||||
* @param renderingWithSsao
|
||||
* if true that means this render call is happening before the SSAO pass
|
||||
* and any objects rendered in this pass will have SSAO applied to them.
|
||||
*/
|
||||
public void render(DhApiRenderParam renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
|
||||
{
|
||||
// render setup //
|
||||
profiler.push("setup");
|
||||
@@ -362,9 +408,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
|
||||
this.shader.bind();
|
||||
this.va.bind();
|
||||
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
|
||||
this.va.bindBufferToAllBindingPoints(this.boxVertexBuffer.getId());
|
||||
|
||||
this.solidIndexBuffer.bind();
|
||||
this.boxIndexBuffer.bind();
|
||||
|
||||
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
|
||||
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
|
||||
@@ -379,21 +425,27 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
|
||||
for (RenderableBoxGroup boxGroup : boxList)
|
||||
{
|
||||
// ignore inactive groups
|
||||
if (boxGroup != null && boxGroup.active)
|
||||
// skip boxes that shouldn't render this pass
|
||||
if (boxGroup.ssaoEnabled == renderingWithSsao)
|
||||
{
|
||||
profiler.popPush("render prep");
|
||||
boxGroup.preRender(renderEventParam);
|
||||
|
||||
if (this.useInstancedRendering)
|
||||
// ignore inactive groups
|
||||
if (boxGroup.active)
|
||||
{
|
||||
profiler.popPush("rendering");
|
||||
this.renderBoxGroupInstanced(boxGroup, camPos, projectionMvmMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
profiler.popPush("rendering");
|
||||
this.renderBoxGroupDirect(boxGroup, projectionMvmMatrix, camPos);
|
||||
if (this.useInstancedRendering)
|
||||
{
|
||||
profiler.popPush("rendering");
|
||||
this.renderBoxGroupInstanced(boxGroup, camPos, projectionMvmMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
profiler.popPush("rendering");
|
||||
this.renderBoxGroupDirect(boxGroup, projectionMvmMatrix, camPos);
|
||||
}
|
||||
|
||||
boxGroup.postRender(renderEventParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,6 +494,18 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
this.shader.setUniform(this.skyLightUniform, boxGroup.skyLight);
|
||||
this.shader.setUniform(this.blockLightUniform, boxGroup.blockLight);
|
||||
|
||||
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||
if (shading == null)
|
||||
{
|
||||
shading = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||
}
|
||||
this.shader.setUniform(this.northShadingUniform, shading.north);
|
||||
this.shader.setUniform(this.southShadingUniform, shading.south);
|
||||
this.shader.setUniform(this.eastShadingUniform, shading.east);
|
||||
this.shader.setUniform(this.westShadingUniform, shading.west);
|
||||
this.shader.setUniform(this.topShadingUniform, shading.top);
|
||||
this.shader.setUniform(this.bottomShadingUniform, shading.bottom);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -466,7 +530,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
// Draw instanced
|
||||
if (boxGroup.uploadedBoxCount > 0)
|
||||
{
|
||||
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount);
|
||||
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -512,7 +576,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
|
||||
for (DhApiRenderableBox box : boxGroup)
|
||||
{
|
||||
renderBox(boxGroup, box, transformMatrix, camPos);
|
||||
this.renderBox(boxGroup, box, transformMatrix, camPos);
|
||||
}
|
||||
}
|
||||
private void renderBox(
|
||||
@@ -543,7 +607,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
|
||||
|
||||
this.shader.setUniform(this.directShaderColorUniform, box.color);
|
||||
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+31
-4
@@ -4,6 +4,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
@@ -37,14 +38,18 @@ public class RenderableBoxGroup
|
||||
|
||||
private final Vec3f originBlockPos;
|
||||
|
||||
|
||||
public boolean active = true;
|
||||
public boolean ssaoEnabled = true;
|
||||
private boolean vertexDataDirty = true;
|
||||
|
||||
public int skyLight = 15;
|
||||
public int blockLight = 0;
|
||||
public DhApiRenderableBoxGroupShading shading = DhApiRenderableBoxGroupShading.getDefaultShaded();
|
||||
|
||||
@Nullable
|
||||
public Consumer<DhApiRenderParam> beforeRenderFunc;
|
||||
|
||||
private boolean vertexDataDirty = true;
|
||||
public boolean active = true;
|
||||
public Consumer<DhApiRenderParam> afterRenderFunc;
|
||||
|
||||
// instance data
|
||||
public int instanceTranslationVbo = 0;
|
||||
@@ -120,6 +125,9 @@ public class RenderableBoxGroup
|
||||
@Override
|
||||
public void setPreRenderFunc(Consumer<DhApiRenderParam> func) { this.beforeRenderFunc = func; }
|
||||
|
||||
@Override
|
||||
public void setPostRenderFunc(Consumer<DhApiRenderParam> func) { this.afterRenderFunc = func; }
|
||||
|
||||
@Override
|
||||
public void triggerBoxChange() { this.vertexDataDirty = true; }
|
||||
|
||||
@@ -128,6 +136,11 @@ public class RenderableBoxGroup
|
||||
@Override
|
||||
public boolean isActive() { return this.active; }
|
||||
|
||||
@Override
|
||||
public void setSsaoEnabled(boolean ssaoEnabled) { this.ssaoEnabled = ssaoEnabled; }
|
||||
@Override
|
||||
public boolean isSsaoEnabled() { return this.ssaoEnabled; }
|
||||
|
||||
public void preRender(DhApiRenderParam renderEventParam)
|
||||
{
|
||||
if (this.beforeRenderFunc != null)
|
||||
@@ -135,10 +148,24 @@ public class RenderableBoxGroup
|
||||
this.beforeRenderFunc.accept(renderEventParam);
|
||||
}
|
||||
}
|
||||
public void postRender(DhApiRenderParam renderEventParam)
|
||||
{
|
||||
if (this.afterRenderFunc != null)
|
||||
{
|
||||
this.afterRenderFunc.accept(renderEventParam);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShading(DhApiRenderableBoxGroupShading shading) { this.shading = shading; }
|
||||
@Override
|
||||
public DhApiRenderableBoxGroupShading getShading() { return this.shading; }
|
||||
|
||||
|
||||
|
||||
// overrides //
|
||||
//================//
|
||||
// List Overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public DhApiRenderableBox get(int index) { return this.boxList.get(index); }
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
@@ -11,6 +11,13 @@ uniform int uSkyLight;
|
||||
uniform int uBlockLight;
|
||||
uniform sampler2D uLightMap;
|
||||
|
||||
uniform float uNorthShading;
|
||||
uniform float uSouthShading;
|
||||
uniform float uEastShading;
|
||||
uniform float uWestShading;
|
||||
uniform float uTopShading;
|
||||
uniform float uBottomShading;
|
||||
|
||||
in vec3 vPosition;
|
||||
|
||||
out vec4 fColor;
|
||||
@@ -41,6 +48,16 @@ void main()
|
||||
float blockLight = (float(uBlockLight)+0.5) / 16.0;
|
||||
float skyLight = (float(uSkyLight)+0.5) / 16.0;
|
||||
vec4 lightColor = vec4(texture(uLightMap, vec2(blockLight, skyLight)).xyz, 1.0);
|
||||
|
||||
|
||||
|
||||
fColor = lightColor * aColor;
|
||||
}
|
||||
|
||||
// apply directional shading
|
||||
if (gl_VertexID >= 0 && gl_VertexID < 4) { fColor.rgb *= uNorthShading; }
|
||||
else if (gl_VertexID >= 4 && gl_VertexID < 8) { fColor.rgb *= uSouthShading; }
|
||||
else if (gl_VertexID >= 8 && gl_VertexID < 12) { fColor.rgb *= uWestShading; }
|
||||
else if (gl_VertexID >= 12 && gl_VertexID < 16) { fColor.rgb *= uEastShading; }
|
||||
else if (gl_VertexID >= 16 && gl_VertexID < 20) { fColor.rgb *= uBottomShading; }
|
||||
else if (gl_VertexID >= 20 && gl_VertexID < 24) { fColor.rgb *= uTopShading; }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user