Update rendering to OpenGL 3.2+ (buffers seem to be corrupted or missing)
The rendering is almost completely functional, only fog needs to be re-implemented.
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
These Files are used when developing the mod.
|
||||
|
||||
Eclipse Auto Formatting
|
||||
IntelliJ Auto Formatting
|
||||
- These files are the auto-formatting settings that should be used when developing for the mod. We want to make sure the style of code is consistant regardless of who is writting the code.
|
||||
|
||||
renderDocMcDistantHorizonsSettings
|
||||
- This file contains the configuration to run a remote debug instance so you can edit the mod in your IDE while also viewing the OpenGL code in RenderDoc.
|
||||
|
||||
minecraft launch options
|
||||
- This file contains the Java command line arguments used to launch the mod from a development environment (specifically Eclipse, James didn't test it with IntelliJ), and is included to more easily edit the options for RenderDoc
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
+3
-3
@@ -11,7 +11,7 @@ buildscript {
|
||||
dependencies {
|
||||
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
|
||||
classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT'
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2'
|
||||
classpath "gradle.plugin.com.github.johnrengelman:shadow:7.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ apply plugin: 'eclipse'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
version = '1.5.3a'
|
||||
version = '1.5.4a'
|
||||
group = 'com.seibel.lod'
|
||||
archivesBaseName = 'Distant-Horizons_1.16.5'
|
||||
archivesBaseName = 'Distant-Horizons_1.17.1'
|
||||
|
||||
// Mojang ships Java 16 to end users in 1.17+ instead of Java 8 in 1.16 or lower, so your mod should target Java 16.
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(16)
|
||||
|
||||
@@ -68,7 +68,7 @@ import net.minecraft.world.level.LightLayer;
|
||||
/**
|
||||
* This object is used to create NearFarBuffer objects.
|
||||
* @author James Seibel
|
||||
* @version 10-23-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodBufferBuilder
|
||||
{
|
||||
@@ -535,13 +535,16 @@ public class LodBufferBuilder
|
||||
*/
|
||||
public void setupBuffers(LodDimension lodDimension)
|
||||
{
|
||||
GlProxy glProxy = GlProxy.getInstance();
|
||||
|
||||
bufferLock.lock();
|
||||
int numbRegionsWide = lodDimension.getWidth();
|
||||
long regionMemoryRequired;
|
||||
int numberOfBuffers;
|
||||
|
||||
GlProxy glProxy = GlProxy.getInstance();
|
||||
GlProxyContext oldContext = glProxy.getGlContext();
|
||||
glProxy.setGlContext(GlProxyContext.LOD_BUILDER);
|
||||
|
||||
|
||||
previousRegionWidth = numbRegionsWide;
|
||||
numberOfBuffersPerRegion = new int[numbRegionsWide][numbRegionsWide];
|
||||
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide][];
|
||||
@@ -632,6 +635,7 @@ public class LodBufferBuilder
|
||||
}
|
||||
}
|
||||
|
||||
glProxy.setGlContext(oldContext);
|
||||
bufferLock.unlock();
|
||||
}
|
||||
|
||||
@@ -794,7 +798,11 @@ public class LodBufferBuilder
|
||||
for (int i = 0; i < buildableBuffers[x][z].length; i++)
|
||||
{
|
||||
ByteBuffer uploadBuffer = buildableBuffers[x][z][i].popNextBuffer().getSecond();
|
||||
vboUpload(buildableVbos[x][z][i], buildableStorageBufferIds[x][z][i], uploadBuffer, true, uploadMethod);
|
||||
int storageBufferId = 0;
|
||||
if (buildableStorageBufferIds != null)
|
||||
storageBufferId = buildableStorageBufferIds[x][z][i];
|
||||
|
||||
vboUpload(buildableVbos[x][z][i], storageBufferId, uploadBuffer, true, uploadMethod);
|
||||
lodDim.setRegenRegionBufferByArrayIndex(x, z, false);
|
||||
}
|
||||
}
|
||||
@@ -818,8 +826,7 @@ public class LodBufferBuilder
|
||||
}
|
||||
}
|
||||
|
||||
/** Uploads the uploadBuffer so the GPU can use it.
|
||||
* @param uploadMethod */
|
||||
/** Uploads the uploadBuffer so the GPU can use it. */
|
||||
private void vboUpload(VertexBuffer vbo, int storageBufferId, ByteBuffer uploadBuffer,
|
||||
boolean allowBufferExpansion, GpuUploadMethod uploadMethod)
|
||||
{
|
||||
@@ -827,15 +834,14 @@ public class LodBufferBuilder
|
||||
if (vbo.vertextBufferId != -1 && GlProxy.getInstance().getGlContext() == GlProxyContext.LOD_BUILDER)
|
||||
{
|
||||
// this is how many points will be rendered
|
||||
// TODO double check that 4 * 6 is correct for the number of points
|
||||
vbo.indexCount = (uploadBuffer.capacity() / (4 * 6));
|
||||
vbo.indexCount = (uploadBuffer.capacity() / (6 * 6)); // TODO make this change with the LodTemplate
|
||||
|
||||
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.vertextBufferId);
|
||||
try
|
||||
{
|
||||
// if possible use the faster buffer storage route
|
||||
if (uploadMethod == GpuUploadMethod.BUFFER_STORAGE)
|
||||
if (uploadMethod == GpuUploadMethod.BUFFER_STORAGE && storageBufferId != 0)
|
||||
{
|
||||
// get a pointer to the buffer in system memory
|
||||
ByteBuffer vboBuffer = GL30.glMapBufferRange(GL15.GL_ARRAY_BUFFER, 0, uploadBuffer.capacity(), GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
@@ -916,7 +922,6 @@ public class LodBufferBuilder
|
||||
// hybrid subData/bufferData //
|
||||
// less stutter, low GPU usage
|
||||
|
||||
//long size = GL31.glGetBufferParameteri64(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE); // hopefully just a int should be long enough
|
||||
long size = GL15.glGetBufferParameteri(GL15.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE);
|
||||
if (size < uploadBuffer.capacity() * BUFFER_EXPANSION_MULTIPLIER)
|
||||
{
|
||||
|
||||
@@ -74,35 +74,58 @@ public class Box
|
||||
public static final Map<Direction, int[][]> DIRECTION_VERTEX_MAP = new HashMap<Direction, int[][]>()
|
||||
{{
|
||||
put(Direction.UP, new int[][] {
|
||||
{ 0, 1, 0 },
|
||||
{ 0, 1, 1 },
|
||||
{ 1, 1, 1 },
|
||||
{ 1, 1, 0 } });
|
||||
{ 0, 1, 0 }, // 0
|
||||
{ 0, 1, 1 }, // 1
|
||||
{ 1, 1, 1 }, // 2
|
||||
|
||||
{ 0, 1, 0 }, // 0
|
||||
{ 1, 1, 1 }, // 2
|
||||
{ 1, 1, 0 } // 3
|
||||
});
|
||||
put(Direction.DOWN, new int[][] {
|
||||
{ 1, 0, 0 },
|
||||
{ 1, 0, 1 },
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 0, 0 } });
|
||||
{ 1, 0, 0 }, // 0
|
||||
{ 1, 0, 1 }, // 1
|
||||
{ 0, 0, 1 }, // 2
|
||||
|
||||
{ 1, 0, 0 }, // 0
|
||||
{ 0, 0, 1 }, // 2
|
||||
{ 0, 0, 0 } // 3
|
||||
});
|
||||
put(Direction.EAST, new int[][] {
|
||||
{ 1, 1, 0 },
|
||||
{ 1, 1, 1 },
|
||||
{ 1, 0, 1 },
|
||||
{ 1, 0, 0 } });
|
||||
{ 1, 1, 0 }, // 0
|
||||
{ 1, 1, 1 }, // 1
|
||||
{ 1, 0, 1 }, // 2
|
||||
|
||||
{ 1, 1, 0 }, // 0
|
||||
{ 1, 0, 1 }, // 2
|
||||
{ 1, 0, 0 } }); // 3
|
||||
put(Direction.WEST, new int[][] {
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 0, 1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0, 1, 0 } });
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 0, 1 }, // 1
|
||||
{ 0, 1, 1 }, // 2
|
||||
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 1, 1 }, // 2
|
||||
{ 0, 1, 0 } // 3
|
||||
});
|
||||
put(Direction.SOUTH, new int[][] {
|
||||
{ 1, 0, 1 },
|
||||
{ 1, 1, 1 },
|
||||
{ 0, 1, 1 },
|
||||
{ 0, 0, 1 } });
|
||||
{ 1, 0, 1 }, // 0
|
||||
{ 1, 1, 1 }, // 1
|
||||
{ 0, 1, 1 }, // 2
|
||||
|
||||
{ 1, 0, 1 }, // 0
|
||||
{ 0, 1, 1 }, // 2
|
||||
{ 0, 0, 1 } // 3
|
||||
});
|
||||
put(Direction.NORTH, new int[][] {
|
||||
{ 0, 0, 0 },
|
||||
{ 0, 1, 0 },
|
||||
{ 1, 1, 0 },
|
||||
{ 1, 0, 0 } });
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 0, 1, 0 }, // 1
|
||||
{ 1, 1, 0 }, // 2
|
||||
|
||||
{ 0, 0, 0 }, // 0
|
||||
{ 1, 1, 0 }, // 2
|
||||
{ 1, 0, 0 } // 3
|
||||
});
|
||||
}};
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -33,7 +33,7 @@ import net.minecraft.core.Direction;
|
||||
/**
|
||||
* Builds LODs as rectangular prisms.
|
||||
* @author James Seibel
|
||||
* @version 10-10-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class CubicLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
@@ -118,10 +118,11 @@ public class CubicLodTemplate extends AbstractLodTemplate
|
||||
{
|
||||
if(box.isCulled(direction))
|
||||
continue;
|
||||
|
||||
int verticalFaceIndex = 0;
|
||||
while (box.shouldRenderFace(direction, verticalFaceIndex))
|
||||
{
|
||||
for (int vertexIndex = 0; vertexIndex < 4; vertexIndex++)
|
||||
for (int vertexIndex = 0; vertexIndex < 6; vertexIndex++)
|
||||
{
|
||||
color = box.getColor(direction);
|
||||
skyLight = box.getSkyLight(direction, verticalFaceIndex);
|
||||
|
||||
@@ -56,7 +56,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
* This handles all events sent to the client,
|
||||
* and is the starting point for most of the mod.
|
||||
* @author James_Seibel
|
||||
* @version 10-31-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class ClientProxy
|
||||
{
|
||||
@@ -131,8 +131,7 @@ public class ClientProxy
|
||||
profiler.pop(); // get out of "terrain"
|
||||
profiler.push("LOD");
|
||||
|
||||
glProxy.setGlContext(GlProxyContext.LOD_RENDER);
|
||||
renderer.drawLODs(lodDim, mcModelViewMatrix, partialTicks, mc.getProfiler());
|
||||
renderer.drawLODs(lodDim, mcModelViewMatrix, projectionMatrix, partialTicks, mc.getProfiler());
|
||||
|
||||
profiler.pop(); // end LOD
|
||||
profiler.push("terrain"); // go back into "terrain"
|
||||
@@ -161,18 +160,19 @@ public class ClientProxy
|
||||
// remind the developer(s) that the config override is active
|
||||
if (!configOverrideReminderPrinted)
|
||||
{
|
||||
// mc.getPlayer().sendMessage(new TextComponent("LOD experimental build 1.5.1"), mc.getPlayer().getUUID());
|
||||
// TODO add a send message method to the MC wrapper
|
||||
// mc.getPlayer().sendMessage(new TextComponent("LOD experimental build " + ModInfo.VERSION), mc.getPlayer().getUUID());
|
||||
// mc.getPlayer().sendMessage(new TextComponent("Here be dragons!"), mc.getPlayer().getUUID());
|
||||
|
||||
mc.getPlayer().sendMessage(new TextComponent("Debug settings enabled!"), mc.getPlayer().getUUID());
|
||||
configOverrideReminderPrinted = true;
|
||||
}
|
||||
|
||||
|
||||
// LodConfig.CLIENT.graphics.drawResolution.set(HorizontalResolution.BLOCK);
|
||||
// LodConfig.CLIENT.worldGenerator.generationResolution.set(HorizontalResolution.BLOCK);
|
||||
// requires a world restart?
|
||||
// LodConfig.CLIENT.worldGenerator.lodQualityMode.set(VerticalQuality.VOXEL);
|
||||
|
||||
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.fogDistance.set(FogDistance.FAR);
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.fogDrawOverride.set(FogDrawOverride.FANCY);
|
||||
// LodConfig.CLIENT.graphics.fogQualityOption.disableVanillaFog.set(true);
|
||||
@@ -181,7 +181,7 @@ public class ClientProxy
|
||||
// LodConfig.CLIENT.graphics.advancedGraphicsOption.vanillaOverdraw.set(VanillaOverdraw.DYNAMIC);
|
||||
|
||||
// LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.set(GpuUploadMethod.BUFFER_STORAGE);
|
||||
|
||||
|
||||
// LodConfig.CLIENT.worldGenerator.distanceGenerationMode.set(DistanceGenerationMode.SURFACE);
|
||||
// LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.set(128);
|
||||
// LodConfig.CLIENT.worldGenerator.lodDistanceCalculatorType.set(DistanceCalculatorType.LINEAR);
|
||||
@@ -251,23 +251,25 @@ public class ClientProxy
|
||||
{
|
||||
// the player just left the server
|
||||
|
||||
// TODO should "resetMod()" be called here? -James
|
||||
|
||||
// if this isn't done unfinished tasks may be left in the queue
|
||||
// preventing new LodChunks form being generated
|
||||
//LodNodeGenWorker.restartExecutorService();
|
||||
//LodNodeGenWorker.restartExecutorService(); // TODO why was this commented out? -James
|
||||
//ThreadMapUtil.clearMaps();
|
||||
|
||||
LodWorldGenerator.INSTANCE.numberOfChunksWaitingToGenerate.set(0);
|
||||
lodWorld.deselectWorld();
|
||||
|
||||
|
||||
// hopefully this should reduce issues related to the buffer builder
|
||||
// prevent issues related to the buffer builder
|
||||
// breaking when changing worlds.
|
||||
renderer.destroyBuffers();
|
||||
recalculateWidths = true;
|
||||
renderer = new LodRenderer(lodBufferBuilder);
|
||||
|
||||
|
||||
// make sure the nilled objects are freed.
|
||||
// make sure the nulled objects are freed.
|
||||
// (this prevents an out of memory error when
|
||||
// changing worlds)
|
||||
System.gc();
|
||||
@@ -358,6 +360,7 @@ public class ClientProxy
|
||||
/** this method reset some static data every time we change world */
|
||||
private void resetMod()
|
||||
{
|
||||
// TODO when should this be used?
|
||||
ThreadMapUtil.clearMaps();
|
||||
LodGenWorker.restartExecutorService();
|
||||
|
||||
|
||||
@@ -22,11 +22,15 @@ package com.seibel.lod.proxy;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.lod.ModInfo;
|
||||
import com.seibel.lod.enums.GlProxyContext;
|
||||
import com.seibel.lod.render.shader.LodShader;
|
||||
import com.seibel.lod.render.shader.LodShaderProgram;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
/**
|
||||
@@ -41,7 +45,7 @@ import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br><br>
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-31-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class GlProxy
|
||||
{
|
||||
@@ -49,6 +53,7 @@ public class GlProxy
|
||||
|
||||
private static MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
|
||||
|
||||
/** Minecraft's GLFW window */
|
||||
public final long minecraftGlContext;
|
||||
/** Minecraft's GL capabilities */
|
||||
@@ -59,16 +64,12 @@ public class GlProxy
|
||||
/** the LodBuilder's GL capabilities */
|
||||
public final GLCapabilities lodBuilderGlCapabilities;
|
||||
|
||||
/** the LodRender's GLFW window */
|
||||
public final long lodRenderGlContext;
|
||||
/** the LodRender's GL capabilities */
|
||||
public final GLCapabilities lodRenderGlCapabilities;
|
||||
|
||||
/**
|
||||
* This is just used for debugging, hopefully it can be removed once
|
||||
* the context switching is more stable.
|
||||
*/
|
||||
public Thread lodBuilderOwnerThread = null;
|
||||
/** This program contains all shaders required when rendering LODs */
|
||||
public LodShaderProgram lodShaderProgram;
|
||||
/** This is the VAO that is used when rendering */
|
||||
public final int vertexArrayObjectId;
|
||||
|
||||
|
||||
/** Does this computer's GPU support fancy fog? */
|
||||
public final boolean fancyFogAvailable;
|
||||
@@ -80,6 +81,8 @@ public class GlProxy
|
||||
public final boolean mapBufferRangeSupported;
|
||||
|
||||
|
||||
|
||||
|
||||
private GlProxy()
|
||||
{
|
||||
ClientProxy.LOGGER.error("Creating " + GlProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
|
||||
@@ -110,13 +113,8 @@ public class GlProxy
|
||||
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
|
||||
|
||||
// create the LodRender context
|
||||
lodRenderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Render Window", 0L, 0L); // create a window to hold the context
|
||||
GLFW.glfwMakeContextCurrent(lodRenderGlContext);
|
||||
lodRenderGlCapabilities = GL.createCapabilities();
|
||||
|
||||
// create the LodBuilder context
|
||||
lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, lodRenderGlContext);
|
||||
lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext);
|
||||
GLFW.glfwMakeContextCurrent(lodBuilderGlContext);
|
||||
lodBuilderGlCapabilities = GL.createCapabilities();
|
||||
|
||||
@@ -124,25 +122,28 @@ public class GlProxy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==================================//
|
||||
// get any GPU related capabilities //
|
||||
//==================================//
|
||||
|
||||
ClientProxy.LOGGER.info("Lod Render OpenGL version [" + GL11.glGetString(GL11.GL_VERSION) + "].");
|
||||
|
||||
// crash the game if the GPU doesn't support OpenGL 1.5
|
||||
if (!minecraftGlCapabilities.OpenGL15)
|
||||
// crash the game if the GPU doesn't support OpenGL 2.0
|
||||
if (!minecraftGlCapabilities.OpenGL20)
|
||||
{
|
||||
// Note: as of MC 1.17 this shouldn't happen since MC
|
||||
// requires OpenGL 3.3, but just in case.
|
||||
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 1.5 or greater.";
|
||||
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 1.5 or greater."));
|
||||
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GlProxy.class.getSimpleName() + " and discoverd this GPU doesn't support OpenGL 2.0 or greater.";
|
||||
mc.crashMinecraft(errorMessage + " Sorry I couldn't tell you sooner :(", new UnsupportedOperationException("This GPU doesn't support OpenGL 2.0 or greater."));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get specific capabilities
|
||||
bufferStorageSupported = lodBuilderGlCapabilities.glBufferStorage != 0;
|
||||
// TODO re-add buffer storage support
|
||||
bufferStorageSupported = false; //lodBuilderGlCapabilities.glBufferStorage != 0;
|
||||
mapBufferRangeSupported = lodBuilderGlCapabilities.glMapBufferRange != 0;
|
||||
fancyFogAvailable = minecraftGlCapabilities.GL_NV_fog_distance;
|
||||
|
||||
@@ -161,20 +162,78 @@ public class GlProxy
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// shader setup //
|
||||
//==============//
|
||||
|
||||
//setGlContext(GlProxyContext.LOD_RENDER);
|
||||
setGlContext(GlProxyContext.MINECRAFT);
|
||||
|
||||
createShaderProgram();
|
||||
|
||||
|
||||
// Note: VAO objects can not be shared between contexts,
|
||||
// this must be created on the LOD render context to work correctly
|
||||
vertexArrayObjectId = GL30.glGenVertexArrays();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// clean up //
|
||||
//==========//
|
||||
|
||||
// Since this is created on the render thread, make sure the Minecraft context is used in the end
|
||||
GLFW.glfwMakeContextCurrent(minecraftGlContext);
|
||||
GL.setCapabilities(minecraftGlCapabilities);
|
||||
setGlContext(GlProxyContext.MINECRAFT);
|
||||
|
||||
|
||||
// GlProxy creation success
|
||||
ClientProxy.LOGGER.error(GlProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
|
||||
}
|
||||
|
||||
|
||||
/** Creates all required shaders */
|
||||
public void createShaderProgram()
|
||||
{
|
||||
LodShader vertexShader = null;
|
||||
LodShader fragmentShader = null;
|
||||
|
||||
try
|
||||
{
|
||||
// get the shaders from the resource folder
|
||||
vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "shaders/unshaded.vert", false);
|
||||
fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "shaders/unshaded.frag", false);
|
||||
|
||||
// this can be used when testing shaders,
|
||||
// since we can't hot swap the files in the resource folder
|
||||
// vertexShader = LodShader.loadShader(GL20.GL_VERTEX_SHADER, "C:/Users/James Seibel/Desktop/shaders/unshaded.vert", true);
|
||||
// fragmentShader = LodShader.loadShader(GL20.GL_FRAGMENT_SHADER, "C:/Users/James Seibel/Desktop/shaders/unshaded.frag", true);
|
||||
|
||||
|
||||
// create the shaders
|
||||
|
||||
lodShaderProgram = new LodShaderProgram();
|
||||
|
||||
// Attach the compiled shaders to the program
|
||||
lodShaderProgram.attachShader(vertexShader);
|
||||
lodShaderProgram.attachShader(fragmentShader);
|
||||
|
||||
// activate the fragment shader output
|
||||
GL30.glBindFragDataLocation(lodShaderProgram.id, 0, "fragColor");
|
||||
|
||||
// attach the shader program to the OpenGL context
|
||||
lodShaderProgram.link();
|
||||
|
||||
// after the shaders have been attached to the program
|
||||
// we don't need their OpenGL references anymore
|
||||
GL20.glDeleteShader(vertexShader.id);
|
||||
GL20.glDeleteShader(fragmentShader.id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ClientProxy.LOGGER.error("Unable to compile shaders. Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -200,11 +259,6 @@ public class GlProxy
|
||||
contextPointer = lodBuilderGlContext;
|
||||
newGlCapabilities = lodBuilderGlCapabilities;
|
||||
break;
|
||||
|
||||
case LOD_RENDER:
|
||||
contextPointer = lodRenderGlContext;
|
||||
newGlCapabilities = lodRenderGlCapabilities;
|
||||
break;
|
||||
|
||||
case MINECRAFT:
|
||||
contextPointer = minecraftGlContext;
|
||||
@@ -221,14 +275,6 @@ public class GlProxy
|
||||
|
||||
GLFW.glfwMakeContextCurrent(contextPointer);
|
||||
GL.setCapabilities(newGlCapabilities);
|
||||
|
||||
|
||||
|
||||
// used for debugging
|
||||
if (newContext == GlProxyContext.LOD_BUILDER)
|
||||
lodBuilderOwnerThread = Thread.currentThread();
|
||||
else if (newContext == GlProxyContext.NONE && currentContext == GlProxyContext.LOD_BUILDER)
|
||||
lodBuilderOwnerThread = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,8 +289,6 @@ public class GlProxy
|
||||
|
||||
if (currentContext == lodBuilderGlContext)
|
||||
return GlProxyContext.LOD_BUILDER;
|
||||
else if (currentContext == lodRenderGlContext)
|
||||
return GlProxyContext.LOD_RENDER;
|
||||
else if (currentContext == minecraftGlContext)
|
||||
return GlProxyContext.MINECRAFT;
|
||||
else if (currentContext == 0L)
|
||||
@@ -255,7 +299,7 @@ public class GlProxy
|
||||
" has a unknown OpenGl context: [" + currentContext + "]. "
|
||||
+ "Minecraft context [" + minecraftGlContext + "], "
|
||||
+ "LodBuilder context [" + lodBuilderGlContext + "], "
|
||||
+ "LodRender context [" + lodRenderGlContext + "], no context [0].");
|
||||
+ "no context [0].");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
|
||||
package com.seibel.lod.render;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.NVFogDistance;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||
import com.mojang.math.Matrix4f;
|
||||
@@ -43,6 +45,7 @@ import com.seibel.lod.objects.NearFarFogSettings;
|
||||
import com.seibel.lod.objects.RegionPos;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.proxy.GlProxy;
|
||||
import com.seibel.lod.render.shader.LodShaderProgram;
|
||||
import com.seibel.lod.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.util.LevelPosUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
@@ -52,6 +55,7 @@ import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.ShaderInstance;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
@@ -63,7 +67,7 @@ import net.minecraft.world.phys.Vec3;
|
||||
* This is where LODs are draw to the world.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 10-31-2021
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodRenderer
|
||||
{
|
||||
@@ -153,9 +157,10 @@ public class LodRenderer
|
||||
* the async process of generating the Buffers that hold those LODs.
|
||||
* @param lodDim The dimension to draw, if null doesn't replace the current dimension.
|
||||
* @param mcModelViewMatrix This matrix stack should come straight from MC's renderChunkLayer (or future equivalent) method
|
||||
* @param mcProjectionMatrix
|
||||
* @param partialTicks how far into the current tick this method was called.
|
||||
*/
|
||||
public void drawLODs(LodDimension lodDim, PoseStack mcModelViewMatrix, float partialTicks, ProfilerFiller newProfiler)
|
||||
public void drawLODs(LodDimension lodDim, PoseStack mcModelViewMatrix, Matrix4f mcProjectionMatrix, float partialTicks, ProfilerFiller newProfiler)
|
||||
{
|
||||
//=================================//
|
||||
// determine if LODs should render //
|
||||
@@ -234,28 +239,13 @@ public class LodRenderer
|
||||
else
|
||||
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
|
||||
|
||||
GL15.glDisable(GL15.GL_TEXTURE_2D);
|
||||
GL15.glEnable(GL15.GL_CULL_FACE);
|
||||
GL15.glEnable(GL15.GL_COLOR_MATERIAL);
|
||||
GL15.glEnable(GL15.GL_DEPTH_TEST);
|
||||
|
||||
// enable transparent rendering
|
||||
GL15.glBlendFunc(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL15.glEnable(GL15.GL_BLEND);
|
||||
|
||||
// disable the lights Minecraft uses
|
||||
GL15.glDisable(GL15.GL_LIGHT0);
|
||||
GL15.glDisable(GL15.GL_LIGHT1);
|
||||
|
||||
|
||||
// get the default projection matrix, so we can
|
||||
// reset it after drawing the LODs
|
||||
float[] mcProjMatrixRaw = new float[16];
|
||||
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
||||
Matrix4f mcProjectionMatrix = new Matrix4f(mcProjMatrixRaw);
|
||||
// OpenGl outputs their matrices in col,row form instead of row,col
|
||||
// (or maybe vice versa I have no idea :P)
|
||||
mcProjectionMatrix.transpose();
|
||||
|
||||
|
||||
Matrix4f modelViewMatrix = offsetTheModelViewMatrix(mcModelViewMatrix, partialTicks);
|
||||
@@ -267,19 +257,21 @@ public class LodRenderer
|
||||
farPlaneBlockDistance = LodConfig.CLIENT.graphics.qualityOption.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH;
|
||||
|
||||
|
||||
setupProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
|
||||
Matrix4f projectionMatrix = createProjectionMatrix(mcProjectionMatrix, vanillaBlockRenderedDistance, partialTicks);
|
||||
|
||||
|
||||
// commented out until we can add shaders to handle lighting
|
||||
//setupLighting(lodDim, partialTicks);
|
||||
|
||||
|
||||
// determine the current fog settings, so they can be
|
||||
// reset after drawing the LODs
|
||||
float defaultFogStartDist = GL15.glGetFloat(GL15.GL_FOG_START);
|
||||
float defaultFogEndDist = GL15.glGetFloat(GL15.GL_FOG_END);
|
||||
int defaultFogMode = GL15.glGetInteger(GL15.GL_FOG_MODE);
|
||||
int defaultFogDistance = glProxy.fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
|
||||
// // determine the current fog settings, so they can be
|
||||
// // reset after drawing the LODs
|
||||
// float defaultFogStartDist = GL15.glGetFloat(GL15.GL_FOG_START);
|
||||
// float defaultFogEndDist = GL15.glGetFloat(GL15.GL_FOG_END);
|
||||
// int defaultFogMode = GL15.glGetInteger(GL15.GL_FOG_MODE);
|
||||
// int defaultFogDistance = glProxy.fancyFogAvailable ? GL15.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV) : -1;
|
||||
|
||||
ShaderInstance mcShader = RenderSystem.getShader();
|
||||
|
||||
NearFarFogSettings fogSettings = determineFogSettings();
|
||||
|
||||
@@ -298,7 +290,8 @@ public class LodRenderer
|
||||
Camera camera = mc.getGameRenderer().getMainCamera();
|
||||
Vector3f cameraDir = camera.getLookVector();
|
||||
|
||||
boolean cullingDisabled = LodConfig.CLIENT.graphics.advancedGraphicsOption.disableDirectionalCulling.get();
|
||||
// TODO re-enable once rendering is totally working
|
||||
boolean cullingDisabled = true; //LodConfig.CLIENT.graphics.advancedGraphicsOption.disableDirectionalCulling.get();
|
||||
boolean renderBufferStorage = LodConfig.CLIENT.graphics.advancedGraphicsOption.gpuUploadMethod.get() == GpuUploadMethod.BUFFER_STORAGE && glProxy.bufferStorageSupported;
|
||||
|
||||
// used to determine what type of fog to render
|
||||
@@ -309,6 +302,31 @@ public class LodRenderer
|
||||
RegionPos vboCenterRegionPos = new RegionPos(vbosCenter);
|
||||
|
||||
|
||||
|
||||
|
||||
// can be used when testing shaders
|
||||
//glProxy.createShaderProgram();
|
||||
|
||||
|
||||
LodShaderProgram shaderProgram = glProxy.lodShaderProgram;
|
||||
shaderProgram.use();
|
||||
|
||||
|
||||
// determine the VertexArrayObject's element positions
|
||||
int posAttrib = shaderProgram.getAttributeLocation("vPosition");
|
||||
shaderProgram.enableVertexAttribute(posAttrib);
|
||||
int colAttrib = shaderProgram.getAttributeLocation("color");
|
||||
shaderProgram.enableVertexAttribute(colAttrib);
|
||||
|
||||
|
||||
// upload the required uniforms
|
||||
int mvmUniform = shaderProgram.getUniformLocation("modelViewMatrix");
|
||||
shaderProgram.setUniform(mvmUniform, modelViewMatrix);
|
||||
int projUniform = shaderProgram.getUniformLocation("projectionMatrix");
|
||||
shaderProgram.setUniform(projUniform, projectionMatrix);
|
||||
|
||||
|
||||
// render each of the buffers
|
||||
for (int x = 0; x < vbos.length; x++)
|
||||
{
|
||||
for (int z = 0; z < vbos.length; z++)
|
||||
@@ -319,19 +337,19 @@ public class LodRenderer
|
||||
|
||||
if (cullingDisabled || RenderUtil.isRegionInViewFrustum(camera.getBlockPosition(), cameraDir, vboPos.blockPos()))
|
||||
{
|
||||
if ((x > halfWidth - quarterWidth && x < halfWidth + quarterWidth)
|
||||
&& (z > halfWidth - quarterWidth && z < halfWidth + quarterWidth))
|
||||
setupFog(fogSettings.near.distance, fogSettings.near.quality);
|
||||
else
|
||||
setupFog(fogSettings.far.distance, fogSettings.far.quality);
|
||||
|
||||
// TODO add fog to the fragment shader
|
||||
// if ((x > halfWidth - quarterWidth && x < halfWidth + quarterWidth)
|
||||
// && (z > halfWidth - quarterWidth && z < halfWidth + quarterWidth))
|
||||
// setupFog(fogSettings.near.distance, fogSettings.near.quality);
|
||||
// else
|
||||
// setupFog(fogSettings.far.distance, fogSettings.far.quality);
|
||||
|
||||
if (storageBufferIds != null && renderBufferStorage)
|
||||
for (int i = 0; i < storageBufferIds[x][z].length; i++)
|
||||
drawArrays(modelViewMatrix, storageBufferIds[x][z][i], vbos[x][z][i].indexCount);
|
||||
drawArrays(storageBufferIds[x][z][i], vbos[x][z][i].indexCount, posAttrib, colAttrib);
|
||||
else
|
||||
for (int i = 0; i < vbos[x][z].length; i++)
|
||||
drawArrays(modelViewMatrix, vbos[x][z][i].vertextBufferId, vbos[x][z][i].indexCount);
|
||||
drawArrays(vbos[x][z][i].vertextBufferId, vbos[x][z][i].indexCount, posAttrib, colAttrib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,23 +366,11 @@ public class LodRenderer
|
||||
profiler.popPush("LOD cleanup");
|
||||
|
||||
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
|
||||
GL15.glEnable(GL15.GL_TEXTURE_2D);
|
||||
GL15.glDisable(LOD_GL_LIGHT_NUMBER);
|
||||
GL15.glDisable(GL15.GL_BLEND);
|
||||
// re-enable the lights Minecraft uses
|
||||
GL15.glEnable(GL15.GL_LIGHT0);
|
||||
GL15.glEnable(GL15.GL_LIGHT1);
|
||||
GL15.glDisable(GL15.GL_LIGHTING);
|
||||
GL15.glDisable(GL15.GL_BLEND); // TODO: what should this be reset to?
|
||||
|
||||
// reset the fog settings so the normal chunks
|
||||
// will be drawn correctly
|
||||
cleanupFog(fogSettings, defaultFogStartDist, defaultFogEndDist, defaultFogMode, defaultFogDistance);
|
||||
RenderSystem.setShader(() -> mcShader);
|
||||
|
||||
// reset the projection matrix so anything drawn after
|
||||
// the LODs will use the correct projection matrix
|
||||
gameRender.resetProjectionMatrix(mcProjectionMatrix);
|
||||
|
||||
// clear the depth buffer so anything drawn is drawn
|
||||
// clear the depth buffer so everything drawn is drawn
|
||||
// over the LODs
|
||||
GL15.glClear(GL15.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
@@ -374,28 +380,29 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
/** This is where the actual drawing happens. */
|
||||
private void drawArrays(Matrix4f modelViewMatrix, int glBufferId, int vertexCount)
|
||||
private void drawArrays(int glBufferId, int vertexCount, int posAttrib, int colAttrib)
|
||||
{
|
||||
if (glBufferId == 0)
|
||||
return;
|
||||
|
||||
// pre draw setup
|
||||
// can be used to check for OpenGL errors
|
||||
// int error = GL15.glGetError();
|
||||
// ClientProxy.LOGGER.info(Integer.toHexString(error));
|
||||
|
||||
|
||||
// bind the buffer we are going to draw
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, glBufferId);
|
||||
LodUtil.LOD_VERTEX_FORMAT.setupBufferState();
|
||||
|
||||
// set up the model view matrix
|
||||
// GL15.glPushMatrix(); // matrix code is only available in OpenGL 3.2 and lower
|
||||
// GL15.glLoadIdentity();
|
||||
FloatBuffer matrixBuffer = FloatBuffer.allocate(16);
|
||||
modelViewMatrix.store(matrixBuffer);
|
||||
// GL15.glMultMatrixf(matrixBuffer);
|
||||
|
||||
GL15.glDrawArrays(GL15.GL_QUADS, 0, vertexCount);
|
||||
|
||||
// post draw cleanup
|
||||
// GL15.glPopMatrix();
|
||||
// GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
LodUtil.LOD_VERTEX_FORMAT.clearBufferState();
|
||||
GL30.glBindVertexArray(GlProxy.getInstance().vertexArrayObjectId);
|
||||
|
||||
// let OpenGL know how our buffer is set up
|
||||
int vertexByteCount = (Float.BYTES * 3) + (Byte.BYTES * 4);
|
||||
GL20.glEnableVertexAttribArray(posAttrib);
|
||||
GL20.glVertexAttribPointer(posAttrib, 3, GL15.GL_FLOAT, false, vertexByteCount, 0);
|
||||
GL20.glEnableVertexAttribArray(colAttrib);
|
||||
GL20.glVertexAttribPointer(colAttrib, 4, GL15.GL_UNSIGNED_BYTE, true, vertexByteCount, Float.BYTES * 3);
|
||||
|
||||
// draw the LODs
|
||||
GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, vertexCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -552,15 +559,15 @@ public class LodRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new projection matrix and send it over to the GPU
|
||||
* create and return a new projection matrix based on MC's projection matrix
|
||||
* @param currentProjectionMatrix this is Minecraft's current projection matrix
|
||||
* @param vanillaBlockRenderedDistance Minecraft's vanilla far plane distance
|
||||
* @param partialTicks how many ticks into the frame we are
|
||||
*/
|
||||
private void setupProjectionMatrix(Matrix4f currentProjectionMatrix, float vanillaBlockRenderedDistance, float partialTicks)
|
||||
private Matrix4f createProjectionMatrix(Matrix4f currentProjectionMatrix, float vanillaBlockRenderedDistance, float partialTicks)
|
||||
{
|
||||
// create the new projection matrix
|
||||
Matrix4f lodPoj =
|
||||
Matrix4f lodProj =
|
||||
Matrix4f.perspective(
|
||||
getFov(partialTicks, true),
|
||||
(float) this.mc.getWindow().getScreenWidth() / (float) this.mc.getWindow().getScreenHeight(),
|
||||
@@ -586,10 +593,9 @@ public class LodRenderer
|
||||
|
||||
// edit the lod projection to match Minecraft's
|
||||
// (so the LODs line up with the real world)
|
||||
lodPoj.multiply(distortionMatrix);
|
||||
lodProj.multiply(distortionMatrix);
|
||||
|
||||
// send the projection over to the GPU
|
||||
gameRender.resetProjectionMatrix(lodPoj);
|
||||
return lodProj;
|
||||
}
|
||||
|
||||
|
||||
@@ -678,7 +684,7 @@ public class LodRenderer
|
||||
lodBufferBuilder.destroyBuffers();
|
||||
}
|
||||
|
||||
|
||||
// TODO move this into the MC wrapper
|
||||
private double getFov(float partialTicks, boolean useFovSetting)
|
||||
{
|
||||
return mc.getGameRenderer().getFov(mc.getGameRenderer().getMainCamera(), partialTicks, useFovSetting);
|
||||
@@ -787,8 +793,6 @@ public class LodRenderer
|
||||
/** Determines if the LODs should have a fullRegen or partialRegen */
|
||||
private void determineIfLodsShouldRegenerate(LodDimension lodDim, float partialTicks)
|
||||
{
|
||||
|
||||
|
||||
short chunkRenderDistance = (short) mc.getRenderDistance();
|
||||
int vanillaRenderedChunksWidth = chunkRenderDistance * 2 + 2;
|
||||
|
||||
@@ -943,6 +947,8 @@ public class LodRenderer
|
||||
vanillaRenderedChunksChanged = true;
|
||||
vanillaRenderedChunksEmptySkip = true;
|
||||
}
|
||||
|
||||
vanillaRenderedChunks = new boolean[vanillaRenderedChunksWidth][vanillaRenderedChunksWidth];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.render.shader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
|
||||
/**
|
||||
* This object holds a OpenGL reference to a shader
|
||||
* and allows for reading in and compiling a shader file.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodShader
|
||||
{
|
||||
/** OpenGL shader ID */
|
||||
public final int id;
|
||||
|
||||
|
||||
|
||||
/** Creates a shader with specified type. */
|
||||
public LodShader(int type)
|
||||
{
|
||||
id = GL20.glCreateShader(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads a shader from file.
|
||||
*
|
||||
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* @param path File path of the shader
|
||||
* @param absoluteFilePath If false the file path is relative to the resource jar folder.
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public static LodShader loadShader(int type, String path, boolean absoluteFilePath) throws Exception
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
// open the file
|
||||
InputStream in = absoluteFilePath ? new FileInputStream(path) : LodShader.class.getClassLoader().getResourceAsStream(path);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
// read in the file
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
stringBuilder.append(line).append("\n");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
ClientProxy.LOGGER.error("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
|
||||
}
|
||||
CharSequence shaderFileSource = stringBuilder.toString();
|
||||
|
||||
return createShader(type, shaderFileSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shader with the specified type and source.
|
||||
*
|
||||
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* @param source Source of the shader
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public static LodShader createShader(int type, CharSequence source) throws Exception
|
||||
{
|
||||
LodShader shader = new LodShader(type);
|
||||
GL20.glShaderSource(shader.id, source);
|
||||
shader.compile();
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the shader and checks it's status afterwards.
|
||||
* @throws Exception if the shader fails to compile
|
||||
*/
|
||||
public void compile() throws Exception
|
||||
{
|
||||
GL20.glCompileShader(id);
|
||||
|
||||
// check if the shader compiled
|
||||
int status = GL20.glGetShaderi(id, GL20.GL_COMPILE_STATUS);
|
||||
if (status != GL20.GL_TRUE)
|
||||
throw new Exception(GL20.glGetShaderInfoLog(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizon mod (formerly the LOD Mod),
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.render.shader;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
/**
|
||||
* This object holds the reference to a OpenGL shader program
|
||||
* and contains a few methods that can be used with OpenGL shader programs.
|
||||
* The reason for many of these simple wrapper methods is as reminders of what
|
||||
* can (and needs to be) done with a shader program.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class LodShaderProgram
|
||||
{
|
||||
/** Stores the handle of the program. */
|
||||
public final int id;
|
||||
|
||||
/** Creates a shader program. */
|
||||
public LodShaderProgram()
|
||||
{
|
||||
id = GL20.glCreateProgram();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Calls GL20.glUseProgram(this.id) */
|
||||
public void use()
|
||||
{
|
||||
GL20.glUseProgram(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glAttachShader(this.id, shader.id)
|
||||
*
|
||||
* @param shader Shader to get attached
|
||||
*/
|
||||
public void attachShader(LodShader shader)
|
||||
{
|
||||
GL20.glAttachShader(this.id, shader.id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Links the shader program to the current OpenGL context.
|
||||
* @throws Exception Exception if the program failed to link
|
||||
*/
|
||||
public void link() throws Exception
|
||||
{
|
||||
GL20.glLinkProgram(this.id);
|
||||
checkLinkStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the program was linked successfully.
|
||||
* @throws Exception if the program failed to link
|
||||
*/
|
||||
public void checkLinkStatus() throws Exception
|
||||
{
|
||||
int status = GL20.glGetProgrami(this.id, GL20.GL_LINK_STATUS);
|
||||
if (status != GL20.GL_TRUE)
|
||||
throw new Exception(GL20.glGetProgramInfoLog(this.id));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the location of an attribute variable with specified name.
|
||||
* Calls GL20.glGetAttribLocation(id, name)
|
||||
*
|
||||
* @param name Attribute name
|
||||
*
|
||||
* @return Location of the attribute
|
||||
*/
|
||||
public int getAttributeLocation(CharSequence name)
|
||||
{
|
||||
return GL20.glGetAttribLocation(id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glEnableVertexAttribArray(location)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
*/
|
||||
public void enableVertexAttribute(int location)
|
||||
{
|
||||
GL20.glEnableVertexAttribArray(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls GL20.glDisableVertexAttribArray(location)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
*/
|
||||
public void disableVertexAttribute(int location)
|
||||
{
|
||||
GL20.glDisableVertexAttribArray(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertex attribute pointer.
|
||||
* Calls GL20.glVertexAttribPointer(...)
|
||||
*
|
||||
* @param location Location of the vertex attribute
|
||||
* @param size Number of values per vertex
|
||||
* @param stride Offset between consecutive generic vertex attributes in
|
||||
* bytes
|
||||
* @param offset Offset of the first component of the first generic vertex
|
||||
* attribute in bytes
|
||||
*/
|
||||
public void pointVertexAttribute(int location, int size, int stride, int offset)
|
||||
{
|
||||
GL20.glVertexAttribPointer(location, size, GL20.GL_FLOAT, false, stride, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of an uniform variable with specified name.
|
||||
* Calls GL20.glGetUniformLocation(id, name)
|
||||
*
|
||||
* @param name Uniform name
|
||||
*
|
||||
* @return -1 = error value, 0 = first value, 1 = second value, etc.
|
||||
*/
|
||||
public int getUniformLocation(CharSequence name)
|
||||
{
|
||||
return GL20.glGetUniformLocation(id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform variable for specified location.
|
||||
*
|
||||
* @param location Uniform location
|
||||
* @param value Value to set
|
||||
*/
|
||||
public void setUniform(int location, int value)
|
||||
{
|
||||
GL20.glUniform1i(location, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the uniform variable for specified location.
|
||||
*
|
||||
* @param location Uniform location
|
||||
* @param value Value to set
|
||||
*/
|
||||
public void setUniform(int location, Matrix4f value)
|
||||
{
|
||||
try (MemoryStack stack = MemoryStack.stackPush())
|
||||
{
|
||||
FloatBuffer buffer = stack.mallocFloat(4 * 4);
|
||||
value.store(buffer);
|
||||
GL20.glUniformMatrix4fv(location, false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#version 150 core
|
||||
|
||||
in vec4 vertexColor;
|
||||
//in vec2 textureCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
//uniform sampler2D texImage;
|
||||
|
||||
|
||||
/**
|
||||
* Fragment Shader
|
||||
*
|
||||
* author: James Seibel
|
||||
* version: 11-8-2021
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
// TODO: add a white texture to support Optifine shaders
|
||||
//vec4 textureColor = texture(texImage, textureCoord);
|
||||
//fragColor = vertexColor * textureColor;
|
||||
|
||||
|
||||
// very simple fragment shader, just return the vertix's color
|
||||
fragColor = vertexColor;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#version 150 core
|
||||
|
||||
in vec3 vPosition;
|
||||
in vec4 color;
|
||||
|
||||
out vec4 vertexColor;
|
||||
//out vec2 textureCoord;
|
||||
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
|
||||
/**
|
||||
* Vertex Shader
|
||||
*
|
||||
* author: James Seibel
|
||||
* version: 11-8-2021
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
// TODO: add a simple white texture to support Optifine shaders
|
||||
//textureCoord = textureCoord;
|
||||
|
||||
vertexColor = color;
|
||||
|
||||
// the vPosition needs to be converted to a vec4 so it can be multiplied
|
||||
// by the 4x4 matrices
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user