materialMap = new HashMap<>();
-
- private VulkanModRenderer() {}
-
- @Override
- public MeshBuilder meshBuilder() {
- return new MeshBuilderImpl();
- }
-
- @Override
- public MaterialFinder materialFinder() {
- return new MaterialFinderImpl();
- }
-
- @Override
- public RenderMaterial materialById(ResourceLocation id) {
- return materialMap.get(id);
- }
-
- @Override
- public boolean registerMaterial(ResourceLocation id, RenderMaterial material) {
- if (materialMap.containsKey(id)) return false;
-
- // cast to prevent acceptance of impostor implementations
- materialMap.put(id, (RenderMaterialImpl) material);
- return true;
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/ColorHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/ColorHelper.java
deleted file mode 100644
index 2723331b2..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/ColorHelper.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.helper;
-
-import java.nio.ByteOrder;
-
-/**
- * Static routines of general utility for renderer implementations.
- * Renderers are not required to use these helpers, but they were
- * designed to be usable without the default renderer.
- */
-public abstract class ColorHelper {
- private ColorHelper() { }
-
- private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
-
- /** Component-wise multiply. Components need to be in same order in both inputs! */
- public static int multiplyColor(int color1, int color2) {
- if (color1 == -1) {
- return color2;
- } else if (color2 == -1) {
- return color1;
- }
-
- final int alpha = ((color1 >>> 24) & 0xFF) * ((color2 >>> 24) & 0xFF) / 0xFF;
- final int red = ((color1 >>> 16) & 0xFF) * ((color2 >>> 16) & 0xFF) / 0xFF;
- final int green = ((color1 >>> 8) & 0xFF) * ((color2 >>> 8) & 0xFF) / 0xFF;
- final int blue = (color1 & 0xFF) * (color2 & 0xFF) / 0xFF;
-
- return (alpha << 24) | (red << 16) | (green << 8) | blue;
- }
-
- /** Multiplies three lowest components by shade. High byte (usually alpha) unchanged. */
- public static int multiplyRGB(int color, float shade) {
- final int alpha = ((color >>> 24) & 0xFF);
- final int red = (int) (((color >>> 16) & 0xFF) * shade);
- final int green = (int) (((color >>> 8) & 0xFF) * shade);
- final int blue = (int) ((color & 0xFF) * shade);
-
- return (alpha << 24) | (red << 16) | (green << 8) | blue;
- }
-
- /**
- * Component-wise max.
- */
- public static int maxBrightness(int b0, int b1) {
- if (b0 == 0) return b1;
- if (b1 == 0) return b0;
-
- return Math.max(b0 & 0xFFFF, b1 & 0xFFFF) | Math.max(b0 & 0xFFFF0000, b1 & 0xFFFF0000);
- }
-
- /*
- Renderer color format: ARGB (0xAARRGGBB)
- Vanilla color format (little endian): ABGR (0xAABBGGRR)
- Vanilla color format (big endian): RGBA (0xRRGGBBAA)
-
- Why does the vanilla color format change based on endianness?
- See VertexConsumer#quad. Quad data is loaded as integers into
- a native byte order buffer. Color is read directly from bytes
- 12, 13, 14 of each vertex. A different byte order will yield
- different results.
-
- The renderer always uses ARGB because the API color methods
- always consume and return ARGB. Vanilla block and item colors
- also use ARGB.
- */
-
- /**
- * Converts from ARGB color to ABGR color if little endian or RGBA color if big endian.
- */
- public static int toVanillaColor(int color) {
- if (color == -1) {
- return -1;
- }
-
- if (BIG_ENDIAN) {
- // ARGB to RGBA
- return ((color & 0x00FFFFFF) << 8) | ((color & 0xFF000000) >>> 24);
- } else {
- // ARGB to ABGR
- return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
- }
- }
-
- /**
- * Converts to ARGB color from ABGR color if little endian or RGBA color if big endian.
- */
- public static int fromVanillaColor(int color) {
- if (color == -1) {
- return -1;
- }
-
- if (BIG_ENDIAN) {
- // RGBA to ARGB
- return ((color & 0xFFFFFF00) >>> 8) | ((color & 0x000000FF) << 24);
- } else {
- // ABGR to ARGB
- return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
- }
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/GeometryHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/GeometryHelper.java
deleted file mode 100644
index 66e8a805e..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/GeometryHelper.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.helper;
-
-import static net.minecraft.util.Mth.equal;
-
-import org.joml.Vector3f;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.core.Direction;
-import net.minecraft.core.Direction.Axis;
-import net.minecraft.core.Direction.AxisDirection;
-
-/**
- * Static routines of general utility for renderer implementations.
- * Renderers are not required to use these helpers, but they were
- * designed to be usable without the default renderer.
- */
-public abstract class GeometryHelper {
- private GeometryHelper() { }
-
- /** set when a quad touches all four corners of a unit cube. */
- public static final int CUBIC_FLAG = 1;
-
- /** set when a quad is parallel to (but not necessarily on) a its light face. */
- public static final int AXIS_ALIGNED_FLAG = CUBIC_FLAG << 1;
-
- /** set when a quad is coplanar with its light face. Implies {@link #AXIS_ALIGNED_FLAG} */
- public static final int LIGHT_FACE_FLAG = AXIS_ALIGNED_FLAG << 1;
-
- /** how many bits quad header encoding should reserve for encoding geometry flags. */
- public static final int FLAG_BIT_COUNT = 3;
-
- private static final float EPS_MIN = 0.0001f;
- private static final float EPS_MAX = 1.0f - EPS_MIN;
-
- /**
- * Analyzes the quad and returns a value with some combination
- * of {@link #AXIS_ALIGNED_FLAG}, {@link #LIGHT_FACE_FLAG} and {@link #CUBIC_FLAG}.
- * Intended use is to optimize lighting when the geometry is regular.
- * Expects convex quads with all points co-planar.
- */
- public static int computeShapeFlags(QuadView quad) {
- Direction lightFace = quad.lightFace();
- int bits = 0;
-
- if (isQuadParallelToFace(lightFace, quad)) {
- bits |= AXIS_ALIGNED_FLAG;
-
- if (isParallelQuadOnFace(lightFace, quad)) {
- bits |= LIGHT_FACE_FLAG;
- }
- }
-
- if (isQuadCubic(lightFace, quad)) {
- bits |= CUBIC_FLAG;
- }
-
- return bits;
- }
-
- /**
- * Returns true if quad is parallel to the given face.
- * Does not validate quad winding order.
- * Expects convex quads with all points co-planar.
- */
- public static boolean isQuadParallelToFace(Direction face, QuadView quad) {
- int i = face.getAxis().ordinal();
- final float val = quad.posByIndex(0, i);
- return equal(val, quad.posByIndex(1, i)) && equal(val, quad.posByIndex(2, i)) && equal(val, quad.posByIndex(3, i));
- }
-
- /**
- * True if quad - already known to be parallel to a face - is actually coplanar with it.
- * For compatibility with vanilla resource packs, also true if quad is outside the face.
- *
- * Test will be unreliable if not already parallel, use {@link #isQuadParallelToFace(Direction, QuadView)}
- * for that purpose. Expects convex quads with all points co-planar.
- */
- public static boolean isParallelQuadOnFace(Direction lightFace, QuadView quad) {
- final float x = quad.posByIndex(0, lightFace.getAxis().ordinal());
- return lightFace.getAxisDirection() == AxisDirection.POSITIVE ? x >= EPS_MAX : x <= EPS_MIN;
- }
-
- /**
- * Returns true if quad is truly a quad (not a triangle) and fills a full block cross-section.
- * If known to be true, allows use of a simpler/faster AO lighting algorithm.
- *
- *
Does not check if quad is actually coplanar with the light face, nor does it check that all
- * quad vertices are coplanar with each other.
- *
- *
Expects convex quads with all points co-planar.
- */
- public static boolean isQuadCubic(Direction lightFace, QuadView quad) {
- int a, b;
-
- switch (lightFace) {
- case EAST:
- case WEST:
- a = 1;
- b = 2;
- break;
- case UP:
- case DOWN:
- a = 0;
- b = 2;
- break;
- case SOUTH:
- case NORTH:
- a = 1;
- b = 0;
- break;
- default:
- // handle WTF case
- return false;
- }
-
- return confirmSquareCorners(a, b, quad);
- }
-
- /**
- * Used by {@link #isQuadCubic(Direction, QuadView)}.
- * True if quad touches all four corners of unit square.
- *
- *
For compatibility with resource packs that contain models with quads exceeding
- * block boundaries, considers corners outside the block to be at the corners.
- */
- private static boolean confirmSquareCorners(int aCoordinate, int bCoordinate, QuadView quad) {
- int flags = 0;
-
- for (int i = 0; i < 4; i++) {
- final float a = quad.posByIndex(i, aCoordinate);
- final float b = quad.posByIndex(i, bCoordinate);
-
- if (a <= EPS_MIN) {
- if (b <= EPS_MIN) {
- flags |= 1;
- } else if (b >= EPS_MAX) {
- flags |= 2;
- } else {
- return false;
- }
- } else if (a >= EPS_MAX) {
- if (b <= EPS_MIN) {
- flags |= 4;
- } else if (b >= EPS_MAX) {
- flags |= 8;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
- return flags == 15;
- }
-
- /**
- * Identifies the face to which the quad is most closely aligned.
- * This mimics the value that {@link BakedQuad#getDirection()} returns, and is
- * used in the vanilla renderer for all diffuse lighting.
- *
- *
Derived from the quad face normal and expects convex quads with all points co-planar.
- */
- public static Direction lightFace(QuadView quad) {
- final Vector3f normal = quad.faceNormal();
- switch (GeometryHelper.longestAxis(normal)) {
- case X:
- return normal.x() > 0 ? Direction.EAST : Direction.WEST;
-
- case Y:
- return normal.y() > 0 ? Direction.UP : Direction.DOWN;
-
- case Z:
- return normal.z() > 0 ? Direction.SOUTH : Direction.NORTH;
-
- default:
- // handle WTF case
- return Direction.UP;
- }
- }
-
- /**
- * Simple 4-way compare, doesn't handle NaN values.
- */
- public static float min(float a, float b, float c, float d) {
- final float x = a < b ? a : b;
- final float y = c < d ? c : d;
- return x < y ? x : y;
- }
-
- /**
- * Simple 4-way compare, doesn't handle NaN values.
- */
- public static float max(float a, float b, float c, float d) {
- final float x = a > b ? a : b;
- final float y = c > d ? c : d;
- return x > y ? x : y;
- }
-
- /**
- * @see #longestAxis(float, float, float)
- */
- public static Axis longestAxis(Vector3f vec) {
- return longestAxis(vec.x(), vec.y(), vec.z());
- }
-
- /**
- * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector.
- */
- public static Axis longestAxis(float normalX, float normalY, float normalZ) {
- Axis result = Axis.Y;
- float longest = Math.abs(normalY);
- float a = Math.abs(normalX);
-
- if (a > longest) {
- result = Axis.X;
- longest = a;
- }
-
- return Math.abs(normalZ) > longest
- ? Axis.Z : result;
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/NormalHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/NormalHelper.java
deleted file mode 100644
index bf6deebb7..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/NormalHelper.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.helper;
-
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import net.vulkanmod.render.vertex.format.I32_SNorm;
-import org.jetbrains.annotations.NotNull;
-import org.joml.Vector3f;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-import net.minecraft.core.Direction;
-import net.minecraft.core.Vec3i;
-import net.minecraft.util.Mth;
-
-/**
- * Static routines of general utility for renderer implementations.
- * Renderers are not required to use these helpers, but they were
- * designed to be usable without the default renderer.
- */
-public abstract class NormalHelper {
- private NormalHelper() { }
-
- private static final float PACK = 127.0f;
- private static final float UNPACK = 1.0f / PACK;
-
- /**
- * Stores a normal plus an extra value as a quartet of signed bytes.
- * This is the same normal format that vanilla rendering expects.
- * The extra value is for use by shaders.
- */
- public static int packNormal(float x, float y, float z, float w) {
- x = Mth.clamp(x, -1, 1);
- y = Mth.clamp(y, -1, 1);
- z = Mth.clamp(z, -1, 1);
- w = Mth.clamp(w, -1, 1);
-
- return ((int) (x * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16) | (((int) (w * PACK) & 0xFF) << 24);
- }
-
- /**
- * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type.
- */
- public static int packNormal(Vector3f normal, float w) {
- return packNormal(normal.x(), normal.y(), normal.z(), w);
- }
-
- /**
- * Like {@link #packNormal(float, float, float, float)}, but without a {@code w} value.
- */
- public static int packNormal(float x, float y, float z) {
- x = Mth.clamp(x, -1, 1);
- y = Mth.clamp(y, -1, 1);
- z = Mth.clamp(z, -1, 1);
-
- return ((int) (x * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16);
- }
-
- /**
- * Like {@link #packNormal(Vector3f, float)}, but without a {@code w} value.
- */
- public static int packNormal(Vector3f normal) {
- return packNormal(normal.x(), normal.y(), normal.z());
- }
-
- public static float unpackNormalX(int packedNormal) {
- return ((byte) (packedNormal & 0xFF)) * UNPACK;
- }
-
- public static float unpackNormalY(int packedNormal) {
- return ((byte) ((packedNormal >>> 8) & 0xFF)) * UNPACK;
- }
-
- public static float unpackNormalZ(int packedNormal) {
- return ((byte) ((packedNormal >>> 16) & 0xFF)) * UNPACK;
- }
-
- public static float unpackNormalW(int packedNormal) {
- return ((byte) ((packedNormal >>> 24) & 0xFF)) * UNPACK;
- }
-
- public static void unpackNormal(int packedNormal, Vector3f target) {
- target.set(unpackNormalX(packedNormal), unpackNormalY(packedNormal), unpackNormalZ(packedNormal));
- }
-
- /**
- * Computes the face normal of the given quad and saves it in the provided non-null vector.
- * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that
- * face and, if so, use the standard normal for that face direction.
- *
- *
Will work with triangles also. Assumes counter-clockwise winding order, which is the norm.
- * Expects convex quads with all points co-planar.
- */
- public static void computeFaceNormal(@NotNull Vector3f saveTo, QuadView q) {
- final Direction nominalFace = q.nominalFace();
-
- if (nominalFace != null && GeometryHelper.isQuadParallelToFace(nominalFace, q)) {
- Vec3i vec = nominalFace.getNormal();
- saveTo.set(vec.getX(), vec.getY(), vec.getZ());
- return;
- }
-
- final float x0 = q.x(0);
- final float y0 = q.y(0);
- final float z0 = q.z(0);
- final float x1 = q.x(1);
- final float y1 = q.y(1);
- final float z1 = q.z(1);
- final float x2 = q.x(2);
- final float y2 = q.y(2);
- final float z2 = q.z(2);
- final float x3 = q.x(3);
- final float y3 = q.y(3);
- final float z3 = q.z(3);
-
- final float dx0 = x2 - x0;
- final float dy0 = y2 - y0;
- final float dz0 = z2 - z0;
- final float dx1 = x3 - x1;
- final float dy1 = y3 - y1;
- final float dz1 = z3 - z1;
-
- float normX = dy0 * dz1 - dz0 * dy1;
- float normY = dz0 * dx1 - dx0 * dz1;
- float normZ = dx0 * dy1 - dy0 * dx1;
-
- float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
-
- if (l != 0) {
- normX /= l;
- normY /= l;
- normZ /= l;
- }
-
- saveTo.set(normX, normY, normZ);
- }
-
- public static int computePackedNormal(ModelQuadView q) {
- final float x0 = q.getX(0);
- final float y0 = q.getY(0);
- final float z0 = q.getZ(0);
- final float x1 = q.getX(1);
- final float y1 = q.getY(1);
- final float z1 = q.getZ(1);
- final float x2 = q.getX(2);
- final float y2 = q.getY(2);
- final float z2 = q.getZ(2);
- final float x3 = q.getX(3);
- final float y3 = q.getY(3);
- final float z3 = q.getZ(3);
-
- final float dx0 = x2 - x0;
- final float dy0 = y2 - y0;
- final float dz0 = z2 - z0;
- final float dx1 = x3 - x1;
- final float dy1 = y3 - y1;
- final float dz1 = z3 - z1;
-
- float normX = dy0 * dz1 - dz0 * dy1;
- float normY = dz0 * dx1 - dx0 * dz1;
- float normZ = dx0 * dy1 - dy0 * dx1;
-
- float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
-
- if (l != 0) {
- normX /= l;
- normY /= l;
- normZ /= l;
- }
-
- return I32_SNorm.packNormal(normX, normY, normZ);
- }
-
- public static int packedNormalFromDirection(Direction direction) {
- Vec3i normal = direction.getNormal();
-
- return I32_SNorm.packNormal(normal.getX(), normal.getY(), normal.getZ());
- }
-
- public static void unpackNormalTo(int packedNormal, Vector3f normal) {
- normal.set(I32_SNorm.unpackX(packedNormal), I32_SNorm.unpackY(packedNormal), I32_SNorm.unpackZ(packedNormal));
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/TextureHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/TextureHelper.java
deleted file mode 100644
index bc622cd92..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/helper/TextureHelper.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.helper;
-
-import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
-import net.minecraft.client.renderer.texture.TextureAtlasSprite;
-import net.minecraft.core.Direction;
-
-/**
- * Handles most texture-baking use cases for model loaders and model libraries
- * via {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. Also used by the API
- * itself to implement automatic block-breaking models for enhanced models.
- */
-public class TextureHelper {
- private TextureHelper() { }
-
- private static final float NORMALIZER = 1f / 16f;
-
- /**
- * Bakes textures in the provided vertex data, handling UV locking,
- * rotation, interpolation, etc. Textures must not be already baked.
- */
- public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, int bakeFlags) {
- if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) {
- // Assigns normalized UV coordinates based on vertex positions
- applyModifier(quad, UVLOCKERS[quad.nominalFace().get3DDataValue()]);
- } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { // flag is NOT set, UVs are assumed to not be normalized yet as is the default, normalize through dividing by 16
- // Scales from 0-16 to 0-1
- applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER));
- }
-
- final int rotation = bakeFlags & 3;
-
- if (rotation != 0) {
- // Rotates texture around the center of sprite.
- // Assumes normalized coordinates.
- applyModifier(quad, ROTATIONS[rotation]);
- }
-
- if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) {
- // Inverts U coordinates. Assumes normalized (0-1) values.
- applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i)));
- }
-
- if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) {
- // Inverts V coordinates. Assumes normalized (0-1) values.
- applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i)));
- }
-
- interpolate(quad, sprite);
- }
-
- /**
- * Faster than sprite method. Sprite computes span and normalizes inputs each call,
- * so we'd have to denormalize before we called, only to have the sprite renormalize immediately.
- */
- private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) {
- final float uMin = sprite.getU0();
- final float uSpan = sprite.getU1() - uMin;
- final float vMin = sprite.getV0();
- final float vSpan = sprite.getV1() - vMin;
-
- for (int i = 0; i < 4; i++) {
- q.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan);
- }
- }
-
- @FunctionalInterface
- private interface VertexModifier {
- void apply(MutableQuadView quad, int vertexIndex);
- }
-
- private static void applyModifier(MutableQuadView quad, VertexModifier modifier) {
- for (int i = 0; i < 4; i++) {
- modifier.apply(quad, i);
- }
- }
-
- private static final VertexModifier[] ROTATIONS = new VertexModifier[] {
- null,
- (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), //90
- (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), //180
- (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270
- };
-
- private static final VertexModifier[] UVLOCKERS = new VertexModifier[6];
-
- static {
- UVLOCKERS[Direction.EAST.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i));
- UVLOCKERS[Direction.WEST.get3DDataValue()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i));
- UVLOCKERS[Direction.NORTH.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i));
- UVLOCKERS[Direction.SOUTH.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i));
- UVLOCKERS[Direction.DOWN.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i));
- UVLOCKERS[Direction.UP.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), q.z(i));
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialFinderImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialFinderImpl.java
deleted file mode 100644
index 91b510452..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialFinderImpl.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.material;
-
-import java.util.Objects;
-
-import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
-import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
-import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
-import net.fabricmc.fabric.api.util.TriState;
-
-public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFinder {
- private static int defaultBits = 0;
-
- static {
- MaterialFinderImpl finder = new MaterialFinderImpl();
- finder.ambientOcclusion(TriState.DEFAULT);
- finder.glint(TriState.DEFAULT);
- defaultBits = finder.bits;
-
- if (!areBitsValid(defaultBits)) {
- throw new AssertionError("Default MaterialFinder bits are not valid!");
- }
- }
-
- public MaterialFinderImpl() {
- super(defaultBits);
- }
-
- @Override
- public MaterialFinder blendMode(BlendMode blendMode) {
- Objects.requireNonNull(blendMode, "BlendMode may not be null");
-
- bits = (bits & ~BLEND_MODE_MASK) | (blendMode.ordinal() << BLEND_MODE_BIT_OFFSET);
- return this;
- }
-
- @Override
- public MaterialFinder disableColorIndex(boolean disable) {
- bits = disable ? (bits | COLOR_DISABLE_FLAG) : (bits & ~COLOR_DISABLE_FLAG);
- return this;
- }
-
- @Override
- public MaterialFinder emissive(boolean isEmissive) {
- bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG);
- return this;
- }
-
- @Override
- public MaterialFinder disableDiffuse(boolean disable) {
- bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG);
- return this;
- }
-
- @Override
- public MaterialFinder ambientOcclusion(TriState mode) {
- Objects.requireNonNull(mode, "ambient occlusion TriState may not be null");
-
- bits = (bits & ~AO_MASK) | (mode.ordinal() << AO_BIT_OFFSET);
- return this;
- }
-
- @Override
- public MaterialFinder glint(TriState mode) {
- Objects.requireNonNull(mode, "glint TriState may not be null");
-
- bits = (bits & ~GLINT_MASK) | (mode.ordinal() << GLINT_BIT_OFFSET);
- return this;
- }
-
- @Override
- public MaterialFinder shadeMode(ShadeMode mode) {
- Objects.requireNonNull(mode, "ShadeMode may not be null");
-
- bits = (bits & ~SHADE_MODE_MASK) | (mode.ordinal() << SHADE_MODE_BIT_OFFSET);
- return this;
- }
-
- @Override
- public MaterialFinder copyFrom(MaterialView material) {
- bits = ((MaterialViewImpl) material).bits;
- return this;
- }
-
- @Override
- public MaterialFinder clear() {
- bits = defaultBits;
- return this;
- }
-
- @Override
- public RenderMaterial find() {
- return RenderMaterialImpl.byIndex(bits);
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialViewImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialViewImpl.java
deleted file mode 100644
index 0ae070574..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/MaterialViewImpl.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.material;
-
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.bitMask;
-
-import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
-import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
-import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
-import net.fabricmc.fabric.api.util.TriState;
-import net.minecraft.util.Mth;
-
-/**
- * Default implementation of the standard render materials.
- * The underlying representation is simply an int with bit-wise
- * packing of the various material properties. This offers
- * easy/fast interning via int/object hashmap.
- */
-public class MaterialViewImpl implements MaterialView {
- private static final BlendMode[] BLEND_MODES = BlendMode.values();
- private static final int BLEND_MODE_COUNT = BLEND_MODES.length;
- private static final TriState[] TRI_STATES = TriState.values();
- private static final int TRI_STATE_COUNT = TRI_STATES.length;
- private static final ShadeMode[] SHADE_MODES = ShadeMode.values();
- private static final int SHADE_MODE_COUNT = SHADE_MODES.length;
-
- protected static final int BLEND_MODE_BIT_LENGTH = Mth.ceillog2(BLEND_MODE_COUNT);
- protected static final int COLOR_DISABLE_BIT_LENGTH = 1;
- protected static final int EMISSIVE_BIT_LENGTH = 1;
- protected static final int DIFFUSE_BIT_LENGTH = 1;
- protected static final int AO_BIT_LENGTH = Mth.ceillog2(TRI_STATE_COUNT);
- protected static final int GLINT_BIT_LENGTH = Mth.ceillog2(TRI_STATE_COUNT);
- protected static final int SHADE_MODE_BIT_LENGTH = Mth.ceillog2(SHADE_MODE_COUNT);
-
- protected static final int BLEND_MODE_BIT_OFFSET = 0;
- protected static final int COLOR_DISABLE_BIT_OFFSET = BLEND_MODE_BIT_OFFSET + BLEND_MODE_BIT_LENGTH;
- protected static final int EMISSIVE_BIT_OFFSET = COLOR_DISABLE_BIT_OFFSET + COLOR_DISABLE_BIT_LENGTH;
- protected static final int DIFFUSE_BIT_OFFSET = EMISSIVE_BIT_OFFSET + EMISSIVE_BIT_LENGTH;
- protected static final int AO_BIT_OFFSET = DIFFUSE_BIT_OFFSET + DIFFUSE_BIT_LENGTH;
- protected static final int GLINT_BIT_OFFSET = AO_BIT_OFFSET + AO_BIT_LENGTH;
- protected static final int SHADE_MODE_BIT_OFFSET = GLINT_BIT_OFFSET + GLINT_BIT_LENGTH;
- public static final int TOTAL_BIT_LENGTH = SHADE_MODE_BIT_OFFSET + SHADE_MODE_BIT_LENGTH;
-
- protected static final int BLEND_MODE_MASK = bitMask(BLEND_MODE_BIT_LENGTH, BLEND_MODE_BIT_OFFSET);
- protected static final int COLOR_DISABLE_FLAG = bitMask(COLOR_DISABLE_BIT_LENGTH, COLOR_DISABLE_BIT_OFFSET);
- protected static final int EMISSIVE_FLAG = bitMask(EMISSIVE_BIT_LENGTH, EMISSIVE_BIT_OFFSET);
- protected static final int DIFFUSE_FLAG = bitMask(DIFFUSE_BIT_LENGTH, DIFFUSE_BIT_OFFSET);
- protected static final int AO_MASK = bitMask(AO_BIT_LENGTH, AO_BIT_OFFSET);
- protected static final int GLINT_MASK = bitMask(GLINT_BIT_LENGTH, GLINT_BIT_OFFSET);
- protected static final int SHADE_MODE_MASK = bitMask(SHADE_MODE_BIT_LENGTH, SHADE_MODE_BIT_OFFSET);
-
- protected static boolean areBitsValid(int bits) {
- int blendMode = (bits & BLEND_MODE_MASK) >>> BLEND_MODE_BIT_OFFSET;
- int ao = (bits & AO_MASK) >>> AO_BIT_OFFSET;
- int glint = (bits & GLINT_MASK) >>> GLINT_BIT_OFFSET;
- int shadeMode = (bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET;
-
- return blendMode < BLEND_MODE_COUNT
- && ao < TRI_STATE_COUNT
- && glint < TRI_STATE_COUNT
- && shadeMode < SHADE_MODE_COUNT;
- }
-
- protected int bits;
-
- protected MaterialViewImpl(int bits) {
- this.bits = bits;
- }
-
- @Override
- public BlendMode blendMode() {
- return BLEND_MODES[(bits & BLEND_MODE_MASK) >>> BLEND_MODE_BIT_OFFSET];
- }
-
- @Override
- public boolean disableColorIndex() {
- return (bits & COLOR_DISABLE_FLAG) != 0;
- }
-
- @Override
- public boolean emissive() {
- return (bits & EMISSIVE_FLAG) != 0;
- }
-
- @Override
- public boolean disableDiffuse() {
- return (bits & DIFFUSE_FLAG) != 0;
- }
-
- @Override
- public TriState ambientOcclusion() {
- return TRI_STATES[(bits & AO_MASK) >>> AO_BIT_OFFSET];
- }
-
- @Override
- public TriState glint() {
- return TRI_STATES[(bits & GLINT_MASK) >>> GLINT_BIT_OFFSET];
- }
-
- @Override
- public ShadeMode shadeMode() {
- return SHADE_MODES[(bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET];
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/RenderMaterialImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/RenderMaterialImpl.java
deleted file mode 100644
index 17e4602bb..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/material/RenderMaterialImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.material;
-
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-
-public class RenderMaterialImpl extends MaterialViewImpl implements RenderMaterial {
- public static final int VALUE_COUNT = 1 << TOTAL_BIT_LENGTH;
- private static final RenderMaterialImpl[] BY_INDEX = new RenderMaterialImpl[VALUE_COUNT];
-
- static {
- for (int i = 0; i < VALUE_COUNT; i++) {
- if (areBitsValid(i)) {
- BY_INDEX[i] = new RenderMaterialImpl(i);
- }
- }
- }
-
- private RenderMaterialImpl(int bits) {
- super(bits);
- }
-
- public int index() {
- return bits;
- }
-
- public static RenderMaterialImpl byIndex(int index) {
- return BY_INDEX[index];
- }
-
- public static RenderMaterialImpl setDisableDiffuse(RenderMaterialImpl material, boolean disable) {
- if (material.disableDiffuse() != disable) {
- return byIndex(disable ? (material.bits | DIFFUSE_FLAG) : (material.bits & ~DIFFUSE_FLAG));
- }
-
- return material;
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/EncodingFormat.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/EncodingFormat.java
deleted file mode 100644
index f1cf763cc..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/EncodingFormat.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.mesh;
-
-import com.google.common.base.Preconditions;
-import com.mojang.blaze3d.vertex.DefaultVertexFormat;
-import com.mojang.blaze3d.vertex.VertexFormat;
-import org.jetbrains.annotations.Nullable;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
-import net.vulkanmod.render.chunk.build.frapi.helper.GeometryHelper;
-import net.vulkanmod.render.chunk.build.frapi.material.MaterialViewImpl;
-import net.vulkanmod.render.chunk.build.frapi.material.RenderMaterialImpl;
-import net.minecraft.core.Direction;
-import net.minecraft.util.Mth;
-
-/**
- * Holds all the array offsets and bit-wise encoders/decoders for
- * packing/unpacking quad data in an array of integers.
- * All of this is implementation-specific - that's why it isn't a "helper" class.
- */
-public abstract class EncodingFormat {
- private EncodingFormat() { }
-
- static final int HEADER_BITS = 0;
- static final int HEADER_FACE_NORMAL = 1;
- static final int HEADER_COLOR_INDEX = 2;
- static final int HEADER_TAG = 3;
- public static final int HEADER_STRIDE = 4;
-
- static final int VERTEX_X;
- static final int VERTEX_Y;
- static final int VERTEX_Z;
- static final int VERTEX_COLOR;
- static final int VERTEX_U;
- static final int VERTEX_V;
- static final int VERTEX_LIGHTMAP;
- static final int VERTEX_NORMAL;
- public static final int VERTEX_STRIDE;
-
- public static final int QUAD_STRIDE;
- public static final int QUAD_STRIDE_BYTES;
- public static final int TOTAL_STRIDE;
-
- static {
- final VertexFormat format = DefaultVertexFormat.BLOCK;
- VERTEX_X = HEADER_STRIDE + 0;
- VERTEX_Y = HEADER_STRIDE + 1;
- VERTEX_Z = HEADER_STRIDE + 2;
- VERTEX_COLOR = HEADER_STRIDE + 3;
- VERTEX_U = HEADER_STRIDE + 4;
- VERTEX_V = VERTEX_U + 1;
- VERTEX_LIGHTMAP = HEADER_STRIDE + 6;
- VERTEX_NORMAL = HEADER_STRIDE + 7;
- VERTEX_STRIDE = format.getVertexSize() / 4;
- QUAD_STRIDE = VERTEX_STRIDE * 4;
- QUAD_STRIDE_BYTES = QUAD_STRIDE * 4;
- TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE;
-
- Preconditions.checkState(VERTEX_STRIDE == QuadView.VANILLA_VERTEX_STRIDE, "Indigo vertex stride (%s) mismatched with rendering API (%s)", VERTEX_STRIDE, QuadView.VANILLA_VERTEX_STRIDE);
- Preconditions.checkState(QUAD_STRIDE == QuadView.VANILLA_QUAD_STRIDE, "Indigo quad stride (%s) mismatched with rendering API (%s)", QUAD_STRIDE, QuadView.VANILLA_QUAD_STRIDE);
- }
-
- /** used for quick clearing of quad buffers. */
- static final int[] EMPTY = new int[TOTAL_STRIDE];
-
- private static final int DIRECTION_COUNT = Direction.values().length;
- private static final int NULLABLE_DIRECTION_COUNT = DIRECTION_COUNT + 1;
-
- private static final int CULL_BIT_LENGTH = Mth.ceillog2(NULLABLE_DIRECTION_COUNT);
- private static final int LIGHT_BIT_LENGTH = Mth.ceillog2(DIRECTION_COUNT);
- private static final int NORMALS_BIT_LENGTH = 4;
- private static final int GEOMETRY_BIT_LENGTH = GeometryHelper.FLAG_BIT_COUNT;
- private static final int MATERIAL_BIT_LENGTH = MaterialViewImpl.TOTAL_BIT_LENGTH;
-
- private static final int CULL_BIT_OFFSET = 0;
- private static final int LIGHT_BIT_OFFSET = CULL_BIT_OFFSET + CULL_BIT_LENGTH;
- private static final int NORMALS_BIT_OFFSET = LIGHT_BIT_OFFSET + LIGHT_BIT_LENGTH;
- private static final int GEOMETRY_BIT_OFFSET = NORMALS_BIT_OFFSET + NORMALS_BIT_LENGTH;
- private static final int MATERIAL_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH;
- private static final int TOTAL_BIT_LENGTH = MATERIAL_BIT_OFFSET + MATERIAL_BIT_LENGTH;
-
- private static final int CULL_MASK = bitMask(CULL_BIT_LENGTH, CULL_BIT_OFFSET);
- private static final int LIGHT_MASK = bitMask(LIGHT_BIT_LENGTH, LIGHT_BIT_OFFSET);
- private static final int NORMALS_MASK = bitMask(NORMALS_BIT_LENGTH, NORMALS_BIT_OFFSET);
- private static final int GEOMETRY_MASK = bitMask(GEOMETRY_BIT_LENGTH, GEOMETRY_BIT_OFFSET);
- private static final int MATERIAL_MASK = bitMask(MATERIAL_BIT_LENGTH, MATERIAL_BIT_OFFSET);
-
- static {
- Preconditions.checkArgument(TOTAL_BIT_LENGTH <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE);
- }
-
- public static int bitMask(int bitLength, int bitOffset) {
- return ((1 << bitLength) - 1) << bitOffset;
- }
-
- @Nullable
- static Direction cullFace(int bits) {
- return ModelHelper.faceFromIndex((bits & CULL_MASK) >>> CULL_BIT_OFFSET);
- }
-
- static int cullFace(int bits, @Nullable Direction face) {
- return (bits & ~CULL_MASK) | (ModelHelper.toFaceIndex(face) << CULL_BIT_OFFSET);
- }
-
- static Direction lightFace(int bits) {
- return ModelHelper.faceFromIndex((bits & LIGHT_MASK) >>> LIGHT_BIT_OFFSET);
- }
-
- static int lightFace(int bits, Direction face) {
- return (bits & ~LIGHT_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_BIT_OFFSET);
- }
-
- /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */
- static int normalFlags(int bits) {
- return (bits & NORMALS_MASK) >>> NORMALS_BIT_OFFSET;
- }
-
- static int normalFlags(int bits, int normalFlags) {
- return (bits & ~NORMALS_MASK) | ((normalFlags << NORMALS_BIT_OFFSET) & NORMALS_MASK);
- }
-
- static int geometryFlags(int bits) {
- return (bits & GEOMETRY_MASK) >>> GEOMETRY_BIT_OFFSET;
- }
-
- static int geometryFlags(int bits, int geometryFlags) {
- return (bits & ~GEOMETRY_MASK) | ((geometryFlags << GEOMETRY_BIT_OFFSET) & GEOMETRY_MASK);
- }
-
- static RenderMaterialImpl material(int bits) {
- return RenderMaterialImpl.byIndex((bits & MATERIAL_MASK) >>> MATERIAL_BIT_OFFSET);
- }
-
- static int material(int bits, RenderMaterialImpl material) {
- return (bits & ~MATERIAL_MASK) | (material.index() << MATERIAL_BIT_OFFSET);
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshBuilderImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshBuilderImpl.java
deleted file mode 100644
index b5119de51..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshBuilderImpl.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.mesh;
-
-import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
-import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
-
-/**
- * Our implementation of {@link MeshBuilder}, used for static mesh creation and baking.
- * Not much to it - mainly it just needs to grow the int[] array as quads are appended
- * and maintain/provide a properly-configured {@link net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView} instance.
- * All the encoding and other work is handled in the quad base classes.
- * The one interesting bit is in {@link Maker#emitDirectly()}.
- */
-public class MeshBuilderImpl implements MeshBuilder {
- private int[] data = new int[256];
- private int index = 0;
- private int limit = data.length;
- private final Maker maker = new Maker();
-
- public MeshBuilderImpl() {
- ensureCapacity(EncodingFormat.TOTAL_STRIDE);
- maker.data = data;
- maker.baseIndex = index;
- maker.clear();
- }
-
- protected void ensureCapacity(int stride) {
- if (stride > limit - index) {
- limit *= 2;
- final int[] bigger = new int[limit];
- System.arraycopy(data, 0, bigger, 0, index);
- data = bigger;
- maker.data = data;
- }
- }
-
- @Override
- public QuadEmitter getEmitter() {
- maker.clear();
- return maker;
- }
-
- @Override
- public Mesh build() {
- final int[] packed = new int[index];
- System.arraycopy(data, 0, packed, 0, index);
- index = 0;
- maker.baseIndex = index;
- maker.clear();
- return new MeshImpl(packed);
- }
-
- /**
- * Our base classes are used differently so we define final
- * encoding steps in subtypes. This will be a static mesh used
- * at render time so we want to capture all geometry now and
- * apply non-location-dependent lighting.
- */
- private class Maker extends MutableQuadViewImpl {
- @Override
- public void emitDirectly() {
- computeGeometry();
- index += EncodingFormat.TOTAL_STRIDE;
- ensureCapacity(EncodingFormat.TOTAL_STRIDE);
- baseIndex = index;
- }
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshImpl.java
deleted file mode 100644
index ff23f44f7..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MeshImpl.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.mesh;
-
-import java.util.function.Consumer;
-
-import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-
-/**
- * Implementation of {@link Mesh}.
- * The way we encode meshes makes it very simple.
- */
-public class MeshImpl implements Mesh {
- /** Used to satisfy external calls to {@link #forEach(Consumer)}. */
- private final ThreadLocal cursorPool = ThreadLocal.withInitial(QuadViewImpl::new);
-
- final int[] data;
-
- MeshImpl(int[] data) {
- this.data = data;
- }
-
- @Override
- public void forEach(Consumer consumer) {
- forEach(consumer, cursorPool.get());
- }
-
- /**
- * The renderer can call this with its own cursor
- * to avoid the performance hit of a thread-local lookup.
- * Also means renderer can hold final references to quad buffers.
- */
- void forEach(Consumer consumer, QuadViewImpl cursor) {
- final int limit = data.length;
- int index = 0;
- cursor.data = this.data;
-
- while (index < limit) {
- cursor.baseIndex = index;
- cursor.load();
- consumer.accept(cursor);
- index += EncodingFormat.TOTAL_STRIDE;
- }
- }
-
- @Override
- public void outputTo(QuadEmitter emitter) {
- MutableQuadViewImpl e = (MutableQuadViewImpl) emitter;
- final int[] data = this.data;
- final int limit = data.length;
- int index = 0;
-
- while (index < limit) {
- System.arraycopy(data, index, e.data, e.baseIndex, EncodingFormat.TOTAL_STRIDE);
- e.load();
- e.emitDirectly();
- index += EncodingFormat.TOTAL_STRIDE;
- }
-
- e.clear();
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MutableQuadViewImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MutableQuadViewImpl.java
deleted file mode 100644
index 3b3fb644e..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/MutableQuadViewImpl.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.mesh;
-
-import net.vulkanmod.render.chunk.build.frapi.VulkanModRenderer;
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import org.jetbrains.annotations.Nullable;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-import net.vulkanmod.render.chunk.build.frapi.helper.ColorHelper;
-import net.vulkanmod.render.chunk.build.frapi.helper.NormalHelper;
-import net.vulkanmod.render.chunk.build.frapi.helper.TextureHelper;
-import net.vulkanmod.render.chunk.build.frapi.material.RenderMaterialImpl;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.client.renderer.texture.TextureAtlasSprite;
-import net.minecraft.core.Direction;
-
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.*;
-
-/**
- * Almost-concrete implementation of a mutable quad. The only missing part is {@link #emitDirectly()},
- * because that depends on where/how it is used. (Mesh encoding vs. render-time transformation).
- *
- * In many cases an instance of this class is used as an "editor quad". The editor quad's
- * {@link #emitDirectly()} method calls some other internal method that transforms the quad
- * data and then buffers it. Transformations should be the same as they would be in a vanilla
- * render - the editor is serving mainly as a way to access vertex data without magical
- * numbers. It also allows for a consistent interface for those transformations.
- */
-public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEmitter {
- public void clear() {
- System.arraycopy(EMPTY, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
- isGeometryInvalid = true;
- nominalFace = null;
- normalFlags(0);
- tag(0);
- colorIndex(-1);
- cullFace(null);
- material(VulkanModRenderer.MATERIAL_STANDARD);
- }
-
- @Override
- public MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) {
- final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
- data[index] = Float.floatToRawIntBits(x);
- data[index + 1] = Float.floatToRawIntBits(y);
- data[index + 2] = Float.floatToRawIntBits(z);
- isGeometryInvalid = true;
- return this;
- }
-
- @Override
- public MutableQuadViewImpl color(int vertexIndex, int color) {
- data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color;
- return this;
- }
-
- @Override
- public MutableQuadViewImpl uv(int vertexIndex, float u, float v) {
- final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
- data[i] = Float.floatToRawIntBits(u);
- data[i + 1] = Float.floatToRawIntBits(v);
- return this;
- }
-
- @Override
- public MutableQuadViewImpl spriteBake(TextureAtlasSprite sprite, int bakeFlags) {
- TextureHelper.bakeSprite(this, sprite, bakeFlags);
- return this;
- }
-
- @Override
- public MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) {
- data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap;
- return this;
- }
-
- protected void normalFlags(int flags) {
- data[baseIndex + HEADER_BITS] = EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS], flags);
- }
-
- @Override
- public MutableQuadViewImpl normal(int vertexIndex, float x, float y, float z) {
- normalFlags(normalFlags() | (1 << vertexIndex));
- data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = NormalHelper.packNormal(x, y, z);
- return this;
- }
-
- /**
- * Internal helper method. Copies face normals to vertex normals lacking one.
- */
- public final void populateMissingNormals() {
- final int normalFlags = this.normalFlags();
-
- if (normalFlags == 0b1111) return;
-
- final int packedFaceNormal = packedFaceNormal();
-
- for (int v = 0; v < 4; v++) {
- if ((normalFlags & (1 << v)) == 0) {
- data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal;
- }
- }
-
- normalFlags(0b1111);
- }
-
- @Override
- public final MutableQuadViewImpl cullFace(@Nullable Direction face) {
- data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(data[baseIndex + HEADER_BITS], face);
- nominalFace(face);
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl nominalFace(@Nullable Direction face) {
- nominalFace = face;
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl material(RenderMaterial material) {
- if (material == null) {
- material = VulkanModRenderer.MATERIAL_STANDARD;
- }
-
- data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (RenderMaterialImpl) material);
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl colorIndex(int colorIndex) {
- data[baseIndex + HEADER_COLOR_INDEX] = colorIndex;
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl tag(int tag) {
- data[baseIndex + HEADER_TAG] = tag;
- return this;
- }
-
- @Override
- public MutableQuadViewImpl copyFrom(QuadView quad) {
- final QuadViewImpl q = (QuadViewImpl) quad;
- q.computeGeometry();
-
- System.arraycopy(q.data, q.baseIndex, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
- faceNormal.set(q.faceNormal);
- nominalFace = q.nominalFace;
- isGeometryInvalid = false;
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) {
- System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, VANILLA_QUAD_STRIDE);
- isGeometryInvalid = true;
-
- int colorIndex = baseIndex + VERTEX_COLOR;
-
- for (int i = 0; i < 4; i++) {
- data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]);
- colorIndex += VERTEX_STRIDE;
- }
-
- return this;
- }
-
- @Override
- public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) {
- fromVanilla(quad.getVertices(), 0);
- data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(0, cullFace);
- nominalFace(quad.getDirection());
- colorIndex(quad.getTintIndex());
-
- if (!quad.isShade()) {
- material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true);
- }
-
- material(material);
- tag(0);
-
- // Copy data from BakedQuad instead of calculating properties
- ModelQuadView quadView = (ModelQuadView) quad;
- int normal = quadView.getNormal();
- data[baseIndex + HEADER_FACE_NORMAL] = normal;
- NormalHelper.unpackNormalTo(normal, faceNormal);
-
- Direction lightFace = quadView.lightFace();
- data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], lightFace);
- data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], quadView.getFlags());
-
- this.facing = quadView.getQuadFacing();
-
- this.isGeometryInvalid = false;
- return this;
- }
-
- /**
- * Emit the quad without clearing the underlying data.
- * Geometry is not guaranteed to be valid when called, but can be computed by calling {@link #computeGeometry()}.
- */
- public abstract void emitDirectly();
-
- @Override
- public final MutableQuadViewImpl emit() {
- emitDirectly();
- clear();
- return this;
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/QuadViewImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/QuadViewImpl.java
deleted file mode 100644
index 526e45b61..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/mesh/QuadViewImpl.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.mesh;
-
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.HEADER_BITS;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.HEADER_COLOR_INDEX;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.HEADER_FACE_NORMAL;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.HEADER_STRIDE;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.HEADER_TAG;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.QUAD_STRIDE;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_COLOR;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_LIGHTMAP;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_NORMAL;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_STRIDE;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_U;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_V;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_X;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_Y;
-import static net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat.VERTEX_Z;
-
-import net.vulkanmod.render.chunk.cull.QuadFacing;
-import net.vulkanmod.render.model.quad.ModelQuadFlags;
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.joml.Vector2f;
-import org.joml.Vector3f;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
-import net.vulkanmod.render.chunk.build.frapi.helper.ColorHelper;
-import net.vulkanmod.render.chunk.build.frapi.helper.GeometryHelper;
-import net.vulkanmod.render.chunk.build.frapi.helper.NormalHelper;
-import net.vulkanmod.render.chunk.build.frapi.material.RenderMaterialImpl;
-import net.minecraft.core.Direction;
-
-/**
- * Base class for all quads / quad makers. Handles the ugly bits
- * of maintaining and encoding the quad state.
- */
-public class QuadViewImpl implements QuadView, ModelQuadView {
- @Nullable
- protected Direction nominalFace;
- /** True when face normal, light face, or geometry flags may not match geometry. */
- protected boolean isGeometryInvalid = true;
- protected final Vector3f faceNormal = new Vector3f();
-
- /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */
- protected int[] data;
-
- /** Beginning of the quad. Also the header index. */
- protected int baseIndex = 0;
-
- protected QuadFacing facing;
-
- /**
- * Decodes necessary state from the backing data array.
- * The encoded data must contain valid computed geometry.
- */
- public void load() {
- isGeometryInvalid = false;
- nominalFace = lightFace();
- NormalHelper.unpackNormal(packedFaceNormal(), faceNormal);
- facing = QuadFacing.fromNormal(faceNormal);
- }
-
- protected void computeGeometry() {
- if (isGeometryInvalid) {
- isGeometryInvalid = false;
-
- NormalHelper.computeFaceNormal(faceNormal, this);
- data[baseIndex + HEADER_FACE_NORMAL] = NormalHelper.packNormal(faceNormal);
-
- // depends on face normal
- Direction lightFace = GeometryHelper.lightFace(this);
- data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], lightFace);
-
- // depends on light face
- data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], ModelQuadFlags.getQuadFlags(this, lightFace));
-
- facing = QuadFacing.fromNormal(faceNormal);
- }
- }
-
- /** gets flags used for lighting - lazily computed via {@link GeometryHelper#computeShapeFlags(QuadView)}. */
- public int geometryFlags() {
- computeGeometry();
- return EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS]);
- }
-
- public boolean hasShade() {
- return !material().disableDiffuse();
- }
-
- @Override
- public float x(int vertexIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]);
- }
-
- @Override
- public float y(int vertexIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]);
- }
-
- @Override
- public float z(int vertexIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]);
- }
-
- @Override
- public float posByIndex(int vertexIndex, int coordinateIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]);
- }
-
- @Override
- public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) {
- if (target == null) {
- target = new Vector3f();
- }
-
- final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
- target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), Float.intBitsToFloat(data[index + 2]));
- return target;
- }
-
- @Override
- public int color(int vertexIndex) {
- return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR];
- }
-
- @Override
- public float u(int vertexIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]);
- }
-
- @Override
- public float v(int vertexIndex) {
- return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]);
- }
-
- @Override
- public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) {
- if (target == null) {
- target = new Vector2f();
- }
-
- final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
- target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]));
- return target;
- }
-
- @Override
- public int lightmap(int vertexIndex) {
- return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP];
- }
-
- public int normalFlags() {
- return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]);
- }
-
- @Override
- public boolean hasNormal(int vertexIndex) {
- return (normalFlags() & (1 << vertexIndex)) != 0;
- }
-
- /** True if any vertex normal has been set. */
- public boolean hasVertexNormals() {
- return normalFlags() != 0;
- }
-
- /** True if all vertex normals have been set. */
- public boolean hasAllVertexNormals() {
- return (normalFlags() & 0b1111) == 0b1111;
- }
-
- protected final int normalIndex(int vertexIndex) {
- return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL;
- }
-
- @Override
- public float normalX(int vertexIndex) {
- return hasNormal(vertexIndex) ? NormalHelper.unpackNormalX(data[normalIndex(vertexIndex)]) : Float.NaN;
- }
-
- @Override
- public float normalY(int vertexIndex) {
- return hasNormal(vertexIndex) ? NormalHelper.unpackNormalY(data[normalIndex(vertexIndex)]) : Float.NaN;
- }
-
- @Override
- public float normalZ(int vertexIndex) {
- return hasNormal(vertexIndex) ? NormalHelper.unpackNormalZ(data[normalIndex(vertexIndex)]) : Float.NaN;
- }
-
- @Override
- @Nullable
- public Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) {
- if (hasNormal(vertexIndex)) {
- if (target == null) {
- target = new Vector3f();
- }
-
- final int normal = data[normalIndex(vertexIndex)];
- NormalHelper.unpackNormal(normal, target);
- return target;
- } else {
- return null;
- }
- }
-
- @Override
- @Nullable
- public final Direction cullFace() {
- return EncodingFormat.cullFace(data[baseIndex + HEADER_BITS]);
- }
-
- @Override
- @NotNull
- public final Direction lightFace() {
- computeGeometry();
- return EncodingFormat.lightFace(data[baseIndex + HEADER_BITS]);
- }
-
- @Override
- @Nullable
- public final Direction nominalFace() {
- return nominalFace;
- }
-
- public final int packedFaceNormal() {
- computeGeometry();
- return data[baseIndex + HEADER_FACE_NORMAL];
- }
-
- @Override
- public final Vector3f faceNormal() {
- computeGeometry();
- return faceNormal;
- }
-
- @Override
- public final RenderMaterialImpl material() {
- return EncodingFormat.material(data[baseIndex + HEADER_BITS]);
- }
-
- @Override
- public final int colorIndex() {
- return data[baseIndex + HEADER_COLOR_INDEX];
- }
-
- @Override
- public final int tag() {
- return data[baseIndex + HEADER_TAG];
- }
-
- @Override
- public final void toVanilla(int[] target, int targetIndex) {
- System.arraycopy(data, baseIndex + HEADER_STRIDE, target, targetIndex, QUAD_STRIDE);
-
- // The color is the fourth integer in each vertex.
- // EncodingFormat.VERTEX_COLOR is not used because it also
- // contains the header size; vanilla quads do not have a header.
- int colorIndex = targetIndex + 3;
-
- for (int i = 0; i < 4; i++) {
- target[colorIndex] = ColorHelper.toVanillaColor(target[colorIndex]);
- colorIndex += VANILLA_VERTEX_STRIDE;
- }
- }
-
- @Override
- public int getFlags() {
- return geometryFlags();
- }
-
- @Override
- public float getX(int idx) {
- return this.x(idx);
- }
-
- @Override
- public float getY(int idx) {
- return this.y(idx);
- }
-
- @Override
- public float getZ(int idx) {
- return this.z(idx);
- }
-
- @Override
- public int getColor(int idx) {
- return this.color(idx);
- }
-
- @Override
- public float getU(int idx) {
- return this.u(idx);
- }
-
- @Override
- public float getV(int idx) {
- return this.v(idx);
- }
-
- @Override
- public int getColorIndex() {
- return this.colorIndex();
- }
-
- @Override
- public Direction getFacingDirection() {
- return this.lightFace();
- }
-
- @Override
- public int getNormal() {
- return packedFaceNormal();
- }
-
- @Override
- public QuadFacing getQuadFacing() {
- return this.facing;
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractBlockRenderContext.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractBlockRenderContext.java
deleted file mode 100644
index 026275612..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractBlockRenderContext.java
+++ /dev/null
@@ -1,303 +0,0 @@
-package net.vulkanmod.render.chunk.build.frapi.render;
-
-import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
-import net.fabricmc.fabric.api.renderer.v1.Renderer;
-import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
-import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
-import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.color.block.BlockColor;
-import net.minecraft.client.color.block.BlockColors;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.util.RandomSource;
-import net.minecraft.world.level.BlockAndTintGetter;
-import net.minecraft.world.level.BlockGetter;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.phys.shapes.BooleanOp;
-import net.minecraft.world.phys.shapes.Shapes;
-import net.minecraft.world.phys.shapes.VoxelShape;
-import net.vulkanmod.interfaces.color.BlockColorsExtended;
-import net.vulkanmod.render.chunk.build.color.BlockColorRegistry;
-import net.vulkanmod.render.chunk.build.light.LightPipeline;
-import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
-import org.jetbrains.annotations.Nullable;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
-import net.fabricmc.fabric.api.util.TriState;
-import net.vulkanmod.render.chunk.build.frapi.helper.ColorHelper;
-import net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat;
-import net.vulkanmod.render.chunk.build.frapi.mesh.MutableQuadViewImpl;
-import net.minecraft.client.renderer.LightTexture;
-import net.minecraft.client.resources.model.BakedModel;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.world.item.ItemDisplayContext;
-import net.minecraft.world.level.block.state.BlockState;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
- private static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
- protected static final RenderMaterial STANDARD_MATERIAL = RENDERER.materialFinder().shadeMode(ShadeMode.VANILLA).find();
- protected static final RenderMaterial NO_AO_MATERIAL = RENDERER.materialFinder().shadeMode(ShadeMode.VANILLA).ambientOcclusion(TriState.FALSE).find();
-
- protected final BlockColorRegistry blockColorRegistry;
-
- private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
- {
- data = new int[EncodingFormat.TOTAL_STRIDE];
- clear();
- }
-
- @Override
- public void emitDirectly() {
- renderQuad(this);
- }
- };
-
- protected BlockState blockState;
- protected BlockPos blockPos;
- protected BlockPos.MutableBlockPos tempPos = new BlockPos.MutableBlockPos();
-
- protected BlockAndTintGetter renderRegion;
-
- protected final Object2ByteLinkedOpenHashMap occlusionCache = new Object2ByteLinkedOpenHashMap<>(2048, 0.25F) {
- protected void rehash(int i) {
- }
- };
-
- protected final QuadLightData quadLightData = new QuadLightData();
- protected LightPipeline smoothLightPipeline;
- protected LightPipeline flatLightPipeline;
-
- protected boolean useAO;
- protected boolean defaultAO;
-
- protected long seed;
- protected RandomSource random;
- public final Supplier randomSupplier = () -> {
- long seed = this.seed;
-
- random.setSeed(seed);
- return random;
- };
-
- protected boolean enableCulling = true;
- protected int cullCompletionFlags;
- protected int cullResultFlags;
-
- protected AbstractBlockRenderContext() {
- this.occlusionCache.defaultReturnValue((byte) 127);
-
- BlockColors blockColors = Minecraft.getInstance().getBlockColors();
- this.blockColorRegistry = BlockColorsExtended.from(blockColors).getColorResolverMap();
- }
-
- protected void setupLightPipelines(LightPipeline flatLightPipeline, LightPipeline smoothLightPipeline) {
- this.flatLightPipeline = flatLightPipeline;
- this.smoothLightPipeline = smoothLightPipeline;
- }
-
- @Override
- public QuadEmitter getEmitter() {
- editorQuad.clear();
- return editorQuad;
- }
-
- @Override
- public ItemDisplayContext itemTransformationMode() {
- throw new IllegalStateException("itemTransformationMode() can only be called on an item render context.");
- }
-
- @SuppressWarnings("removal")
- @Override
- public BakedModelConsumer bakedModelConsumer() {
- return null;
- }
-
- public void prepareForWorld(BlockAndTintGetter blockView, boolean enableCulling) {
- this.renderRegion = blockView;
- this.enableCulling = enableCulling;
- }
-
- public void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo) {
- this.blockPos = blockPos;
- this.blockState = blockState;
-
- this.useAO = Minecraft.useAmbientOcclusion();
- this.defaultAO = this.useAO && modelAo && blockState.getLightEmission() == 0;
-
- this.cullCompletionFlags = 0;
- this.cullResultFlags = 0;
- }
-
- @Override
- public boolean isFaceCulled(@Nullable Direction face) {
- return !this.shouldRenderFace(face);
- }
-
- public boolean shouldRenderFace(Direction face) {
- if (face == null || !enableCulling) {
- return true;
- }
-
- final int mask = 1 << face.get3DDataValue();
-
- if ((cullCompletionFlags & mask) == 0) {
- cullCompletionFlags |= mask;
-
- if (this.faceNotOccluded(blockState, face)) {
- cullResultFlags |= mask;
- return true;
- } else {
- return false;
- }
- } else {
- return (cullResultFlags & mask) != 0;
- }
- }
-
- public boolean faceNotOccluded(BlockState blockState, Direction face) {
- BlockGetter blockGetter = this.renderRegion;
-
- BlockPos adjPos = tempPos.setWithOffset(blockPos, face);
- BlockState adjBlockState = blockGetter.getBlockState(adjPos);
-
- if (blockState.skipRendering(adjBlockState, face)) {
- return false;
- }
-
- if (adjBlockState.canOcclude()) {
- VoxelShape shape = blockState.getFaceOcclusionShape(blockGetter, blockPos, face);
-
- if (shape.isEmpty())
- return true;
-
- VoxelShape adjShape = adjBlockState.getFaceOcclusionShape(blockGetter, adjPos, face.getOpposite());
-
- if (adjShape.isEmpty())
- return true;
-
- if (shape == Shapes.block() && adjShape == Shapes.block()) {
- return false;
- }
-
- Block.BlockStatePairKey blockStatePairKey = new Block.BlockStatePairKey(blockState, adjBlockState, face);
-
- byte b = occlusionCache.getAndMoveToFirst(blockStatePairKey);
- if (b != 127) {
- return b != 0;
- } else {
- boolean bl = Shapes.joinIsNotEmpty(shape, adjShape, BooleanOp.ONLY_FIRST);
-
- if (occlusionCache.size() == 2048) {
- occlusionCache.removeLastByte();
- }
-
- occlusionCache.putAndMoveToFirst(blockStatePairKey, (byte) (bl ? 1 : 0));
- return bl;
- }
- }
-
- return true;
- }
-
- private void renderQuad(MutableQuadViewImpl quad) {
- if (!transform(quad)) {
- return;
- }
-
- if (isFaceCulled(quad.cullFace())) {
- return;
- }
-
- endRenderQuad(quad);
- }
-
- protected void endRenderQuad(MutableQuadViewImpl quad) {}
-
- /** handles block color, common to all renders. */
- protected void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
- if (colorIndex != -1) {
- final int blockColor = getBlockColor(this.renderRegion, colorIndex);
-
- for (int i = 0; i < 4; i++) {
- quad.color(i, ColorHelper.multiplyColor(blockColor, quad.color(i)));
- }
- }
- }
-
- private int getBlockColor(BlockAndTintGetter region, int colorIndex) {
- BlockColor blockColor = this.blockColorRegistry.getBlockColor(this.blockState.getBlock());
-
- int color = blockColor != null ? blockColor.getColor(blockState, region, blockPos, colorIndex) : -1;
- return 0xFF000000 | color;
- }
-
- protected void shadeQuad(MutableQuadViewImpl quad, LightPipeline lightPipeline, boolean emissive, boolean vanillaShade) {
- QuadLightData data = this.quadLightData;
-
- // TODO: enhanced AO
- lightPipeline.calculate(quad, this.blockPos, data, quad.cullFace(), quad.lightFace(), quad.hasShade());
-
- if (emissive) {
- for (int i = 0; i < 4; i++) {
- quad.color(i, ColorHelper.multiplyRGB(quad.color(i), data.br[i]));
- data.lm[i] = LightTexture.FULL_BRIGHT;
- }
- } else {
- for (int i = 0; i < 4; i++) {
- quad.color(i, ColorHelper.multiplyRGB(quad.color(i), data.br[i]));
- data.lm[i] = ColorHelper.maxBrightness(quad.lightmap(i), data.lm[i]);
- }
- }
- }
-
- public void emitBlockQuads(BakedModel model, @Nullable BlockState state, Supplier randomSupplier, RenderContext context) {
- MutableQuadViewImpl quad = this.editorQuad;
- final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? STANDARD_MATERIAL : NO_AO_MATERIAL;
-
- boolean noTransform = !this.hasTransform();
-
- if (noTransform) {
- for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
- final Direction cullFace = ModelHelper.faceFromIndex(i);
-
- if (context.isFaceCulled(cullFace)) {
- // Skip entire quad list if possible.
- continue;
- }
-
- final List quads = model.getQuads(state, cullFace, randomSupplier.get());
- final int count = quads.size();
-
- //noinspection ForLoopReplaceableByForEach
- for (int j = 0; j < count; j++) {
- final BakedQuad q = quads.get(j);
- quad.fromVanilla(q, defaultMaterial, cullFace);
-
- this.endRenderQuad(quad);
- }
- }
- } else {
- for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
- final Direction cullFace = ModelHelper.faceFromIndex(i);
-
- final List quads = model.getQuads(state, cullFace, randomSupplier.get());
- final int count = quads.size();
-
- //noinspection ForLoopReplaceableByForEach
- for (int j = 0; j < count; j++) {
- final BakedQuad q = quads.get(j);
- quad.fromVanilla(q, defaultMaterial, cullFace);
-
- this.renderQuad(quad);
- }
- }
- }
-
- }
-
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractRenderContext.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractRenderContext.java
deleted file mode 100644
index 5048e0874..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/AbstractRenderContext.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.render;
-
-import java.util.function.Consumer;
-import com.mojang.blaze3d.vertex.VertexConsumer;
-import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import org.joml.Matrix3f;
-import org.joml.Matrix4f;
-import org.joml.Vector3f;
-import org.joml.Vector4f;
-import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
-import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
-import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
-import net.vulkanmod.render.chunk.build.frapi.mesh.MutableQuadViewImpl;
-
-abstract class AbstractRenderContext implements RenderContext {
- private static final QuadTransform NO_TRANSFORM = q -> true;
-
- private QuadTransform activeTransform = NO_TRANSFORM;
- private final ObjectArrayList transformStack = new ObjectArrayList<>();
- private final QuadTransform stackTransform = q -> {
- int i = transformStack.size() - 1;
-
- while (i >= 0) {
- if (!transformStack.get(i--).transform(q)) {
- return false;
- }
- }
-
- return true;
- };
-
- @Deprecated
- private final Consumer meshConsumer = mesh -> mesh.outputTo(getEmitter());
-
- protected Matrix4f matrix;
- protected Matrix3f normalMatrix;
- protected int overlay;
- private final Vector4f posVec = new Vector4f();
- private final Vector3f normalVec = new Vector3f();
-
- protected final boolean transform(MutableQuadView q) {
- return activeTransform.transform(q);
- }
-
- @Override
- public boolean hasTransform() {
- return activeTransform != NO_TRANSFORM;
- }
-
- @Override
- public void pushTransform(QuadTransform transform) {
- if (transform == null) {
- throw new NullPointerException("Renderer received null QuadTransform.");
- }
-
- transformStack.push(transform);
-
- if (transformStack.size() == 1) {
- activeTransform = transform;
- } else if (transformStack.size() == 2) {
- activeTransform = stackTransform;
- }
- }
-
- @Override
- public void popTransform() {
- transformStack.pop();
-
- if (transformStack.size() == 0) {
- activeTransform = NO_TRANSFORM;
- } else if (transformStack.size() == 1) {
- activeTransform = transformStack.get(0);
- }
- }
-
- // Overridden to prevent allocating a lambda every time this method is called.
- @Deprecated
- @Override
- public Consumer meshConsumer() {
- return meshConsumer;
- }
-
- /** final output step, common to all renders. */
- protected void bufferQuad(MutableQuadViewImpl quad, VertexConsumer vertexConsumer) {
- final Vector4f posVec = this.posVec;
- final Vector3f normalVec = this.normalVec;
- final boolean useNormals = quad.hasVertexNormals();
-
- if (useNormals) {
- quad.populateMissingNormals();
- } else {
- normalVec.set(quad.faceNormal());
- normalVec.mul(normalMatrix);
- }
-
- for (int i = 0; i < 4; i++) {
- posVec.set(quad.x(i), quad.y(i), quad.z(i), 1.0f);
- posVec.mul(matrix);
- vertexConsumer.addVertex(posVec.x(), posVec.y(), posVec.z());
-
- final int color = quad.color(i);
- vertexConsumer.setColor(color);
- vertexConsumer.setUv(quad.u(i), quad.v(i));
- vertexConsumer.setOverlay(overlay);
- vertexConsumer.setLight(quad.lightmap(i));
-
- if (useNormals) {
- quad.copyNormal(i, normalVec);
- normalVec.mul(normalMatrix);
- }
-
- vertexConsumer.setNormal(normalVec.x(), normalVec.y(), normalVec.z());
- }
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/BlockRenderContext.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/BlockRenderContext.java
deleted file mode 100644
index 4ea9392be..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/BlockRenderContext.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.vulkanmod.render.chunk.build.frapi.render;
-
-import com.mojang.blaze3d.vertex.PoseStack;
-import com.mojang.blaze3d.vertex.VertexConsumer;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
-import net.fabricmc.fabric.api.util.TriState;
-import net.minecraft.client.resources.model.BakedModel;
-import net.minecraft.core.BlockPos;
-import net.minecraft.util.RandomSource;
-import net.minecraft.world.level.BlockAndTintGetter;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.phys.Vec3;
-import net.vulkanmod.Initializer;
-import net.vulkanmod.render.chunk.build.frapi.mesh.MutableQuadViewImpl;
-import net.vulkanmod.render.chunk.build.light.LightMode;
-import net.vulkanmod.render.chunk.build.light.LightPipeline;
-import net.vulkanmod.render.chunk.build.light.data.ArrayLightDataCache;
-import net.vulkanmod.render.chunk.build.light.flat.FlatLightPipeline;
-import net.vulkanmod.render.chunk.build.light.smooth.NewSmoothLightPipeline;
-import net.vulkanmod.render.chunk.build.light.smooth.SmoothLightPipeline;
-
-/**
- * Context for non-terrain block rendering.
- */
-public class BlockRenderContext extends AbstractBlockRenderContext {
- private VertexConsumer vertexConsumer;
-
- private final ArrayLightDataCache lightDataCache = new ArrayLightDataCache();
-
- public BlockRenderContext() {
- LightPipeline flatLightPipeline = new FlatLightPipeline(this.lightDataCache);
-
- LightPipeline smoothLightPipeline;
- if (Initializer.CONFIG.ambientOcclusion == LightMode.SUB_BLOCK) {
- smoothLightPipeline = new NewSmoothLightPipeline(lightDataCache);
- }
- else {
- smoothLightPipeline = new SmoothLightPipeline(lightDataCache);
- }
-
- this.setupLightPipelines(flatLightPipeline, smoothLightPipeline);
- }
-
- public void render(BlockAndTintGetter blockView, BakedModel model, BlockState state, BlockPos pos, PoseStack matrixStack, VertexConsumer buffer, boolean cull, RandomSource random, long seed, int overlay) {
- Vec3 offset = state.getOffset(blockView, pos);
- matrixStack.translate(offset.x, offset.y, offset.z);
-
- this.blockPos = pos;
- this.vertexConsumer = buffer;
- this.matrix = matrixStack.last().pose();
- this.normalMatrix = matrixStack.last().normal();
- this.overlay = overlay;
-
- this.random = random;
- this.seed = seed;
-
- this.lightDataCache.reset(blockView, pos);
-
- this.prepareForWorld(blockView, cull);
- this.prepareForBlock(state, pos, model.useAmbientOcclusion());
-
- model.emitBlockQuads(blockView, state, pos, this.randomSupplier, this);
-
- this.vertexConsumer = null;
- }
-
- protected void endRenderQuad(MutableQuadViewImpl quad) {
- final RenderMaterial mat = quad.material();
- final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
- final TriState aoMode = mat.ambientOcclusion();
- final boolean ao = this.useAO && (aoMode == TriState.TRUE || (aoMode == TriState.DEFAULT && this.defaultAO));
- final boolean emissive = mat.emissive();
- final boolean vanillaShade = mat.shadeMode() == ShadeMode.VANILLA;
-
- LightPipeline lightPipeline = ao ? this.smoothLightPipeline : this.flatLightPipeline;
-
- colorizeQuad(quad, colorIndex);
- shadeQuad(quad, lightPipeline, emissive, vanillaShade);
- copyLightData(quad);
- bufferQuad(quad, vertexConsumer);
- }
-
- private void copyLightData(MutableQuadViewImpl quad) {
- for (int i = 0; i < 4; i++) {
- quad.lightmap(i, this.quadLightData.lm[i]);
- }
- }
-
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/ItemRenderContext.java b/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/ItemRenderContext.java
deleted file mode 100644
index 0aef4c9a8..000000000
--- a/src/main/java/net/vulkanmod/render/chunk/build/frapi/render/ItemRenderContext.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.vulkanmod.render.chunk.build.frapi.render;
-
-import com.mojang.blaze3d.vertex.PoseStack;
-import com.mojang.blaze3d.vertex.VertexConsumer;
-import com.mojang.math.MatrixUtil;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.vulkanmod.mixin.render.frapi.ItemRendererAccessor;
-import org.jetbrains.annotations.Nullable;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.color.item.ItemColors;
-import net.minecraft.client.renderer.ItemBlockRenderTypes;
-import net.minecraft.client.renderer.LightTexture;
-import net.minecraft.client.renderer.MultiBufferSource;
-import net.minecraft.client.renderer.RenderType;
-import net.minecraft.client.renderer.Sheets;
-import net.minecraft.client.renderer.entity.ItemRenderer;
-import net.minecraft.client.resources.model.BakedModel;
-import net.minecraft.core.Direction;
-import net.minecraft.util.RandomSource;
-import net.minecraft.world.item.BlockItem;
-import net.minecraft.world.item.Item;
-import net.minecraft.world.item.ItemDisplayContext;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.level.block.state.BlockState;
-import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
-import net.fabricmc.fabric.api.util.TriState;
-import net.vulkanmod.render.chunk.build.frapi.helper.ColorHelper;
-import net.vulkanmod.render.chunk.build.frapi.mesh.EncodingFormat;
-import net.vulkanmod.render.chunk.build.frapi.mesh.MutableQuadViewImpl;
-import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
-
-import static net.vulkanmod.render.chunk.build.frapi.render.AbstractBlockRenderContext.STANDARD_MATERIAL;
-
-/**
- * The render context used for item rendering.
- */
-@SuppressWarnings("removal")
-public class ItemRenderContext extends AbstractRenderContext {
- /** Value vanilla uses for item rendering. The only sensible choice, of course. */
- private static final long ITEM_RANDOM_SEED = 42L;
-
- private final ItemColors itemColors;
- private final RandomSource random = RandomSource.create();
- private final Supplier randomSupplier = () -> {
- random.setSeed(ITEM_RANDOM_SEED);
- return random;
- };
-
- private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
- {
- data = new int[EncodingFormat.TOTAL_STRIDE];
- clear();
- }
-
- @Override
- public void emitDirectly() {
- renderQuad(this);
- }
- };
-
- private final BakedModelConsumerImpl vanillaModelConsumer = new BakedModelConsumerImpl();
-
- private ItemStack itemStack;
- private ItemDisplayContext transformMode;
- private PoseStack matrixStack;
- private MultiBufferSource vertexConsumerProvider;
- private int lightmap;
-
- private boolean isDefaultTranslucent;
- private boolean isTranslucentDirect;
- private boolean isDefaultGlint;
- private boolean isGlintDynamicDisplay;
-
- private PoseStack.Pose dynamicDisplayGlintEntry;
- private VertexConsumer translucentVertexConsumer;
- private VertexConsumer cutoutVertexConsumer;
- private VertexConsumer translucentGlintVertexConsumer;
- private VertexConsumer cutoutGlintVertexConsumer;
-
- public ItemRenderContext(ItemColors itemColors) {
- this.itemColors = itemColors;
- }
-
- @Override
- public QuadEmitter getEmitter() {
- editorQuad.clear();
- return editorQuad;
- }
-
- @Override
- public boolean isFaceCulled(@Nullable Direction face) {
- throw new IllegalStateException("isFaceCulled can only be called on a block render context.");
- }
-
- @Override
- public ItemDisplayContext itemTransformationMode() {
- return transformMode;
- }
-
- @Override
- public BakedModelConsumer bakedModelConsumer() {
- return vanillaModelConsumer;
- }
-
- public void renderModel(ItemStack itemStack, ItemDisplayContext transformMode, boolean invert, PoseStack matrixStack, MultiBufferSource vertexConsumerProvider, int lightmap, int overlay, BakedModel model) {
- this.itemStack = itemStack;
- this.transformMode = transformMode;
- this.matrixStack = matrixStack;
- this.vertexConsumerProvider = vertexConsumerProvider;
- this.lightmap = lightmap;
- this.overlay = overlay;
- computeOutputInfo();
-
- matrix = matrixStack.last().pose();
- normalMatrix = matrixStack.last().normal();
-
- model.emitItemQuads(itemStack, randomSupplier, this);
-
- this.itemStack = null;
- this.matrixStack = null;
- this.vertexConsumerProvider = null;
-
- dynamicDisplayGlintEntry = null;
- translucentVertexConsumer = null;
- cutoutVertexConsumer = null;
- translucentGlintVertexConsumer = null;
- cutoutGlintVertexConsumer = null;
- }
-
- public void emitItemQuads(BakedModel model, @Nullable BlockState state, Supplier randomSupplier) {
- if (!this.hasTransform()) {
- for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
- final Direction cullFace = ModelHelper.faceFromIndex(i);
- final List quads = model.getQuads(state, cullFace, randomSupplier.get());
- final int count = quads.size();
-
- //noinspection ForLoopReplaceableByForEach
- for (int j = 0; j < count; j++) {
- final BakedQuad q = quads.get(j);
- editorQuad.fromVanilla(q, STANDARD_MATERIAL, cullFace);
-
- endRenderQuad(editorQuad);
- }
- }
- }
- else {
- for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
- final Direction cullFace = ModelHelper.faceFromIndex(i);
- final List quads = model.getQuads(state, cullFace, randomSupplier.get());
- final int count = quads.size();
-
- //noinspection ForLoopReplaceableByForEach
- for (int j = 0; j < count; j++) {
- final BakedQuad q = quads.get(j);
- editorQuad.fromVanilla(q, STANDARD_MATERIAL, cullFace);
-
- this.renderQuad(editorQuad);
- }
- }
- }
- }
-
- private void computeOutputInfo() {
- isDefaultTranslucent = true;
- isTranslucentDirect = true;
-
- Item item = itemStack.getItem();
-
- if (item instanceof BlockItem blockItem) {
- BlockState state = blockItem.getBlock().defaultBlockState();
- RenderType renderLayer = ItemBlockRenderTypes.getChunkRenderType(state);
-
- if (renderLayer != RenderType.translucent()) {
- isDefaultTranslucent = false;
- }
-
- if (transformMode != ItemDisplayContext.GUI && !transformMode.firstPerson()) {
- isTranslucentDirect = false;
- }
- }
-
- isDefaultGlint = itemStack.hasFoil();
- isGlintDynamicDisplay = ItemRendererAccessor.hasAnimatedTexture(itemStack);
- }
-
- private void renderQuad(MutableQuadViewImpl quad) {
- if (!transform(quad)) {
- return;
- }
-
- endRenderQuad(quad);
- }
-
- private void endRenderQuad(MutableQuadViewImpl quad) {
- final RenderMaterial mat = quad.material();
- final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
- final boolean emissive = mat.emissive();
- final VertexConsumer vertexConsumer = getVertexConsumer(mat.blendMode(), mat.glint());
-
- colorizeQuad(quad, colorIndex);
- shadeQuad(quad, emissive);
- bufferQuad(quad, vertexConsumer);
- }
-
- private void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
- if (colorIndex != -1) {
- final int itemColor = itemColors.getColor(itemStack, colorIndex);
-
- for (int i = 0; i < 4; i++) {
- quad.color(i, ColorHelper.multiplyColor(itemColor, quad.color(i)));
- }
- }
- }
-
- private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) {
- if (emissive) {
- for (int i = 0; i < 4; i++) {
- quad.lightmap(i, LightTexture.FULL_BRIGHT);
- }
- } else {
- final int lightmap = this.lightmap;
-
- for (int i = 0; i < 4; i++) {
- quad.lightmap(i, ColorHelper.maxBrightness(quad.lightmap(i), lightmap));
- }
- }
- }
-
- /**
- * Caches custom blend mode / vertex consumers and mimics the logic
- * in {@code RenderLayers.getEntityBlockLayer}. Layers other than
- * translucent are mapped to cutout.
- */
- private VertexConsumer getVertexConsumer(BlendMode blendMode, TriState glintMode) {
- boolean translucent;
- boolean glint;
-
- if (blendMode == BlendMode.DEFAULT) {
- translucent = isDefaultTranslucent;
- } else {
- translucent = blendMode == BlendMode.TRANSLUCENT;
- }
-
- if (glintMode == TriState.DEFAULT) {
- glint = isDefaultGlint;
- } else {
- glint = glintMode == TriState.TRUE;
- }
-
- if (translucent) {
- if (glint) {
- if (translucentGlintVertexConsumer == null) {
- translucentGlintVertexConsumer = createTranslucentVertexConsumer(true);
- }
-
- return translucentGlintVertexConsumer;
- } else {
- if (translucentVertexConsumer == null) {
- translucentVertexConsumer = createTranslucentVertexConsumer(false);
- }
-
- return translucentVertexConsumer;
- }
- } else {
- if (glint) {
- if (cutoutGlintVertexConsumer == null) {
- cutoutGlintVertexConsumer = createCutoutVertexConsumer(true);
- }
-
- return cutoutGlintVertexConsumer;
- } else {
- if (cutoutVertexConsumer == null) {
- cutoutVertexConsumer = createCutoutVertexConsumer(false);
- }
-
- return cutoutVertexConsumer;
- }
- }
- }
-
- private VertexConsumer createTranslucentVertexConsumer(boolean glint) {
- if (glint && isGlintDynamicDisplay) {
- return createDynamicDisplayGlintVertexConsumer(Minecraft.useShaderTransparency() && !isTranslucentDirect ? Sheets.translucentItemSheet() : Sheets.translucentCullBlockSheet());
- }
-
- if (isTranslucentDirect) {
- return ItemRenderer.getFoilBufferDirect(vertexConsumerProvider, Sheets.translucentCullBlockSheet(), true, glint);
- } else if (Minecraft.useShaderTransparency()) {
- return ItemRenderer.getFoilBuffer(vertexConsumerProvider, Sheets.translucentItemSheet(), true, glint);
- } else {
- return ItemRenderer.getFoilBuffer(vertexConsumerProvider, Sheets.translucentCullBlockSheet(), true, glint);
- }
- }
-
- private VertexConsumer createCutoutVertexConsumer(boolean glint) {
- if (glint && isGlintDynamicDisplay) {
- return createDynamicDisplayGlintVertexConsumer(Sheets.cutoutBlockSheet());
- }
-
- return ItemRenderer.getFoilBufferDirect(vertexConsumerProvider, Sheets.cutoutBlockSheet(), true, glint);
- }
-
- private VertexConsumer createDynamicDisplayGlintVertexConsumer(RenderType layer) {
- if (dynamicDisplayGlintEntry == null) {
- dynamicDisplayGlintEntry = matrixStack.last().copy();
-
- if (transformMode == ItemDisplayContext.GUI) {
- MatrixUtil.mulComponentWise(dynamicDisplayGlintEntry.pose(), 0.5F);
- } else if (transformMode.firstPerson()) {
- MatrixUtil.mulComponentWise(dynamicDisplayGlintEntry.pose(), 0.75F);
- }
- }
-
- return ItemRenderer.getCompassFoilBuffer(vertexConsumerProvider, layer, dynamicDisplayGlintEntry);
- }
-
- private class BakedModelConsumerImpl implements BakedModelConsumer {
- @Override
- public void accept(BakedModel model) {
- accept(model, null);
- }
-
- @Override
- public void accept(BakedModel model, @Nullable BlockState state) {
- VanillaModelEncoder.emitItemQuads(model, state, randomSupplier, ItemRenderContext.this);
- }
- }
-}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/LightMode.java b/src/main/java/net/vulkanmod/render/chunk/build/light/LightMode.java
index cc82f119a..339138466 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/LightMode.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/LightMode.java
@@ -4,4 +4,4 @@ public abstract class LightMode {
public static final int FLAT = 0;
public static final int SMOOTH = 1;
public static final int SUB_BLOCK = 2;
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/LightPipeline.java b/src/main/java/net/vulkanmod/render/chunk/build/light/LightPipeline.java
index 69d3c184e..fc4ec50a3 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/LightPipeline.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/LightPipeline.java
@@ -2,22 +2,23 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
-import net.vulkanmod.render.model.quad.ModelQuadView;
import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
+import net.vulkanmod.render.model.quad.ModelQuadView;
/**
* Light pipelines allow model quads for any location in the world to be lit using various backends, including fluids
- * and block entities.
+ * and block entities.
*/
public interface LightPipeline {
/**
* Calculates the light data for a given block model quad, storing the result in {@param out}.
- * @param quad The block model quad
- * @param pos The block position of the model this quad belongs to
- * @param out The data arrays which will store the calculated light data results
- * @param cullFace The cull face of the quad
+ *
+ * @param quad The block model quad
+ * @param pos The block position of the model this quad belongs to
+ * @param out The data arrays which will store the calculated light data results
+ * @param cullFace The cull face of the quad
* @param lightFace The light face of the quad
- * @param shade True if the block is shaded by ambient occlusion
+ * @param shade True if the block is shaded by ambient occlusion
*/
void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade);
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/data/LightDataAccess.java b/src/main/java/net/vulkanmod/render/chunk/build/light/data/LightDataAccess.java
index 1312b4671..c04ddc9ef 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/data/LightDataAccess.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/data/LightDataAccess.java
@@ -42,100 +42,14 @@ public abstract class LightDataAccess {
private static final int FC_OFFSET = 31;
private static final float AO_INV = 1.0f / 2048.0f;
-
+ final boolean subBlockLighting;
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
protected BlockAndTintGetter region;
- final boolean subBlockLighting;
-
protected LightDataAccess() {
this.subBlockLighting = Initializer.CONFIG.ambientOcclusion == LightMode.SUB_BLOCK;
}
- public int get(int x, int y, int z, SimpleDirection d1, SimpleDirection d2) {
- return this.get(x + d1.getStepX() + d2.getStepX(),
- y + d1.getStepY() + d2.getStepY(),
- z + d1.getStepZ() + d2.getStepZ());
- }
-
- public int get(int x, int y, int z, SimpleDirection dir) {
- return this.get(x + dir.getStepX(),
- y + dir.getStepY(),
- z + dir.getStepZ());
- }
-
- public int get(BlockPos pos, SimpleDirection dir) {
- return this.get(pos.getX(), pos.getY(), pos.getZ(), dir);
- }
-
- public int get(BlockPos pos) {
- return this.get(pos.getX(), pos.getY(), pos.getZ());
- }
-
- /**
- * Returns the light data for the block at the given position. The property fields can then be accessed using
- * the various unpack methods below.
- */
- public abstract int get(int x, int y, int z);
-
- protected int compute(int x, int y, int z) {
- BlockPos pos = this.pos.set(x, y, z);
- BlockState state = region.getBlockState(pos);
-
- boolean em = state.emissiveRendering(region, pos);
-
- boolean op;
- if (this.subBlockLighting)
- op = state.canOcclude();
- else
- op = state.isViewBlocking(region, pos) && state.getLightBlock(region, pos) != 0;
-
- boolean fo = state.isSolidRender(region, pos);
- boolean fc = state.isCollisionShapeFullBlock(region, pos);
-
- int lu = state.getLightEmission();
-
- // OPTIMIZE: Do not calculate light data if the block is full and opaque and does not emit light.
- int bl;
- int sl;
- if (fo && lu == 0) {
- bl = 0;
- sl = 0;
- }
- else {
- if (em) {
- bl = region.getBrightness(LightLayer.BLOCK, pos);
- sl = region.getBrightness(LightLayer.SKY, pos);
- }
- else {
- int light = LevelRenderer.getLightColor(region, state, pos);
- bl = LightTexture.block(light);
- sl = LightTexture.sky(light);
- }
- }
-
- // FIX: Do not apply AO from blocks that emit light
- float ao;
- if (lu == 0) {
- ao = state.getShadeBrightness(region, pos);
- }
- else {
- ao = 1.0f;
- }
-
- boolean useAo = ao < 1.0f;
-
- bl = Math.max(bl, lu);
-
- int crs = (fo || fc) && lu == 0 && useAo ? 0xFF : 0;
- if (!fo && op) {
- VoxelShape shape = state.getShape(region, pos);
- crs = ((VoxelShapeExtended) (shape)).getCornerOcclusion();
- }
-
- return packFC(fc) | packFO(fo) | packOP(op) | packEM(em) | packCO(crs) | packAO(ao) | packSL(sl) | packBL(bl);
- }
-
public static int packBL(int blockLight) {
return (blockLight & 0xF) << BL_OFFSET;
}
@@ -217,13 +131,89 @@ public static int getLightmap(int word) {
public static int getEmissiveLightmap(int word) {
if (unpackEM(word)) {
return LightTexture.FULL_BRIGHT;
- }
- else {
+ } else {
return getLightmap(word);
}
}
+ public int get(int x, int y, int z, SimpleDirection d1, SimpleDirection d2) {
+ return this.get(x + d1.getStepX() + d2.getStepX(),
+ y + d1.getStepY() + d2.getStepY(),
+ z + d1.getStepZ() + d2.getStepZ());
+ }
+
+ public int get(int x, int y, int z, SimpleDirection dir) {
+ return this.get(x + dir.getStepX(),
+ y + dir.getStepY(),
+ z + dir.getStepZ());
+ }
+
+ public int get(BlockPos pos, SimpleDirection dir) {
+ return this.get(pos.getX(), pos.getY(), pos.getZ(), dir);
+ }
+
+ public int get(BlockPos pos) {
+ return this.get(pos.getX(), pos.getY(), pos.getZ());
+ }
+
+ /**
+ * Returns the light data for the block at the given position. The property fields can then be accessed using
+ * the various unpack methods below.
+ */
+ public abstract int get(int x, int y, int z);
+
+ protected int compute(int x, int y, int z) {
+ BlockPos pos = this.pos.set(x, y, z);
+ BlockState state = region.getBlockState(pos);
+
+ boolean em = state.emissiveRendering(region, pos);
+
+ boolean op = this.subBlockLighting ? state.canOcclude() : (state.isSolidRender() && state.getLightBlock() != 0);
+
+ boolean fo = state.isSolidRender();
+ boolean fc = state.isCollisionShapeFullBlock(region, pos);
+
+ int lu = state.getLightEmission();
+
+ // OPTIMIZE: Do not calculate light data if the block is full and opaque and does not emit light.
+ int bl;
+ int sl;
+ if (fo && lu == 0) {
+ bl = 0;
+ sl = 0;
+ } else {
+ if (em) {
+ bl = region.getBrightness(LightLayer.BLOCK, pos);
+ sl = region.getBrightness(LightLayer.SKY, pos);
+ } else {
+ int light = LevelRenderer.getLightColor(region, pos);
+ bl = LightTexture.block(light);
+ sl = LightTexture.sky(light);
+ }
+ }
+
+ // FIX: Do not apply AO from blocks that emit light
+ float ao;
+ if (lu == 0) {
+ ao = state.getShadeBrightness(region, pos);
+ } else {
+ ao = 1.0f;
+ }
+
+ boolean useAo = ao < 1.0f;
+
+ bl = Math.max(bl, lu);
+
+ int crs = (fo || fc) && lu == 0 && useAo ? 0xFF : 0;
+ if (!fo && op) {
+ VoxelShape shape = state.getShape(region, pos);
+ crs = ((VoxelShapeExtended) (shape)).getCornerOcclusion();
+ }
+
+ return packFC(fc) | packFO(fo) | packOP(op) | packEM(em) | packCO(crs) | packAO(ao) | packSL(sl) | packBL(bl);
+ }
+
public BlockAndTintGetter getRegion() {
return this.region;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/data/QuadLightData.java b/src/main/java/net/vulkanmod/render/chunk/build/light/data/QuadLightData.java
index 6014eaf6a..6d1ab0029 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/data/QuadLightData.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/data/QuadLightData.java
@@ -14,4 +14,4 @@ public class QuadLightData {
* The lightmap texture coordinates for each vertex in the quad.
*/
public final int[] lm = new int[4];
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/flat/FlatLightPipeline.java b/src/main/java/net/vulkanmod/render/chunk/build/light/flat/FlatLightPipeline.java
index b11f4e352..333c09f0f 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/flat/FlatLightPipeline.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/flat/FlatLightPipeline.java
@@ -3,12 +3,12 @@
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
-import net.vulkanmod.render.chunk.util.SimpleDirection;
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.LightPipeline;
+import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
+import net.vulkanmod.render.chunk.util.SimpleDirection;
import net.vulkanmod.render.model.quad.ModelQuadFlags;
+import net.vulkanmod.render.model.quad.ModelQuadView;
import java.util.Arrays;
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoFaceData.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoFaceData.java
index d4be249f3..9d51ea902 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoFaceData.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoFaceData.java
@@ -2,8 +2,8 @@
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.BlockPos;
-import net.vulkanmod.render.chunk.util.SimpleDirection;
import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
+import net.vulkanmod.render.chunk.util.SimpleDirection;
import static net.vulkanmod.render.chunk.build.light.data.LightDataAccess.*;
@@ -16,6 +16,65 @@ class AoFaceData {
protected int flags;
+ static float weightedSum(float[] v, float[] w) {
+ float t0 = v[0] * w[0];
+ float t1 = v[1] * w[1];
+ float t2 = v[2] * w[2];
+ float t3 = v[3] * w[3];
+
+ return t0 + t1 + t2 + t3;
+ }
+
+ static float unpackSkyLight(int i) {
+ return (i >> 16) & 0xFF;
+ }
+
+ static float unpackBlockLight(int i) {
+ return i & 0xFF;
+ }
+
+ static int calculateCornerBrightness(int a, int b, int c, int d, boolean aem, boolean bem, boolean cem, boolean dem) {
+ // FIX: Normalize corner vectors correctly to the minimum non-zero value between each one to prevent
+ // strange issues
+ if ((a == 0) || (b == 0) || (c == 0) || (d == 0)) {
+ // Find the minimum value between all corners
+ final int min = minNonZero(minNonZero(a, b), minNonZero(c, d));
+
+ // Normalize the corner values
+ a = Math.max(a, min);
+ b = Math.max(b, min);
+ c = Math.max(c, min);
+ d = Math.max(d, min);
+ }
+
+ // FIX: Apply the fullbright lightmap from emissive blocks at the very end so it cannot influence
+ // the minimum lightmap and produce incorrect results (for example, sculk sensors in a dark room)
+ if (aem) {
+ a = LightTexture.FULL_BRIGHT;
+ }
+ if (bem) {
+ b = LightTexture.FULL_BRIGHT;
+ }
+ if (cem) {
+ c = LightTexture.FULL_BRIGHT;
+ }
+ if (dem) {
+ d = LightTexture.FULL_BRIGHT;
+ }
+
+ return ((a + b + c + d) >> 2) & 0xFF00FF;
+ }
+
+ static int minNonZero(int a, int b) {
+ if (a == 0) {
+ return b;
+ } else if (b == 0) {
+ return a;
+ }
+
+ return Math.min(a, b);
+ }
+
public void initLightData(LightDataAccess cache, BlockPos pos, SimpleDirection direction, boolean offset) {
final int oX = pos.getX();
final int oY = pos.getY();
@@ -191,65 +250,6 @@ public float getBlendedShade(float[] w) {
return weightedSum(this.ao, w);
}
- static float weightedSum(float[] v, float[] w) {
- float t0 = v[0] * w[0];
- float t1 = v[1] * w[1];
- float t2 = v[2] * w[2];
- float t3 = v[3] * w[3];
-
- return t0 + t1 + t2 + t3;
- }
-
- static float unpackSkyLight(int i) {
- return (i >> 16) & 0xFF;
- }
-
- static float unpackBlockLight(int i) {
- return i & 0xFF;
- }
-
- static int calculateCornerBrightness(int a, int b, int c, int d, boolean aem, boolean bem, boolean cem, boolean dem) {
- // FIX: Normalize corner vectors correctly to the minimum non-zero value between each one to prevent
- // strange issues
- if ((a == 0) || (b == 0) || (c == 0) || (d == 0)) {
- // Find the minimum value between all corners
- final int min = minNonZero(minNonZero(a, b), minNonZero(c, d));
-
- // Normalize the corner values
- a = Math.max(a, min);
- b = Math.max(b, min);
- c = Math.max(c, min);
- d = Math.max(d, min);
- }
-
- // FIX: Apply the fullbright lightmap from emissive blocks at the very end so it cannot influence
- // the minimum lightmap and produce incorrect results (for example, sculk sensors in a dark room)
- if (aem) {
- a = LightTexture.FULL_BRIGHT;
- }
- if (bem) {
- b = LightTexture.FULL_BRIGHT;
- }
- if (cem) {
- c = LightTexture.FULL_BRIGHT;
- }
- if (dem) {
- d = LightTexture.FULL_BRIGHT;
- }
-
- return ((a + b + c + d) >> 2) & 0xFF00FF;
- }
-
- static int minNonZero(int a, int b) {
- if (a == 0) {
- return b;
- } else if (b == 0) {
- return a;
- }
-
- return Math.min(a, b);
- }
-
public boolean hasLightData() {
return (this.flags & FaceDataFlags.HAS_LIGHT_DATA) != 0;
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoNeighborInfo.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoNeighborInfo.java
index c3ccad908..bd68fdc4c 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoNeighborInfo.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/AoNeighborInfo.java
@@ -8,10 +8,10 @@
*/
@SuppressWarnings("UnnecessaryLocalVariable")
enum AoNeighborInfo {
- DOWN(new SimpleDirection[] { SimpleDirection.SOUTH, SimpleDirection.WEST, SimpleDirection.NORTH, SimpleDirection.EAST },
- new int[] {4, 5, 6, 7,
- 0, 1, 2, 3},
- 0.5F) {
+ DOWN(new SimpleDirection[]{SimpleDirection.SOUTH, SimpleDirection.WEST, SimpleDirection.NORTH, SimpleDirection.EAST},
+ new int[]{4, 5, 6, 7,
+ 0, 1, 2, 3},
+ 0.5F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
final float u = 1.0f - x;
@@ -35,10 +35,10 @@ public float getDepth(float x, float y, float z) {
return y;
}
},
- UP(new SimpleDirection[] { SimpleDirection.NORTH, SimpleDirection.WEST, SimpleDirection.SOUTH, SimpleDirection.EAST },
- new int[] {2, 3, 0, 1,
+ UP(new SimpleDirection[]{SimpleDirection.NORTH, SimpleDirection.WEST, SimpleDirection.SOUTH, SimpleDirection.EAST},
+ new int[]{2, 3, 0, 1,
6, 7, 4, 5},
- 1.0F) {
+ 1.0F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
final float u = 1.0f - x;
@@ -62,8 +62,8 @@ public float getDepth(float x, float y, float z) {
return 1.0f - y;
}
},
- NORTH(new SimpleDirection[] { SimpleDirection.UP, SimpleDirection.EAST, SimpleDirection.DOWN, SimpleDirection.WEST },
- new int[] {3, 2, 7, 6,
+ NORTH(new SimpleDirection[]{SimpleDirection.UP, SimpleDirection.EAST, SimpleDirection.DOWN, SimpleDirection.WEST},
+ new int[]{3, 2, 7, 6,
1, 0, 5, 4},
0.8F) {
@Override
@@ -89,8 +89,8 @@ public float getDepth(float x, float y, float z) {
return z;
}
},
- SOUTH(new SimpleDirection[] { SimpleDirection.UP, SimpleDirection.WEST, SimpleDirection.DOWN, SimpleDirection.EAST },
- new int[] {0, 1, 4, 5,
+ SOUTH(new SimpleDirection[]{SimpleDirection.UP, SimpleDirection.WEST, SimpleDirection.DOWN, SimpleDirection.EAST},
+ new int[]{0, 1, 4, 5,
2, 3, 6, 7},
0.8F) {
@Override
@@ -116,8 +116,8 @@ public float getDepth(float x, float y, float z) {
return 1.0f - z;
}
},
- WEST(new SimpleDirection[] { SimpleDirection.UP, SimpleDirection.NORTH, SimpleDirection.DOWN, SimpleDirection.SOUTH },
- new int[] {1, 3, 5, 7,
+ WEST(new SimpleDirection[]{SimpleDirection.UP, SimpleDirection.NORTH, SimpleDirection.DOWN, SimpleDirection.SOUTH},
+ new int[]{1, 3, 5, 7,
0, 2, 4, 6},
0.6F) {
@Override
@@ -143,8 +143,8 @@ public float getDepth(float x, float y, float z) {
return x;
}
},
- EAST(new SimpleDirection[] { SimpleDirection.UP, SimpleDirection.SOUTH, SimpleDirection.DOWN, SimpleDirection.NORTH },
- new int[] {2, 0, 6, 4,
+ EAST(new SimpleDirection[]{SimpleDirection.UP, SimpleDirection.SOUTH, SimpleDirection.DOWN, SimpleDirection.NORTH},
+ new int[]{2, 0, 6, 4,
3, 1, 7, 5},
0.6F) {
@Override
@@ -171,23 +171,21 @@ public float getDepth(float x, float y, float z) {
}
};
+ private static final AoNeighborInfo[] VALUES = AoNeighborInfo.values();
/**
* The direction of each corner block from this face, which can be retrieved by offsetting the position of the origin
* block by the direction vector.
*/
public final SimpleDirection[] faces;
-
/**
* The constant brightness modifier for this face. This data exists to emulate the results of the OpenGL lighting
* model which gives a faux directional light appearance to blocks in the game. Not currently used.
*/
public final float strength;
-
/**
* The indexes of each inner corner occlusion bit for every model vertex.
*/
public final int[] inCornerBits = new int[4 * 2];
-
/**
* The indexes of each outer corner occlusion bit for every model vertex.
*/
@@ -201,55 +199,6 @@ public float getDepth(float x, float y, float z) {
getOutCornerBits(this.outCornerBits, indices);
}
- /**
- * Calculates how much each corner contributes to the final "darkening" of the vertex at the specified position. The
- * weight is a function of the distance from the vertex's position to the corner block's position.
- *
- * @param x The x-position of the vertex
- * @param y The y-position of the vertex
- * @param z The z-position of the vertex
- * @param out The weight values for each corner
- */
- public abstract void calculateCornerWeights(float x, float y, float z, float[] out);
-
- public abstract float getU(float x, float y, float z);
-
- public abstract float getV(float x, float y, float z);
-
- /**
- * Maps the light map and occlusion value arrays {@param lm0} and {@param ao0} from {@link AoFaceData} to the
- * correct corners for this facing.
- *
- * @param lm0 The input light map texture coordinates array
- * @param ao0 The input ambient occlusion color array
- * @param lm1 The re-orientated output light map texture coordinates array
- * @param ao1 The re-orientated output ambient occlusion color array
- */
- public void copyLightValues(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
- lm1[0] = lm0[0];
- lm1[1] = lm0[1];
- lm1[2] = lm0[2];
- lm1[3] = lm0[3];
-
- ao1[0] = ao0[0];
- ao1[1] = ao0[1];
- ao1[2] = ao0[2];
- ao1[3] = ao0[3];
- }
-
- /**
- * Calculates the depth (or inset) of the vertex into this facing of the block. Used to determine
- * how much shadow is contributed by the direct neighbors of a block.
- *
- * @param x The x-position of the vertex
- * @param y The y-position of the vertex
- * @param z The z-position of the vertex
- * @return The depth of the vertex into this face
- */
- public abstract float getDepth(float x, float y, float z);
-
- private static final AoNeighborInfo[] VALUES = AoNeighborInfo.values();
-
/**
* @return Returns the {@link AoNeighborInfo} which corresponds with the specified direction
*/
@@ -319,4 +268,51 @@ private static void getOutCornerBits(int[] cornersBits, int[] idxs) {
cornersBits[12 + 10] = idxs[4 + 1];
cornersBits[12 + 11] = idxs[4 + 0];
}
+
+ /**
+ * Calculates how much each corner contributes to the final "darkening" of the vertex at the specified position. The
+ * weight is a function of the distance from the vertex's position to the corner block's position.
+ *
+ * @param x The x-position of the vertex
+ * @param y The y-position of the vertex
+ * @param z The z-position of the vertex
+ * @param out The weight values for each corner
+ */
+ public abstract void calculateCornerWeights(float x, float y, float z, float[] out);
+
+ public abstract float getU(float x, float y, float z);
+
+ public abstract float getV(float x, float y, float z);
+
+ /**
+ * Maps the light map and occlusion value arrays {@param lm0} and {@param ao0} from {@link AoFaceData} to the
+ * correct corners for this facing.
+ *
+ * @param lm0 The input light map texture coordinates array
+ * @param ao0 The input ambient occlusion color array
+ * @param lm1 The re-orientated output light map texture coordinates array
+ * @param ao1 The re-orientated output ambient occlusion color array
+ */
+ public void copyLightValues(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
+ lm1[0] = lm0[0];
+ lm1[1] = lm0[1];
+ lm1[2] = lm0[2];
+ lm1[3] = lm0[3];
+
+ ao1[0] = ao0[0];
+ ao1[1] = ao0[1];
+ ao1[2] = ao0[2];
+ ao1[3] = ao0[3];
+ }
+
+ /**
+ * Calculates the depth (or inset) of the vertex into this facing of the block. Used to determine
+ * how much shadow is contributed by the direct neighbors of a block.
+ *
+ * @param x The x-position of the vertex
+ * @param y The y-position of the vertex
+ * @param z The z-position of the vertex
+ * @return The depth of the vertex into this face
+ */
+ public abstract float getDepth(float x, float y, float z);
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/FaceDataFlags.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/FaceDataFlags.java
index 0e2f6a27b..afa7bf3a9 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/FaceDataFlags.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/FaceDataFlags.java
@@ -13,4 +13,4 @@ abstract class FaceDataFlags {
* The light data has been unpacked into normalized floating point values.
*/
public static final int HAS_UNPACKED_LIGHT_DATA = 0b10;
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/NewSmoothLightPipeline.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/NewSmoothLightPipeline.java
index 503d27ff9..81a876727 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/NewSmoothLightPipeline.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/NewSmoothLightPipeline.java
@@ -3,12 +3,12 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
-import net.vulkanmod.render.chunk.util.SimpleDirection;
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.LightPipeline;
+import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
+import net.vulkanmod.render.chunk.util.SimpleDirection;
import net.vulkanmod.render.model.quad.ModelQuadFlags;
+import net.vulkanmod.render.model.quad.ModelQuadView;
/**
* A smooth light pipeline which introduces sub-block AO computations
@@ -25,13 +25,11 @@ public class NewSmoothLightPipeline implements LightPipeline {
* Face data to allow face self-occlusion computation.
*/
private final SubBlockAoFace self = new SubBlockAoFace();
-
- private long cachedPos = Long.MIN_VALUE;
-
/**
* A temporary array for storing the intermediary results of weight data for non-aligned face blending.
*/
private final float[] weights = new float[4];
+ private long cachedPos = Long.MIN_VALUE;
public NewSmoothLightPipeline(LightDataAccess cache) {
this.lightCache = cache;
@@ -41,6 +39,26 @@ public NewSmoothLightPipeline(LightDataAccess cache) {
}
}
+ /**
+ * Clamps the given float to the range [0.0, 1.0].
+ */
+ private static float clamp(float v) {
+ if (v < 0.0f) {
+ return 0.0f;
+ } else if (v > 1.0f) {
+ return 1.0f;
+ }
+
+ return v;
+ }
+
+ /**
+ * Returns texture coordinates for the light map texture using the given block and sky light values.
+ */
+ private static int packLightMap(float sl, float bl) {
+ return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF);
+ }
+
@Override
public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFaceO, boolean shade) {
this.updateCachedData(pos.asLong());
@@ -260,24 +278,4 @@ private void updateCachedData(long key) {
}
}
- /**
- * Clamps the given float to the range [0.0, 1.0].
- */
- private static float clamp(float v) {
- if (v < 0.0f) {
- return 0.0f;
- } else if (v > 1.0f) {
- return 1.0f;
- }
-
- return v;
- }
-
- /**
- * Returns texture coordinates for the light map texture using the given block and sky light values.
- */
- private static int packLightMap(float sl, float bl) {
- return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF);
- }
-
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SmoothLightPipeline.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SmoothLightPipeline.java
index 154eb0518..d023fffce 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SmoothLightPipeline.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SmoothLightPipeline.java
@@ -3,39 +3,39 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
-import net.vulkanmod.render.chunk.util.SimpleDirection;
-import net.vulkanmod.render.model.quad.ModelQuadView;
-import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.LightPipeline;
+import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
+import net.vulkanmod.render.chunk.util.SimpleDirection;
import net.vulkanmod.render.model.quad.ModelQuadFlags;
+import net.vulkanmod.render.model.quad.ModelQuadView;
/**
* Re-adapted Sodium's smooth light pipeline
- *
+ *
* A light pipeline which produces smooth interpolated lighting and ambient occlusion for model quads. This
* implementation makes a number of improvements over vanilla's own "smooth lighting" option. In no particular order:
- *
+ *
* - Corner blocks are now selected from the correct set of neighbors above block faces (fixes MC-148689 and MC-12558)
* - Shading issues caused by anisotropy are fixed by re-orientating quads to a consistent ordering (fixes MC-138211)
* - Inset block faces are correctly shaded by their neighbors, fixing a number of problems with non-full blocks such as
- * grass paths (fixes MC-11783 and MC-108621)
+ * grass paths (fixes MC-11783 and MC-108621)
* - Blocks next to emissive blocks are too bright (MC-260989)
* - Synchronization issues between the main render thread's light engine and chunk build worker threads are corrected
- * by copying light data alongside block states, fixing a number of inconsistencies in baked chunks (no open issue)
- *
+ * by copying light data alongside block states, fixing a number of inconsistencies in baked chunks (no open issue)
+ *
* This implementation also includes a significant number of optimizations:
- *
+ *
* - Computed light data for a given block face is cached and re-used again when multiple quads exist for a given
- * facing, making complex block models less expensive to render
+ * facing, making complex block models less expensive to render
* - The light data cache encodes as much information as possible into integer words to improve cache locality and
- * to eliminate the multiple array lookups that would otherwise be needed, significantly speeding up this section
+ * to eliminate the multiple array lookups that would otherwise be needed, significantly speeding up this section
* - Block faces aligned to the block grid use a fast-path for mapping corner light values to vertices without expensive
- * interpolation or blending, speeding up most block renders
+ * interpolation or blending, speeding up most block renders
* - Some critical code paths have been re-written to hit the JVM's happy path, allowing it to perform auto-vectorization
- * of the blend functions
+ * of the blend functions
* - Information about a given model quad is cached to enable the light pipeline to make certain assumptions and skip
- * unnecessary computation
+ * unnecessary computation
*/
public class SmoothLightPipeline implements LightPipeline {
/**
@@ -47,16 +47,14 @@ public class SmoothLightPipeline implements LightPipeline {
* The cached face data for each side of a block, both inner and outer.
*/
private final AoFaceData[] cachedFaceData = new AoFaceData[6 * 2];
-
- /**
- * The position at which the cached face data was taken at.
- */
- private long cachedPos = Long.MIN_VALUE;
-
/**
* A temporary array for storing the intermediary results of weight data for non-aligned face blending.
*/
private final float[] weights = new float[4];
+ /**
+ * The position at which the cached face data was taken at.
+ */
+ private long cachedPos = Long.MIN_VALUE;
public SmoothLightPipeline(LightDataAccess cache) {
this.lightCache = cache;
@@ -66,6 +64,20 @@ public SmoothLightPipeline(LightDataAccess cache) {
}
}
+ private static float clamp(float v) {
+ if (v < 0.0f) {
+ return 0.0f;
+ } else if (v > 1.0f) {
+ return 1.0f;
+ }
+
+ return v;
+ }
+
+ private static int packLightMap(float sl, float bl) {
+ return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF);
+ }
+
@Override
public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFaceO, boolean shade) {
this.updateCachedData(pos.asLong());
@@ -248,18 +260,4 @@ private void updateCachedData(long key) {
}
}
- private static float clamp(float v) {
- if (v < 0.0f) {
- return 0.0f;
- } else if (v > 1.0f) {
- return 1.0f;
- }
-
- return v;
- }
-
- private static int packLightMap(float sl, float bl) {
- return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF);
- }
-
}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SubBlockAoFace.java b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SubBlockAoFace.java
index 765039c17..dee91e210 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SubBlockAoFace.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/light/smooth/SubBlockAoFace.java
@@ -1,8 +1,8 @@
package net.vulkanmod.render.chunk.build.light.smooth;
import net.minecraft.core.BlockPos;
-import net.vulkanmod.render.chunk.util.SimpleDirection;
import net.vulkanmod.render.chunk.build.light.data.LightDataAccess;
+import net.vulkanmod.render.chunk.util.SimpleDirection;
import static net.vulkanmod.render.chunk.build.light.data.LightDataAccess.*;
@@ -83,14 +83,13 @@ public void initLightData(LightDataAccess cache, BlockPos pos, SimpleDirection d
float c0ao = c0oc ? 0.2f : 1.0f;
final boolean c0em;
- if((f0c0 && f1c0) || (c0oc && d0co)) {
+ if ((f0c0 && f1c0) || (c0oc && d0co)) {
c0ao = 1.6f;
- }
- else {
+ } else {
c0ao += f0c0 ? 0.2f : 1.0f;
c0ao += f1c0 ? 0.2f : 1.0f;
- if(offset)
+ if (offset)
c0ao += d0co ? 0.2f : 1.0f;
else
c0ao += unpackFO(d0) ? 0.2f : 1.0f;
@@ -115,14 +114,13 @@ public void initLightData(LightDataAccess cache, BlockPos pos, SimpleDirection d
float c1ao = c1oc ? 0.2f : 1.0f;
final boolean c1em;
- if((f1c1 && f2c1) || (c1oc && d1co)) {
+ if ((f1c1 && f2c1) || (c1oc && d1co)) {
c1ao = 1.6f;
- }
- else {
+ } else {
c1ao += f1c1 ? 0.2f : 1.0f;
c1ao += f2c1 ? 0.2f : 1.0f;
- if(offset)
+ if (offset)
c1ao += d1co ? 0.2f : 1.0f;
else
c1ao += unpackFO(d1) ? 0.2f : 1.0f;
@@ -147,14 +145,13 @@ public void initLightData(LightDataAccess cache, BlockPos pos, SimpleDirection d
float c2ao = c2oc ? 0.2f : 1.0f;
final boolean c2em;
- if((f2c2 && f3c2) || (c2oc && d2co)) {
+ if ((f2c2 && f3c2) || (c2oc && d2co)) {
c2ao = 1.6f;
- }
- else {
+ } else {
c2ao += f2c2 ? 0.2f : 1.0f;
c2ao += f3c2 ? 0.2f : 1.0f;
- if(offset)
+ if (offset)
c2ao += d2co ? 0.2f : 1.0f;
else
c2ao += unpackFO(d2) ? 0.2f : 1.0f;
@@ -179,14 +176,13 @@ public void initLightData(LightDataAccess cache, BlockPos pos, SimpleDirection d
float c3ao = c3oc ? 0.2f : 1.0f;
final boolean c3em;
- if((f3c3 && f0c3) || (c3oc && d3co)) {
+ if ((f3c3 && f0c3) || (c3oc && d3co)) {
c3ao = 1.6f;
- }
- else {
+ } else {
c3ao += f3c3 ? 0.2f : 1.0f;
c3ao += f0c3 ? 0.2f : 1.0f;
- if(offset)
+ if (offset)
c3ao += d3co ? 0.2f : 1.0f;
else
c3ao += unpackFO(d3) ? 0.2f : 1.0f;
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/ColorHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/ColorHelper.java
new file mode 100644
index 000000000..fc3408f75
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/ColorHelper.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.helper;
+
+import java.nio.ByteOrder;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class ColorHelper {
+ private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
+
+ private ColorHelper() {
+ }
+
+ /**
+ * Component-wise multiply. Components need to be in same order in both inputs!
+ */
+ public static int multiplyColor(int color1, int color2) {
+ if (color1 == -1) {
+ return color2;
+ } else if (color2 == -1) {
+ return color1;
+ }
+
+ final int alpha = ((color1 >>> 24) & 0xFF) * ((color2 >>> 24) & 0xFF) / 0xFF;
+ final int red = ((color1 >>> 16) & 0xFF) * ((color2 >>> 16) & 0xFF) / 0xFF;
+ final int green = ((color1 >>> 8) & 0xFF) * ((color2 >>> 8) & 0xFF) / 0xFF;
+ final int blue = (color1 & 0xFF) * (color2 & 0xFF) / 0xFF;
+
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /**
+ * Multiplies three lowest components by shade. High byte (usually alpha) unchanged.
+ */
+ public static int multiplyRGB(int color, float shade) {
+ final int alpha = ((color >>> 24) & 0xFF);
+ final int red = (int) (((color >>> 16) & 0xFF) * shade);
+ final int green = (int) (((color >>> 8) & 0xFF) * shade);
+ final int blue = (int) ((color & 0xFF) * shade);
+
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /**
+ * Component-wise max.
+ */
+ public static int maxBrightness(int b0, int b1) {
+ if (b0 == 0) return b1;
+ if (b1 == 0) return b0;
+
+ return Math.max(b0 & 0xFFFF, b1 & 0xFFFF) | Math.max(b0 & 0xFFFF0000, b1 & 0xFFFF0000);
+ }
+
+ /*
+ Renderer color format: ARGB (0xAARRGGBB)
+ Vanilla color format (little endian): ABGR (0xAABBGGRR)
+ Vanilla color format (big endian): RGBA (0xRRGGBBAA)
+
+ Why does the vanilla color format change based on endianness?
+ See VertexConsumer#quad. Quad data is loaded as integers into
+ a native byte order buffer. Color is read directly from bytes
+ 12, 13, 14 of each vertex. A different byte order will yield
+ different results.
+
+ The renderer always uses ARGB because the API color methods
+ always consume and return ARGB. Vanilla block and item colors
+ also use ARGB.
+ */
+
+ /**
+ * Converts from ARGB color to ABGR color if little endian or RGBA color if big endian.
+ */
+ public static int toVanillaColor(int color) {
+ if (color == -1) {
+ return -1;
+ }
+
+ if (BIG_ENDIAN) {
+ // ARGB to RGBA
+ return ((color & 0x00FFFFFF) << 8) | ((color & 0xFF000000) >>> 24);
+ } else {
+ // ARGB to ABGR
+ return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
+ }
+ }
+
+ /**
+ * Converts to ARGB color from ABGR color if little endian or RGBA color if big endian.
+ */
+ public static int fromVanillaColor(int color) {
+ if (color == -1) {
+ return -1;
+ }
+
+ if (BIG_ENDIAN) {
+ // RGBA to ARGB
+ return ((color & 0xFFFFFF00) >>> 8) | ((color & 0x000000FF) << 24);
+ } else {
+ // ABGR to ARGB
+ return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/GeometryHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/GeometryHelper.java
new file mode 100644
index 000000000..f638d4e17
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/GeometryHelper.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.helper;
+
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.core.Direction;
+import net.minecraft.core.Direction.Axis;
+import net.minecraft.core.Direction.AxisDirection;
+import net.vulkanmod.render.quad.QuadView;
+import org.joml.Vector3f;
+
+import static net.minecraft.util.Mth.equal;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class GeometryHelper {
+ /**
+ * set when a quad touches all four corners of a unit cube.
+ */
+ public static final int CUBIC_FLAG = 1;
+ /**
+ * set when a quad is parallel to (but not necessarily on) a its light face.
+ */
+ public static final int AXIS_ALIGNED_FLAG = CUBIC_FLAG << 1;
+ /**
+ * set when a quad is coplanar with its light face. Implies {@link #AXIS_ALIGNED_FLAG}
+ */
+ public static final int LIGHT_FACE_FLAG = AXIS_ALIGNED_FLAG << 1;
+ /**
+ * how many bits quad header encoding should reserve for encoding geometry flags.
+ */
+ public static final int FLAG_BIT_COUNT = 3;
+ private static final float EPS_MIN = 0.0001f;
+ private static final float EPS_MAX = 1.0f - EPS_MIN;
+ private GeometryHelper() {
+ }
+
+ /**
+ * Analyzes the quad and returns a value with some combination
+ * of {@link #AXIS_ALIGNED_FLAG}, {@link #LIGHT_FACE_FLAG} and {@link #CUBIC_FLAG}.
+ * Intended use is to optimize lighting when the geometry is regular.
+ * Expects convex quads with all points co-planar.
+ */
+ public static int computeShapeFlags(QuadView quad) {
+ Direction lightFace = quad.lightFace();
+ int bits = 0;
+
+ if (isQuadParallelToFace(lightFace, quad)) {
+ bits |= AXIS_ALIGNED_FLAG;
+
+ if (isParallelQuadOnFace(lightFace, quad)) {
+ bits |= LIGHT_FACE_FLAG;
+ }
+ }
+
+ if (isQuadCubic(lightFace, quad)) {
+ bits |= CUBIC_FLAG;
+ }
+
+ return bits;
+ }
+
+ /**
+ * Returns true if quad is parallel to the given face.
+ * Does not validate quad winding order.
+ * Expects convex quads with all points co-planar.
+ */
+ public static boolean isQuadParallelToFace(Direction face, QuadView quad) {
+ int i = face.getAxis().ordinal();
+ final float val = quad.posByIndex(0, i);
+ return equal(val, quad.posByIndex(1, i)) && equal(val, quad.posByIndex(2, i)) && equal(val, quad.posByIndex(3, i));
+ }
+
+ /**
+ * True if quad - already known to be parallel to a face - is actually coplanar with it.
+ * For compatibility with vanilla resource packs, also true if quad is outside the face.
+ *
+ *
Test will be unreliable if not already parallel, use {@link #isQuadParallelToFace(Direction, QuadView)}
+ * for that purpose. Expects convex quads with all points co-planar.
+ */
+ public static boolean isParallelQuadOnFace(Direction lightFace, QuadView quad) {
+ final float x = quad.posByIndex(0, lightFace.getAxis().ordinal());
+ return lightFace.getAxisDirection() == AxisDirection.POSITIVE ? x >= EPS_MAX : x <= EPS_MIN;
+ }
+
+ /**
+ * Returns true if quad is truly a quad (not a triangle) and fills a full block cross-section.
+ * If known to be true, allows use of a simpler/faster AO lighting algorithm.
+ *
+ *
Does not check if quad is actually coplanar with the light face, nor does it check that all
+ * quad vertices are coplanar with each other.
+ *
+ *
Expects convex quads with all points co-planar.
+ */
+ public static boolean isQuadCubic(Direction lightFace, QuadView quad) {
+ int a, b;
+
+ switch (lightFace) {
+ case EAST:
+ case WEST:
+ a = 1;
+ b = 2;
+ break;
+ case UP:
+ case DOWN:
+ a = 0;
+ b = 2;
+ break;
+ case SOUTH:
+ case NORTH:
+ a = 1;
+ b = 0;
+ break;
+ default:
+ // handle WTF case
+ return false;
+ }
+
+ return confirmSquareCorners(a, b, quad);
+ }
+
+ /**
+ * Used by {@link #isQuadCubic(Direction, QuadView)}.
+ * True if quad touches all four corners of unit square.
+ *
+ *
For compatibility with resource packs that contain models with quads exceeding
+ * block boundaries, considers corners outside the block to be at the corners.
+ */
+ private static boolean confirmSquareCorners(int aCoordinate, int bCoordinate, QuadView quad) {
+ int flags = 0;
+
+ for (int i = 0; i < 4; i++) {
+ final float a = quad.posByIndex(i, aCoordinate);
+ final float b = quad.posByIndex(i, bCoordinate);
+
+ if (a <= EPS_MIN) {
+ if (b <= EPS_MIN) {
+ flags |= 1;
+ } else if (b >= EPS_MAX) {
+ flags |= 2;
+ } else {
+ return false;
+ }
+ } else if (a >= EPS_MAX) {
+ if (b <= EPS_MIN) {
+ flags |= 4;
+ } else if (b >= EPS_MAX) {
+ flags |= 8;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ return flags == 15;
+ }
+
+ /**
+ * Identifies the face to which the quad is most closely aligned.
+ * This mimics the value that {@link BakedQuad#getDirection()} returns, and is
+ * used in the vanilla renderer for all diffuse lighting.
+ *
+ *
Derived from the quad face normal and expects convex quads with all points co-planar.
+ */
+ public static Direction lightFace(QuadView quad) {
+ final Vector3f normal = quad.faceNormal();
+ switch (GeometryHelper.longestAxis(normal)) {
+ case X:
+ return normal.x() > 0 ? Direction.EAST : Direction.WEST;
+
+ case Y:
+ return normal.y() > 0 ? Direction.UP : Direction.DOWN;
+
+ case Z:
+ return normal.z() > 0 ? Direction.SOUTH : Direction.NORTH;
+
+ default:
+ // handle WTF case
+ return Direction.UP;
+ }
+ }
+
+ /**
+ * Simple 4-way compare, doesn't handle NaN values.
+ */
+ public static float min(float a, float b, float c, float d) {
+ final float x = a < b ? a : b;
+ final float y = c < d ? c : d;
+ return x < y ? x : y;
+ }
+
+ /**
+ * Simple 4-way compare, doesn't handle NaN values.
+ */
+ public static float max(float a, float b, float c, float d) {
+ final float x = a > b ? a : b;
+ final float y = c > d ? c : d;
+ return x > y ? x : y;
+ }
+
+ /**
+ * @see #longestAxis(float, float, float)
+ */
+ public static Axis longestAxis(Vector3f vec) {
+ return longestAxis(vec.x(), vec.y(), vec.z());
+ }
+
+ /**
+ * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector.
+ */
+ public static Axis longestAxis(float normalX, float normalY, float normalZ) {
+ Axis result = Axis.Y;
+ float longest = Math.abs(normalY);
+ float a = Math.abs(normalX);
+
+ if (a > longest) {
+ result = Axis.X;
+ longest = a;
+ }
+
+ return Math.abs(normalZ) > longest
+ ? Axis.Z : result;
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/NormalHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/NormalHelper.java
new file mode 100644
index 000000000..d8760698b
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/NormalHelper.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.helper;
+
+import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
+import net.vulkanmod.render.model.quad.ModelQuadView;
+import net.vulkanmod.render.quad.QuadView;
+import net.vulkanmod.render.vertex.format.I32_SNorm;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector3f;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class NormalHelper {
+ private static final float PACK = 127.0f;
+ private static final float UNPACK = 1.0f / PACK;
+ private NormalHelper() {
+ }
+
+ /**
+ * Stores a normal plus an extra value as a quartet of signed bytes.
+ * This is the same normal format that vanilla rendering expects.
+ * The extra value is for use by shaders.
+ */
+ public static int packNormal(float x, float y, float z, float w) {
+ x = Mth.clamp(x, -1, 1);
+ y = Mth.clamp(y, -1, 1);
+ z = Mth.clamp(z, -1, 1);
+ w = Mth.clamp(w, -1, 1);
+
+ return ((int) (x * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16) | (((int) (w * PACK) & 0xFF) << 24);
+ }
+
+ /**
+ * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type.
+ */
+ public static int packNormal(Vector3f normal, float w) {
+ return packNormal(normal.x(), normal.y(), normal.z(), w);
+ }
+
+ /**
+ * Like {@link #packNormal(float, float, float, float)}, but without a {@code w} value.
+ */
+ public static int packNormal(float x, float y, float z) {
+ x = Mth.clamp(x, -1, 1);
+ y = Mth.clamp(y, -1, 1);
+ z = Mth.clamp(z, -1, 1);
+
+ return ((int) (x * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16);
+ }
+
+ /**
+ * Like {@link #packNormal(Vector3f, float)}, but without a {@code w} value.
+ */
+ public static int packNormal(Vector3f normal) {
+ return packNormal(normal.x(), normal.y(), normal.z());
+ }
+
+ public static float unpackNormalX(int packedNormal) {
+ return ((byte) (packedNormal & 0xFF)) * UNPACK;
+ }
+
+ public static float unpackNormalY(int packedNormal) {
+ return ((byte) ((packedNormal >>> 8) & 0xFF)) * UNPACK;
+ }
+
+ public static float unpackNormalZ(int packedNormal) {
+ return ((byte) ((packedNormal >>> 16) & 0xFF)) * UNPACK;
+ }
+
+ public static float unpackNormalW(int packedNormal) {
+ return ((byte) ((packedNormal >>> 24) & 0xFF)) * UNPACK;
+ }
+
+ public static void unpackNormal(int packedNormal, Vector3f target) {
+ target.set(unpackNormalX(packedNormal), unpackNormalY(packedNormal), unpackNormalZ(packedNormal));
+ }
+
+ /**
+ * Computes the face normal of the given quad and saves it in the provided non-null vector.
+ * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that
+ * face and, if so, use the standard normal for that face direction.
+ *
+ *
Will work with triangles also. Assumes counter-clockwise winding order, which is the norm.
+ * Expects convex quads with all points co-planar.
+ */
+ public static void computeFaceNormal(@NotNull Vector3f saveTo, QuadView q) {
+ final Direction nominalFace = q.nominalFace();
+
+ if (nominalFace != null && GeometryHelper.isQuadParallelToFace(nominalFace, q)) {
+ saveTo.set(nominalFace.getStepX(), nominalFace.getStepY(), nominalFace.getStepZ());
+ return;
+ }
+
+ final float x0 = q.x(0);
+ final float y0 = q.y(0);
+ final float z0 = q.z(0);
+ final float x1 = q.x(1);
+ final float y1 = q.y(1);
+ final float z1 = q.z(1);
+ final float x2 = q.x(2);
+ final float y2 = q.y(2);
+ final float z2 = q.z(2);
+ final float x3 = q.x(3);
+ final float y3 = q.y(3);
+ final float z3 = q.z(3);
+
+ final float dx0 = x2 - x0;
+ final float dy0 = y2 - y0;
+ final float dz0 = z2 - z0;
+ final float dx1 = x3 - x1;
+ final float dy1 = y3 - y1;
+ final float dz1 = z3 - z1;
+
+ float normX = dy0 * dz1 - dz0 * dy1;
+ float normY = dz0 * dx1 - dx0 * dz1;
+ float normZ = dx0 * dy1 - dy0 * dx1;
+
+ float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
+
+ if (l != 0) {
+ normX /= l;
+ normY /= l;
+ normZ /= l;
+ }
+
+ saveTo.set(normX, normY, normZ);
+ }
+
+ public static int computePackedNormal(ModelQuadView q) {
+ final float x0 = q.getX(0);
+ final float y0 = q.getY(0);
+ final float z0 = q.getZ(0);
+ final float x1 = q.getX(1);
+ final float y1 = q.getY(1);
+ final float z1 = q.getZ(1);
+ final float x2 = q.getX(2);
+ final float y2 = q.getY(2);
+ final float z2 = q.getZ(2);
+ final float x3 = q.getX(3);
+ final float y3 = q.getY(3);
+ final float z3 = q.getZ(3);
+
+ final float dx0 = x2 - x0;
+ final float dy0 = y2 - y0;
+ final float dz0 = z2 - z0;
+ final float dx1 = x3 - x1;
+ final float dy1 = y3 - y1;
+ final float dz1 = z3 - z1;
+
+ float normX = dy0 * dz1 - dz0 * dy1;
+ float normY = dz0 * dx1 - dx0 * dz1;
+ float normZ = dx0 * dy1 - dy0 * dx1;
+
+ float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
+
+ if (l != 0) {
+ normX /= l;
+ normY /= l;
+ normZ /= l;
+ }
+
+ return I32_SNorm.packNormal(normX, normY, normZ);
+ }
+
+ public static int packedNormalFromDirection(Direction direction) {
+ return I32_SNorm.packNormal(direction.getStepX(), direction.getStepY(), direction.getStepZ());
+ }
+
+ public static void unpackNormalTo(int packedNormal, Vector3f normal) {
+ normal.set(I32_SNorm.unpackX(packedNormal), I32_SNorm.unpackY(packedNormal), I32_SNorm.unpackZ(packedNormal));
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/TextureHelper.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/TextureHelper.java
new file mode 100644
index 000000000..d14206a56
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/helper/TextureHelper.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.helper;
+
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import net.vulkanmod.render.quad.MutableQuadView;
+
+/**
+ * Handles most texture-baking use cases for model loaders and model libraries
+ * via {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. Also used by the API
+ * itself to implement automatic block-breaking models for enhanced models.
+ */
+public class TextureHelper {
+ private static final float NORMALIZER = 1f / 16f;
+ private static final VertexModifier[] ROTATIONS = new VertexModifier[]{
+ null,
+ (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), //90
+ (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), //180
+ (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270
+ };
+ private static final VertexModifier[] UVLOCKERS = new VertexModifier[6];
+
+ static {
+ UVLOCKERS[Direction.EAST.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i));
+ UVLOCKERS[Direction.WEST.get3DDataValue()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i));
+ UVLOCKERS[Direction.NORTH.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i));
+ UVLOCKERS[Direction.SOUTH.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i));
+ UVLOCKERS[Direction.DOWN.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i));
+ UVLOCKERS[Direction.UP.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), q.z(i));
+ }
+
+ private TextureHelper() {
+ }
+
+ /**
+ * Bakes textures in the provided vertex data, handling UV locking,
+ * rotation, interpolation, etc. Textures must not be already baked.
+ */
+ public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, int bakeFlags) {
+ if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) {
+ // Assigns normalized UV coordinates based on vertex positions
+ applyModifier(quad, UVLOCKERS[quad.nominalFace().get3DDataValue()]);
+ } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { // flag is NOT set, UVs are assumed to not be normalized yet as is the default, normalize through dividing by 16
+ // Scales from 0-16 to 0-1
+ applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER));
+ }
+
+ final int rotation = bakeFlags & 3;
+
+ if (rotation != 0) {
+ // Rotates texture around the center of sprite.
+ // Assumes normalized coordinates.
+ applyModifier(quad, ROTATIONS[rotation]);
+ }
+
+ if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) {
+ // Inverts U coordinates. Assumes normalized (0-1) values.
+ applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i)));
+ }
+
+ if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) {
+ // Inverts V coordinates. Assumes normalized (0-1) values.
+ applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i)));
+ }
+
+ interpolate(quad, sprite);
+ }
+
+ /**
+ * Faster than sprite method. Sprite computes span and normalizes inputs each call,
+ * so we'd have to denormalize before we called, only to have the sprite renormalize immediately.
+ */
+ private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) {
+ final float uMin = sprite.getU0();
+ final float uSpan = sprite.getU1() - uMin;
+ final float vMin = sprite.getV0();
+ final float vSpan = sprite.getV1() - vMin;
+
+ for (int i = 0; i < 4; i++) {
+ q.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan);
+ }
+ }
+
+ private static void applyModifier(MutableQuadView quad, VertexModifier modifier) {
+ for (int i = 0; i < 4; i++) {
+ modifier.apply(quad, i);
+ }
+ }
+
+ @FunctionalInterface
+ private interface VertexModifier {
+ void apply(MutableQuadView quad, int vertexIndex);
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/EncodingFormat.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/EncodingFormat.java
new file mode 100644
index 000000000..917c41890
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/EncodingFormat.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.mesh;
+
+import com.google.common.base.Preconditions;
+import com.mojang.blaze3d.vertex.DefaultVertexFormat;
+import com.mojang.blaze3d.vertex.VertexFormat;
+import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
+import net.vulkanmod.render.chunk.build.pipeline.helper.GeometryHelper;
+import net.vulkanmod.render.material.RenderMaterial;
+import net.vulkanmod.render.material.RenderMaterialRegistry;
+import net.vulkanmod.render.model.ModelHelper;
+import net.vulkanmod.render.quad.QuadView;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Holds all the array offsets and bit-wise encoders/decoders for
+ * packing/unpacking quad data in an array of integers.
+ * All of this is implementation-specific - that's why it isn't a "helper" class.
+ */
+public abstract class EncodingFormat {
+ public static final int HEADER_STRIDE = 4;
+ public static final int VERTEX_STRIDE;
+ public static final int QUAD_STRIDE;
+ public static final int QUAD_STRIDE_BYTES;
+ public static final int TOTAL_STRIDE;
+ static final int HEADER_BITS = 0;
+ static final int HEADER_FACE_NORMAL = 1;
+ static final int HEADER_COLOR_INDEX = 2;
+ static final int HEADER_TAG = 3;
+ static final int VERTEX_X;
+ static final int VERTEX_Y;
+ static final int VERTEX_Z;
+ static final int VERTEX_COLOR;
+ static final int VERTEX_U;
+ static final int VERTEX_V;
+ static final int VERTEX_LIGHTMAP;
+ static final int VERTEX_NORMAL;
+ /**
+ * used for quick clearing of quad buffers.
+ */
+ static final int[] EMPTY;
+ private static final int DIRECTION_COUNT = Direction.values().length;
+ private static final int NULLABLE_DIRECTION_COUNT = DIRECTION_COUNT + 1;
+ private static final int CULL_BIT_LENGTH = Mth.ceillog2(NULLABLE_DIRECTION_COUNT);
+ private static final int LIGHT_BIT_OFFSET = CULL_BIT_OFFSET + CULL_BIT_LENGTH;
+ private static final int CULL_MASK = bitMask(CULL_BIT_LENGTH, CULL_BIT_OFFSET);
+ private static final int NORMALS_BIT_LENGTH = 4;
+ private static final int GEOMETRY_BIT_LENGTH = GeometryHelper.FLAG_BIT_COUNT;
+ private static final int MATERIAL_BIT_LENGTH = 12;
+ private static final int CULL_BIT_OFFSET = 0;
+ private static final int LIGHT_BIT_LENGTH = Mth.ceillog2(DIRECTION_COUNT);
+ private static final int NORMALS_BIT_OFFSET = LIGHT_BIT_OFFSET + LIGHT_BIT_LENGTH;
+ private static final int GEOMETRY_BIT_OFFSET = NORMALS_BIT_OFFSET + NORMALS_BIT_LENGTH;
+ private static final int MATERIAL_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH;
+ private static final int TOTAL_BIT_LENGTH = MATERIAL_BIT_OFFSET + MATERIAL_BIT_LENGTH;
+ private static final int MATERIAL_MASK = bitMask(MATERIAL_BIT_LENGTH, MATERIAL_BIT_OFFSET);
+ private static final int GEOMETRY_MASK = bitMask(GEOMETRY_BIT_LENGTH, GEOMETRY_BIT_OFFSET);
+ private static final int NORMALS_MASK = bitMask(NORMALS_BIT_LENGTH, NORMALS_BIT_OFFSET);
+ private static final int LIGHT_MASK = bitMask(LIGHT_BIT_LENGTH, LIGHT_BIT_OFFSET);
+
+ static {
+ final VertexFormat format = DefaultVertexFormat.BLOCK;
+ VERTEX_X = HEADER_STRIDE;
+ VERTEX_Y = HEADER_STRIDE + 1;
+ VERTEX_Z = HEADER_STRIDE + 2;
+ VERTEX_COLOR = HEADER_STRIDE + 3;
+ VERTEX_U = HEADER_STRIDE + 4;
+ VERTEX_V = VERTEX_U + 1;
+ VERTEX_LIGHTMAP = HEADER_STRIDE + 6;
+ VERTEX_NORMAL = HEADER_STRIDE + 7;
+ VERTEX_STRIDE = format.getVertexSize() / 4;
+ QUAD_STRIDE = VERTEX_STRIDE * 4;
+ QUAD_STRIDE_BYTES = QUAD_STRIDE * 4;
+ TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE;
+ EMPTY = new int[TOTAL_STRIDE];
+
+ Preconditions.checkState(VERTEX_STRIDE == QuadView.VANILLA_VERTEX_STRIDE, "Indigo vertex stride (%s) mismatched with rendering API (%s)", VERTEX_STRIDE, QuadView.VANILLA_VERTEX_STRIDE);
+ Preconditions.checkState(QUAD_STRIDE == QuadView.VANILLA_QUAD_STRIDE, "Indigo quad stride (%s) mismatched with rendering API (%s)", QUAD_STRIDE, QuadView.VANILLA_QUAD_STRIDE);
+ }
+
+ static {
+ Preconditions.checkArgument(TOTAL_BIT_LENGTH <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE);
+ }
+
+ private EncodingFormat() {
+ }
+
+ public static int bitMask(int bitLength, int bitOffset) {
+ return ((1 << bitLength) - 1) << bitOffset;
+ }
+
+ @Nullable
+ static Direction cullFace(int bits) {
+ return ModelHelper.faceFromIndex((bits & CULL_MASK) >>> CULL_BIT_OFFSET);
+ }
+
+ static int cullFace(int bits, @Nullable Direction face) {
+ return (bits & ~CULL_MASK) | (ModelHelper.toFaceIndex(face) << CULL_BIT_OFFSET);
+ }
+
+ static Direction lightFace(int bits) {
+ return ModelHelper.faceFromIndex((bits & LIGHT_MASK) >>> LIGHT_BIT_OFFSET);
+ }
+
+ static int lightFace(int bits, Direction face) {
+ return (bits & ~LIGHT_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_BIT_OFFSET);
+ }
+
+ /**
+ * indicate if vertex normal has been set - bits correspond to vertex ordinals.
+ */
+ static int normalFlags(int bits) {
+ return (bits & NORMALS_MASK) >>> NORMALS_BIT_OFFSET;
+ }
+
+ static int normalFlags(int bits, int normalFlags) {
+ return (bits & ~NORMALS_MASK) | ((normalFlags << NORMALS_BIT_OFFSET) & NORMALS_MASK);
+ }
+
+ static int geometryFlags(int bits) {
+ return (bits & GEOMETRY_MASK) >>> GEOMETRY_BIT_OFFSET;
+ }
+
+ static int geometryFlags(int bits, int geometryFlags) {
+ return (bits & ~GEOMETRY_MASK) | ((geometryFlags << GEOMETRY_BIT_OFFSET) & GEOMETRY_MASK);
+ }
+
+ static RenderMaterial material(int bits) {
+ int id = (bits & MATERIAL_MASK) >>> MATERIAL_BIT_OFFSET;
+ return RenderMaterialRegistry.fromId(id);
+ }
+
+ static int material(int bits, RenderMaterial material) {
+ int id = RenderMaterialRegistry.getId(material);
+ return (bits & ~MATERIAL_MASK) | ((id << MATERIAL_BIT_OFFSET) & MATERIAL_MASK);
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/MutableQuadViewImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/MutableQuadViewImpl.java
new file mode 100644
index 000000000..89ac5114e
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/MutableQuadViewImpl.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.mesh;
+
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import net.vulkanmod.render.chunk.build.pipeline.helper.ColorHelper;
+import net.vulkanmod.render.chunk.build.pipeline.helper.NormalHelper;
+import net.vulkanmod.render.chunk.build.pipeline.helper.TextureHelper;
+import net.vulkanmod.render.material.RenderMaterial;
+import net.vulkanmod.render.material.RenderMaterialRegistry;
+import net.vulkanmod.render.model.quad.ModelQuadView;
+import net.vulkanmod.render.quad.MutableQuadView;
+import net.vulkanmod.render.quad.QuadView;
+import org.jetbrains.annotations.Nullable;
+
+import static net.vulkanmod.render.chunk.build.pipeline.mesh.EncodingFormat.*;
+
+/**
+ * Almost-concrete implementation of a mutable quad. The only missing part is {@link #emitDirectly()},
+ * because that depends on where/how it is used. (Mesh encoding vs. render-time transformation).
+ *
+ *
In many cases an instance of this class is used as an "editor quad". The editor quad's
+ * {@link #emitDirectly()} method calls some other internal method that transforms the quad
+ * data and then buffers it. Transformations should be the same as they would be in a vanilla
+ * render - the editor is serving mainly as a way to access vertex data without magical
+ * numbers. It also allows for a consistent interface for those transformations.
+ */
+public abstract class MutableQuadViewImpl extends QuadViewImpl implements MutableQuadView {
+ public void clear() {
+ System.arraycopy(EMPTY, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
+ isGeometryInvalid = true;
+ nominalFace = null;
+ normalFlags(0);
+ tag(0);
+ colorIndex(-1);
+ cullFace(null);
+ material(RenderMaterialRegistry.STANDARD_MATERIAL);
+ }
+
+ @Override
+ public MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) {
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
+ data[index] = Float.floatToRawIntBits(x);
+ data[index + 1] = Float.floatToRawIntBits(y);
+ data[index + 2] = Float.floatToRawIntBits(z);
+ isGeometryInvalid = true;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl color(int vertexIndex, int color) {
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl uv(int vertexIndex, float u, float v) {
+ final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
+ data[i] = Float.floatToRawIntBits(u);
+ data[i + 1] = Float.floatToRawIntBits(v);
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl spriteBake(TextureAtlasSprite sprite, int bakeFlags) {
+ TextureHelper.bakeSprite(this, sprite, bakeFlags);
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) {
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap;
+ return this;
+ }
+
+ protected void normalFlags(int flags) {
+ data[baseIndex + HEADER_BITS] = EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS], flags);
+ }
+
+ @Override
+ public MutableQuadViewImpl normal(int vertexIndex, float x, float y, float z) {
+ normalFlags(normalFlags() | (1 << vertexIndex));
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = NormalHelper.packNormal(x, y, z);
+ return this;
+ }
+
+ /**
+ * Internal helper method. Copies face normals to vertex normals lacking one.
+ */
+ public final void populateMissingNormals() {
+ final int normalFlags = this.normalFlags();
+
+ if (normalFlags == 0b1111) return;
+
+ final int packedFaceNormal = packedFaceNormal();
+
+ for (int v = 0; v < 4; v++) {
+ if ((normalFlags & (1 << v)) == 0) {
+ data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal;
+ }
+ }
+
+ normalFlags(0b1111);
+ }
+
+ @Override
+ public final MutableQuadViewImpl cullFace(@Nullable Direction face) {
+ data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(data[baseIndex + HEADER_BITS], face);
+ nominalFace(face);
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl nominalFace(@Nullable Direction face) {
+ nominalFace = face;
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl material(RenderMaterial material) {
+ if (material == null) {
+ material = RenderMaterialRegistry.STANDARD_MATERIAL;
+ }
+
+ data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], material);
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl colorIndex(int colorIndex) {
+ data[baseIndex + HEADER_COLOR_INDEX] = colorIndex;
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl tag(int tag) {
+ data[baseIndex + HEADER_TAG] = tag;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl copyFrom(QuadView quad) {
+ final QuadViewImpl q = (QuadViewImpl) quad;
+ q.computeGeometry();
+
+ System.arraycopy(q.data, q.baseIndex, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
+ faceNormal.set(q.faceNormal);
+ nominalFace = q.nominalFace;
+ isGeometryInvalid = false;
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) {
+ System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, VANILLA_QUAD_STRIDE);
+ isGeometryInvalid = true;
+
+ int colorIndex = baseIndex + VERTEX_COLOR;
+
+ for (int i = 0; i < 4; i++) {
+ data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]);
+ colorIndex += VERTEX_STRIDE;
+ }
+
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) {
+ fromVanilla(quad.vertices(), 0);
+ data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(0, cullFace);
+ nominalFace(quad.direction());
+ colorIndex(quad.tintIndex());
+
+ if (!quad.shade()) {
+ material = RenderMaterialRegistry.disableDiffuse(material, true);
+ }
+
+ material(material);
+ tag(0);
+
+ // Copy data from BakedQuad instead of calculating properties
+ ModelQuadView quadView = (ModelQuadView) (Object) quad;
+ int normal = quadView.getNormal();
+ data[baseIndex + HEADER_FACE_NORMAL] = normal;
+ NormalHelper.unpackNormalTo(normal, faceNormal);
+
+ Direction lightFace = quadView.lightFace();
+ data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], lightFace);
+ data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], quadView.getFlags());
+
+ this.facing = quadView.getQuadFacing();
+
+ this.isGeometryInvalid = false;
+ return this;
+ }
+
+ /**
+ * Emit the quad without clearing the underlying data.
+ * Geometry is not guaranteed to be valid when called, but can be computed by calling {@link #computeGeometry()}.
+ */
+ public abstract void emitDirectly();
+
+ @Override
+ public final MutableQuadViewImpl emit() {
+ emitDirectly();
+ clear();
+ return this;
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/QuadViewImpl.java b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/QuadViewImpl.java
new file mode 100644
index 000000000..279a6afe0
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/chunk/build/pipeline/mesh/QuadViewImpl.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.vulkanmod.render.chunk.build.pipeline.mesh;
+
+import net.minecraft.core.Direction;
+import net.vulkanmod.render.chunk.build.pipeline.helper.ColorHelper;
+import net.vulkanmod.render.chunk.build.pipeline.helper.GeometryHelper;
+import net.vulkanmod.render.chunk.build.pipeline.helper.NormalHelper;
+import net.vulkanmod.render.chunk.cull.QuadFacing;
+import net.vulkanmod.render.material.RenderMaterial;
+import net.vulkanmod.render.model.quad.ModelQuadFlags;
+import net.vulkanmod.render.model.quad.ModelQuadView;
+import net.vulkanmod.render.quad.QuadView;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector2f;
+import org.joml.Vector3f;
+
+import static net.vulkanmod.render.chunk.build.pipeline.mesh.EncodingFormat.*;
+
+/**
+ * Base class for all quads / quad makers. Handles the ugly bits
+ * of maintaining and encoding the quad state.
+ */
+public class QuadViewImpl implements QuadView, ModelQuadView {
+ protected final Vector3f faceNormal = new Vector3f();
+ @Nullable
+ protected Direction nominalFace;
+ /**
+ * True when face normal, light face, or geometry flags may not match geometry.
+ */
+ protected boolean isGeometryInvalid = true;
+ /**
+ * Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array.
+ */
+ protected int[] data;
+
+ /**
+ * Beginning of the quad. Also the header index.
+ */
+ protected int baseIndex = 0;
+
+ protected QuadFacing facing;
+
+ /**
+ * Decodes necessary state from the backing data array.
+ * The encoded data must contain valid computed geometry.
+ */
+ public void load() {
+ isGeometryInvalid = false;
+ nominalFace = lightFace();
+ NormalHelper.unpackNormal(packedFaceNormal(), faceNormal);
+ facing = QuadFacing.fromNormal(faceNormal);
+ }
+
+ protected void computeGeometry() {
+ if (isGeometryInvalid) {
+ isGeometryInvalid = false;
+
+ NormalHelper.computeFaceNormal(faceNormal, this);
+ data[baseIndex + HEADER_FACE_NORMAL] = NormalHelper.packNormal(faceNormal);
+
+ // depends on face normal
+ Direction lightFace = GeometryHelper.lightFace(this);
+ data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], lightFace);
+
+ // depends on light face
+ data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], ModelQuadFlags.getQuadFlags(this, lightFace));
+
+ facing = QuadFacing.fromNormal(faceNormal);
+ }
+ }
+
+ /**
+ * gets flags used for lighting - lazily computed via {@link GeometryHelper#computeShapeFlags(QuadView)}.
+ */
+ public int geometryFlags() {
+ computeGeometry();
+ return EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS]);
+ }
+
+ public boolean hasShade() {
+ return !material().disableDiffuse();
+ }
+
+ @Override
+ public float x(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]);
+ }
+
+ @Override
+ public float y(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]);
+ }
+
+ @Override
+ public float z(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]);
+ }
+
+ @Override
+ public float posByIndex(int vertexIndex, int coordinateIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]);
+ }
+
+ @Override
+ public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) {
+ if (target == null) {
+ target = new Vector3f();
+ }
+
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
+ target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), Float.intBitsToFloat(data[index + 2]));
+ return target;
+ }
+
+ @Override
+ public int color(int vertexIndex) {
+ return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR];
+ }
+
+ @Override
+ public float u(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]);
+ }
+
+ @Override
+ public float v(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]);
+ }
+
+ @Override
+ public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) {
+ if (target == null) {
+ target = new Vector2f();
+ }
+
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
+ target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]));
+ return target;
+ }
+
+ @Override
+ public int lightmap(int vertexIndex) {
+ return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP];
+ }
+
+ public int normalFlags() {
+ return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ public boolean hasNormal(int vertexIndex) {
+ return (normalFlags() & (1 << vertexIndex)) != 0;
+ }
+
+ /**
+ * True if any vertex normal has been set.
+ */
+ public boolean hasVertexNormals() {
+ return normalFlags() != 0;
+ }
+
+ /**
+ * True if all vertex normals have been set.
+ */
+ public boolean hasAllVertexNormals() {
+ return (normalFlags() & 0b1111) == 0b1111;
+ }
+
+ protected final int normalIndex(int vertexIndex) {
+ return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL;
+ }
+
+ @Override
+ public float normalX(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormalHelper.unpackNormalX(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ public float normalY(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormalHelper.unpackNormalY(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ public float normalZ(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormalHelper.unpackNormalZ(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ @Nullable
+ public Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) {
+ if (hasNormal(vertexIndex)) {
+ if (target == null) {
+ target = new Vector3f();
+ }
+
+ final int normal = data[normalIndex(vertexIndex)];
+ NormalHelper.unpackNormal(normal, target);
+ return target;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ public final Direction cullFace() {
+ return EncodingFormat.cullFace(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ @NotNull
+ public final Direction lightFace() {
+ computeGeometry();
+ return EncodingFormat.lightFace(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ @Nullable
+ public final Direction nominalFace() {
+ return nominalFace;
+ }
+
+ public final int packedFaceNormal() {
+ computeGeometry();
+ return data[baseIndex + HEADER_FACE_NORMAL];
+ }
+
+ @Override
+ public final Vector3f faceNormal() {
+ computeGeometry();
+ return faceNormal;
+ }
+
+ @Override
+ public final RenderMaterial material() {
+ return EncodingFormat.material(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ public final int colorIndex() {
+ return data[baseIndex + HEADER_COLOR_INDEX];
+ }
+
+ @Override
+ public final int tag() {
+ return data[baseIndex + HEADER_TAG];
+ }
+
+ @Override
+ public final void toVanilla(int[] target, int targetIndex) {
+ System.arraycopy(data, baseIndex + HEADER_STRIDE, target, targetIndex, QUAD_STRIDE);
+
+ // The color is the fourth integer in each vertex.
+ // EncodingFormat.VERTEX_COLOR is not used because it also
+ // contains the header size; vanilla quads do not have a header.
+ int colorIndex = targetIndex + 3;
+
+ for (int i = 0; i < 4; i++) {
+ target[colorIndex] = ColorHelper.toVanillaColor(target[colorIndex]);
+ colorIndex += VANILLA_VERTEX_STRIDE;
+ }
+ }
+
+ @Override
+ public int getFlags() {
+ return geometryFlags();
+ }
+
+ @Override
+ public float getX(int idx) {
+ return this.x(idx);
+ }
+
+ @Override
+ public float getY(int idx) {
+ return this.y(idx);
+ }
+
+ @Override
+ public float getZ(int idx) {
+ return this.z(idx);
+ }
+
+ @Override
+ public int getColor(int idx) {
+ return this.color(idx);
+ }
+
+ @Override
+ public float getU(int idx) {
+ return this.u(idx);
+ }
+
+ @Override
+ public float getV(int idx) {
+ return this.v(idx);
+ }
+
+ @Override
+ public int getColorIndex() {
+ return this.colorIndex();
+ }
+
+ @Override
+ public Direction getFacingDirection() {
+ return this.lightFace();
+ }
+
+ @Override
+ public int getNormal() {
+ return packedFaceNormal();
+ }
+
+ @Override
+ public QuadFacing getQuadFacing() {
+ return this.facing;
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/renderer/BlockRenderer.java b/src/main/java/net/vulkanmod/render/chunk/build/renderer/BlockRenderer.java
index f04244f3f..3f8a14ecc 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/renderer/BlockRenderer.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/renderer/BlockRenderer.java
@@ -1,124 +1,233 @@
package net.vulkanmod.render.chunk.build.renderer;
-import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
-import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
-import net.fabricmc.fabric.api.renderer.v1.material.ShadeMode;
-import net.fabricmc.fabric.api.util.TriState;
+import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.color.block.BlockColor;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
-import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.client.renderer.block.BlockRenderDispatcher;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.block.model.BlockModelPart;
+import net.minecraft.client.renderer.block.model.BlockStateModel;
import net.minecraft.core.BlockPos;
-import net.minecraft.core.Vec3i;
+import net.minecraft.core.Direction;
+import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.levelgen.SingleThreadedRandomSource;
import net.minecraft.world.phys.Vec3;
import net.vulkanmod.Initializer;
-import net.vulkanmod.render.chunk.build.frapi.mesh.MutableQuadViewImpl;
-import net.vulkanmod.render.chunk.build.frapi.render.AbstractBlockRenderContext;
+import net.vulkanmod.interfaces.color.BlockColorsExtended;
+import net.vulkanmod.render.chunk.build.RenderRegion;
import net.vulkanmod.render.chunk.build.light.LightPipeline;
import net.vulkanmod.render.chunk.build.light.data.QuadLightData;
+import net.vulkanmod.render.chunk.build.pipeline.helper.ColorHelper;
+import net.vulkanmod.render.chunk.build.pipeline.mesh.EncodingFormat;
+import net.vulkanmod.render.chunk.build.pipeline.mesh.MutableQuadViewImpl;
import net.vulkanmod.render.chunk.build.thread.BuilderResources;
import net.vulkanmod.render.chunk.cull.QuadFacing;
-import net.vulkanmod.render.model.quad.QuadUtils;
+import net.vulkanmod.render.material.RenderMaterial;
+import net.vulkanmod.render.material.RenderMaterialRegistry;
import net.vulkanmod.render.model.quad.ModelQuadView;
+import net.vulkanmod.render.model.quad.QuadUtils;
import net.vulkanmod.render.vertex.TerrainBufferBuilder;
import net.vulkanmod.render.vertex.TerrainBuilder;
import net.vulkanmod.render.vertex.TerrainRenderType;
import net.vulkanmod.render.vertex.format.I32_SNorm;
import net.vulkanmod.vulkan.util.ColorUtil;
+import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
-public class BlockRenderer extends AbstractBlockRenderContext {
- private Vector3f pos;
+import java.util.List;
- private BuilderResources resources;
- private TerrainBuilder terrainBuilder;
+public class BlockRenderer {
+ private static final Direction[] DIRECTIONS = Direction.values();
- final boolean backFaceCulling = Initializer.CONFIG.backFaceCulling;
+ private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
+ {
+ data = new int[EncodingFormat.TOTAL_STRIDE];
+ clear();
+ }
+ @Override
+ public void emitDirectly() {
+ // not used – quads are consumed immediately
+ }
+ };
+
+ private final Object2ByteLinkedOpenHashMap occlusionCache = new Object2ByteLinkedOpenHashMap<>(2048, 0.25F) {
+ @Override
+ protected void rehash(int i) {
+ }
+ };
+ private final OcclusionKey lookupKey = new OcclusionKey();
+
+ private final RandomSource random = RandomSource.create();
+ private final QuadLightData quadLightData = new QuadLightData();
+ private final LightPipeline flatLightPipeline;
+ private final LightPipeline smoothLightPipeline;
+ private final net.vulkanmod.render.chunk.build.color.BlockColorRegistry blockColorRegistry;
+ private final boolean backFaceCulling = Initializer.CONFIG.backFaceCulling;
+ private final BlockPos.MutableBlockPos tempPos = new BlockPos.MutableBlockPos();
+ private BuilderResources resources;
+ private BlockAndTintGetter renderRegion;
+ private boolean enableCulling = true;
+ private BlockState blockState;
+ private BlockPos blockPos;
+ private boolean useAO;
+ private long seed;
private TerrainRenderType renderType;
+ private TerrainBuilder terrainBuilder;
+ private Vector3f currentPos;
+ private int cullCompletionFlags;
+ private int cullResultFlags;
+
+ public BlockRenderer(LightPipeline flatLightPipeline, LightPipeline smoothLightPipeline) {
+ this.flatLightPipeline = flatLightPipeline;
+ this.smoothLightPipeline = smoothLightPipeline;
+ this.occlusionCache.defaultReturnValue((byte) 127);
+ this.blockColorRegistry = BlockColorsExtended.from(Minecraft.getInstance().getBlockColors()).getColorResolverMap();
+ }
public void setResources(BuilderResources resources) {
this.resources = resources;
}
- public BlockRenderer(LightPipeline flatLightPipeline, LightPipeline smoothLightPipeline) {
- super();
- this.setupLightPipelines(flatLightPipeline, smoothLightPipeline);
-
- this.random = new SingleThreadedRandomSource(42L);
+ public void prepareForWorld(RenderRegion region, boolean enableCulling) {
+ this.renderRegion = region;
+ this.enableCulling = enableCulling;
}
public void renderBlock(BlockState blockState, BlockPos blockPos, Vector3f pos) {
- this.pos = pos;
- this.blockPos = blockPos;
+ if (this.renderRegion == null) {
+ return;
+ }
+
this.blockState = blockState;
+ this.blockPos = blockPos;
+ this.currentPos = pos;
this.seed = blockState.getSeed(blockPos);
+ this.random.setSeed(this.seed);
+ this.useAO = Minecraft.useAmbientOcclusion() && blockState.getLightEmission() == 0;
- TerrainRenderType renderType = TerrainRenderType.get(ItemBlockRenderTypes.getChunkRenderType(blockState));
- renderType = TerrainRenderType.getRemapped(renderType);
- this.renderType = renderType;
- this.terrainBuilder = this.resources.builderPack.builder(renderType);
+ TerrainRenderType baseType = TerrainRenderType.fromChunkLayer(ItemBlockRenderTypes.getChunkRenderType(blockState));
+ baseType = TerrainRenderType.getRemapped(baseType);
+ this.renderType = baseType;
+ this.terrainBuilder = this.resources.builderPack.builder(baseType);
this.terrainBuilder.setBlockAttributes(blockState);
- BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(blockState);
-
- BlockAndTintGetter renderRegion = this.renderRegion;
- Vec3 offset = blockState.getOffset(renderRegion, blockPos);
+ BlockAndTintGetter region = this.renderRegion;
+ Vec3 offset = blockState.getOffset(blockPos);
pos.add((float) offset.x, (float) offset.y, (float) offset.z);
- this.prepareForBlock(blockState, blockPos, model.useAmbientOcclusion());
+ BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();
+ BlockStateModel stateModel = dispatcher.getBlockModel(blockState);
+
+ this.cullCompletionFlags = 0;
+ this.cullResultFlags = 0;
+
+ List parts = new ObjectArrayList<>();
+ stateModel.collectParts(this.random, parts);
+
+ for (BlockModelPart part : parts) {
+ boolean partUsesAo = part.useAmbientOcclusion();
+ RenderMaterial baseMaterial = partUsesAo ? RenderMaterialRegistry.STANDARD_MATERIAL : RenderMaterialRegistry.NO_AO_MATERIAL;
+ emitQuads(part.getQuads(null), baseMaterial, partUsesAo, null);
- model.emitBlockQuads(renderRegion, blockState, blockPos, this.randomSupplier, this);
+ for (Direction direction : DIRECTIONS) {
+ if (!shouldRenderFace(direction)) {
+ continue;
+ }
+
+ emitQuads(part.getQuads(direction), baseMaterial, partUsesAo, direction);
+ }
+ }
}
- protected void endRenderQuad(MutableQuadViewImpl quad) {
- final RenderMaterial mat = quad.material();
- final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
- final TriState aoMode = mat.ambientOcclusion();
- final boolean ao = this.useAO && (aoMode == TriState.TRUE || (aoMode == TriState.DEFAULT && this.defaultAO));
- final boolean emissive = mat.emissive();
- final boolean vanillaShade = mat.shadeMode() == ShadeMode.VANILLA;
+ private void emitQuads(List quads, RenderMaterial baseMaterial, boolean partUsesAo, @Nullable Direction cullFace) {
+ if (quads == null || quads.isEmpty()) {
+ return;
+ }
+
+ for (BakedQuad bakedQuad : quads) {
+ renderQuad(bakedQuad, baseMaterial, partUsesAo, cullFace);
+ }
+ }
+
+ private void renderQuad(BakedQuad bakedQuad, RenderMaterial baseMaterial, boolean partUsesAo, @Nullable Direction cullFace) {
+ MutableQuadViewImpl quad = this.editorQuad;
+ quad.clear();
+
+ RenderMaterial material = bakedQuad.shade()
+ ? baseMaterial
+ : RenderMaterialRegistry.disableDiffuse(baseMaterial, true);
+
+ quad.fromVanilla(bakedQuad, material, cullFace);
+
+ colorizeQuad(quad, quad.colorIndex());
+
+ boolean emissive = bakedQuad.lightEmission() > 0;
+ boolean applyAo = this.useAO && partUsesAo;
+ LightPipeline pipeline = applyAo ? this.smoothLightPipeline : this.flatLightPipeline;
+
+ shadeQuad(quad, pipeline, emissive);
+ copyLightData(quad);
+ bufferQuad(this.terrainBuilder, this.currentPos, quad, this.quadLightData);
+ }
- TerrainBuilder terrainBuilder = getBufferBuilder(mat.blendMode());
+ private void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
+ if (colorIndex == -1) {
+ return;
+ }
- LightPipeline lightPipeline = ao ? this.smoothLightPipeline : this.flatLightPipeline;
+ BlockColor blockColor = this.blockColorRegistry.getBlockColor(this.blockState.getBlock());
+ int color = blockColor != null ? blockColor.getColor(this.blockState, this.renderRegion, this.blockPos, colorIndex) : -1;
+ color = 0xFF000000 | color;
- colorizeQuad(quad, colorIndex);
- shadeQuad(quad, lightPipeline, emissive, vanillaShade);
- bufferQuad(terrainBuilder, this.pos, quad, this.quadLightData);
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyColor(color, quad.color(i)));
+ }
}
- private TerrainBuilder getBufferBuilder(BlendMode blendMode) {
- if (blendMode == BlendMode.DEFAULT) {
- return this.terrainBuilder;
+ private void shadeQuad(MutableQuadViewImpl quad, LightPipeline pipeline, boolean emissive) {
+ pipeline.calculate(quad, this.blockPos, this.quadLightData, quad.cullFace(), quad.lightFace(), quad.hasShade());
+
+ if (emissive) {
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyRGB(quad.color(i), this.quadLightData.br[i]));
+ this.quadLightData.lm[i] = net.minecraft.client.renderer.LightTexture.FULL_BRIGHT;
+ }
} else {
- TerrainRenderType renderType = TerrainRenderType.get(blendMode.blockRenderLayer);
- renderType = TerrainRenderType.getRemapped(renderType);
- TerrainBuilder bufferBuilder = this.resources.builderPack.builder(renderType);
- bufferBuilder.setBlockAttributes(this.blockState);
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyRGB(quad.color(i), this.quadLightData.br[i]));
+ this.quadLightData.lm[i] = ColorHelper.maxBrightness(quad.lightmap(i), this.quadLightData.lm[i]);
+ }
+ }
+ }
- return bufferBuilder;
+ private void copyLightData(MutableQuadViewImpl quad) {
+ for (int i = 0; i < 4; i++) {
+ quad.lightmap(i, this.quadLightData.lm[i]);
}
}
- public void bufferQuad(TerrainBuilder terrainBuilder, Vector3f pos, ModelQuadView quad, QuadLightData quadLightData) {
+ private void bufferQuad(TerrainBuilder terrainBuilder, Vector3f pos, ModelQuadView quad, QuadLightData quadLightData) {
QuadFacing quadFacing = quad.getQuadFacing();
- if (renderType == TerrainRenderType.TRANSLUCENT || !this.backFaceCulling) {
+ if (this.renderType == TerrainRenderType.TRANSLUCENT || !this.backFaceCulling) {
quadFacing = QuadFacing.UNDEFINED;
}
TerrainBufferBuilder bufferBuilder = terrainBuilder.getBufferBuilder(quadFacing.ordinal());
- Vec3i normal = quad.getFacingDirection().getNormal();
- int packedNormal = I32_SNorm.packNormal(normal.getX(), normal.getY(), normal.getZ());
+ Direction facingDirection = quad.getFacingDirection();
+ int packedNormal = facingDirection != null
+ ? I32_SNorm.packNormal(facingDirection.getStepX(), facingDirection.getStepY(), facingDirection.getStepZ())
+ : quad.getNormal();
float[] brightnessArr = quadLightData.br;
int[] lights = quadLightData.lm;
- // Rotate triangles if needed to fix AO anisotropy
int idx = QuadUtils.getIterationStartIdx(brightnessArr, lights);
bufferBuilder.ensureCapacity();
@@ -129,7 +238,6 @@ public void bufferQuad(TerrainBuilder terrainBuilder, Vector3f pos, ModelQuadVie
final float z = pos.z() + quad.getZ(idx);
final int quadColor = quad.getColor(idx);
-
int color = ColorUtil.ARGB.toRGBA(quadColor);
final int light = lights[idx];
@@ -140,8 +248,112 @@ public void bufferQuad(TerrainBuilder terrainBuilder, Vector3f pos, ModelQuadVie
idx = (idx + 1) & 0b11;
}
+ }
+
+ private boolean shouldRenderFace(@Nullable Direction face) {
+ if (face == null || !this.enableCulling) {
+ return true;
+ }
+
+ int mask = 1 << face.get3DDataValue();
+ if ((this.cullCompletionFlags & mask) == 0) {
+ this.cullCompletionFlags |= mask;
+
+ if (faceNotOccluded(this.blockState, face)) {
+ this.cullResultFlags |= mask;
+ return true;
+ }
+
+ return false;
+ }
+ return (this.cullResultFlags & mask) != 0;
}
-}
+ private boolean faceNotOccluded(BlockState state, Direction face) {
+ BlockGetter getter = this.renderRegion;
+ BlockPos adjPos = this.tempPos.setWithOffset(this.blockPos, face);
+ BlockState adjacent = getter.getBlockState(adjPos);
+
+ if (state.skipRendering(adjacent, face)) {
+ return false;
+ }
+ if (adjacent.canOcclude()) {
+ var shape = state.getFaceOcclusionShape(face);
+ if (shape.isEmpty()) {
+ return true;
+ }
+
+ var adjShape = adjacent.getFaceOcclusionShape(face.getOpposite());
+ if (adjShape.isEmpty()) {
+ return true;
+ }
+
+ if (shape == net.minecraft.world.phys.shapes.Shapes.block() && adjShape == net.minecraft.world.phys.shapes.Shapes.block()) {
+ return false;
+ }
+
+ OcclusionKey key = this.lookupKey.set(state, adjacent, face);
+ byte cached = this.occlusionCache.getAndMoveToFirst(key);
+ if (cached != 127) {
+ return cached != 0;
+ }
+
+ boolean result = net.minecraft.world.phys.shapes.Shapes.joinIsNotEmpty(shape, adjShape, net.minecraft.world.phys.shapes.BooleanOp.ONLY_FIRST);
+ if (this.occlusionCache.size() == 2048) {
+ this.occlusionCache.removeLastByte();
+ }
+
+ this.occlusionCache.putAndMoveToFirst(new OcclusionKey(state, adjacent, face), (byte) (result ? 1 : 0));
+ return result;
+ }
+
+ return true;
+ }
+
+ public void clearCache() {
+ this.occlusionCache.clear();
+ }
+
+ private static final class OcclusionKey {
+ private BlockState state;
+ private BlockState adjacent;
+ private Direction face;
+
+ OcclusionKey() {
+ }
+
+ OcclusionKey(BlockState state, BlockState adjacent, Direction face) {
+ this.state = state;
+ this.adjacent = adjacent;
+ this.face = face;
+ }
+
+ OcclusionKey set(BlockState state, BlockState adjacent, Direction face) {
+ this.state = state;
+ this.adjacent = adjacent;
+ this.face = face;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof OcclusionKey other)) {
+ return false;
+ }
+ return this.state == other.state && this.adjacent == other.adjacent && this.face == other.face;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = System.identityHashCode(this.state);
+ result = 31 * result + System.identityHashCode(this.adjacent);
+ result = 31 * result + this.face.ordinal();
+ return result;
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/renderer/DefaultFluidRenderers.java b/src/main/java/net/vulkanmod/render/chunk/build/renderer/DefaultFluidRenderers.java
index 0fbbe5415..6f7cf270d 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/renderer/DefaultFluidRenderers.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/renderer/DefaultFluidRenderers.java
@@ -5,13 +5,13 @@
public abstract class DefaultFluidRenderers {
- private static final ReferenceOpenHashSet set = new ReferenceOpenHashSet<>();
+ private static final ReferenceOpenHashSet set = new ReferenceOpenHashSet<>();
- public static void add(FluidRenderHandler handler) {
- set.add(handler);
- }
+ public static void add(FluidRenderHandler handler) {
+ set.add(handler);
+ }
- public static boolean has(FluidRenderHandler handler) {
- return set.contains(handler);
- }
+ public static boolean has(FluidRenderHandler handler) {
+ return set.contains(handler);
+ }
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/renderer/FluidRenderer.java b/src/main/java/net/vulkanmod/render/chunk/build/renderer/FluidRenderer.java
index 30c5317f8..45617eda3 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/renderer/FluidRenderer.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/renderer/FluidRenderer.java
@@ -40,19 +40,29 @@ public class FluidRenderer implements FluidRendering.DefaultRenderer {
private final BlockPos.MutableBlockPos mBlockPos = new BlockPos.MutableBlockPos();
private final ModelQuad modelQuad = new ModelQuad();
-
- BuilderResources resources;
-
private final LightPipeline smoothLightPipeline;
private final LightPipeline flatLightPipeline;
-
private final int[] quadColors = new int[4];
+ BuilderResources resources;
public FluidRenderer(LightPipeline flatLightPipeline, LightPipeline smoothLightPipeline) {
this.smoothLightPipeline = smoothLightPipeline;
this.flatLightPipeline = flatLightPipeline;
}
+ public static boolean shouldRenderFace(BlockAndTintGetter blockAndTintGetter, BlockPos blockPos, FluidState fluidState, BlockState blockState, Direction direction, BlockState adjBlockState) {
+
+ if (adjBlockState.getFluidState().getType().isSame(fluidState.getType()))
+ return false;
+
+ // self-occlusion by waterlogging
+ if (blockState.canOcclude()) {
+ return !blockState.isFaceSturdy(blockAndTintGetter, blockPos, direction);
+ }
+
+ return true;
+ }
+
public void setResources(BuilderResources resources) {
this.resources = resources;
}
@@ -60,7 +70,7 @@ public void setResources(BuilderResources resources) {
public void renderLiquid(BlockState blockState, FluidState fluidState, BlockPos blockPos) {
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getType());
- TerrainRenderType renderType = TerrainRenderType.get(ItemBlockRenderTypes.getRenderLayer(fluidState));
+ TerrainRenderType renderType = TerrainRenderType.fromChunkLayer(ItemBlockRenderTypes.getRenderLayer(fluidState));
renderType = TerrainRenderType.getRemapped(renderType);
TerrainBufferBuilder bufferBuilder = this.resources.builderPack.builder(renderType).getBufferBuilder(QuadFacing.UNDEFINED.ordinal());
@@ -70,14 +80,14 @@ public void renderLiquid(BlockState blockState, FluidState fluidState, BlockPos
handler = FluidRenderHandlerRegistry.INSTANCE.get(isLava ? Fluids.LAVA : Fluids.WATER);
}
- FluidRendering.render(handler, this.resources.getRegion(),blockPos, bufferBuilder, blockState, fluidState, this);
+ FluidRendering.render(handler, this.resources.getRegion(), blockPos, bufferBuilder, blockState, fluidState, this);
}
private boolean isFaceOccludedByState(BlockGetter blockGetter, float h, Direction direction, BlockPos blockPos, BlockState blockState) {
- mBlockPos.set(blockPos).offset(Direction.DOWN.getNormal());
+ mBlockPos.set(blockPos).move(Direction.DOWN);
if (blockState.canOcclude()) {
- VoxelShape occlusionShape = blockState.getOcclusionShape(blockGetter, mBlockPos);
+ VoxelShape occlusionShape = blockState.getOcclusionShape();
if (occlusionShape == Shapes.block()) {
return direction != Direction.UP;
@@ -86,25 +96,12 @@ private boolean isFaceOccludedByState(BlockGetter blockGetter, float h, Directio
}
VoxelShape voxelShape = Shapes.box(0.0, 0.0, 0.0, 1.0, h, 1.0);
- return Shapes.blockOccudes(voxelShape, occlusionShape, direction);
+ return Shapes.blockOccludes(voxelShape, occlusionShape, direction);
} else {
return false;
}
}
- public static boolean shouldRenderFace(BlockAndTintGetter blockAndTintGetter, BlockPos blockPos, FluidState fluidState, BlockState blockState, Direction direction, BlockState adjBlockState) {
-
- if (adjBlockState.getFluidState().getType().isSame(fluidState.getType()))
- return false;
-
- // self-occlusion by waterlogging
- if (blockState.canOcclude()) {
- return !blockState.isFaceSturdy(blockAndTintGetter, blockPos, direction);
- }
-
- return true;
- }
-
public BlockState getAdjBlockState(BlockAndTintGetter blockAndTintGetter, int x, int y, int z, Direction dir) {
mBlockPos.set(x + dir.getStepX(), y + dir.getStepY(), z + dir.getStepZ());
return blockAndTintGetter.getBlockState(mBlockPos);
@@ -164,14 +161,14 @@ public void render(FluidRenderHandler handler, BlockState blockState, FluidState
seHeight = 1.0F;
swHeight = 1.0F;
} else {
- float s = this.getHeight(region, fluid, mBlockPos.set(blockPos).offset(Direction.NORTH.getNormal()), northState);
- float t = this.getHeight(region, fluid, mBlockPos.set(blockPos).offset(Direction.SOUTH.getNormal()), southState);
- float u = this.getHeight(region, fluid, mBlockPos.set(blockPos).offset(Direction.EAST.getNormal()), eastState);
- float v = this.getHeight(region, fluid, mBlockPos.set(blockPos).offset(Direction.WEST.getNormal()), westState);
- neHeight = this.calculateAverageHeight(region, fluid, height, s, u, mBlockPos.set(blockPos).offset(Direction.NORTH.getNormal()).offset(Direction.EAST.getNormal()));
- nwHeight = this.calculateAverageHeight(region, fluid, height, s, v, mBlockPos.set(blockPos).offset(Direction.NORTH.getNormal()).offset(Direction.WEST.getNormal()));
- seHeight = this.calculateAverageHeight(region, fluid, height, t, u, mBlockPos.set(blockPos).offset(Direction.SOUTH.getNormal()).offset(Direction.EAST.getNormal()));
- swHeight = this.calculateAverageHeight(region, fluid, height, t, v, mBlockPos.set(blockPos).offset(Direction.SOUTH.getNormal()).offset(Direction.WEST.getNormal()));
+ float s = this.getHeight(region, fluid, mBlockPos.set(blockPos).move(Direction.NORTH), northState);
+ float t = this.getHeight(region, fluid, mBlockPos.set(blockPos).move(Direction.SOUTH), southState);
+ float u = this.getHeight(region, fluid, mBlockPos.set(blockPos).move(Direction.EAST), eastState);
+ float v = this.getHeight(region, fluid, mBlockPos.set(blockPos).move(Direction.WEST), westState);
+ neHeight = this.calculateAverageHeight(region, fluid, height, s, u, mBlockPos.set(blockPos).move(Direction.NORTH).move(Direction.EAST));
+ nwHeight = this.calculateAverageHeight(region, fluid, height, s, v, mBlockPos.set(blockPos).move(Direction.NORTH).move(Direction.WEST));
+ seHeight = this.calculateAverageHeight(region, fluid, height, t, u, mBlockPos.set(blockPos).move(Direction.SOUTH).move(Direction.EAST));
+ swHeight = this.calculateAverageHeight(region, fluid, height, t, v, mBlockPos.set(blockPos).move(Direction.SOUTH).move(Direction.WEST));
}
float x0 = (posX & 15);
@@ -422,7 +419,7 @@ private float getHeight(BlockAndTintGetter blockAndTintGetter, Fluid fluid, Bloc
private float getHeight(BlockAndTintGetter blockAndTintGetter, Fluid fluid, BlockPos blockPos, BlockState adjBlockState) {
FluidState adjFluidState = adjBlockState.getFluidState();
if (fluid.isSame(adjFluidState.getType())) {
- BlockState blockState2 = blockAndTintGetter.getBlockState(blockPos.offset(Direction.UP.getNormal()));
+ BlockState blockState2 = blockAndTintGetter.getBlockState(blockPos.relative(Direction.UP));
return fluid.isSame(blockState2.getFluidState().getType()) ? 1.0F : adjFluidState.getOwnHeight();
} else {
return !adjBlockState.isSolid() ? 0.0F : -1.0f;
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/task/BuildTask.java b/src/main/java/net/vulkanmod/render/chunk/build/task/BuildTask.java
index 068700b6d..2aaf0e668 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/task/BuildTask.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/task/BuildTask.java
@@ -1,6 +1,7 @@
package net.vulkanmod.render.chunk.build.task;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.chunk.VisGraph;
import net.minecraft.core.BlockPos;
@@ -12,10 +13,10 @@
import net.vulkanmod.Initializer;
import net.vulkanmod.render.chunk.RenderSection;
import net.vulkanmod.render.chunk.WorldRenderer;
-import net.vulkanmod.render.chunk.build.renderer.BlockRenderer;
-import net.vulkanmod.render.chunk.build.renderer.FluidRenderer;
import net.vulkanmod.render.chunk.build.RenderRegion;
import net.vulkanmod.render.chunk.build.UploadBuffer;
+import net.vulkanmod.render.chunk.build.renderer.BlockRenderer;
+import net.vulkanmod.render.chunk.build.renderer.FluidRenderer;
import net.vulkanmod.render.chunk.build.thread.BuilderResources;
import net.vulkanmod.render.chunk.build.thread.ThreadBuilderPack;
import net.vulkanmod.render.chunk.cull.QuadFacing;
@@ -104,7 +105,7 @@ private CompileResult compile(float camX, float camY, float camZ, BuilderResourc
blockPos.set(section.xOffset() + x, section.yOffset() + y, section.zOffset() + z);
BlockState blockState = this.region.getBlockState(blockPos);
- if (blockState.isSolidRender(this.region, blockPos)) {
+ if (blockState.isSolidRender()) {
visGraph.setOpaque(blockPos);
}
@@ -181,13 +182,13 @@ private TerrainRenderType compactRenderTypes(TerrainRenderType renderType) {
}
private void handleBlockEntity(CompileResult compileResult, E blockEntity) {
- BlockEntityRenderer blockEntityRenderer = Minecraft.getInstance().getBlockEntityRenderDispatcher().getRenderer(blockEntity);
- if (blockEntityRenderer != null) {
+ BlockEntityRenderDispatcher dispatcher = Minecraft.getInstance().getBlockEntityRenderDispatcher();
+ BlockEntityRenderer renderer = dispatcher.getRenderer(blockEntity);
+ if (renderer != null) {
compileResult.blockEntities.add(blockEntity);
- if (blockEntityRenderer.shouldRenderOffScreen(blockEntity)) {
+ if (renderer.shouldRenderOffScreen()) {
compileResult.globalBlockEntities.add(blockEntity);
}
}
-
}
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/task/ChunkTask.java b/src/main/java/net/vulkanmod/render/chunk/build/task/ChunkTask.java
index c1acc33df..5b692119a 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/task/ChunkTask.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/task/ChunkTask.java
@@ -10,17 +10,19 @@ public abstract class ChunkTask {
public static final boolean BENCH = true;
protected static TaskDispatcher taskDispatcher;
+ protected final RenderSection section;
+ public boolean highPriority = false;
+ protected AtomicBoolean cancelled = new AtomicBoolean(false);
+ ChunkTask(RenderSection renderSection) {
+ this.section = renderSection;
+ }
public static BuildTask createBuildTask(RenderSection renderSection, RenderRegion renderRegion, boolean highPriority) {
return new BuildTask(renderSection, renderRegion, highPriority);
}
- protected AtomicBoolean cancelled = new AtomicBoolean(false);
- protected final RenderSection section;
- public boolean highPriority = false;
-
- ChunkTask(RenderSection renderSection) {
- this.section = renderSection;
+ public static void setTaskDispatcher(TaskDispatcher dispatcher) {
+ taskDispatcher = dispatcher;
}
public abstract String name();
@@ -31,10 +33,6 @@ public void cancel() {
this.cancelled.set(true);
}
- public static void setTaskDispatcher(TaskDispatcher dispatcher) {
- taskDispatcher = dispatcher;
- }
-
public enum Result {
CANCELLED,
SUCCESSFUL
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/task/CompileResult.java b/src/main/java/net/vulkanmod/render/chunk/build/task/CompileResult.java
index 7a00bcf36..13c1d4322 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/task/CompileResult.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/task/CompileResult.java
@@ -15,11 +15,9 @@
public class CompileResult {
public final RenderSection renderSection;
public final boolean fullUpdate;
-
+ public final EnumMap renderedLayers = new EnumMap<>(TerrainRenderType.class);
final List globalBlockEntities = new ArrayList<>();
final List blockEntities = new ArrayList<>();
- public final EnumMap renderedLayers = new EnumMap<>(TerrainRenderType.class);
-
VisibilitySet visibilitySet;
QuadSorter.SortState transparencyState;
CompiledSection compiledSection;
@@ -32,7 +30,7 @@ public class CompileResult {
public void updateSection() {
this.renderSection.updateGlobalBlockEntities(globalBlockEntities);
this.renderSection.setCompiledSection(compiledSection);
- this.renderSection.setVisibility(((VisibilitySetExtended)visibilitySet).getVisibility());
+ this.renderSection.setVisibility(((VisibilitySetExtended) visibilitySet).getVisibility());
this.renderSection.setCompletelyEmpty(compiledSection.isCompletelyEmpty);
this.renderSection.setContainsBlockEntities(!blockEntities.isEmpty());
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/task/CompiledSection.java b/src/main/java/net/vulkanmod/render/chunk/build/task/CompiledSection.java
index e233ab0a2..d54a3e9d7 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/task/CompiledSection.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/task/CompiledSection.java
@@ -3,15 +3,14 @@
import com.google.common.collect.Lists;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.vulkanmod.render.vertex.QuadSorter;
-
import org.jetbrains.annotations.Nullable;
+
import java.util.List;
public class CompiledSection {
public static final CompiledSection UNCOMPILED = new CompiledSection();
-
- boolean isCompletelyEmpty = false;
final List blockEntities = Lists.newArrayList();
+ boolean isCompletelyEmpty = false;
@Nullable QuadSorter.SortState transparencyState;
public boolean hasTransparencyState() {
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/task/TaskDispatcher.java b/src/main/java/net/vulkanmod/render/chunk/build/task/TaskDispatcher.java
index e9bdac845..cce281f88 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/task/TaskDispatcher.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/task/TaskDispatcher.java
@@ -7,24 +7,22 @@
import net.vulkanmod.render.chunk.WorldRenderer;
import net.vulkanmod.render.chunk.buffer.DrawBuffers;
import net.vulkanmod.render.chunk.build.UploadBuffer;
-import net.vulkanmod.render.chunk.build.thread.ThreadBuilderPack;
import net.vulkanmod.render.chunk.build.thread.BuilderResources;
+import net.vulkanmod.render.chunk.build.thread.ThreadBuilderPack;
import net.vulkanmod.render.vertex.TerrainRenderType;
-
import org.jetbrains.annotations.Nullable;
import java.util.Queue;
public class TaskDispatcher {
- private final Queue compileResults = Queues.newLinkedBlockingDeque();
public final ThreadBuilderPack fixedBuffers;
-
+ private final Queue compileResults = Queues.newLinkedBlockingDeque();
+ private final Queue highPriorityTasks = Queues.newConcurrentLinkedQueue();
+ private final Queue lowPriorityTasks = Queues.newConcurrentLinkedQueue();
private volatile boolean stopThreads;
private Thread[] threads;
private BuilderResources[] resources;
private int idleThreads;
- private final Queue highPriorityTasks = Queues.newConcurrentLinkedQueue();
- private final Queue lowPriorityTasks = Queues.newConcurrentLinkedQueue();
public TaskDispatcher() {
this.fixedBuffers = new ThreadBuilderPack();
@@ -38,13 +36,13 @@ public void createThreads() {
}
public void createThreads(int n) {
- if(!this.stopThreads) {
+ if (!this.stopThreads) {
this.stopThreads();
}
this.stopThreads = false;
- if(this.resources != null) {
+ if (this.resources != null) {
for (BuilderResources resources : this.resources) {
resources.clear();
}
@@ -71,10 +69,10 @@ public void createThreads(int n) {
}
private void runTaskThread(BuilderResources builderResources) {
- while(!this.stopThreads) {
+ while (!this.stopThreads) {
ChunkTask task = this.pollTask();
- if(task == null)
+ if (task == null)
synchronized (this) {
try {
this.idleThreads++;
@@ -85,7 +83,7 @@ private void runTaskThread(BuilderResources builderResources) {
this.idleThreads--;
}
- if(task == null)
+ if (task == null)
continue;
task.runTask(builderResources);
@@ -93,7 +91,7 @@ private void runTaskThread(BuilderResources builderResources) {
}
public void schedule(ChunkTask chunkTask) {
- if(chunkTask == null)
+ if (chunkTask == null)
return;
if (chunkTask.highPriority) {
@@ -111,14 +109,14 @@ public void schedule(ChunkTask chunkTask) {
private ChunkTask pollTask() {
ChunkTask task = this.highPriorityTasks.poll();
- if(task == null)
+ if (task == null)
task = this.lowPriorityTasks.poll();
return task;
}
public void stopThreads() {
- if(this.stopThreads)
+ if (this.stopThreads)
return;
this.stopThreads = true;
@@ -140,7 +138,7 @@ public void stopThreads() {
public boolean updateSections() {
CompileResult result;
boolean flag = false;
- while((result = this.compileResults.poll()) != null) {
+ while ((result = this.compileResults.poll()) != null) {
flag = true;
doSectionUpdate(result);
}
@@ -162,12 +160,12 @@ private void doSectionUpdate(CompileResult compileResult) {
if (chunkAreaManager.getChunkArea(renderArea.index) != renderArea)
return;
- if(compileResult.fullUpdate) {
+ if (compileResult.fullUpdate) {
var renderLayers = compileResult.renderedLayers;
- for(TerrainRenderType renderType : TerrainRenderType.VALUES) {
+ for (TerrainRenderType renderType : TerrainRenderType.VALUES) {
UploadBuffer uploadBuffer = renderLayers.get(renderType);
- if(uploadBuffer != null) {
+ if (uploadBuffer != null) {
drawBuffers.upload(section, uploadBuffer, renderType);
} else {
section.resetDrawParameters(renderType);
@@ -175,24 +173,25 @@ private void doSectionUpdate(CompileResult compileResult) {
}
compileResult.updateSection();
- }
- else {
+ } else {
UploadBuffer uploadBuffer = compileResult.renderedLayers.get(TerrainRenderType.TRANSLUCENT);
drawBuffers.upload(section, uploadBuffer, TerrainRenderType.TRANSLUCENT);
}
}
- public boolean isIdle() { return this.idleThreads == this.threads.length && this.compileResults.isEmpty(); }
+ public boolean isIdle() {
+ return this.idleThreads == this.threads.length && this.compileResults.isEmpty();
+ }
public void clearBatchQueue() {
- while(!this.highPriorityTasks.isEmpty()) {
+ while (!this.highPriorityTasks.isEmpty()) {
ChunkTask chunkTask = this.highPriorityTasks.poll();
if (chunkTask != null) {
chunkTask.cancel();
}
}
- while(!this.lowPriorityTasks.isEmpty()) {
+ while (!this.lowPriorityTasks.isEmpty()) {
ChunkTask chunkTask = this.lowPriorityTasks.poll();
if (chunkTask != null) {
chunkTask.cancel();
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/thread/BuilderResources.java b/src/main/java/net/vulkanmod/render/chunk/build/thread/BuilderResources.java
index fd6e69f11..35b065ae4 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/thread/BuilderResources.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/thread/BuilderResources.java
@@ -2,8 +2,6 @@
import net.vulkanmod.Initializer;
import net.vulkanmod.render.chunk.RenderSection;
-import net.vulkanmod.render.chunk.build.renderer.BlockRenderer;
-import net.vulkanmod.render.chunk.build.renderer.FluidRenderer;
import net.vulkanmod.render.chunk.build.RenderRegion;
import net.vulkanmod.render.chunk.build.color.TintCache;
import net.vulkanmod.render.chunk.build.light.LightMode;
@@ -13,6 +11,8 @@
import net.vulkanmod.render.chunk.build.light.flat.FlatLightPipeline;
import net.vulkanmod.render.chunk.build.light.smooth.NewSmoothLightPipeline;
import net.vulkanmod.render.chunk.build.light.smooth.SmoothLightPipeline;
+import net.vulkanmod.render.chunk.build.renderer.BlockRenderer;
+import net.vulkanmod.render.chunk.build.renderer.FluidRenderer;
public class BuilderResources {
public final ThreadBuilderPack builderPack = new ThreadBuilderPack();
@@ -34,8 +34,7 @@ public BuilderResources() {
LightPipeline smoothLightPipeline;
if (Initializer.CONFIG.ambientOcclusion == LightMode.SUB_BLOCK) {
smoothLightPipeline = new NewSmoothLightPipeline(lightDataCache);
- }
- else {
+ } else {
smoothLightPipeline = new SmoothLightPipeline(lightDataCache);
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/build/thread/ThreadBuilderPack.java b/src/main/java/net/vulkanmod/render/chunk/build/thread/ThreadBuilderPack.java
index 84102838f..151f57d43 100644
--- a/src/main/java/net/vulkanmod/render/chunk/build/thread/ThreadBuilderPack.java
+++ b/src/main/java/net/vulkanmod/render/chunk/build/thread/ThreadBuilderPack.java
@@ -10,15 +10,6 @@
public class ThreadBuilderPack {
private static Function terrainBuilderConstructor;
-
- public static void defaultTerrainBuilderConstructor() {
- terrainBuilderConstructor = renderType -> new TerrainBuilder(TerrainRenderType.getRenderType(renderType).bufferSize());
- }
-
- public static void setTerrainBuilderConstructor(Function constructor) {
- terrainBuilderConstructor = constructor;
- }
-
private final Map builders;
public ThreadBuilderPack() {
@@ -30,6 +21,14 @@ public ThreadBuilderPack() {
builders = map;
}
+ public static void defaultTerrainBuilderConstructor() {
+ terrainBuilderConstructor = renderType -> new TerrainBuilder(TerrainRenderType.getRenderType(renderType).bufferSize());
+ }
+
+ public static void setTerrainBuilderConstructor(Function constructor) {
+ terrainBuilderConstructor = constructor;
+ }
+
public TerrainBuilder builder(TerrainRenderType renderType) {
return this.builders.get(renderType);
}
@@ -38,4 +37,4 @@ public void clearAll() {
this.builders.values().forEach(TerrainBuilder::clear);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/cull/QuadFacing.java b/src/main/java/net/vulkanmod/render/chunk/cull/QuadFacing.java
index 642fd9bf4..a51bf47f2 100644
--- a/src/main/java/net/vulkanmod/render/chunk/cull/QuadFacing.java
+++ b/src/main/java/net/vulkanmod/render/chunk/cull/QuadFacing.java
@@ -63,4 +63,4 @@ public static QuadFacing fromNormal(float x, float y, float z) {
return QuadFacing.UNDEFINED;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/frustum/VFrustum.java b/src/main/java/net/vulkanmod/render/chunk/frustum/VFrustum.java
index 396e1f4dd..158ca23ef 100644
--- a/src/main/java/net/vulkanmod/render/chunk/frustum/VFrustum.java
+++ b/src/main/java/net/vulkanmod/render/chunk/frustum/VFrustum.java
@@ -6,14 +6,13 @@
import org.joml.Vector4f;
public class VFrustum {
+ private final FrustumIntersection frustum = new FrustumIntersection();
+ private final Matrix4f matrix = new Matrix4f();
private Vector4f viewVector = new Vector4f();
private double camX;
private double camY;
private double camZ;
- private final FrustumIntersection frustum = new FrustumIntersection();
- private final Matrix4f matrix = new Matrix4f();
-
public VFrustum offsetToFullyIncludeCameraCube(int offset) {
double d0 = Math.floor(this.camX / (double) offset) * (double) offset;
double d1 = Math.floor(this.camY / (double) offset) * (double) offset;
diff --git a/src/main/java/net/vulkanmod/render/chunk/graph/GraphDirections.java b/src/main/java/net/vulkanmod/render/chunk/graph/GraphDirections.java
index e570ba2b2..36529b607 100644
--- a/src/main/java/net/vulkanmod/render/chunk/graph/GraphDirections.java
+++ b/src/main/java/net/vulkanmod/render/chunk/graph/GraphDirections.java
@@ -7,4 +7,4 @@ public abstract class GraphDirections {
public static final int SOUTH = 3;
public static final int WEST = 4;
public static final int EAST = 5;
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/graph/SectionGraph.java b/src/main/java/net/vulkanmod/render/chunk/graph/SectionGraph.java
index 8a3d641be..2396f671d 100644
--- a/src/main/java/net/vulkanmod/render/chunk/graph/SectionGraph.java
+++ b/src/main/java/net/vulkanmod/render/chunk/graph/SectionGraph.java
@@ -11,7 +11,10 @@
import net.minecraft.world.phys.Vec3;
import net.vulkanmod.Initializer;
import net.vulkanmod.interfaces.FrustumMixed;
-import net.vulkanmod.render.chunk.*;
+import net.vulkanmod.render.chunk.ChunkAreaManager;
+import net.vulkanmod.render.chunk.RenderSection;
+import net.vulkanmod.render.chunk.SectionGrid;
+import net.vulkanmod.render.chunk.WorldRenderer;
import net.vulkanmod.render.chunk.build.RenderRegionBuilder;
import net.vulkanmod.render.chunk.build.task.TaskDispatcher;
import net.vulkanmod.render.chunk.frustum.VFrustum;
@@ -23,23 +26,19 @@
import java.util.List;
public class SectionGraph {
- Minecraft minecraft;
private final Level level;
-
private final SectionGrid sectionGrid;
private final ChunkAreaManager chunkAreaManager;
private final TaskDispatcher taskDispatcher;
private final ResettableQueue sectionQueue = new ResettableQueue<>();
- private AreaSetQueue chunkAreaQueue;
- private short lastFrame = 0;
-
private final ResettableQueue blockEntitiesSections = new ResettableQueue<>();
private final ResettableQueue rebuildQueue = new ResettableQueue<>();
-
- private VFrustum frustum;
-
public RenderRegionBuilder renderRegionCache;
+ Minecraft minecraft;
int nonEmptyChunks;
+ private AreaSetQueue chunkAreaQueue;
+ private short lastFrame = 0;
+ private VFrustum frustum;
public SectionGraph(Level level, SectionGrid sectionGrid, TaskDispatcher taskDispatcher) {
@@ -53,15 +52,35 @@ public SectionGraph(Level level, SectionGrid sectionGrid, TaskDispatcher taskDis
this.renderRegionCache = WorldRenderer.getInstance().renderRegionCache;
}
+ private static void initFirstNode(RenderSection renderSection, short frame) {
+ renderSection.mainDir = 7;
+ renderSection.sourceDirs = (byte) (1 << 7);
+ renderSection.directions = (byte) 0xFF;
+ renderSection.setLastFrame(frame);
+ renderSection.visibility |= initVisibility();
+ renderSection.directionChanges = 0;
+ renderSection.steps = 0;
+ }
+
+ // Init special value used by first graph node
+ private static long initVisibility() {
+ long vis = 0;
+ for (int dir = 0; dir < 6; dir++) {
+ vis |= 1L << ((6 << 3) + dir);
+ vis |= 1L << ((7 << 3) + dir);
+ }
+
+ return vis;
+ }
+
public void update(Camera camera, Frustum frustum, boolean spectator) {
Profiler profiler = Profiler.getMainProfiler();
+ profiler.push("update");
BlockPos blockpos = camera.getBlockPosition();
- this.minecraft.getProfiler().popPush("update");
-
boolean flag = this.minecraft.smartCull;
- if (spectator && this.level.getBlockState(blockpos).isSolidRender(this.level, blockpos)) {
+ if (spectator && this.level.getBlockState(blockpos).isSolidRender()) {
flag = false;
}
@@ -70,7 +89,7 @@ public void update(Camera camera, Frustum frustum, boolean spectator) {
this.sectionGrid.updateFrustumVisibility(this.frustum);
profiler.pop();
- this.minecraft.getProfiler().push("partial_update");
+ profiler.push("partial_update");
this.initUpdate();
this.initializeQueueForFullUpdate(camera);
@@ -82,7 +101,8 @@ public void update(Camera camera, Frustum frustum, boolean spectator) {
this.scheduleRebuilds();
- this.minecraft.getProfiler().pop();
+ profiler.pop(); // partial_update
+ profiler.pop(); // update
}
private void initializeQueueForFullUpdate(Camera camera) {
@@ -91,8 +111,8 @@ private void initializeQueueForFullUpdate(Camera camera) {
RenderSection renderSection = this.sectionGrid.getSectionAtBlockPos(blockpos);
if (renderSection == null) {
- boolean flag = blockpos.getY() > this.level.getMinBuildHeight();
- int y = flag ? this.level.getMaxBuildHeight() - 8 : this.level.getMinBuildHeight() + 8;
+ boolean flag = blockpos.getY() > this.level.getMinY();
+ int y = flag ? this.level.getMaxY() - 8 : this.level.getMinY() + 8;
int x = Mth.floor(vec3.x / 16.0D) * 16;
int z = Mth.floor(vec3.z / 16.0D) * 16;
@@ -123,27 +143,6 @@ private void initializeQueueForFullUpdate(Camera camera) {
}
- private static void initFirstNode(RenderSection renderSection, short frame) {
- renderSection.mainDir = 7;
- renderSection.sourceDirs = (byte) (1 << 7);
- renderSection.directions = (byte) 0xFF;
- renderSection.setLastFrame(frame);
- renderSection.visibility |= initVisibility();
- renderSection.directionChanges = 0;
- renderSection.steps = 0;
- }
-
- // Init special value used by first graph node
- private static long initVisibility() {
- long vis = 0;
- for (int dir = 0; dir < 6; dir++) {
- vis |= 1L << ((6 << 3) + dir);
- vis |= 1L << ((7 << 3) + dir);
- }
-
- return vis;
- }
-
private void initUpdate() {
this.resetUpdateQueues();
@@ -318,4 +317,3 @@ public String getStatistics() {
return String.format("Chunks: %d(%d)/%d D: %d, %s", this.nonEmptyChunks, sections, totalSections, renderDistance, tasksInfo);
}
}
-
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/BufferUtil.java b/src/main/java/net/vulkanmod/render/chunk/util/BufferUtil.java
index fb9bcd6e2..0ecb2ef8d 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/BufferUtil.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/BufferUtil.java
@@ -15,4 +15,4 @@ public static ByteBuffer clone(ByteBuffer src) {
public static ByteBuffer bufferSlice(ByteBuffer buffer, int start, int end) {
return MemoryUtil.memSlice(buffer, start, end - start);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/CircularIntList.java b/src/main/java/net/vulkanmod/render/chunk/util/CircularIntList.java
index d8964eaa9..9d33fa9ff 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/CircularIntList.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/CircularIntList.java
@@ -7,10 +7,9 @@
public class CircularIntList {
private final int size;
private final int[] list;
- private int startIndex;
-
private final OwnIterator iterator;
private final RangeIterator rangeIterator;
+ private int startIndex;
public CircularIntList(int size) {
this.size = size;
@@ -28,11 +27,11 @@ public void updateStartIdx(int startIndex) {
list[size + 1] = -1;
int k = 1;
- for(int i = startIndex; i < size; ++i) {
+ for (int i = startIndex; i < size; ++i) {
list[k] = i;
++k;
}
- for(int i = 0; i < startIndex; ++i) {
+ for (int i = 0; i < startIndex; ++i) {
list[k] = i;
++k;
}
@@ -60,8 +59,8 @@ public RangeIterator createRangeIterator() {
}
public class OwnIterator implements Iterator {
- private int currentIndex = 0;
private final int maxIndex = size;
+ private int currentIndex = 0;
@Override
public boolean hasNext() {
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/ResettableQueue.java b/src/main/java/net/vulkanmod/render/chunk/util/ResettableQueue.java
index 910b435a4..9893bebe5 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/ResettableQueue.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/ResettableQueue.java
@@ -73,8 +73,8 @@ public void clear() {
public Iterator iterator(boolean reverseOrder) {
return reverseOrder ? new Iterator<>() {
- int pos = ResettableQueue.this.limit - 1;
final int limit = -1;
+ int pos = ResettableQueue.this.limit - 1;
@Override
public boolean hasNext() {
@@ -87,8 +87,8 @@ public T next() {
}
}
: new Iterator<>() {
- int pos = 0;
final int limit = ResettableQueue.this.limit;
+ int pos = 0;
@Override
public boolean hasNext() {
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/SimpleDirection.java b/src/main/java/net/vulkanmod/render/chunk/util/SimpleDirection.java
index b4c53e808..75bdd757d 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/SimpleDirection.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/SimpleDirection.java
@@ -12,17 +12,11 @@ public enum SimpleDirection {
EAST(5, 4, 3, new Vec3i(1, 0, 0));
private static final SimpleDirection[] VALUES = SimpleDirection.values();
-
- public static SimpleDirection of(Direction direction) {
- return VALUES[direction.get3DDataValue()];
- }
-
+ public final byte nx, ny, nz;
private final int data3d;
private final int oppositeIndex;
private final int data2d;
- public final byte nx, ny, nz;
-
SimpleDirection(int j, int k, int l, Vec3i normal) {
this.data3d = j;
this.oppositeIndex = k;
@@ -33,6 +27,10 @@ public static SimpleDirection of(Direction direction) {
this.nz = (byte) normal.getZ();
}
+ public static SimpleDirection of(Direction direction) {
+ return VALUES[direction.get3DDataValue()];
+ }
+
public int get3DDataValue() {
return this.data3d;
}
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java b/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java
index 2d811c072..b2a919a4e 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/StaticQueue.java
@@ -7,9 +7,9 @@
public class StaticQueue implements Iterable {
final T[] queue;
+ final int capacity;
int position = 0;
int limit = 0;
- final int capacity;
public StaticQueue() {
this(1024);
@@ -48,8 +48,8 @@ public void clear() {
public Iterator iterator(boolean reverseOrder) {
return reverseOrder ? new Iterator<>() {
- int pos = StaticQueue.this.limit - 1;
final int limit = -1;
+ int pos = StaticQueue.this.limit - 1;
@Override
public boolean hasNext() {
@@ -62,8 +62,8 @@ public T next() {
}
}
: new Iterator<>() {
- int pos = 0;
final int limit = StaticQueue.this.limit;
+ int pos = 0;
@Override
public boolean hasNext() {
diff --git a/src/main/java/net/vulkanmod/render/chunk/util/Util.java b/src/main/java/net/vulkanmod/render/chunk/util/Util.java
index caa063410..81be1eae0 100644
--- a/src/main/java/net/vulkanmod/render/chunk/util/Util.java
+++ b/src/main/java/net/vulkanmod/render/chunk/util/Util.java
@@ -1,9 +1,6 @@
package net.vulkanmod.render.chunk.util;
import net.minecraft.core.Direction;
-import org.lwjgl.system.MemoryUtil;
-
-import java.nio.ByteBuffer;
public class Util {
diff --git a/src/main/java/net/vulkanmod/render/material/BlendMode.java b/src/main/java/net/vulkanmod/render/material/BlendMode.java
new file mode 100644
index 000000000..3c00b6eff
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/material/BlendMode.java
@@ -0,0 +1,23 @@
+package net.vulkanmod.render.material;
+
+/**
+ * Blend mode indicator used by VulkanMod's material system.
+ *
+ * The enum is intentionally small – only the modes referenced by
+ * the existing chunk and item renderers are implemented. Additional
+ * modes can be added later without breaking the binary layout used
+ * by encoded quads.
+ */
+public enum BlendMode {
+ DEFAULT,
+ CUTOUT,
+ CUTOUT_MIPPED,
+ TRANSLUCENT;
+
+ /**
+ * Returns {@code true} when this mode should render with translucency.
+ */
+ public boolean isTranslucent() {
+ return this == TRANSLUCENT;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/material/RenderMaterial.java b/src/main/java/net/vulkanmod/render/material/RenderMaterial.java
new file mode 100644
index 000000000..6a5da91e5
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/material/RenderMaterial.java
@@ -0,0 +1,110 @@
+package net.vulkanmod.render.material;
+
+import net.vulkanmod.util.TriState;
+
+import java.util.Objects;
+
+/**
+ * Immutable material descriptor used by the new rendering path.
+ *
+ * Materials are interned via {@link RenderMaterialRegistry} so instances
+ * can be compared with {@code ==} once retrieved from the registry.
+ */
+public final class RenderMaterial {
+ private final BlendMode blendMode;
+ private final boolean disableColorIndex;
+ private final boolean emissive;
+ private final boolean disableDiffuse;
+ private final TriState ambientOcclusion;
+ private final TriState glint;
+ private final ShadeMode shadeMode;
+
+ RenderMaterial(BlendMode blendMode,
+ boolean disableColorIndex,
+ boolean emissive,
+ boolean disableDiffuse,
+ TriState ambientOcclusion,
+ TriState glint,
+ ShadeMode shadeMode) {
+ this.blendMode = Objects.requireNonNull(blendMode, "blendMode");
+ this.ambientOcclusion = Objects.requireNonNull(ambientOcclusion, "ambientOcclusion");
+ this.glint = Objects.requireNonNull(glint, "glint");
+ this.shadeMode = Objects.requireNonNull(shadeMode, "shadeMode");
+ this.disableColorIndex = disableColorIndex;
+ this.emissive = emissive;
+ this.disableDiffuse = disableDiffuse;
+ }
+
+ public BlendMode blendMode() {
+ return this.blendMode;
+ }
+
+ public boolean disableColorIndex() {
+ return this.disableColorIndex;
+ }
+
+ public boolean emissive() {
+ return this.emissive;
+ }
+
+ public boolean disableDiffuse() {
+ return this.disableDiffuse;
+ }
+
+ public TriState ambientOcclusion() {
+ return this.ambientOcclusion;
+ }
+
+ public TriState glint() {
+ return this.glint;
+ }
+
+ public ShadeMode shadeMode() {
+ return this.shadeMode;
+ }
+
+ RenderMaterial withDisableDiffuse(boolean disable) {
+ if (disable == this.disableDiffuse) {
+ return this;
+ }
+
+ return RenderMaterialRegistry.intern(new RenderMaterial(this.blendMode,
+ this.disableColorIndex,
+ this.emissive,
+ disable,
+ this.ambientOcclusion,
+ this.glint,
+ this.shadeMode));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof RenderMaterial that)) {
+ return false;
+ }
+
+ return this.disableColorIndex == that.disableColorIndex
+ && this.emissive == that.emissive
+ && this.disableDiffuse == that.disableDiffuse
+ && this.blendMode == that.blendMode
+ && this.ambientOcclusion == that.ambientOcclusion
+ && this.glint == that.glint
+ && this.shadeMode == that.shadeMode;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = this.blendMode.hashCode();
+ result = 31 * result + Boolean.hashCode(this.disableColorIndex);
+ result = 31 * result + Boolean.hashCode(this.emissive);
+ result = 31 * result + Boolean.hashCode(this.disableDiffuse);
+ result = 31 * result + this.ambientOcclusion.hashCode();
+ result = 31 * result + this.glint.hashCode();
+ result = 31 * result + this.shadeMode.hashCode();
+ return result;
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/material/RenderMaterialBuilder.java b/src/main/java/net/vulkanmod/render/material/RenderMaterialBuilder.java
new file mode 100644
index 000000000..141e17ad1
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/material/RenderMaterialBuilder.java
@@ -0,0 +1,85 @@
+package net.vulkanmod.render.material;
+
+import net.vulkanmod.util.TriState;
+
+/**
+ * Fluent builder used to construct {@link RenderMaterial} instances.
+ * Works similarly to Fabric's MaterialFinder but only exposes the knobs
+ * relied upon by VulkanMod.
+ */
+public final class RenderMaterialBuilder {
+ private BlendMode blendMode = BlendMode.DEFAULT;
+ private boolean disableColorIndex;
+ private boolean emissive;
+ private boolean disableDiffuse;
+ private TriState ambientOcclusion = TriState.DEFAULT;
+ private TriState glint = TriState.DEFAULT;
+ private ShadeMode shadeMode = ShadeMode.VANILLA;
+
+ public RenderMaterialBuilder blendMode(BlendMode blendMode) {
+ this.blendMode = blendMode;
+ return this;
+ }
+
+ public RenderMaterialBuilder disableColorIndex(boolean disable) {
+ this.disableColorIndex = disable;
+ return this;
+ }
+
+ public RenderMaterialBuilder emissive(boolean emissive) {
+ this.emissive = emissive;
+ return this;
+ }
+
+ public RenderMaterialBuilder disableDiffuse(boolean disable) {
+ this.disableDiffuse = disable;
+ return this;
+ }
+
+ public RenderMaterialBuilder ambientOcclusion(TriState ao) {
+ this.ambientOcclusion = ao;
+ return this;
+ }
+
+ public RenderMaterialBuilder glint(TriState glintMode) {
+ this.glint = glintMode;
+ return this;
+ }
+
+ public RenderMaterialBuilder shadeMode(ShadeMode shadeMode) {
+ this.shadeMode = shadeMode;
+ return this;
+ }
+
+ public RenderMaterialBuilder copyFrom(RenderMaterial material) {
+ this.blendMode = material.blendMode();
+ this.disableColorIndex = material.disableColorIndex();
+ this.emissive = material.emissive();
+ this.disableDiffuse = material.disableDiffuse();
+ this.ambientOcclusion = material.ambientOcclusion();
+ this.glint = material.glint();
+ this.shadeMode = material.shadeMode();
+ return this;
+ }
+
+ public RenderMaterialBuilder clear() {
+ this.blendMode = BlendMode.DEFAULT;
+ this.disableColorIndex = false;
+ this.emissive = false;
+ this.disableDiffuse = false;
+ this.ambientOcclusion = TriState.DEFAULT;
+ this.glint = TriState.DEFAULT;
+ this.shadeMode = ShadeMode.VANILLA;
+ return this;
+ }
+
+ public RenderMaterial build() {
+ return RenderMaterialRegistry.intern(new RenderMaterial(this.blendMode,
+ this.disableColorIndex,
+ this.emissive,
+ this.disableDiffuse,
+ this.ambientOcclusion,
+ this.glint,
+ this.shadeMode));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/material/RenderMaterialRegistry.java b/src/main/java/net/vulkanmod/render/material/RenderMaterialRegistry.java
new file mode 100644
index 000000000..3af7058f9
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/material/RenderMaterialRegistry.java
@@ -0,0 +1,77 @@
+package net.vulkanmod.render.material;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import net.vulkanmod.util.TriState;
+
+/**
+ * Central registry for {@link RenderMaterial} instances. Quads encode the
+ * registry index to avoid storing large structures per vertex.
+ */
+public final class RenderMaterialRegistry {
+ public static final RenderMaterial STANDARD_MATERIAL;
+ public static final RenderMaterial NO_AO_MATERIAL;
+ private static final Int2ObjectMap BY_ID = new Int2ObjectArrayMap<>();
+ private static final Object2IntMap TO_ID = new Object2IntOpenHashMap<>();
+ private static int nextId;
+
+ static {
+ TO_ID.defaultReturnValue(-1);
+
+ STANDARD_MATERIAL = intern(new RenderMaterial(BlendMode.DEFAULT,
+ false,
+ false,
+ false,
+ TriState.DEFAULT,
+ TriState.DEFAULT,
+ ShadeMode.VANILLA));
+
+ NO_AO_MATERIAL = intern(new RenderMaterial(BlendMode.DEFAULT,
+ false,
+ false,
+ false,
+ TriState.FALSE,
+ TriState.DEFAULT,
+ ShadeMode.VANILLA));
+ }
+
+ private RenderMaterialRegistry() {
+ }
+
+ public static synchronized RenderMaterial intern(RenderMaterial material) {
+ int id = TO_ID.getInt(material);
+ if (id != -1) {
+ return BY_ID.get(id);
+ }
+
+ id = nextId++;
+ TO_ID.put(material, id);
+ BY_ID.put(id, material);
+ return material;
+ }
+
+ public static synchronized int getId(RenderMaterial material) {
+ int id = TO_ID.getInt(material);
+ if (id == -1) {
+ id = nextId++;
+ TO_ID.put(material, id);
+ BY_ID.put(id, material);
+ }
+ return id;
+ }
+
+ public static RenderMaterial fromId(int id) {
+ RenderMaterial material = BY_ID.get(id);
+ if (material == null) {
+ throw new IllegalStateException("Unknown material id " + id);
+ }
+
+ return material;
+ }
+
+ public static RenderMaterial disableDiffuse(RenderMaterial material, boolean disable) {
+ return material.withDisableDiffuse(disable);
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/material/ShadeMode.java b/src/main/java/net/vulkanmod/render/material/ShadeMode.java
new file mode 100644
index 000000000..f94be7612
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/material/ShadeMode.java
@@ -0,0 +1,10 @@
+package net.vulkanmod.render.material;
+
+/**
+ * Describes how a quad should be shaded. Currently only provides parity with
+ * the vanilla Fabric API behaviour that VulkanMod relied on.
+ */
+public enum ShadeMode {
+ VANILLA,
+ FLAT
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/model/CubeModel.java b/src/main/java/net/vulkanmod/render/model/CubeModel.java
deleted file mode 100644
index da988f39d..000000000
--- a/src/main/java/net/vulkanmod/render/model/CubeModel.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package net.vulkanmod.render.model;
-
-import net.minecraft.client.model.geom.ModelPart;
-import net.minecraft.core.Direction;
-import org.joml.Matrix4f;
-import org.joml.Vector3f;
-
-import java.util.Set;
-
-public class CubeModel {
-
- private ModelPart.Polygon[] polygons = new ModelPart.Polygon[6];
- public float minX;
- public float minY;
- public float minZ;
- public float maxX;
- public float maxY;
- public float maxZ;
-
- Vector3f[] vertices;
- Vector3f[] transformed = new Vector3f[8];
-
- public void setVertices(int i, int j, float f, float g, float h, float k, float l, float m, float n, float o, float p, boolean bl, float q, float r, Set set) {
- this.minX = f;
- this.minY = g;
- this.minZ = h;
- this.maxX = f + k;
- this.maxY = g + l;
- this.maxZ = h + m;
- this.polygons = new ModelPart.Polygon[set.size()];
- float s = maxX;
- float t = maxY;
- float u = maxZ;
- f -= n;
- g -= o;
- h -= p;
- s += n;
- t += o;
- u += p;
- if (bl) {
- float v = s;
- s = f;
- f = v;
- }
-
- this.vertices = new Vector3f[]{
- new Vector3f(f, g, h),
- new Vector3f(s, g, h),
- new Vector3f(s, t, h),
- new Vector3f(f, t, h),
- new Vector3f(f, g, u),
- new Vector3f(s, g, u),
- new Vector3f(s, t, u),
- new Vector3f(f, t, u)
- };
-
- for (int i1 = 0; i1 < 8; i1++) {
- //pre-divide all vertices once
- this.vertices[i1].div(16.0f);
- this.transformed[i1] = new Vector3f(0.0f);
- }
-
- ModelPart.Vertex vertex1 = new ModelPart.Vertex(transformed[0], 0.0F, 0.0F);
- ModelPart.Vertex vertex2 = new ModelPart.Vertex(transformed[1], 0.0F, 8.0F);
- ModelPart.Vertex vertex3 = new ModelPart.Vertex(transformed[2], 8.0F, 8.0F);
- ModelPart.Vertex vertex4 = new ModelPart.Vertex(transformed[3], 8.0F, 0.0F);
- ModelPart.Vertex vertex5 = new ModelPart.Vertex(transformed[4], 0.0F, 0.0F);
- ModelPart.Vertex vertex6 = new ModelPart.Vertex(transformed[5], 0.0F, 8.0F);
- ModelPart.Vertex vertex7 = new ModelPart.Vertex(transformed[6], 8.0F, 8.0F);
- ModelPart.Vertex vertex8 = new ModelPart.Vertex(transformed[7], 8.0F, 0.0F);
-
- float w = (float)i;
- float x = (float)i + m;
- float y = (float)i + m + k;
- float z = (float)i + m + k + k;
- float aa = (float)i + m + k + m;
- float ab = (float)i + m + k + m + k;
- float ac = (float)j;
- float ad = (float)j + m;
- float ae = (float)j + m + l;
- int idx = 0;
- if (set.contains(Direction.DOWN)) {
- this.polygons[idx++] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex6, vertex5, vertex1, vertex2}, x, ac, y, ad, q, r, bl, Direction.DOWN);
- }
-
- if (set.contains(Direction.UP)) {
- this.polygons[idx++] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex3, vertex4, vertex8, vertex7}, y, ad, z, ac, q, r, bl, Direction.UP);
- }
-
- if (set.contains(Direction.WEST)) {
- this.polygons[idx++] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex1, vertex5, vertex8, vertex4}, w, ad, x, ae, q, r, bl, Direction.WEST);
- }
-
- if (set.contains(Direction.NORTH)) {
- this.polygons[idx++] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex2, vertex1, vertex4, vertex3}, x, ad, y, ae, q, r, bl, Direction.NORTH);
- }
-
- if (set.contains(Direction.EAST)) {
- this.polygons[idx++] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex6, vertex2, vertex3, vertex7}, y, ad, aa, ae, q, r, bl, Direction.EAST);
- }
-
- if (set.contains(Direction.SOUTH)) {
- this.polygons[idx] = new ModelPart.Polygon(new ModelPart.Vertex[]{vertex5, vertex6, vertex7, vertex8}, aa, ad, ab, ae, q, r, bl, Direction.SOUTH);
- }
- }
-
- public void transformVertices(Matrix4f matrix) {
- //Transform original vertices and store them
- for(int i = 0; i < 8; ++i) {
- this.vertices[i].mulPosition(matrix, this.transformed[i]);
- }
- }
-
- public ModelPart.Polygon[] getPolygons() { return this.polygons; }
-}
diff --git a/src/main/java/net/vulkanmod/render/model/ModelHelper.java b/src/main/java/net/vulkanmod/render/model/ModelHelper.java
new file mode 100644
index 000000000..e2943bf92
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/model/ModelHelper.java
@@ -0,0 +1,30 @@
+package net.vulkanmod.render.model;
+
+import net.minecraft.core.Direction;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Simple helper mirroring the handful of face-index utilities that were
+ * previously provided by Fabric's ModelHelper.
+ */
+public final class ModelHelper {
+ public static final int NULL_FACE_ID = Direction.values().length;
+
+ private static final Direction[] DIRECTIONS = Direction.values();
+
+ private ModelHelper() {
+ }
+
+ public static int toFaceIndex(@Nullable Direction face) {
+ return face == null ? NULL_FACE_ID : face.get3DDataValue();
+ }
+
+ @Nullable
+ public static Direction faceFromIndex(int index) {
+ if (index < 0 || index >= NULL_FACE_ID) {
+ return null;
+ }
+
+ return DIRECTIONS[index];
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/model/quad/ModelQuad.java b/src/main/java/net/vulkanmod/render/model/quad/ModelQuad.java
index d87df233d..9316097c1 100644
--- a/src/main/java/net/vulkanmod/render/model/quad/ModelQuad.java
+++ b/src/main/java/net/vulkanmod/render/model/quad/ModelQuad.java
@@ -9,23 +9,24 @@
*/
public class ModelQuad implements ModelQuadView {
public static final int VERTEX_SIZE = 8;
+ private final int[] data = new int[4 * VERTEX_SIZE];
+ Direction direction;
+ TextureAtlasSprite sprite;
+ private int flags;
public static int vertexOffset(int vertexIndex) {
return vertexIndex * VERTEX_SIZE;
}
- private final int[] data = new int[4 * VERTEX_SIZE];
-
- Direction direction;
- TextureAtlasSprite sprite;
-
- private int flags;
-
@Override
public int getFlags() {
return flags;
}
+ public void setFlags(int f) {
+ this.flags = f;
+ }
+
@Override
public float getX(int idx) {
return Float.intBitsToFloat(this.data[vertexOffset(idx)]);
@@ -104,10 +105,6 @@ public float setV(int idx, float f) {
}
- public void setFlags(int f) {
- this.flags = f;
- }
-
public void setSprite(TextureAtlasSprite sprite) {
this.sprite = sprite;
}
diff --git a/src/main/java/net/vulkanmod/render/model/quad/ModelQuadFlags.java b/src/main/java/net/vulkanmod/render/model/quad/ModelQuadFlags.java
index bb1dc0cca..41bd087c7 100644
--- a/src/main/java/net/vulkanmod/render/model/quad/ModelQuadFlags.java
+++ b/src/main/java/net/vulkanmod/render/model/quad/ModelQuadFlags.java
@@ -51,7 +51,7 @@ public static int getQuadFlags(ModelQuadView quad, Direction face) {
case Z -> minX >= 0.0001f || minY >= 0.0001f || maxX <= 0.9999F || maxY <= 0.9999F;
};
- boolean parallel = switch(face.getAxis()) {
+ boolean parallel = switch (face.getAxis()) {
case X -> minX == maxX;
case Y -> minY == maxY;
case Z -> minZ == maxZ;
diff --git a/src/main/java/net/vulkanmod/render/model/quad/ModelQuadView.java b/src/main/java/net/vulkanmod/render/model/quad/ModelQuadView.java
index ac791d9a5..8eda41f25 100644
--- a/src/main/java/net/vulkanmod/render/model/quad/ModelQuadView.java
+++ b/src/main/java/net/vulkanmod/render/model/quad/ModelQuadView.java
@@ -34,4 +34,4 @@ default boolean isTinted() {
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/model/quad/QuadUtils.java b/src/main/java/net/vulkanmod/render/model/quad/QuadUtils.java
index 9f7c7f1d7..f1500d1c4 100644
--- a/src/main/java/net/vulkanmod/render/model/quad/QuadUtils.java
+++ b/src/main/java/net/vulkanmod/render/model/quad/QuadUtils.java
@@ -10,9 +10,9 @@ public abstract class QuadUtils {
public static int getIterationStartIdx(float[] aos, int[] lms) {
final float ao00_11 = aos[0] + aos[2];
final float ao10_01 = aos[1] + aos[3];
- if(ao00_11 > ao10_01) {
+ if (ao00_11 > ao10_01) {
return DEFAULT_START_IDX;
- } else if(ao00_11 < ao10_01) {
+ } else if (ao00_11 < ao10_01) {
return FLIPPED_START_IDX;
}
@@ -24,7 +24,7 @@ public static int getIterationStartIdx(float[] aos, int[] lms) {
// return FLIPPED_START_IDX;
// }
- if(lm00_11 >= lm10_01) {
+ if (lm00_11 >= lm10_01) {
return FLIPPED_START_IDX;
} else {
return DEFAULT_START_IDX;
@@ -37,7 +37,7 @@ public static int getIterationStartIdx(float[] aos, int[] lms) {
public static int getIterationStartIdx(float[] aos) {
final float ao00_11 = aos[0] + aos[2];
final float ao10_01 = aos[1] + aos[3];
- if(ao00_11 >= ao10_01) {
+ if (ao00_11 >= ao10_01) {
return DEFAULT_START_IDX;
} else {
return FLIPPED_START_IDX;
diff --git a/src/main/java/net/vulkanmod/render/pipeline/VulkanPipelineCompiler.java b/src/main/java/net/vulkanmod/render/pipeline/VulkanPipelineCompiler.java
new file mode 100644
index 000000000..6e6dcdcdc
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/pipeline/VulkanPipelineCompiler.java
@@ -0,0 +1,27 @@
+package net.vulkanmod.render.pipeline;
+
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import net.vulkanmod.vulkan.shader.GraphicsPipeline;
+import net.vulkanmod.vulkan.shader.Pipeline;
+import net.vulkanmod.vulkan.shader.converter.GlslConverter;
+import net.vulkanmod.vulkan.shader.descriptor.UBO;
+
+import java.util.Collections;
+
+public final class VulkanPipelineCompiler {
+ private VulkanPipelineCompiler() {
+ }
+
+ public static GraphicsPipeline compile(RenderPipeline pipeline, String vertexSource, String fragmentSource) {
+ GlslConverter converter = new GlslConverter();
+ converter.process(vertexSource, fragmentSource);
+
+ UBO ubo = converter.createUBO();
+
+ Pipeline.Builder builder = new Pipeline.Builder(pipeline.getVertexFormat(), pipeline.getLocation().toString());
+ builder.setUniforms(Collections.singletonList(ubo), converter.getSamplerList());
+ builder.compileShaders(pipeline.getLocation().toString(), converter.getVshConverted(), converter.getFshConverted());
+
+ return builder.createGraphicsPipeline();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/render/profiling/BuildTimeProfiler.java b/src/main/java/net/vulkanmod/render/profiling/BuildTimeProfiler.java
index f93c28fb7..e7455a599 100644
--- a/src/main/java/net/vulkanmod/render/profiling/BuildTimeProfiler.java
+++ b/src/main/java/net/vulkanmod/render/profiling/BuildTimeProfiler.java
@@ -9,12 +9,12 @@ public abstract class BuildTimeProfiler {
private static float deltaTime;
public static void runBench(boolean building) {
- if(bench) {
+ if (bench) {
if (startTime == 0) {
startTime = System.nanoTime();
}
- if(!building) {
+ if (!building) {
deltaTime = (System.nanoTime() - startTime) * 0.000001f;
bench = false;
startTime = 0;
diff --git a/src/main/java/net/vulkanmod/render/profiling/Profiler.java b/src/main/java/net/vulkanmod/render/profiling/Profiler.java
index ccfe5cb59..4287d36b5 100644
--- a/src/main/java/net/vulkanmod/render/profiling/Profiler.java
+++ b/src/main/java/net/vulkanmod/render/profiling/Profiler.java
@@ -16,41 +16,33 @@ public class Profiler {
private static final float CONVERSION = NANOS_IN_MS;
private static final float INV_CONVERSION = 1.0f / CONVERSION;
private static final int SAMPLE_COUNT = 200;
-
- public static boolean ACTIVE = FORCE_ACTIVE;
-
private static final Profiler MAIN_PROFILER = new Profiler("Main");
-
- public static Profiler getMainProfiler() {
- return MAIN_PROFILER;
- }
-
- public static void setActive(boolean b) {
- if (!FORCE_ACTIVE)
- ACTIVE = b;
-
- }
-
+ public static boolean ACTIVE = FORCE_ACTIVE;
private final String name;
-
LongArrayList startTimes = new LongArrayList();
ObjectArrayList nodeStack = new ObjectArrayList<>();
-
ObjectArrayList nodes = new ObjectArrayList<>();
ObjectArrayList currentFrameNodes = new ObjectArrayList<>();
Object2ReferenceOpenHashMap nodeMap = new Object2ReferenceOpenHashMap<>();
-
Node mainNode;
Node selectedNode;
Node currentNode;
-
ProfilerResults profilerResults = new ProfilerResults();
-
public Profiler(String s) {
this.name = s;
this.currentNode = this.selectedNode = this.mainNode = new Node(s);
}
+ public static Profiler getMainProfiler() {
+ return MAIN_PROFILER;
+ }
+
+ public static void setActive(boolean b) {
+ if (!FORCE_ACTIVE)
+ ACTIVE = b;
+
+ }
+
public void push(String s) {
if (!(ACTIVE))
return;
diff --git a/src/main/java/net/vulkanmod/render/profiling/ProfilerOverlay.java b/src/main/java/net/vulkanmod/render/profiling/ProfilerOverlay.java
index 8f0ffdd9f..ffe9a5d7d 100644
--- a/src/main/java/net/vulkanmod/render/profiling/ProfilerOverlay.java
+++ b/src/main/java/net/vulkanmod/render/profiling/ProfilerOverlay.java
@@ -1,9 +1,6 @@
package net.vulkanmod.render.profiling;
import com.google.common.base.Strings;
-import com.mojang.blaze3d.systems.RenderSystem;
-import com.mojang.blaze3d.vertex.DefaultVertexFormat;
-import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
@@ -12,6 +9,7 @@
import net.vulkanmod.render.chunk.WorldRenderer;
import net.vulkanmod.render.chunk.build.task.ChunkTask;
import net.vulkanmod.render.chunk.build.thread.BuilderResources;
+import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.util.ColorUtil;
@@ -56,7 +54,6 @@ public static void onKeyPress(int key) {
public void render(GuiGraphics guiGraphics) {
GuiRenderer.guiGraphics = guiGraphics;
- GuiRenderer.pose = guiGraphics.pose();
List infoList = this.buildInfo();
@@ -67,8 +64,7 @@ public void render(GuiGraphics guiGraphics) {
Objects.requireNonNull(this.font);
- RenderSystem.enableBlend();
- GuiRenderer.beginBatch();
+ VRenderSystem.enableBlend();
for (int i = 0; i < infoList.size(); ++i) {
String line = infoList.get(i);
@@ -81,9 +77,7 @@ public void render(GuiGraphics guiGraphics) {
0, backgroundColor);
}
}
-
- GuiRenderer.endBatch();
- RenderSystem.disableBlend();
+ VRenderSystem.disableBlend();
for (int i = 0; i < infoList.size(); ++i) {
String line = infoList.get(i);
@@ -168,4 +162,4 @@ private String getBuildStats() {
return String.format("Builders time: %dms avg %dms (%d builds)",
totalTime, totalTime / resourcesArray.length, buildCount);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/net/vulkanmod/render/quad/MutableQuadView.java b/src/main/java/net/vulkanmod/render/quad/MutableQuadView.java
new file mode 100644
index 000000000..f1c942480
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/quad/MutableQuadView.java
@@ -0,0 +1,44 @@
+package net.vulkanmod.render.quad;
+
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import net.vulkanmod.render.material.RenderMaterial;
+import org.jetbrains.annotations.Nullable;
+
+public interface MutableQuadView extends QuadView {
+ int BAKE_LOCK_UV = 1;
+ int BAKE_NORMALIZED = 1 << 1;
+ int BAKE_FLIP_U = 1 << 2;
+ int BAKE_FLIP_V = 1 << 3;
+
+ MutableQuadView pos(int vertexIndex, float x, float y, float z);
+
+ MutableQuadView color(int vertexIndex, int color);
+
+ MutableQuadView uv(int vertexIndex, float u, float v);
+
+ MutableQuadView spriteBake(TextureAtlasSprite sprite, int bakeFlags);
+
+ MutableQuadView lightmap(int vertexIndex, int lightmap);
+
+ MutableQuadView normal(int vertexIndex, float x, float y, float z);
+
+ MutableQuadView cullFace(@Nullable Direction face);
+
+ MutableQuadView nominalFace(@Nullable Direction face);
+
+ MutableQuadView material(RenderMaterial material);
+
+ MutableQuadView colorIndex(int colorIndex);
+
+ MutableQuadView tag(int tag);
+
+ MutableQuadView copyFrom(QuadView quad);
+
+ MutableQuadView fromVanilla(int[] quadData, int startIndex);
+
+ MutableQuadView fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace);
+
+ MutableQuadView emit();
+}
diff --git a/src/main/java/net/vulkanmod/render/quad/QuadView.java b/src/main/java/net/vulkanmod/render/quad/QuadView.java
new file mode 100644
index 000000000..dd438881b
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/quad/QuadView.java
@@ -0,0 +1,69 @@
+package net.vulkanmod.render.quad;
+
+import net.minecraft.core.Direction;
+import net.vulkanmod.render.material.RenderMaterial;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector2f;
+import org.joml.Vector3f;
+
+/**
+ * Lightweight quad view abstraction used by the new renderer. Derived from the
+ * Fabric API interface but pared down to the members actually consumed by
+ * VulkanMod.
+ */
+public interface QuadView {
+ int VANILLA_VERTEX_STRIDE = 8;
+ int VANILLA_QUAD_STRIDE = VANILLA_VERTEX_STRIDE * 4;
+
+ float x(int vertexIndex);
+
+ float y(int vertexIndex);
+
+ float z(int vertexIndex);
+
+ /**
+ * Returns the position component given a vertex index and axis (0 = X, 1 = Y, 2 = Z).
+ */
+ float posByIndex(int vertexIndex, int coordinateIndex);
+
+ Vector3f copyPos(int vertexIndex, @Nullable Vector3f target);
+
+ int color(int vertexIndex);
+
+ float u(int vertexIndex);
+
+ float v(int vertexIndex);
+
+ Vector2f copyUv(int vertexIndex, @Nullable Vector2f target);
+
+ int lightmap(int vertexIndex);
+
+ boolean hasNormal(int vertexIndex);
+
+ float normalX(int vertexIndex);
+
+ float normalY(int vertexIndex);
+
+ float normalZ(int vertexIndex);
+
+ @Nullable
+ Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target);
+
+ @Nullable
+ Direction cullFace();
+
+ Direction lightFace();
+
+ @Nullable
+ Direction nominalFace();
+
+ Vector3f faceNormal();
+
+ RenderMaterial material();
+
+ int colorIndex();
+
+ int tag();
+
+ void toVanilla(int[] target, int targetIndex);
+}
diff --git a/src/main/java/net/vulkanmod/render/shader/ShaderLoadUtil.java b/src/main/java/net/vulkanmod/render/shader/ShaderLoadUtil.java
index b7b036307..bbe2b4844 100644
--- a/src/main/java/net/vulkanmod/render/shader/ShaderLoadUtil.java
+++ b/src/main/java/net/vulkanmod/render/shader/ShaderLoadUtil.java
@@ -8,7 +8,10 @@
import net.vulkanmod.vulkan.shader.SPIRVUtils;
import org.apache.commons.io.IOUtils;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystems;
@@ -162,7 +165,7 @@ public static String removeNameSpace(String path) {
public static String[] splitPath(String path) {
int idx = path.lastIndexOf('/');
- return new String[] {path.substring(0, idx), path.substring(idx + 1)};
+ return new String[]{path.substring(0, idx), path.substring(idx + 1)};
}
public static InputStream getInputStream(String path) {
diff --git a/src/main/java/net/vulkanmod/render/sky/CloudRenderer.java b/src/main/java/net/vulkanmod/render/sky/CloudRenderer.java
index 2227c7b22..0d66aa79e 100644
--- a/src/main/java/net/vulkanmod/render/sky/CloudRenderer.java
+++ b/src/main/java/net/vulkanmod/render/sky/CloudRenderer.java
@@ -1,16 +1,14 @@
package net.vulkanmod.render.sky;
import com.mojang.blaze3d.platform.NativeImage;
-import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import net.minecraft.client.CloudStatus;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
-import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
-import net.minecraft.world.phys.Vec3;
+import net.minecraft.util.ARGB;
import net.vulkanmod.render.PipelineManager;
import net.vulkanmod.render.VBO;
import net.vulkanmod.vulkan.VRenderSystem;
@@ -18,6 +16,7 @@
import net.vulkanmod.vulkan.util.ColorUtil;
import org.apache.commons.lang3.Validate;
import org.joml.Matrix4f;
+import org.lwjgl.opengl.GL11;
import java.io.IOException;
@@ -53,17 +52,44 @@ public CloudRenderer() {
loadTexture();
}
+ private static void putVertex(BufferBuilder bufferBuilder, float x, float y, float z, int color) {
+ bufferBuilder.addVertex(x, y, z).setColor(color);
+ }
+
+ private static CloudGrid createCloudGrid(ResourceLocation textureLocation) {
+ ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
+
+ try {
+ Resource resource = resourceManager.getResourceOrThrow(textureLocation);
+
+ try (var inputStream = resource.open()) {
+ NativeImage image = NativeImage.read(inputStream);
+
+ int width = image.getWidth();
+ int height = image.getHeight();
+ Validate.isTrue(width == height, "Image width and height must be the same");
+
+ int[] pixels = image.getPixels();
+
+ return new CloudGrid(pixels, width);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public void loadTexture() {
this.cloudGrid = createCloudGrid(TEXTURE_LOCATION);
}
public void renderClouds(ClientLevel level, PoseStack poseStack, Matrix4f modelView, Matrix4f projection, float ticks, float partialTicks, double camX, double camY, double camZ) {
- float cloudHeight = level.effects().getCloudHeight();
-
- if (Float.isNaN(cloudHeight)) {
+ var cloudHeightOpt = level.dimensionType().cloudHeight();
+ if (cloudHeightOpt.isEmpty()) {
return;
}
+ float cloudHeight = cloudHeightOpt.get() + 0.33F;
+
Minecraft minecraft = Minecraft.getInstance();
double timeOffset = (ticks + partialTicks) * 0.03F;
@@ -77,11 +103,9 @@ public void renderClouds(ClientLevel level, PoseStack poseStack, Matrix4f modelV
byte yState;
if (centerY < -4.0f) {
yState = Y_BELOW_CLOUDS;
- }
- else if (centerY > 0.0f) {
+ } else if (centerY > 0.0f) {
yState = Y_ABOVE_CLOUDS;
- }
- else {
+ } else {
yState = Y_INSIDE_CLOUDS;
}
@@ -110,7 +134,7 @@ else if (centerY > 0.0f) {
return;
}
- this.cloudBuffer = new VBO(VertexBuffer.Usage.STATIC);
+ this.cloudBuffer = new VBO();
this.cloudBuffer.upload(cloudsMesh);
}
@@ -118,8 +142,6 @@ else if (centerY > 0.0f) {
return;
}
- FogRenderer.levelFogColor();
-
float xTranslation = (float) (centerX - (centerCellX * CELL_WIDTH));
float yTranslation = (float) (centerY);
float zTranslation = (float) (centerZ - (centerCellZ * CELL_WIDTH));
@@ -130,33 +152,36 @@ else if (centerY > 0.0f) {
VRenderSystem.setModelOffset(-xTranslation, 0, -zTranslation);
- Vec3 cloudColor = level.getCloudColor(partialTicks);
- RenderSystem.setShaderColor((float) cloudColor.x, (float) cloudColor.y, (float) cloudColor.z, 0.8f);
+ int cloudColor = level.getCloudColor(partialTicks);
+ float r = ARGB.red(cloudColor) / 255.0F;
+ float g = ARGB.green(cloudColor) / 255.0F;
+ float b = ARGB.blue(cloudColor) / 255.0F;
+ VRenderSystem.setShaderColor(r, g, b, 0.8f);
GraphicsPipeline pipeline = PipelineManager.getCloudsPipeline();
- RenderSystem.enableBlend();
- RenderSystem.defaultBlendFunc();
- RenderSystem.enableDepthTest();
+ VRenderSystem.enableBlend();
+ VRenderSystem.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ VRenderSystem.enableDepthTest();
boolean fastClouds = this.prevCloudsType == CloudStatus.FAST;
boolean insideClouds = yState == Y_INSIDE_CLOUDS;
boolean disableCull = insideClouds || (fastClouds && centerY <= 0.0f);
if (disableCull) {
- RenderSystem.disableCull();
+ VRenderSystem.disableCull();
}
if (!fastClouds) {
- RenderSystem.colorMask(false, false, false, false);
+ VRenderSystem.colorMask(false, false, false, false);
this.cloudBuffer.drawWithShader(poseStack.last().pose(), projection, pipeline);
- RenderSystem.colorMask(true, true, true, true);
+ VRenderSystem.colorMask(true, true, true, true);
}
this.cloudBuffer.drawWithShader(poseStack.last().pose(), projection, pipeline);
- RenderSystem.enableCull();
- RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
+ VRenderSystem.enableCull();
+ VRenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
VRenderSystem.setModelOffset(0.0f, 0.0f, 0.0f);
poseStack.popPose();
@@ -194,25 +219,25 @@ private MeshData buildClouds(Tesselator tesselator, int centerCellX, int centerC
if ((renderFaces & DIR_POS_Y_BIT) != 0 && cloudY <= 0.0f) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, upFaceBrightness);
putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + 0.0f, color);
- putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + 0.0f, color);
- putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + CELL_WIDTH, color);
}
if ((renderFaces & DIR_NEG_Y_BIT) != 0 && cloudY >= -CELL_HEIGHT) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, downFaceBrightness);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
}
if ((renderFaces & DIR_POS_X_BIT) != 0 && (x < 1.0f || insideClouds)) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, xDirBrightness);
putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + 0.0f, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + 0.0f, color);
}
if ((renderFaces & DIR_NEG_X_BIT) != 0 && (x > -1.0f || insideClouds)) {
@@ -225,24 +250,23 @@ private MeshData buildClouds(Tesselator tesselator, int centerCellX, int centerC
if ((renderFaces & DIR_POS_Z_BIT) != 0 && (z < 1.0f || insideClouds)) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, zDirBrightness);
- putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + CELL_WIDTH, color);
}
if ((renderFaces & DIR_NEG_Z_BIT) != 0 && (z > -1.0f || insideClouds)) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, zDirBrightness);
putVertex(bufferBuilder, x + CELL_WIDTH, CELL_HEIGHT, z + 0.0f, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
- putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + 0.0f, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, CELL_HEIGHT, z + 0.0f, color);
}
}
}
- }
- else {
+ } else {
for (int cellX = -renderDistance; cellX < renderDistance; ++cellX) {
for (int cellZ = -renderDistance; cellZ < renderDistance; ++cellZ) {
@@ -255,9 +279,9 @@ private MeshData buildClouds(Tesselator tesselator, int centerCellX, int centerC
if ((renderFaces & DIR_NEG_Y_BIT) != 0) {
final int color = ColorUtil.ARGB.multiplyRGB(baseColor, upFaceBrightness);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
- putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
- putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + CELL_WIDTH, color);
+ putVertex(bufferBuilder, x + 0.0f, 0.0f, z + 0.0f, color);
+ putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + 0.0f, color);
putVertex(bufferBuilder, x + CELL_WIDTH, 0.0f, z + CELL_WIDTH, color);
}
@@ -268,32 +292,6 @@ private MeshData buildClouds(Tesselator tesselator, int centerCellX, int centerC
return bufferBuilder.build();
}
- private static void putVertex(BufferBuilder bufferBuilder, float x, float y, float z, int color) {
- bufferBuilder.addVertex(x, y, z).setColor(color);
- }
-
- private static CloudGrid createCloudGrid(ResourceLocation textureLocation) {
- ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
-
- try {
- Resource resource = resourceManager.getResourceOrThrow(textureLocation);
-
- try (var inputStream = resource.open()) {
- NativeImage image = NativeImage.read(inputStream);
-
- int width = image.getWidth();
- int height = image.getHeight();
- Validate.isTrue(width == height, "Image width and height must be the same");
-
- int[] pixels = image.getPixelsRGBA();
-
- return new CloudGrid(pixels, width);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
static class CloudGrid {
final int width;
final int[] pixels;
@@ -306,6 +304,10 @@ static class CloudGrid {
this.renderFaces = computeRenderFaces();
}
+ private static boolean hasColor(int pixel) {
+ return ((pixel >> 24) & 0xFF) > 1;
+ }
+
byte[] computeRenderFaces() {
byte[] renderFaces = new byte[pixels.length];
@@ -379,9 +381,5 @@ int getWrappedIdx(int x, int z) {
int getIdx(int x, int z) {
return z * this.width + x;
}
-
- private static boolean hasColor(int pixel) {
- return ((pixel >> 24) & 0xFF) > 1;
- }
}
}
diff --git a/src/main/java/net/vulkanmod/render/texture/SpriteUpdateUtil.java b/src/main/java/net/vulkanmod/render/texture/SpriteUpdateUtil.java
index 82f0ceab2..7e3082cc1 100644
--- a/src/main/java/net/vulkanmod/render/texture/SpriteUpdateUtil.java
+++ b/src/main/java/net/vulkanmod/render/texture/SpriteUpdateUtil.java
@@ -9,8 +9,8 @@
public abstract class SpriteUpdateUtil {
- private static boolean doUpload = true;
private static final Set transitionedLayouts = new HashSet<>();
+ private static boolean doUpload = true;
public static void setDoUpload(boolean b) {
doUpload = b;
diff --git a/src/main/java/net/vulkanmod/render/util/DrawUtil.java b/src/main/java/net/vulkanmod/render/util/DrawUtil.java
index 430194d69..cc0e0e6dd 100644
--- a/src/main/java/net/vulkanmod/render/util/DrawUtil.java
+++ b/src/main/java/net/vulkanmod/render/util/DrawUtil.java
@@ -1,10 +1,12 @@
package net.vulkanmod.render.util;
+import com.mojang.blaze3d.ProjectionType;
+import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import net.vulkanmod.vulkan.Renderer;
+import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.shader.GraphicsPipeline;
-import net.vulkanmod.vulkan.shader.Pipeline;
import net.vulkanmod.vulkan.texture.VTextureSelector;
import net.vulkanmod.vulkan.texture.VulkanImage;
import org.joml.Matrix4f;
@@ -12,13 +14,15 @@
public class DrawUtil {
+ private static final MatrixUniformBuffer PROJECTION_BUFFER = new MatrixUniformBuffer("Vulkan UI Projection");
+
public static void blitQuad() {
blitQuad(0.0f, 1.0f, 1.0f, 0.0f);
}
public static void drawTexQuad(BufferBuilder builder, float x0, float y0, float x1, float y1, float z,
float u0, float v0, float u1, float v1) {
- Tesselator tesselator = RenderSystem.renderThreadTesselator();
+ Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferBuilder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferBuilder.addVertex(x0, y0, z).setUv(0.0F, 1.0F);
bufferBuilder.addVertex(x1, y0, z).setUv(1.0F, 1.0F);
@@ -32,7 +36,7 @@ public static void drawTexQuad(BufferBuilder builder, float x0, float y0, float
}
public static void blitQuad(float x0, float y0, float x1, float y1) {
- Tesselator tesselator = RenderSystem.renderThreadTesselator();
+ Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bufferBuilder = tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX);
bufferBuilder.addVertex(x0, y0, 0.0f).setUv(0.0F, 1.0F);
bufferBuilder.addVertex(x1, y0, 0.0f).setUv(1.0F, 1.0F);
@@ -52,11 +56,13 @@ public static void drawFramebuffer(GraphicsPipeline pipeline, VulkanImage attach
VTextureSelector.bindTexture(attachment);
Matrix4f matrix4f = new Matrix4f().setOrtho(0.0F, 1.0F, 0.0F, 1.0F, 0.0F, 1.0F, true);
- RenderSystem.setProjectionMatrix(matrix4f, VertexSorting.DISTANCE_TO_ORIGIN);
+ GpuBufferSlice projectionSlice = PROJECTION_BUFFER.upload(matrix4f);
+ RenderSystem.setProjectionMatrix(projectionSlice, ProjectionType.ORTHOGRAPHIC);
Matrix4fStack posestack = RenderSystem.getModelViewStack();
posestack.pushMatrix();
posestack.identity();
- RenderSystem.applyModelViewMatrix();
+ VRenderSystem.applyModelViewMatrix(new Matrix4f(posestack));
+ VRenderSystem.calculateMVP();
posestack.popMatrix();
Renderer.getInstance().uploadAndBindUBOs(pipeline);
diff --git a/src/main/java/net/vulkanmod/render/util/MatrixUniformBuffer.java b/src/main/java/net/vulkanmod/render/util/MatrixUniformBuffer.java
new file mode 100644
index 000000000..58a01e774
--- /dev/null
+++ b/src/main/java/net/vulkanmod/render/util/MatrixUniformBuffer.java
@@ -0,0 +1,35 @@
+package net.vulkanmod.render.util;
+
+import com.mojang.blaze3d.buffers.GpuBuffer;
+import com.mojang.blaze3d.buffers.GpuBufferSlice;
+import com.mojang.blaze3d.buffers.Std140Builder;
+import com.mojang.blaze3d.systems.RenderSystem;
+import org.joml.Matrix4f;
+import org.joml.Matrix4fc;
+import org.lwjgl.system.MemoryStack;
+
+import java.nio.ByteBuffer;
+
+public final class MatrixUniformBuffer implements AutoCloseable {
+ private final GpuBuffer buffer;
+ private final GpuBufferSlice slice;
+
+ public MatrixUniformBuffer(String debugName) {
+ this.buffer = RenderSystem.getDevice().createBuffer(() -> debugName, 136, RenderSystem.PROJECTION_MATRIX_UBO_SIZE);
+ this.slice = this.buffer.slice(0, RenderSystem.PROJECTION_MATRIX_UBO_SIZE);
+ }
+
+ public GpuBufferSlice upload(Matrix4f matrix) {
+ try (MemoryStack stack = MemoryStack.stackPush()) {
+ ByteBuffer data = Std140Builder.onStack(stack, RenderSystem.PROJECTION_MATRIX_UBO_SIZE).putMat4f((Matrix4fc) matrix).get();
+ RenderSystem.getDevice().createCommandEncoder().writeToBuffer(this.buffer.slice(), data);
+ }
+ return this.slice;
+ }
+
+ @Override
+ public void close() {
+ this.buffer.close();
+ }
+}
+
diff --git a/src/main/java/net/vulkanmod/render/util/SortUtil.java b/src/main/java/net/vulkanmod/render/util/SortUtil.java
index ef524b6ce..08f6150b5 100644
--- a/src/main/java/net/vulkanmod/render/util/SortUtil.java
+++ b/src/main/java/net/vulkanmod/render/util/SortUtil.java
@@ -23,13 +23,12 @@ public static void mergeSort(int[] indices, float[] distances, int from, int to,
if (Float.compare(distances[supp[mid]], distances[supp[mid - 1]]) <= 0) {
System.arraycopy(supp, from, indices, from, len);
- }
- else {
+ } else {
int i = from;
int p = from;
- for(int q = mid; i < to; ++i) {
- if (q < to && (p >= mid || Float.compare(distances[supp[q]], distances[supp[p]]) > 0)) {
+ for (int q = mid; i < to; ++i) {
+ if (q < to && (p >= mid || Float.compare(distances[supp[q]], distances[supp[p]]) > 0)) {
indices[i] = supp[q++];
} else {
indices[i] = supp[p++];
@@ -68,33 +67,31 @@ public static void quickSort(int[] is, float[] distances, int from, int to) {
swap(is, m, d);
float mValue = distances[v];
- while(true) {
+ while (true) {
- while(b < c) {
- if(Float.compare(distances[is[b]], mValue) > 0) {
- while(b < c) {
- if(Float.compare(distances[is[c]], mValue) < 0) {
+ while (b < c) {
+ if (Float.compare(distances[is[b]], mValue) > 0) {
+ while (b < c) {
+ if (Float.compare(distances[is[c]], mValue) < 0) {
swap(is, b, c);
b++;
c--;
break;
- }
- else {
+ } else {
c--;
}
}
- }
- else {
+ } else {
b++;
}
}
swap(is, d, b);
- if(b - a > 1)
+ if (b - a > 1)
quickSort(is, distances, a, b);
- if(d - b > 1)
+ if (d - b > 1)
quickSort(is, distances, b, d);
return;
@@ -106,7 +103,7 @@ public static void quickSort(int[] is, float[] distances, int from, int to) {
private static void insertionSort(int[] is, float[] distances, int from, int to) {
int i = from;
- while(true) {
+ while (true) {
++i;
if (i >= to) {
return;
@@ -115,7 +112,7 @@ private static void insertionSort(int[] is, float[] distances, int from, int to)
int t = is[i];
int j = i;
- for(int u = is[i - 1]; Float.compare(distances[u], distances[t]) < 0; u = is[j - 1]) {
+ for (int u = is[i - 1]; Float.compare(distances[u], distances[t]) < 0; u = is[j - 1]) {
is[j] = u;
if (from == j - 1) {
--j;
@@ -130,7 +127,7 @@ private static void insertionSort(int[] is, float[] distances, int from, int to)
}
public static void swap(int[] x, int a, int b, int n) {
- for(int i = 0; i < n; ++b, ++i, ++a) {
+ for (int i = 0; i < n; ++b, ++i, ++a) {
swap(x, a, b);
}
diff --git a/src/main/java/net/vulkanmod/render/vertex/CustomVertexFormat.java b/src/main/java/net/vulkanmod/render/vertex/CustomVertexFormat.java
index 437345ff8..8c32da15f 100644
--- a/src/main/java/net/vulkanmod/render/vertex/CustomVertexFormat.java
+++ b/src/main/java/net/vulkanmod/render/vertex/CustomVertexFormat.java
@@ -5,16 +5,16 @@
public class CustomVertexFormat {
- public static final VertexFormatElement ELEMENT_POSITION = new VertexFormatElement(0, 0,VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.POSITION, 4);
+ public static final VertexFormatElement ELEMENT_POSITION = new VertexFormatElement(0, 0, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.POSITION, 4);
public static final VertexFormatElement ELEMENT_COLOR = new VertexFormatElement(1, 0, VertexFormatElement.Type.UINT, VertexFormatElement.Usage.COLOR, 1);
public static final VertexFormatElement ELEMENT_UV0 = new VertexFormatElement(2, 0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.UV, 2);
public static final VertexFormat COMPRESSED_TERRAIN =
VertexFormat.builder()
- .add("Position", ELEMENT_POSITION)
- .add("UV0", ELEMENT_UV0)
- .add("Color", ELEMENT_COLOR)
- .build();
+ .add("Position", ELEMENT_POSITION)
+ .add("UV0", ELEMENT_UV0)
+ .add("Color", ELEMENT_COLOR)
+ .build();
public static final VertexFormat NONE = VertexFormat.builder().build();
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/render/vertex/TerrainBufferBuilder.java b/src/main/java/net/vulkanmod/render/vertex/TerrainBufferBuilder.java
index 9e8651dae..24003226f 100644
--- a/src/main/java/net/vulkanmod/render/vertex/TerrainBufferBuilder.java
+++ b/src/main/java/net/vulkanmod/render/vertex/TerrainBufferBuilder.java
@@ -11,16 +11,12 @@
public class TerrainBufferBuilder implements VertexConsumer {
private static final Logger LOGGER = Initializer.LOGGER;
private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator(false);
-
- private int capacity;
- private int vertexSize;
-
protected long bufferPtr;
-
protected int nextElementByte;
int vertices;
-
- private long elementPtr;
+ private int capacity;
+ private int vertexSize;
+ private long elementPtr;
private VertexBuilder vertexBuilder;
@@ -88,54 +84,54 @@ public int getNextElementByte() {
return nextElementByte;
}
- @Override
- public VertexConsumer addVertex(float x, float y, float z) {
- this.elementPtr = this.bufferPtr + this.nextElementByte;
- this.endVertex();
+ @Override
+ public VertexConsumer addVertex(float x, float y, float z) {
+ this.elementPtr = this.bufferPtr + this.nextElementByte;
+ this.endVertex();
- this.vertexBuilder.position(this.elementPtr, x, y, z);
+ this.vertexBuilder.position(this.elementPtr, x, y, z);
- return this;
- }
+ return this;
+ }
- @Override
- public VertexConsumer setColor(int r, int g, int b, int a) {
- int color = (a & 0xFF) << 24 | (b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF);
+ @Override
+ public VertexConsumer setColor(int r, int g, int b, int a) {
+ int color = (a & 0xFF) << 24 | (b & 0xFF) << 16 | (g & 0xFF) << 8 | (r & 0xFF);
- this.vertexBuilder.color(this.elementPtr, color);
+ this.vertexBuilder.color(this.elementPtr, color);
- return this;
- }
+ return this;
+ }
- @Override
- public VertexConsumer setUv(float u, float v) {
- this.vertexBuilder.uv(this.elementPtr, u, v);
+ @Override
+ public VertexConsumer setUv(float u, float v) {
+ this.vertexBuilder.uv(this.elementPtr, u, v);
- return this;
- }
+ return this;
+ }
- public VertexConsumer setLight(int i) {
- this.vertexBuilder.light(this.elementPtr, i);
+ public VertexConsumer setLight(int i) {
+ this.vertexBuilder.light(this.elementPtr, i);
- return this;
- }
+ return this;
+ }
- @Override
- public VertexConsumer setNormal(float f, float g, float h) {
- int packedNormal = I32_SNorm.packNormal(f, g, h);
+ @Override
+ public VertexConsumer setNormal(float f, float g, float h) {
+ int packedNormal = I32_SNorm.packNormal(f, g, h);
- this.vertexBuilder.normal(this.elementPtr, packedNormal);
+ this.vertexBuilder.normal(this.elementPtr, packedNormal);
- return this;
- }
+ return this;
+ }
- @Override
- public VertexConsumer setUv1(int i, int j) {
- return this;
- }
+ @Override
+ public VertexConsumer setUv1(int i, int j) {
+ return this;
+ }
- @Override
- public VertexConsumer setUv2(int i, int j) {
- return this;
- }
+ @Override
+ public VertexConsumer setUv2(int i, int j) {
+ return this;
+ }
}
diff --git a/src/main/java/net/vulkanmod/render/vertex/TerrainBuilder.java b/src/main/java/net/vulkanmod/render/vertex/TerrainBuilder.java
index f12c69a17..188604ca2 100644
--- a/src/main/java/net/vulkanmod/render/vertex/TerrainBuilder.java
+++ b/src/main/java/net/vulkanmod/render/vertex/TerrainBuilder.java
@@ -13,25 +13,17 @@
public class TerrainBuilder {
private static final Logger LOGGER = Initializer.LOGGER;
private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator(false);
-
+ private final VertexFormat format;
+ private final QuadSorter quadSorter = new QuadSorter();
+ private final TerrainBufferBuilder[] bufferBuilders;
protected long indexBufferPtr;
-
- private int indexBufferCapacity;
protected long bufferPtr;
-
- private final VertexFormat format;
-
+ protected VertexBuilder vertexBuilder;
+ private int indexBufferCapacity;
private boolean building;
-
- private final QuadSorter quadSorter = new QuadSorter();
-
private boolean needsSorting;
private boolean indexOnly;
- protected VertexBuilder vertexBuilder;
-
- private final TerrainBufferBuilder[] bufferBuilders;
-
public TerrainBuilder(int size) {
// TODO index buffer
this.indexBufferPtr = ALLOCATOR.malloc(size);
diff --git a/src/main/java/net/vulkanmod/render/vertex/TerrainRenderType.java b/src/main/java/net/vulkanmod/render/vertex/TerrainRenderType.java
index 2eb1a14d0..4d58649bb 100644
--- a/src/main/java/net/vulkanmod/render/vertex/TerrainRenderType.java
+++ b/src/main/java/net/vulkanmod/render/vertex/TerrainRenderType.java
@@ -1,6 +1,7 @@
package net.vulkanmod.render.vertex;
import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.vulkanmod.Initializer;
import net.vulkanmod.interfaces.ExtendedRenderType;
import net.vulkanmod.vulkan.VRenderSystem;
@@ -37,12 +38,8 @@ public enum TerrainRenderType {
this.alphaCutout = alphaCutout;
}
- public void setCutoutUniform() {
- VRenderSystem.alphaCutout = this.alphaCutout;
- }
-
public static TerrainRenderType get(RenderType renderType) {
- return ((ExtendedRenderType)renderType).getTerrainRenderType();
+ return ((ExtendedRenderType) renderType).getTerrainRenderType();
}
public static TerrainRenderType get(String name) {
@@ -56,12 +53,22 @@ public static TerrainRenderType get(String name) {
};
}
+ public static TerrainRenderType fromChunkLayer(ChunkSectionLayer layer) {
+ return switch (layer) {
+ case SOLID -> SOLID;
+ case CUTOUT -> CUTOUT;
+ case CUTOUT_MIPPED -> CUTOUT_MIPPED;
+ case TRANSLUCENT -> TRANSLUCENT;
+ case TRIPWIRE -> TRIPWIRE;
+ };
+ }
+
public static RenderType getRenderType(TerrainRenderType renderType) {
return switch (renderType) {
case SOLID -> RenderType.solid();
case CUTOUT -> RenderType.cutout();
case CUTOUT_MIPPED -> RenderType.cutoutMipped();
- case TRANSLUCENT -> RenderType.translucent();
+ case TRANSLUCENT -> RenderType.translucentMovingBlock();
case TRIPWIRE -> RenderType.tripwire();
};
}
@@ -84,4 +91,8 @@ public static void updateMapping() {
public static TerrainRenderType getRemapped(TerrainRenderType renderType) {
return remapper.apply(renderType);
}
+
+ public void setCutoutUniform() {
+ VRenderSystem.alphaCutout = this.alphaCutout;
+ }
}
diff --git a/src/main/java/net/vulkanmod/render/vertex/VertexBuilder.java b/src/main/java/net/vulkanmod/render/vertex/VertexBuilder.java
index 5f6555459..459ab9531 100644
--- a/src/main/java/net/vulkanmod/render/vertex/VertexBuilder.java
+++ b/src/main/java/net/vulkanmod/render/vertex/VertexBuilder.java
@@ -69,13 +69,11 @@ public int getStride() {
}
class CompressedVertexBuilder implements VertexBuilder {
- private static final int VERTEX_SIZE = 16;
-
public static final float POS_CONV_MUL = 2048.0f;
public static final float POS_OFFSET = -4.0f;
public static final float POS_OFFSET_CONV = POS_OFFSET * POS_CONV_MUL;
-
public static final float UV_CONV_MUL = 32768.0f;
+ private static final int VERTEX_SIZE = 16;
public void vertex(long ptr, float x, float y, float z, int color, float u, float v, int light, int packedNormal) {
final short sX = (short) (x * POS_CONV_MUL + POS_OFFSET_CONV);
diff --git a/src/main/java/net/vulkanmod/render/vertex/format/I32_SNorm.java b/src/main/java/net/vulkanmod/render/vertex/format/I32_SNorm.java
index fb8366991..e1e4923d2 100644
--- a/src/main/java/net/vulkanmod/render/vertex/format/I32_SNorm.java
+++ b/src/main/java/net/vulkanmod/render/vertex/format/I32_SNorm.java
@@ -8,22 +8,22 @@ public static int packNormal(float x, float y, float z) {
y *= 127.0f;
z *= 127.0f;
- return ((int)x & 0xFF) | ((int)y & 0xFF) << 8| ((int)z & 0xFF) << 16;
+ return ((int) x & 0xFF) | ((int) y & 0xFF) << 8 | ((int) z & 0xFF) << 16;
}
public static int packNormal(int x, int y, int z) {
- return (x & 0xFF) | (y & 0xFF) << 8| (z & 0xFF) << 16;
+ return (x & 0xFF) | (y & 0xFF) << 8 | (z & 0xFF) << 16;
}
public static float unpackX(int i) {
- return (byte)(i & 0xFF) * NORM_INV;
+ return (byte) (i & 0xFF) * NORM_INV;
}
public static float unpackY(int i) {
- return (byte)((i >> 8) & 0xFF) * NORM_INV;
+ return (byte) ((i >> 8) & 0xFF) * NORM_INV;
}
public static float unpackZ(int i) {
- return (byte)((i >> 16) & 0xFF) * NORM_INV;
+ return (byte) ((i >> 16) & 0xFF) * NORM_INV;
}
}
diff --git a/src/main/java/net/vulkanmod/util/TriState.java b/src/main/java/net/vulkanmod/util/TriState.java
new file mode 100644
index 000000000..56cf640cf
--- /dev/null
+++ b/src/main/java/net/vulkanmod/util/TriState.java
@@ -0,0 +1,22 @@
+package net.vulkanmod.util;
+
+/**
+ * Minimal tri-state representation used by VulkanMod's rendering helpers.
+ */
+public enum TriState {
+ DEFAULT,
+ TRUE,
+ FALSE;
+
+ public boolean isDefault() {
+ return this == DEFAULT;
+ }
+
+ public boolean isTrue() {
+ return this == TRUE;
+ }
+
+ public boolean isFalse() {
+ return this == FALSE;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/vulkan/Drawer.java b/src/main/java/net/vulkanmod/vulkan/Drawer.java
index fd2ae33f8..753179351 100644
--- a/src/main/java/net/vulkanmod/vulkan/Drawer.java
+++ b/src/main/java/net/vulkanmod/vulkan/Drawer.java
@@ -1,7 +1,8 @@
package net.vulkanmod.vulkan;
import com.mojang.blaze3d.vertex.VertexFormat;
-import net.vulkanmod.vulkan.memory.*;
+import net.vulkanmod.vulkan.memory.MemoryManager;
+import net.vulkanmod.vulkan.memory.MemoryTypes;
import net.vulkanmod.vulkan.memory.buffer.Buffer;
import net.vulkanmod.vulkan.memory.buffer.IndexBuffer;
import net.vulkanmod.vulkan.memory.buffer.UniformBuffer;
@@ -26,18 +27,15 @@ public class Drawer {
private static final LongBuffer offsets = MemoryUtil.memAllocLong(1);
private static final long pBuffers = MemoryUtil.memAddress0(buffers);
private static final long pOffsets = MemoryUtil.memAddress0(offsets);
-
- private int framesNum;
- private VertexBuffer[] vertexBuffers;
- private IndexBuffer[] indexBuffers;
-
private final AutoIndexBuffer quadsIndexBuffer;
private final AutoIndexBuffer quadsIntIndexBuffer;
private final AutoIndexBuffer linesIndexBuffer;
private final AutoIndexBuffer debugLineStripIndexBuffer;
private final AutoIndexBuffer triangleFanIndexBuffer;
private final AutoIndexBuffer triangleStripIndexBuffer;
-
+ private int framesNum;
+ private VertexBuffer[] vertexBuffers;
+ private IndexBuffer[] indexBuffers;
private UniformBuffer[] uniformBuffers;
private int currentFrame;
@@ -60,28 +58,22 @@ public void createResources(int framesNum) {
this.framesNum = framesNum;
if (this.vertexBuffers != null) {
- Arrays.stream(this.vertexBuffers).iterator().forEachRemaining(
- Buffer::scheduleFree
- );
+ Arrays.stream(this.vertexBuffers).iterator().forEachRemaining(Buffer::scheduleFree);
}
this.vertexBuffers = new VertexBuffer[framesNum];
- Arrays.setAll(this.vertexBuffers, i -> new VertexBuffer(INITIAL_VB_SIZE, MemoryTypes.HOST_MEM));
+ Arrays.setAll(this.vertexBuffers, _ -> new VertexBuffer(INITIAL_VB_SIZE, MemoryTypes.HOST_MEM));
if (this.indexBuffers != null) {
- Arrays.stream(this.indexBuffers).iterator().forEachRemaining(
- Buffer::scheduleFree
- );
+ Arrays.stream(this.indexBuffers).iterator().forEachRemaining(Buffer::scheduleFree);
}
this.indexBuffers = new IndexBuffer[framesNum];
- Arrays.setAll(this.indexBuffers, i -> new IndexBuffer(INITIAL_IB_SIZE, MemoryTypes.HOST_MEM));
+ Arrays.setAll(this.indexBuffers, _ -> new IndexBuffer(INITIAL_IB_SIZE, MemoryTypes.HOST_MEM));
if (this.uniformBuffers != null) {
- Arrays.stream(this.uniformBuffers).iterator().forEachRemaining(
- Buffer::scheduleFree
- );
+ Arrays.stream(this.uniformBuffers).iterator().forEachRemaining(Buffer::scheduleFree);
}
this.uniformBuffers = new UniformBuffer[framesNum];
- Arrays.setAll(this.uniformBuffers, i -> new UniformBuffer(INITIAL_UB_SIZE, MemoryTypes.HOST_MEM));
+ Arrays.setAll(this.uniformBuffers, _ -> new UniformBuffer(INITIAL_UB_SIZE, MemoryTypes.HOST_MEM));
}
public void resetBuffers(int currentFrame) {
@@ -106,8 +98,7 @@ public void draw(ByteBuffer vertexData, ByteBuffer indexData, VertexFormat.Mode
int indexCount = vertexCount * 3 / 2;
drawIndexed(vertexBuffer, indexBuffer, indexCount);
- }
- else {
+ } else {
AutoIndexBuffer autoIndexBuffer = getAutoIndexBuffer(mode, vertexCount);
if (autoIndexBuffer != null) {
@@ -115,22 +106,21 @@ public void draw(ByteBuffer vertexData, ByteBuffer indexData, VertexFormat.Mode
autoIndexBuffer.checkCapacity(indexCount);
drawIndexed(vertexBuffer, autoIndexBuffer.getIndexBuffer(), indexCount);
- }
- else {
+ } else {
draw(vertexBuffer, vertexCount);
}
}
}
public void drawIndexed(Buffer vertexBuffer, IndexBuffer indexBuffer, int indexCount) {
- drawIndexed(vertexBuffer, indexBuffer, indexCount, indexBuffer.indexType.value);
+ drawIndexed(vertexBuffer, indexBuffer, indexCount, indexBuffer.indexType.value);
}
public void drawIndexed(Buffer vertexBuffer, Buffer indexBuffer, int indexCount, int indexType) {
VkCommandBuffer commandBuffer = Renderer.getCommandBuffer();
- VUtil.UNSAFE.putLong(pBuffers, vertexBuffer.getId());
- VUtil.UNSAFE.putLong(pOffsets, vertexBuffer.getOffset());
+ VUtil.putLong(pBuffers, vertexBuffer.getId());
+ VUtil.putLong(pOffsets, vertexBuffer.getOffset());
nvkCmdBindVertexBuffers(commandBuffer, 0, 1, pBuffers, pOffsets);
bindIndexBuffer(commandBuffer, indexBuffer, indexType);
@@ -140,8 +130,8 @@ public void drawIndexed(Buffer vertexBuffer, Buffer indexBuffer, int indexCount,
public void draw(VertexBuffer vertexBuffer, int vertexCount) {
VkCommandBuffer commandBuffer = Renderer.getCommandBuffer();
- VUtil.UNSAFE.putLong(pBuffers, vertexBuffer.getId());
- VUtil.UNSAFE.putLong(pOffsets, vertexBuffer.getOffset());
+ VUtil.putLong(pBuffers, vertexBuffer.getId());
+ VUtil.putLong(pOffsets, vertexBuffer.getOffset());
nvkCmdBindVertexBuffers(commandBuffer, 0, 1, pBuffers, pOffsets);
vkCmdDraw(commandBuffer, vertexCount, 1, 0, 0);
@@ -201,14 +191,13 @@ public AutoIndexBuffer getAutoIndexBuffer(VertexFormat.Mode mode, int vertexCoun
case QUADS -> {
int indexCount = vertexCount * 3 / 2;
- yield indexCount > AutoIndexBuffer.U16_MAX_VERTEX_COUNT
- ? this.quadsIntIndexBuffer : this.quadsIndexBuffer;
+ yield indexCount > AutoIndexBuffer.U16_MAX_VERTEX_COUNT ? this.quadsIntIndexBuffer : this.quadsIndexBuffer;
}
case LINES -> this.linesIndexBuffer;
case TRIANGLE_FAN -> this.triangleFanIndexBuffer;
case TRIANGLE_STRIP, LINE_STRIP -> this.triangleStripIndexBuffer;
case DEBUG_LINE_STRIP -> this.debugLineStripIndexBuffer;
case TRIANGLES, DEBUG_LINES -> null;
- };
+ };
}
}
diff --git a/src/main/java/net/vulkanmod/vulkan/Renderer.java b/src/main/java/net/vulkanmod/vulkan/Renderer.java
index 45267dcb4..0fe619572 100644
--- a/src/main/java/net/vulkanmod/vulkan/Renderer.java
+++ b/src/main/java/net/vulkanmod/vulkan/Renderer.java
@@ -1,6 +1,8 @@
package net.vulkanmod.vulkan;
-import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.opengl.GlStateManager;
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import com.mojang.blaze3d.vertex.VertexFormat;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.client.Minecraft;
@@ -19,19 +21,18 @@
import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.pass.DefaultMainPass;
import net.vulkanmod.vulkan.pass.MainPass;
-import net.vulkanmod.vulkan.shader.GraphicsPipeline;
-import net.vulkanmod.vulkan.shader.Pipeline;
-import net.vulkanmod.vulkan.shader.PipelineState;
-import net.vulkanmod.vulkan.shader.Uniforms;
+import net.vulkanmod.vulkan.shader.*;
import net.vulkanmod.vulkan.shader.layout.PushConstants;
import net.vulkanmod.vulkan.texture.VTextureSelector;
import net.vulkanmod.vulkan.util.VUtil;
import net.vulkanmod.vulkan.util.VkResult;
-import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.vulkan.*;
+import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.ValueLayout;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
@@ -39,8 +40,8 @@
import java.util.List;
import java.util.Set;
-import static com.mojang.blaze3d.platform.GlConst.GL_COLOR_BUFFER_BIT;
-import static com.mojang.blaze3d.platform.GlConst.GL_DEPTH_BUFFER_BIT;
+import static com.mojang.blaze3d.opengl.GlConst.GL_COLOR_BUFFER_BIT;
+import static com.mojang.blaze3d.opengl.GlConst.GL_DEPTH_BUFFER_BIT;
import static net.vulkanmod.vulkan.Vulkan.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.vulkan.EXTDebugUtils.*;
@@ -48,12 +49,37 @@
import static org.lwjgl.vulkan.VK10.*;
public class Renderer {
+ public static boolean skipRendering = false;
private static Renderer INSTANCE;
-
private static VkDevice device;
-
private static boolean swapChainUpdate = false;
- public static boolean skipRendering = false;
+ private static int currentFrame = 0;
+ private static int imageIndex;
+ private static int lastReset = -1;
+ private final Set usedPipelines = new ObjectOpenHashSet<>();
+ private final List onResizeCallbacks = new ObjectArrayList<>();
+ MainPass mainPass;
+ private Pipeline boundPipeline;
+ private long boundPipelineHandle;
+
+ private Drawer drawer;
+
+ private SwapChain swapChain;
+
+ private int framesNum;
+ private List commandBuffers;
+ private ArrayList imageAvailableSemaphores;
+ private ArrayList renderFinishedSemaphores;
+ private ArrayList inFlightFences;
+
+ private Framebuffer boundFramebuffer;
+ private RenderPass boundRenderPass;
+ private VkCommandBuffer currentCmdBuffer;
+ private boolean recordingCmds = false;
+ public Renderer() {
+ device = Vulkan.getVkDevice();
+ framesNum = Initializer.CONFIG.frameQueueSize;
+ }
public static void initRenderer() {
INSTANCE = new Renderer();
@@ -76,43 +102,222 @@ public static int getCurrentImage() {
return imageIndex;
}
- private final Set usedPipelines = new ObjectOpenHashSet<>();
- private Pipeline boundPipeline;
- private long boundPipelineHandle;
+ public static void setLineWidth(float width) {
+ if (INSTANCE.boundFramebuffer == null) {
+ return;
+ }
+ vkCmdSetLineWidth(INSTANCE.currentCmdBuffer, width);
+ }
- private Drawer drawer;
+ private static void resetDynamicState(VkCommandBuffer commandBuffer) {
+ vkCmdSetDepthBias(commandBuffer, 0.0F, 0.0F, 0.0F);
- private SwapChain swapChain;
+ vkCmdSetLineWidth(commandBuffer, 1.0F);
+ }
- private int framesNum;
- private List commandBuffers;
- private ArrayList imageAvailableSemaphores;
- private ArrayList renderFinishedSemaphores;
- private ArrayList inFlightFences;
+ public static void setDepthBias(float constant, float slope) {
+ VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
- private Framebuffer boundFramebuffer;
- private RenderPass boundRenderPass;
+ vkCmdSetDepthBias(commandBuffer, constant, 0.0f, slope);
+ }
- private static int currentFrame = 0;
- private static int imageIndex;
- private static int lastReset = -1;
- private VkCommandBuffer currentCmdBuffer;
- private boolean recordingCmds = false;
+ public static void clearAttachments(int v) {
+ Framebuffer framebuffer = Renderer.getInstance().boundFramebuffer;
+ if (framebuffer == null) return;
- MainPass mainPass;
+ clearAttachments(v, framebuffer.getWidth(), framebuffer.getHeight());
+ }
- private final List onResizeCallbacks = new ObjectArrayList<>();
+ public static void clearAttachments(int v, int width, int height) {
+ if (skipRendering) return;
+
+ try (Arena arena = Arena.ofConfined()) {
+ VkClearValue colorValue = VUtil.struct(
+ arena,
+ VkClearValue.SIZEOF,
+ VkClearValue.ALIGNOF,
+ VkClearValue::create
+ );
+ float clearR = VRenderSystem.clearColor.get(0);
+ float clearG = VRenderSystem.clearColor.get(1);
+ float clearB = VRenderSystem.clearColor.get(2);
+ float clearA = VRenderSystem.clearColor.get(3);
+ colorValue.color().float32(0, clearR);
+ colorValue.color().float32(1, clearG);
+ colorValue.color().float32(2, clearB);
+ colorValue.color().float32(3, clearA);
+
+ VkClearValue depthValue = VUtil.struct(
+ arena,
+ VkClearValue.SIZEOF,
+ VkClearValue.ALIGNOF,
+ VkClearValue::create
+ );
+ depthValue.depthStencil().set(VRenderSystem.clearDepthValue, 0);
- public Renderer() {
- device = Vulkan.getVkDevice();
- framesNum = Initializer.CONFIG.frameQueueSize;
+ int attachmentsCount = v == (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) ? 2 : 1;
+ VkClearAttachment.Buffer attachments = VUtil.structBuffer(
+ arena,
+ VkClearAttachment.SIZEOF,
+ VkClearAttachment.ALIGNOF,
+ attachmentsCount,
+ VkClearAttachment::create
+ );
+
+ switch (v) {
+ case GL_DEPTH_BUFFER_BIT -> {
+ VkClearAttachment clearDepth = attachments.get(0);
+ clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
+ clearDepth.colorAttachment(0);
+ clearDepth.clearValue(depthValue);
+ }
+ case GL_COLOR_BUFFER_BIT -> {
+ VkClearAttachment clearColor = attachments.get(0);
+ clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
+ clearColor.colorAttachment(0);
+ clearColor.clearValue(colorValue);
+ }
+ case GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT -> {
+ VkClearAttachment clearColor = attachments.get(0);
+ clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
+ clearColor.colorAttachment(0);
+ clearColor.clearValue(colorValue);
+
+ VkClearAttachment clearDepth = attachments.get(1);
+ clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
+ clearDepth.colorAttachment(0);
+ clearDepth.clearValue(depthValue);
+ }
+ default -> throw new RuntimeException("unexpected value");
+ }
+
+ VkClearRect.Buffer rect = VUtil.structBuffer(
+ arena,
+ VkClearRect.SIZEOF,
+ VkClearRect.ALIGNOF,
+ 1,
+ VkClearRect::create
+ );
+ rect.get(0).rect().offset().set(0, 0);
+ rect.get(0).rect().extent().set(width, height);
+ rect.get(0).baseArrayLayer(0);
+ rect.get(0).layerCount(1);
+
+ vkCmdClearAttachments(INSTANCE.currentCmdBuffer, attachments, rect);
+ }
}
- public static void setLineWidth(float width) {
- if (INSTANCE.boundFramebuffer == null) {
- return;
+ public static void setInvertedViewport(int x, int y, int width, int height) {
+ setViewportState(x, y + height, width, -height);
+ }
+
+ public static void resetViewport() {
+ int width = INSTANCE.getSwapChain().getWidth();
+ int height = INSTANCE.getSwapChain().getHeight();
+
+ setViewportState(0, 0, width, height);
+ }
+
+ public static void setViewportState(int x, int y, int width, int height) {
+ GlStateManager._viewport(x, y, width, height);
+ }
+
+ public static void setViewport(int x, int y, int width, int height) {
+ if (!INSTANCE.recordingCmds) return;
+
+ try (Arena arena = Arena.ofConfined()) {
+ VkViewport.Buffer viewport = VUtil.structBuffer(
+ arena,
+ VkViewport.SIZEOF,
+ VkViewport.ALIGNOF,
+ 1,
+ VkViewport::create
+ );
+ viewport.x(x);
+ viewport.y(height + y);
+ viewport.width(width);
+ viewport.height(-height);
+ viewport.minDepth(0.0f);
+ viewport.maxDepth(1.0f);
+
+ vkCmdSetViewport(INSTANCE.currentCmdBuffer, 0, viewport);
}
- vkCmdSetLineWidth(INSTANCE.currentCmdBuffer, width);
+ }
+
+ public static void setScissor(int x, int y, int width, int height) {
+ if (INSTANCE.boundFramebuffer == null) return;
+
+ try (Arena arena = Arena.ofConfined()) {
+ int framebufferHeight = INSTANCE.boundFramebuffer.getHeight();
+
+ x = Math.max(0, x);
+
+ VkRect2D.Buffer scissor = VUtil.structBuffer(
+ arena,
+ VkRect2D.SIZEOF,
+ VkRect2D.ALIGNOF,
+ 1,
+ VkRect2D::create
+ );
+ scissor.offset().set(x, framebufferHeight - (y + height));
+ scissor.extent().set(width, height);
+
+ vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor);
+ }
+ }
+
+ public static void resetScissor() {
+ if (INSTANCE.boundFramebuffer == null) return;
+
+ INSTANCE.boundFramebuffer.applyScissor(INSTANCE.currentCmdBuffer);
+ }
+
+ public static void pushDebugSection(String s) {
+ if (Vulkan.ENABLE_VALIDATION_LAYERS) {
+ VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
+
+ try (Arena arena = Arena.ofConfined()) {
+ VkDebugUtilsLabelEXT markerInfo = VUtil.struct(
+ arena,
+ VkDebugUtilsLabelEXT.SIZEOF,
+ VkDebugUtilsLabelEXT.ALIGNOF,
+ VkDebugUtilsLabelEXT::create
+ );
+ markerInfo.sType(VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT);
+ ByteBuffer label = VUtil.utf8String(arena, s);
+ markerInfo.pLabelName(label);
+ vkCmdBeginDebugUtilsLabelEXT(commandBuffer, markerInfo);
+ }
+ }
+ }
+
+ public static void popDebugSection() {
+ if (Vulkan.ENABLE_VALIDATION_LAYERS) {
+ VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
+
+ vkCmdEndDebugUtilsLabelEXT(commandBuffer);
+ }
+ }
+
+ public static void popPushDebugSection(String s) {
+ popDebugSection();
+ pushDebugSection(s);
+ }
+
+ public static int getFramesNum() {
+ return INSTANCE.framesNum;
+ }
+
+ public static VkCommandBuffer getCommandBuffer() {
+ return INSTANCE.currentCmdBuffer;
+ }
+
+ public static boolean isRecording() {
+ return INSTANCE.recordingCmds;
+ }
+
+ public static void scheduleSwapChainUpdate() {
+ swapChainUpdate = true;
}
private void init() {
@@ -140,23 +345,30 @@ private void allocateCommandBuffers() {
commandBuffers = new ArrayList<>(framesNum);
- try (MemoryStack stack = stackPush()) {
-
- VkCommandBufferAllocateInfo allocInfo = VkCommandBufferAllocateInfo.calloc(stack);
+ try (Arena arena = Arena.ofConfined()) {
+ VkCommandBufferAllocateInfo allocInfo = VUtil.struct(
+ arena,
+ VkCommandBufferAllocateInfo.SIZEOF,
+ VkCommandBufferAllocateInfo.ALIGNOF,
+ VkCommandBufferAllocateInfo::create
+ );
allocInfo.sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO);
allocInfo.commandPool(getCommandPool());
allocInfo.level(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
allocInfo.commandBufferCount(framesNum);
- PointerBuffer pCommandBuffers = stack.mallocPointer(framesNum);
+ MemorySegment pCommandBuffers = arena.allocate(ValueLayout.ADDRESS, framesNum);
- int vkResult = vkAllocateCommandBuffers(device, allocInfo, pCommandBuffers);
+ int vkResult = VK10.nvkAllocateCommandBuffers(device, allocInfo.address(), pCommandBuffers.address());
if (vkResult != VK_SUCCESS) {
throw new RuntimeException("Failed to allocate command buffers: %s".formatted(VkResult.decode(vkResult)));
}
+ long stride = ValueLayout.ADDRESS.byteSize();
for (int i = 0; i < framesNum; i++) {
- commandBuffers.add(new VkCommandBuffer(pCommandBuffers.get(i), device));
+ MemorySegment handleSegment = pCommandBuffers.get(ValueLayout.ADDRESS, (long) i * stride);
+ long handle = handleSegment.address();
+ commandBuffers.add(new VkCommandBuffer(handle, device));
}
}
}
@@ -166,34 +378,39 @@ private void createSyncObjects() {
renderFinishedSemaphores = new ArrayList<>(framesNum);
inFlightFences = new ArrayList<>(framesNum);
- try (MemoryStack stack = stackPush()) {
-
- VkSemaphoreCreateInfo semaphoreInfo = VkSemaphoreCreateInfo.calloc(stack);
+ try (Arena arena = Arena.ofConfined()) {
+ VkSemaphoreCreateInfo semaphoreInfo = VUtil.struct(
+ arena,
+ VkSemaphoreCreateInfo.SIZEOF,
+ VkSemaphoreCreateInfo.ALIGNOF,
+ VkSemaphoreCreateInfo::create
+ );
semaphoreInfo.sType(VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
- VkFenceCreateInfo fenceInfo = VkFenceCreateInfo.calloc(stack);
+ VkFenceCreateInfo fenceInfo = VUtil.struct(
+ arena,
+ VkFenceCreateInfo.SIZEOF,
+ VkFenceCreateInfo.ALIGNOF,
+ VkFenceCreateInfo::create
+ );
fenceInfo.sType(VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
fenceInfo.flags(VK_FENCE_CREATE_SIGNALED_BIT);
- LongBuffer pImageAvailableSemaphore = stack.mallocLong(1);
- LongBuffer pRenderFinishedSemaphore = stack.mallocLong(1);
- LongBuffer pFence = stack.mallocLong(1);
+ LongBuffer pImageAvailableSemaphore = VUtil.allocateLongBuffer(arena, 1);
+ LongBuffer pRenderFinishedSemaphore = VUtil.allocateLongBuffer(arena, 1);
+ LongBuffer pFence = VUtil.allocateLongBuffer(arena, 1);
for (int i = 0; i < framesNum; i++) {
-
if (vkCreateSemaphore(device, semaphoreInfo, null, pImageAvailableSemaphore) != VK_SUCCESS
|| vkCreateSemaphore(device, semaphoreInfo, null, pRenderFinishedSemaphore) != VK_SUCCESS
|| vkCreateFence(device, fenceInfo, null, pFence) != VK_SUCCESS) {
-
throw new RuntimeException("Failed to create synchronization objects for the frame: " + i);
}
imageAvailableSemaphores.add(pImageAvailableSemaphore.get(0));
renderFinishedSemaphores.add(pRenderFinishedSemaphore.get(0));
inFlightFences.add(pFence.get(0));
-
}
-
}
}
@@ -203,6 +420,11 @@ public void preInitFrame() {
p.round();
p.push("Frame_ops");
+ Minecraft minecraft = Minecraft.getInstance();
+ float frameTime = minecraft.getDeltaTracker().getGameTimeDeltaPartialTick(false);
+ float baseTime = minecraft.level != null ? (float) minecraft.level.getGameTime() : 0.0f;
+ VRenderSystem.setShaderGameTime(baseTime + frameTime);
+
// runTick might be called recursively,
// this check forces sync to avoid upload corruption
if (lastReset == currentFrame) {
@@ -235,8 +457,7 @@ public void beginFrame() {
}
- if (skipRendering || recordingCmds)
- return;
+ if (skipRendering || recordingCmds) return;
vkWaitForFences(device, inFlightFences.get(currentFrame), true, VUtil.UINT64_MAX);
@@ -255,8 +476,7 @@ public void beginFrame() {
IntBuffer pImageIndex = stack.mallocInt(1);
- int vkResult = vkAcquireNextImageKHR(device, swapChain.getId(), VUtil.UINT64_MAX,
- imageAvailableSemaphores.get(currentFrame), VK_NULL_HANDLE, pImageIndex);
+ int vkResult = vkAcquireNextImageKHR(device, swapChain.getId(), VUtil.UINT64_MAX, imageAvailableSemaphores.get(currentFrame), VK_NULL_HANDLE, pImageIndex);
if (vkResult == VK_SUBOPTIMAL_KHR || vkResult == VK_ERROR_OUT_OF_DATE_KHR || swapChainUpdate) {
swapChainUpdate = true;
@@ -270,37 +490,47 @@ public void beginFrame() {
imageIndex = pImageIndex.get(0);
- this.beginRenderPass(stack);
+ this.beginRenderPass();
}
p.pop();
}
- private void beginRenderPass(MemoryStack stack) {
- VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.calloc(stack);
- beginInfo.sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO);
- beginInfo.flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
-
+ private void beginRenderPass() {
VkCommandBuffer commandBuffer = currentCmdBuffer;
- int vkResult = vkBeginCommandBuffer(commandBuffer, beginInfo);
- if (vkResult != VK_SUCCESS) {
- throw new RuntimeException("Failed to begin recording command buffer: %s".formatted(VkResult.decode(vkResult)));
+ try (Arena arena = Arena.ofConfined()) {
+ VkCommandBufferBeginInfo beginInfo = VUtil.struct(
+ arena,
+ VkCommandBufferBeginInfo.SIZEOF,
+ VkCommandBufferBeginInfo.ALIGNOF,
+ VkCommandBufferBeginInfo::create
+ );
+ beginInfo.sType(VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO);
+ beginInfo.flags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
+
+ int vkResult = vkBeginCommandBuffer(commandBuffer, beginInfo);
+ if (vkResult != VK_SUCCESS) {
+ throw new RuntimeException("Failed to begin recording command buffer: %s".formatted(VkResult.decode(vkResult)));
+ }
}
recordingCmds = true;
- mainPass.begin(commandBuffer, stack);
+ mainPass.begin(commandBuffer);
resetDynamicState(commandBuffer);
}
public void endFrame() {
- if (skipRendering || !recordingCmds)
- return;
+ if (skipRendering || !recordingCmds) return;
Profiler p = Profiler.getMainProfiler();
p.push("End_rendering");
+ if (Initializer.CONFIG.enableRayTracing) {
+ doRayTracing();
+ }
+
mainPass.end(currentCmdBuffer);
waitFences();
@@ -313,8 +543,7 @@ public void endFrame() {
}
private void submitFrame() {
- if (swapChainUpdate)
- return;
+ if (swapChainUpdate) return;
try (MemoryStack stack = stackPush()) {
int vkResult;
@@ -362,8 +591,7 @@ private void submitFrame() {
* Called in case draw results are needed before the end of the frame
*/
public void flushCmds() {
- if (!this.recordingCmds)
- return;
+ if (!this.recordingCmds) return;
try (MemoryStack stack = stackPush()) {
int vkResult;
@@ -386,9 +614,9 @@ public void flushCmds() {
}
vkWaitForFences(device, inFlightFences.get(currentFrame), true, VUtil.UINT64_MAX);
-
- this.beginRenderPass(stack);
}
+
+ this.beginRenderPass();
}
public void endRenderPass() {
@@ -396,13 +624,10 @@ public void endRenderPass() {
}
public void endRenderPass(VkCommandBuffer commandBuffer) {
- if (skipRendering || !recordingCmds || this.boundFramebuffer == null)
- return;
+ if (skipRendering || !recordingCmds || this.boundFramebuffer == null) return;
- if (!DYNAMIC_RENDERING)
- this.boundRenderPass.endRenderPass(currentCmdBuffer);
- else
- KHRDynamicRendering.vkCmdEndRenderingKHR(commandBuffer);
+ if (!DYNAMIC_RENDERING) this.boundRenderPass.endRenderPass(currentCmdBuffer);
+ else KHRDynamicRendering.vkCmdEndRenderingKHR(commandBuffer);
this.boundRenderPass = null;
this.boundFramebuffer = null;
@@ -411,15 +636,11 @@ public void endRenderPass(VkCommandBuffer commandBuffer) {
}
public boolean beginRendering(RenderPass renderPass, Framebuffer framebuffer) {
- if (skipRendering || !recordingCmds)
- return false;
+ if (skipRendering || !recordingCmds) return false;
if (this.boundFramebuffer != framebuffer) {
this.endRenderPass(currentCmdBuffer);
-
- try (MemoryStack stack = stackPush()) {
- framebuffer.beginRenderPass(currentCmdBuffer, renderPass, stack);
- }
+ framebuffer.beginRenderPass(currentCmdBuffer, renderPass);
this.boundFramebuffer = framebuffer;
}
@@ -457,10 +678,7 @@ void waitForSwapChain() {
// constexpr VkPipelineStageFlags t=VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
try (MemoryStack stack = MemoryStack.stackPush()) {
//Empty Submit
- VkSubmitInfo info = VkSubmitInfo.calloc(stack)
- .sType$Default()
- .pWaitSemaphores(stack.longs(imageAvailableSemaphores.get(currentFrame)))
- .pWaitDstStageMask(stack.ints(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
+ VkSubmitInfo info = VkSubmitInfo.calloc(stack).sType$Default().pWaitSemaphores(stack.longs(imageAvailableSemaphores.get(currentFrame))).pWaitDstStageMask(stack.ints(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
vkQueueSubmit(DeviceManager.getGraphicsQueue().queue(), info, inFlightFences.get(currentFrame));
vkWaitForFences(device, inFlightFences.get(currentFrame), true, -1);
@@ -545,6 +763,57 @@ public void bindGraphicsPipeline(GraphicsPipeline pipeline) {
addUsedPipeline(pipeline);
}
+ public void bindGraphicsPipeline(RenderPipeline pipeline, VertexFormat vertexFormat) {
+ GraphicsPipeline graphicsPipeline = PipelineManager.getPipeline(pipeline, vertexFormat);
+ bindGraphicsPipeline(graphicsPipeline);
+ }
+
+ private void doRayTracing() {
+ RayTracingPipeline pipeline = PipelineManager.getRayTracingPipeline();
+ if (pipeline == null) {
+ return;
+ }
+ bindRayTracingPipeline(pipeline);
+
+ uploadAndBindUBOs(pipeline);
+
+ try (MemoryStack stack = stackPush()) {
+ VkStridedDeviceAddressRegionKHR raygenShaderSbtEntry = VkStridedDeviceAddressRegionKHR.calloc(stack);
+ raygenShaderSbtEntry.deviceAddress(pipeline.getSbtBufferAddress());
+ raygenShaderSbtEntry.stride(pipeline.getSbtStride());
+ raygenShaderSbtEntry.size(pipeline.getSbtStride());
+
+ VkStridedDeviceAddressRegionKHR missShaderSbtEntry = VkStridedDeviceAddressRegionKHR.calloc(stack);
+ missShaderSbtEntry.deviceAddress(pipeline.getSbtBufferAddress() + pipeline.getSbtStride());
+ missShaderSbtEntry.stride(pipeline.getSbtStride());
+ missShaderSbtEntry.size(pipeline.getSbtStride());
+
+ VkStridedDeviceAddressRegionKHR hitShaderSbtEntry = VkStridedDeviceAddressRegionKHR.calloc(stack);
+ hitShaderSbtEntry.deviceAddress(pipeline.getSbtBufferAddress() + 2 * pipeline.getSbtStride());
+ hitShaderSbtEntry.stride(pipeline.getSbtStride());
+ hitShaderSbtEntry.size(pipeline.getSbtStride());
+
+ VkStridedDeviceAddressRegionKHR callableShaderSbtEntry = VkStridedDeviceAddressRegionKHR.calloc(stack);
+
+ KHRRayTracingPipeline.vkCmdTraceRaysKHR(currentCmdBuffer, raygenShaderSbtEntry, missShaderSbtEntry, hitShaderSbtEntry, callableShaderSbtEntry, swapChain.getWidth(), swapChain.getHeight(), 1);
+ }
+ }
+
+ public void bindRayTracingPipeline(RayTracingPipeline pipeline) {
+ VkCommandBuffer commandBuffer = currentCmdBuffer;
+
+ final long handle = pipeline.getHandle();
+
+ if (boundPipelineHandle == handle) {
+ return;
+ }
+
+ vkCmdBindPipeline(commandBuffer, KHRRayTracingPipeline.VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, handle);
+ boundPipelineHandle = handle;
+ boundPipeline = pipeline;
+ addUsedPipeline(pipeline);
+ }
+
public void uploadAndBindUBOs(Pipeline pipeline) {
VkCommandBuffer commandBuffer = currentCmdBuffer;
pipeline.bindDescriptorSets(commandBuffer, currentFrame);
@@ -569,216 +838,31 @@ public Pipeline getBoundPipeline() {
return boundPipeline;
}
- public void setBoundFramebuffer(Framebuffer framebuffer) {
- this.boundFramebuffer = framebuffer;
- }
-
public Framebuffer getBoundFramebuffer() {
return boundFramebuffer;
}
- public void setBoundRenderPass(RenderPass boundRenderPass) {
- this.boundRenderPass = boundRenderPass;
+ public void setBoundFramebuffer(Framebuffer framebuffer) {
+ this.boundFramebuffer = framebuffer;
}
public RenderPass getBoundRenderPass() {
return boundRenderPass;
}
- public void setMainPass(MainPass mainPass) {
- this.mainPass = mainPass;
+ public void setBoundRenderPass(RenderPass boundRenderPass) {
+ this.boundRenderPass = boundRenderPass;
}
public MainPass getMainPass() {
return this.mainPass;
}
- public SwapChain getSwapChain() {
- return swapChain;
- }
-
- private static void resetDynamicState(VkCommandBuffer commandBuffer) {
- vkCmdSetDepthBias(commandBuffer, 0.0F, 0.0F, 0.0F);
-
- vkCmdSetLineWidth(commandBuffer, 1.0F);
- }
-
- public static void setDepthBias(float constant, float slope) {
- VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
-
- vkCmdSetDepthBias(commandBuffer, constant, 0.0f, slope);
- }
-
- public static void clearAttachments(int v) {
- Framebuffer framebuffer = Renderer.getInstance().boundFramebuffer;
- if (framebuffer == null)
- return;
-
- clearAttachments(v, framebuffer.getWidth(), framebuffer.getHeight());
- }
-
- public static void clearAttachments(int v, int width, int height) {
- if (skipRendering)
- return;
-
- try (MemoryStack stack = stackPush()) {
- //ClearValues have to be different for each attachment to clear,
- //it seems it uses the same buffer: color and depth values override themselves
- VkClearValue colorValue = VkClearValue.calloc(stack);
- colorValue.color().float32(VRenderSystem.clearColor);
-
- VkClearValue depthValue = VkClearValue.calloc(stack);
- depthValue.depthStencil().set(VRenderSystem.clearDepthValue, 0); //Use fast depth clears if possible
-
- int attachmentsCount = v == (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) ? 2 : 1;
- final VkClearAttachment.Buffer pAttachments = VkClearAttachment.malloc(attachmentsCount, stack);
- switch (v) {
- case GL_DEPTH_BUFFER_BIT -> {
-
- VkClearAttachment clearDepth = pAttachments.get(0);
- clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
- clearDepth.colorAttachment(0);
- clearDepth.clearValue(depthValue);
- }
- case GL_COLOR_BUFFER_BIT -> {
-
- VkClearAttachment clearColor = pAttachments.get(0);
- clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
- clearColor.colorAttachment(0);
- clearColor.clearValue(colorValue);
- }
- case GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT -> {
-
- VkClearAttachment clearColor = pAttachments.get(0);
- clearColor.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
- clearColor.colorAttachment(0);
- clearColor.clearValue(colorValue);
-
- VkClearAttachment clearDepth = pAttachments.get(1);
- clearDepth.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
- clearDepth.colorAttachment(0);
- clearDepth.clearValue(depthValue);
- }
- default -> throw new RuntimeException("unexpected value");
- }
-
- //Rect to clear
- VkRect2D renderArea = VkRect2D.malloc(stack);
- renderArea.offset().set(0, 0);
- renderArea.extent().set(width, height);
-
- VkClearRect.Buffer pRect = VkClearRect.malloc(1, stack);
- pRect.rect(renderArea);
- pRect.baseArrayLayer(0);
- pRect.layerCount(1);
-
- vkCmdClearAttachments(INSTANCE.currentCmdBuffer, pAttachments, pRect);
- }
- }
-
- public static void setInvertedViewport(int x, int y, int width, int height) {
- setViewportState(x, y + height, width, -height);
- }
-
- public static void resetViewport() {
- int width = INSTANCE.getSwapChain().getWidth();
- int height = INSTANCE.getSwapChain().getHeight();
-
- setViewportState(0, 0, width, height);
- }
-
- public static void setViewportState(int x, int y, int width, int height) {
- GlStateManager._viewport(x, y, width, height);
- }
-
- public static void setViewport(int x, int y, int width, int height) {
- try (MemoryStack stack = stackPush()) {
- setViewport(x, y, width, height, stack);
- }
- }
-
- public static void setViewport(int x, int y, int width, int height, MemoryStack stack) {
- if (!INSTANCE.recordingCmds)
- return;
-
- VkViewport.Buffer viewport = VkViewport.malloc(1, stack);
- viewport.x(x);
- viewport.y(height + y);
- viewport.width(width);
- viewport.height(-height);
- viewport.minDepth(0.0f);
- viewport.maxDepth(1.0f);
-
- vkCmdSetViewport(INSTANCE.currentCmdBuffer, 0, viewport);
- }
-
- public static void setScissor(int x, int y, int width, int height) {
- if (INSTANCE.boundFramebuffer == null)
- return;
-
- try (MemoryStack stack = stackPush()) {
- int framebufferHeight = INSTANCE.boundFramebuffer.getHeight();
-
- x = Math.max(0, x);
-
- VkRect2D.Buffer scissor = VkRect2D.malloc(1, stack);
- scissor.offset().set(x, framebufferHeight - (y + height));
- scissor.extent().set(width, height);
-
- vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor);
- }
- }
-
- public static void resetScissor() {
- if (INSTANCE.boundFramebuffer == null)
- return;
-
- try (MemoryStack stack = stackPush()) {
- VkRect2D.Buffer scissor = INSTANCE.boundFramebuffer.scissor(stack);
- vkCmdSetScissor(INSTANCE.currentCmdBuffer, 0, scissor);
- }
- }
-
- public static void pushDebugSection(String s) {
- if (Vulkan.ENABLE_VALIDATION_LAYERS) {
- VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
-
- try (MemoryStack stack = stackPush()) {
- VkDebugUtilsLabelEXT markerInfo = VkDebugUtilsLabelEXT.calloc(stack);
- markerInfo.sType(VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT);
- ByteBuffer string = stack.UTF8(s);
- markerInfo.pLabelName(string);
- vkCmdBeginDebugUtilsLabelEXT(commandBuffer, markerInfo);
- }
- }
- }
-
- public static void popDebugSection() {
- if (Vulkan.ENABLE_VALIDATION_LAYERS) {
- VkCommandBuffer commandBuffer = INSTANCE.currentCmdBuffer;
-
- vkCmdEndDebugUtilsLabelEXT(commandBuffer);
- }
- }
-
- public static void popPushDebugSection(String s) {
- popDebugSection();
- pushDebugSection(s);
- }
-
- public static int getFramesNum() {
- return INSTANCE.framesNum;
- }
-
- public static VkCommandBuffer getCommandBuffer() {
- return INSTANCE.currentCmdBuffer;
- }
-
- public static boolean isRecording() {
- return INSTANCE.recordingCmds;
+ public void setMainPass(MainPass mainPass) {
+ this.mainPass = mainPass;
}
- public static void scheduleSwapChainUpdate() {
- swapChainUpdate = true;
+ public SwapChain getSwapChain() {
+ return swapChain;
}
}
diff --git a/src/main/java/net/vulkanmod/vulkan/Synchronization.java b/src/main/java/net/vulkanmod/vulkan/Synchronization.java
index 609052db3..ee508a230 100644
--- a/src/main/java/net/vulkanmod/vulkan/Synchronization.java
+++ b/src/main/java/net/vulkanmod/vulkan/Synchronization.java
@@ -24,22 +24,31 @@ public class Synchronization {
this.fences = MemoryUtil.memAllocLong(allocSize);
}
+ public static void waitFence(long fence) {
+ VkDevice device = Vulkan.getVkDevice();
+
+ vkWaitForFences(device, fence, true, VUtil.UINT64_MAX);
+ }
+
+ public static boolean checkFenceStatus(long fence) {
+ VkDevice device = Vulkan.getVkDevice();
+ return vkGetFenceStatus(device, fence) == VK_SUCCESS;
+ }
+
public synchronized void addCommandBuffer(CommandPool.CommandBuffer commandBuffer) {
this.addFence(commandBuffer.getFence());
this.commandBuffers.add(commandBuffer);
}
public synchronized void addFence(long fence) {
- if (idx == ALLOCATION_SIZE)
- waitFences();
+ if (idx == ALLOCATION_SIZE) waitFences();
fences.put(idx, fence);
idx++;
}
public synchronized void waitFences() {
- if (idx == 0)
- return;
+ if (idx == 0) return;
VkDevice device = Vulkan.getVkDevice();
@@ -54,15 +63,4 @@ public synchronized void waitFences() {
idx = 0;
}
- public static void waitFence(long fence) {
- VkDevice device = Vulkan.getVkDevice();
-
- vkWaitForFences(device, fence, true, VUtil.UINT64_MAX);
- }
-
- public static boolean checkFenceStatus(long fence) {
- VkDevice device = Vulkan.getVkDevice();
- return vkGetFenceStatus(device, fence) == VK_SUCCESS;
- }
-
}
diff --git a/src/main/java/net/vulkanmod/vulkan/SystemInfo.java b/src/main/java/net/vulkanmod/vulkan/SystemInfo.java
index d64417c40..3c0d664cf 100644
--- a/src/main/java/net/vulkanmod/vulkan/SystemInfo.java
+++ b/src/main/java/net/vulkanmod/vulkan/SystemInfo.java
@@ -9,4 +9,4 @@ public class SystemInfo {
CentralProcessor centralProcessor = new oshi.SystemInfo().getHardware().getProcessor();
cpuInfo = String.format("%s", centralProcessor.getProcessorIdentifier().getName()).replaceAll("\\s+", " ");
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java b/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java
index db4996d69..3b63db968 100644
--- a/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java
+++ b/src/main/java/net/vulkanmod/vulkan/VRenderSystem.java
@@ -1,7 +1,6 @@
package net.vulkanmod.vulkan;
import com.mojang.blaze3d.platform.Window;
-
import net.minecraft.client.Minecraft;
import net.vulkanmod.vulkan.device.DeviceManager;
import net.vulkanmod.vulkan.shader.PipelineState;
@@ -12,49 +11,44 @@
import org.lwjgl.opengl.GL11;
import org.lwjgl.system.MemoryUtil;
-import static org.lwjgl.vulkan.VK10.*;
-
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
+import static org.lwjgl.vulkan.VK10.*;
+
public abstract class VRenderSystem {
private static final float DEFAULT_DEPTH_VALUE = 1.0f;
-
- private static long window;
-
+ private static final float[] shaderColorArray = new float[]{1.0f, 1.0f, 1.0f, 1.0f};
+ private static final float[] shaderFogColorArray = new float[]{0.0f, 0.0f, 0.0f, 1.0f};
public static boolean depthTest = true;
public static boolean depthMask = true;
public static int depthFun = 515;
public static int topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
public static int polygonMode = VK_POLYGON_MODE_FILL;
public static boolean canSetLineWidth = false;
-
public static int colorMask = PipelineState.ColorMask.getColorMask(true, true, true, true);
-
public static boolean cull = true;
-
public static boolean logicOp = false;
public static int logicOpFun = 0;
-
public static float clearDepthValue = DEFAULT_DEPTH_VALUE;
public static FloatBuffer clearColor = MemoryUtil.memCallocFloat(4);
-
public static MappedBuffer modelViewMatrix = new MappedBuffer(16 * 4);
public static MappedBuffer projectionMatrix = new MappedBuffer(16 * 4);
public static MappedBuffer TextureMatrix = new MappedBuffer(16 * 4);
public static MappedBuffer MVP = new MappedBuffer(16 * 4);
-
public static MappedBuffer modelOffset = new MappedBuffer(3 * 4);
public static MappedBuffer lightDirection0 = new MappedBuffer(3 * 4);
public static MappedBuffer lightDirection1 = new MappedBuffer(3 * 4);
-
public static MappedBuffer shaderColor = new MappedBuffer(4 * 4);
public static MappedBuffer shaderFogColor = new MappedBuffer(4 * 4);
-
public static MappedBuffer screenSize = new MappedBuffer(2 * 4);
-
public static float alphaCutout = 0.0f;
-
+ private static long window;
+ private static float fogRenderStart;
+ private static float fogRenderEnd;
+ private static int fogShapeIndex;
+ private static float shaderGameTime;
+ private static float glintAlpha = 1.0f;
private static boolean depthBiasEnabled = false;
private static float depthBiasConstant = 0.0f;
private static float depthBiasSlope = 0.0f;
@@ -108,14 +102,14 @@ public static void calculateMVP() {
P.mul(MV).get(MVP.buffer);
}
- public static void setTextureMatrix(Matrix4f mat) {
- mat.get(TextureMatrix.buffer.asFloatBuffer());
- }
-
public static MappedBuffer getTextureMatrix() {
return TextureMatrix;
}
+ public static void setTextureMatrix(Matrix4f mat) {
+ mat.get(TextureMatrix.buffer.asFloatBuffer());
+ }
+
public static MappedBuffer getModelViewMatrix() {
return modelViewMatrix;
}
@@ -130,17 +124,80 @@ public static MappedBuffer getMVP() {
public static void setModelOffset(float x, float y, float z) {
long ptr = modelOffset.ptr;
- VUtil.UNSAFE.putFloat(ptr, x);
- VUtil.UNSAFE.putFloat(ptr + 4, y);
- VUtil.UNSAFE.putFloat(ptr + 8, z);
+ VUtil.putFloat(ptr, x);
+ VUtil.putFloat(ptr + 4, y);
+ VUtil.putFloat(ptr + 8, z);
}
public static void setShaderColor(float f1, float f2, float f3, float f4) {
ColorUtil.setRGBA_Buffer(shaderColor, f1, f2, f3, f4);
+ shaderColorArray[0] = f1;
+ shaderColorArray[1] = f2;
+ shaderColorArray[2] = f3;
+ shaderColorArray[3] = f4;
}
public static void setShaderFogColor(float f1, float f2, float f3, float f4) {
ColorUtil.setRGBA_Buffer(shaderFogColor, f1, f2, f3, f4);
+ shaderFogColorArray[0] = f1;
+ shaderFogColorArray[1] = f2;
+ shaderFogColorArray[2] = f3;
+ shaderFogColorArray[3] = f4;
+ }
+
+ public static void setShaderLights(float lx0, float ly0, float lz0, float lx1, float ly1, float lz1) {
+ lightDirection0.buffer.putFloat(0, lx0);
+ lightDirection0.buffer.putFloat(4, ly0);
+ lightDirection0.buffer.putFloat(8, lz0);
+
+ lightDirection1.buffer.putFloat(0, lx1);
+ lightDirection1.buffer.putFloat(4, ly1);
+ lightDirection1.buffer.putFloat(8, lz1);
+ }
+
+ public static void setFogParameters(float environmentalStart, float renderStart, float environmentalEnd, float renderEnd, float skyEnd, float cloudEnd) {
+ fogRenderStart = renderStart;
+ fogRenderEnd = renderEnd;
+ }
+
+ public static float[] getShaderColorArray() {
+ return shaderColorArray;
+ }
+
+ public static float[] getShaderFogColorArray() {
+ return shaderFogColorArray;
+ }
+
+ public static float getFogStart() {
+ return fogRenderStart;
+ }
+
+ public static float getFogEnd() {
+ return fogRenderEnd;
+ }
+
+ public static int getFogShapeIndex() {
+ return fogShapeIndex;
+ }
+
+ public static void setFogShapeIndex(int shapeIndex) {
+ fogShapeIndex = shapeIndex;
+ }
+
+ public static float getShaderGameTime() {
+ return shaderGameTime;
+ }
+
+ public static void setShaderGameTime(float gameTime) {
+ shaderGameTime = gameTime;
+ }
+
+ public static float getGlintAlpha() {
+ return glintAlpha;
+ }
+
+ public static void setGlintAlpha(float alpha) {
+ glintAlpha = alpha;
}
public static MappedBuffer getShaderColor() {
@@ -175,7 +232,7 @@ public static void depthMask(boolean b) {
public static void setPrimitiveTopologyGL(final int mode) {
VRenderSystem.topology = switch (mode) {
- case GL11.GL_LINES, GL11.GL_LINE_STRIP -> VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+ case GL11.GL_LINES, GL11.GL_LINE_STRIP -> VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
case GL11.GL_TRIANGLE_FAN, GL11.GL_TRIANGLES, GL11.GL_TRIANGLE_STRIP -> VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
default -> throw new RuntimeException(String.format("Unknown GL primitive topology: %s", mode));
};
diff --git a/src/main/java/net/vulkanmod/vulkan/Vulkan.java b/src/main/java/net/vulkanmod/vulkan/Vulkan.java
index 0ab7e7124..dad541306 100644
--- a/src/main/java/net/vulkanmod/vulkan/Vulkan.java
+++ b/src/main/java/net/vulkanmod/vulkan/Vulkan.java
@@ -3,9 +3,9 @@
import net.vulkanmod.vulkan.device.Device;
import net.vulkanmod.vulkan.device.DeviceManager;
import net.vulkanmod.vulkan.framebuffer.SwapChain;
-import net.vulkanmod.vulkan.memory.buffer.Buffer;
import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.memory.MemoryTypes;
+import net.vulkanmod.vulkan.memory.buffer.Buffer;
import net.vulkanmod.vulkan.memory.buffer.StagingBuffer;
import net.vulkanmod.vulkan.queue.Queue;
import net.vulkanmod.vulkan.shader.Pipeline;
@@ -31,7 +31,11 @@
import static org.lwjgl.util.vma.Vma.vmaCreateAllocator;
import static org.lwjgl.util.vma.Vma.vmaDestroyAllocator;
import static org.lwjgl.vulkan.EXTDebugUtils.*;
+import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME;
+import static org.lwjgl.vulkan.KHRBufferDeviceAddress.VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME;
+import static org.lwjgl.vulkan.KHRDeferredHostOperations.VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME;
import static org.lwjgl.vulkan.KHRDynamicRendering.VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME;
+import static org.lwjgl.vulkan.KHRRayTracingPipeline.VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME;
import static org.lwjgl.vulkan.KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME;
import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK12.VK_API_VERSION_1_2;
@@ -45,6 +49,18 @@ public class Vulkan {
public static final boolean DYNAMIC_RENDERING = false;
public static final Set VALIDATION_LAYERS;
+ public static final Set REQUIRED_EXTENSION = getRequiredExtensionSet();
+ public static long window;
+ public static boolean use24BitsDepthFormat = true;
+ private static VkInstance instance;
+ private static long debugMessenger;
+ private static long surface;
+ private static long commandPool;
+ private static VkCommandBuffer immediateCmdBuffer;
+ private static long immediateFence;
+ private static long allocator;
+ private static StagingBuffer[] stagingBuffers;
+ private static int DEFAULT_DEPTH_FORMAT = 0;
static {
if (ENABLE_VALIDATION_LAYERS) {
@@ -58,10 +74,8 @@ public class Vulkan {
}
}
- public static final Set REQUIRED_EXTENSION = getRequiredExtensionSet();
-
private static Set getRequiredExtensionSet() {
- ArrayList extensions = new ArrayList<>(List.of(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
+ ArrayList extensions = new ArrayList<>(List.of(VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME));
if (DYNAMIC_RENDERING) {
extensions.add(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
@@ -86,14 +100,12 @@ private static int debugCallback(int messageSeverity, int messageType, long pCal
System.err.println(s);
- if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0)
- System.nanoTime();
+ if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0) System.nanoTime();
return VK_FALSE;
}
- private static int createDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT createInfo,
- VkAllocationCallbacks allocationCallbacks, LongBuffer pDebugMessenger) {
+ private static int createDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT createInfo, VkAllocationCallbacks allocationCallbacks, LongBuffer pDebugMessenger) {
if (vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT") != NULL) {
return vkCreateDebugUtilsMessengerEXT(instance, createInfo, allocationCallbacks, pDebugMessenger);
@@ -118,23 +130,6 @@ public static long getAllocator() {
return allocator;
}
- public static long window;
-
- private static VkInstance instance;
- private static long debugMessenger;
- private static long surface;
-
- private static long commandPool;
- private static VkCommandBuffer immediateCmdBuffer;
- private static long immediateFence;
-
- private static long allocator;
-
- private static StagingBuffer[] stagingBuffers;
-
- public static boolean use24BitsDepthFormat = true;
- private static int DEFAULT_DEPTH_FORMAT = 0;
-
public static void initVulkan(long window) {
createInstance();
setupDebugMessenger();
@@ -195,6 +190,7 @@ public static void cleanUp() {
destroyDebugUtilsMessengerEXT(instance, debugMessenger, null);
KHRSurface.vkDestroySurfaceKHR(instance, surface, null);
vkDestroyInstance(instance, null);
+
}
private static void freeStagingBuffers() {
@@ -214,9 +210,9 @@ private static void createInstance() {
VkApplicationInfo appInfo = VkApplicationInfo.calloc(stack);
appInfo.sType(VK_STRUCTURE_TYPE_APPLICATION_INFO);
- appInfo.pApplicationName(stack.UTF8Safe("VulkanMod"));
+ appInfo.pApplicationName(Objects.requireNonNull(stack.UTF8Safe("VulkanMod")));
appInfo.applicationVersion(VK_MAKE_VERSION(1, 0, 0));
- appInfo.pEngineName(stack.UTF8Safe("VulkanMod Engine"));
+ appInfo.pEngineName(Objects.requireNonNull(stack.UTF8Safe("VulkanMod Engine")));
appInfo.engineVersion(VK_MAKE_VERSION(1, 0, 0));
appInfo.apiVersion(VK_API_VERSION_1_2);
@@ -241,7 +237,14 @@ private static void createInstance() {
int result = vkCreateInstance(createInfo, null, instancePtr);
checkResult(result, "Failed to create instance");
- instance = new VkInstance(instancePtr.get(0), createInfo);
+ // Workaround for LWJGL 3.3.x + Java 25 infinite recursion bug in VkInstance constructor
+ // The standard constructor with createInfo: new VkInstance(handle, createInfo)
+ // causes stack overflow in getInstanceCapabilities() -> getAvailableDeviceExtensions()
+ //
+ // Workaround: Pass null for createInfo to skip automatic capability detection
+ // Capabilities will need to be manually queried later if needed
+ long handle = instancePtr.get(0);
+ instance = new VkInstance(handle, null);
}
}
@@ -257,9 +260,7 @@ static boolean checkValidationLayerSupport() {
vkEnumerateInstanceLayerProperties(layerCount, availableLayers);
- Set availableLayerNames = availableLayers.stream()
- .map(VkLayerProperties::layerNameString)
- .collect(toSet());
+ Set availableLayerNames = availableLayers.stream().map(VkLayerProperties::layerNameString).collect(toSet());
return availableLayerNames.containsAll(Vulkan.VALIDATION_LAYERS);
}
@@ -288,8 +289,7 @@ private static void setupDebugMessenger() {
LongBuffer pDebugMessenger = stack.longs(VK_NULL_HANDLE);
- checkResult(createDebugUtilsMessengerEXT(instance, createInfo, null, pDebugMessenger),
- "Failed to set up debug messenger");
+ checkResult(createDebugUtilsMessengerEXT(instance, createInfo, null, pDebugMessenger), "Failed to set up debug messenger");
debugMessenger = pDebugMessenger.get(0);
}
@@ -313,8 +313,7 @@ private static void createSurface(long handle) {
LongBuffer pSurface = stack.longs(VK_NULL_HANDLE);
- checkResult(glfwCreateWindowSurface(instance, window, null, pSurface),
- "Failed to create window surface");
+ checkResult(glfwCreateWindowSurface(instance, window, null, pSurface), "Failed to create window surface");
surface = pSurface.get(0);
}
@@ -335,8 +334,7 @@ private static void createVma() {
PointerBuffer pAllocator = stack.pointers(VK_NULL_HANDLE);
- checkResult(vmaCreateAllocator(allocatorCreateInfo, pAllocator),
- "Failed to create Allocator");
+ checkResult(vmaCreateAllocator(allocatorCreateInfo, pAllocator), "Failed to create Allocator");
allocator = pAllocator.get(0);
}
@@ -355,8 +353,7 @@ private static void createCommandPool() {
LongBuffer pCommandPool = stack.mallocLong(1);
- checkResult(vkCreateCommandPool(DeviceManager.vkDevice, poolInfo, null, pCommandPool),
- "Failed to create command pool");
+ checkResult(vkCreateCommandPool(DeviceManager.vkDevice, poolInfo, null, pCommandPool), "Failed to create command pool");
commandPool = pCommandPool.get(0);
}
@@ -416,4 +413,3 @@ public static Device getDevice() {
return DeviceManager.device;
}
}
-
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanCommandEncoder.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanCommandEncoder.java
new file mode 100644
index 000000000..a7c1a14f6
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanCommandEncoder.java
@@ -0,0 +1,231 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.buffers.GpuBuffer;
+import com.mojang.blaze3d.buffers.GpuBufferSlice;
+import com.mojang.blaze3d.platform.NativeImage;
+import com.mojang.blaze3d.systems.CommandEncoder;
+import com.mojang.blaze3d.systems.RenderPass;
+import com.mojang.blaze3d.textures.GpuTexture;
+import com.mojang.blaze3d.textures.GpuTextureView;
+import com.mojang.blaze3d.vertex.VertexFormat;
+import java.lang.foreign.MemorySegment;
+import java.util.Collection;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.function.Supplier;
+
+/**
+ * Placeholder implementation. Methods currently throw
+ * {@link UnsupportedOperationException} until the Vulkan translation layer
+ * is implemented.
+ */
+public final class VulkanCommandEncoder implements CommandEncoder {
+
+ private final VulkanGpuDevice device;
+ private VulkanRenderPass currentPass;
+ private boolean inRenderPass = false;
+
+ VulkanCommandEncoder(VulkanGpuDevice device) {
+ this.device = device;
+ }
+
+ public VulkanGpuDevice device() {
+ return device;
+ }
+
+ private static UnsupportedOperationException nyi(String method) {
+ return new UnsupportedOperationException("CommandEncoder#" + method + " is not implemented yet");
+ }
+
+ private static VulkanGpuBuffer expectBuffer(GpuBuffer buffer) {
+ if (buffer instanceof VulkanGpuBuffer vulkanBuffer) {
+ return vulkanBuffer;
+ }
+ throw new IllegalArgumentException("Unsupported buffer implementation: " + buffer.getClass().getName());
+ }
+
+ private static VulkanGpuTexture expectTexture(GpuTexture texture) {
+ if (texture instanceof VulkanGpuTexture vkTexture) {
+ return vkTexture;
+ }
+ throw new IllegalArgumentException("Unsupported texture implementation: " + texture.getClass().getName());
+ }
+
+ @Override
+ public RenderPass createRenderPass(Supplier label,
+ GpuTextureView colorTarget,
+ OptionalInt colorLevel) {
+ return createRenderPass(label, colorTarget, colorLevel, null, OptionalDouble.empty());
+ }
+
+ @Override
+ public RenderPass createRenderPass(Supplier label,
+ GpuTextureView colorTarget,
+ OptionalInt colorLevel,
+ GpuTextureView depthTarget,
+ OptionalDouble clearDepth) {
+ VulkanGpuTexture color = expectTexture(colorTarget.texture());
+ VulkanGpuTexture depth = depthTarget != null ? expectTexture(depthTarget.texture()) : null;
+ if (inRenderPass) {
+ throw new IllegalStateException("Close the existing render pass before creating a new one!");
+ }
+ VulkanFramebuffer framebuffer = new VulkanFramebuffer(color, depth);
+ VulkanRenderPassState state = VulkanRenderPassState.create(framebuffer,
+ colorTarget, colorLevel, depthTarget, clearDepth);
+ currentPass = new VulkanRenderPass(this, state);
+ inRenderPass = true;
+ return currentPass;
+ }
+
+ void onRenderPassClosed() {
+ inRenderPass = false;
+ currentPass = null;
+ }
+
+ @Override
+ public void clearColorTexture(GpuTexture texture, int level) {
+ throw nyi("clearColorTexture");
+ }
+
+ @Override
+ public void clearColorAndDepthTextures(GpuTexture color,
+ int level,
+ GpuTexture depth,
+ double depthValue) {
+ throw nyi("clearColorAndDepthTextures");
+ }
+
+ @Override
+ public void clearColorAndDepthTextures(GpuTexture color,
+ int level,
+ GpuTexture depth,
+ double depthValue,
+ int x,
+ int y,
+ int width,
+ int height) {
+ throw nyi("clearColorAndDepthTextures");
+ }
+
+ @Override
+ public void clearDepthTexture(GpuTexture texture, double value) {
+ throw nyi("clearDepthTexture");
+ }
+
+ @Override
+ public void writeToBuffer(GpuBufferSlice slice, java.nio.ByteBuffer data) {
+ VulkanGpuBuffer buffer = expectBuffer(slice.buffer());
+ int available = Math.min(data.remaining(), slice.length());
+ if (available <= 0) {
+ return;
+ }
+ MemorySegment src = MemorySegment.ofBuffer(data).asSlice(data.position(), available);
+ MemorySegment dst = buffer.mapSegment(slice.offset(), available);
+ dst.copyFrom(src);
+ data.position(data.position() + available);
+ }
+
+ @Override
+ public GpuBuffer.MappedView mapBuffer(GpuBuffer buffer, boolean read, boolean write) {
+ VulkanGpuBuffer vkBuffer = expectBuffer(buffer);
+ MemorySegment segment = vkBuffer.mapSegment(0, buffer.size());
+ return new VulkanGpuBuffer.VulkanMappedView(segment);
+ }
+
+ @Override
+ public GpuBuffer.MappedView mapBuffer(GpuBufferSlice slice, boolean read, boolean write) {
+ VulkanGpuBuffer vkBuffer = expectBuffer(slice.buffer());
+ MemorySegment segment = vkBuffer.mapSegment(slice.offset(), slice.length());
+ return new VulkanGpuBuffer.VulkanMappedView(segment);
+ }
+
+ @Override
+ public void copyToBuffer(GpuBufferSlice src, GpuBufferSlice dst) {
+ VulkanGpuBuffer srcBuffer = expectBuffer(src.buffer());
+ VulkanGpuBuffer dstBuffer = expectBuffer(dst.buffer());
+ int length = Math.min(src.length(), dst.length());
+ if (length <= 0) {
+ return;
+ }
+ MemorySegment srcSegment = srcBuffer.mapSegment(src.offset(), length);
+ MemorySegment dstSegment = dstBuffer.mapSegment(dst.offset(), length);
+ dstSegment.copyFrom(srcSegment);
+ }
+
+ @Override
+ public void writeToTexture(GpuTexture texture, NativeImage image) {
+ throw nyi("writeToTexture");
+ }
+
+ @Override
+ public void writeToTexture(GpuTexture texture,
+ NativeImage image,
+ int x,
+ int y,
+ int width,
+ int height,
+ int level,
+ int depth,
+ int layer,
+ int stride) {
+ throw nyi("writeToTexture");
+ }
+
+ @Override
+ public void writeToTexture(GpuTexture texture,
+ java.nio.ByteBuffer data,
+ NativeImage.Format format,
+ int x,
+ int y,
+ int width,
+ int height,
+ int level,
+ int depth) {
+ throw nyi("writeToTexture");
+ }
+
+ @Override
+ public void copyTextureToBuffer(GpuTexture texture,
+ GpuBuffer buffer,
+ int level,
+ Runnable onComplete,
+ int stride) {
+ throw nyi("copyTextureToBuffer");
+ }
+
+ @Override
+ public void copyTextureToBuffer(GpuTexture texture,
+ GpuBuffer buffer,
+ int level,
+ Runnable onComplete,
+ int x,
+ int y,
+ int width,
+ int height,
+ int stride) {
+ throw nyi("copyTextureToBuffer");
+ }
+
+ @Override
+ public void copyTextureToTexture(GpuTexture src,
+ GpuTexture dst,
+ int srcLevel,
+ int dstLevel,
+ int srcX,
+ int srcY,
+ int width,
+ int height,
+ int depth) {
+ throw nyi("copyTextureToTexture");
+ }
+
+ @Override
+ public void presentTexture(GpuTextureView view) {
+ throw nyi("presentTexture");
+ }
+
+ @Override
+ public VulkanGpuFence createFence() {
+ return new VulkanGpuFence();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanFramebuffer.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanFramebuffer.java
new file mode 100644
index 000000000..2db6bb6a6
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanFramebuffer.java
@@ -0,0 +1,33 @@
+package net.vulkanmod.vulkan.blaze;
+
+import net.vulkanmod.vulkan.framebuffer.Framebuffer;
+import net.vulkanmod.vulkan.texture.VulkanImage;
+
+/**
+ * Thin wrapper around the existing {@link Framebuffer} class so the Vulkan
+ * render pass placeholder can store colour/depth attachments without touching
+ * Mojang's GL objects.
+ */
+final class VulkanFramebuffer {
+
+ private final Framebuffer framebuffer;
+
+ VulkanFramebuffer(VulkanGpuTexture color, VulkanGpuTexture depth) {
+ VulkanImage colorImage = color != null ? color.image() : null;
+ VulkanImage depthImage = depth != null ? depth.image() : null;
+ this.framebuffer = Framebuffer.builder(colorImage, depthImage)
+ .build();
+ }
+
+ Framebuffer handle() {
+ return framebuffer;
+ }
+
+ VulkanImage colorAttachment() {
+ return framebuffer.getColorAttachment();
+ }
+
+ VulkanImage depthAttachment() {
+ return framebuffer.getDepthAttachment();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuBuffer.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuBuffer.java
new file mode 100644
index 000000000..28e0532be
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuBuffer.java
@@ -0,0 +1,91 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.buffers.GpuBuffer;
+import net.vulkanmod.vulkan.memory.MemoryTypes;
+import net.vulkanmod.vulkan.memory.buffer.Buffer;
+import java.lang.foreign.MemorySegment;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Minimal Vulkan-backed buffer wrapper. Actual upload and command submission
+ * will be implemented during later stages of the refactor.
+ */
+public final class VulkanGpuBuffer extends GpuBuffer {
+
+ private final VulkanGpuDevice device;
+ private final String label;
+ private final Buffer backingBuffer;
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ VulkanGpuBuffer(VulkanGpuDevice device, String label, int usage, int size) {
+ super(usage, size);
+ this.device = device;
+ this.label = label;
+ this.backingBuffer = new Buffer(usage, MemoryTypes.HOST_MEM);
+ this.backingBuffer.createBuffer(size);
+ }
+
+ public VulkanGpuDevice device() {
+ return device;
+ }
+
+ public Buffer backingBuffer() {
+ return backingBuffer;
+ }
+
+ public String label() {
+ return label;
+ }
+
+ void upload(ByteBuffer data) {
+ backingBuffer.copyBuffer(data, data.remaining());
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed.get();
+ }
+
+ @Override
+ public void close() {
+ if (closed.compareAndSet(false, true)) {
+ backingBuffer.scheduleFree();
+ }
+ }
+
+ @Override
+ public com.mojang.blaze3d.buffers.GpuBufferSlice slice(int offset, int length) {
+ return new com.mojang.blaze3d.buffers.GpuBufferSlice(this, offset, length);
+ }
+
+ @Override
+ public com.mojang.blaze3d.buffers.GpuBufferSlice slice() {
+ return new com.mojang.blaze3d.buffers.GpuBufferSlice(this, 0, (int) backingBuffer.getBufferSize());
+ }
+
+ MemorySegment mapSegment(int offset, int length) {
+ long base = backingBuffer.getDataPtr() + offset;
+ return MemorySegment.ofAddress(base).reinterpret(length);
+ }
+
+ static final class VulkanMappedView implements GpuBuffer.MappedView {
+ private final MemorySegment segment;
+ private final ByteBuffer view;
+
+ VulkanMappedView(MemorySegment segment) {
+ this.segment = segment;
+ this.view = segment.asByteBuffer();
+ }
+
+ @Override
+ public ByteBuffer data() {
+ return view;
+ }
+
+ @Override
+ public void close() {
+ // Host coherent memory, nothing to flush for now.
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuDevice.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuDevice.java
new file mode 100644
index 000000000..172bd594f
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuDevice.java
@@ -0,0 +1,264 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.pipeline.CompiledRenderPipeline;
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import com.mojang.blaze3d.shaders.ShaderType;
+import com.mojang.blaze3d.systems.CommandEncoder;
+import com.mojang.blaze3d.systems.GpuDevice;
+import com.mojang.blaze3d.textures.GpuTexture;
+import com.mojang.blaze3d.textures.GpuTextureView;
+import com.mojang.blaze3d.textures.TextureFormat;
+import net.minecraft.resources.ResourceLocation;
+import net.vulkanmod.vulkan.Renderer;
+import net.vulkanmod.vulkan.device.DeviceManager;
+import net.vulkanmod.vulkan.texture.VulkanImage;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiFunction;
+
+import static org.lwjgl.vulkan.VK10.VK_FORMAT_D32_SFLOAT;
+import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8_SINT;
+import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8_UNORM;
+import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_UNORM;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_SAMPLED_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
+/**
+ * WIP Vulkan-backed replacement for Mojang's {@link com.mojang.blaze3d.opengl.GlDevice}.
+ * At this stage the implementation only satisfies the type contracts so we can
+ * wire it into RenderSystem; concrete behaviour will be filled in incrementally.
+ */
+public final class VulkanGpuDevice implements GpuDevice {
+
+ private final long windowHandle;
+ private final int debugVerbosity;
+ private final boolean debugSync;
+ private final boolean debugLabels;
+ private final BiFunction shaderSourceProvider;
+
+ public VulkanGpuDevice(long windowHandle,
+ int debugVerbosity,
+ boolean debugSync,
+ BiFunction shaderSourceProvider,
+ boolean debugLabels) {
+ this.windowHandle = windowHandle;
+ this.debugVerbosity = debugVerbosity;
+ this.debugSync = debugSync;
+ this.shaderSourceProvider = shaderSourceProvider;
+ this.debugLabels = debugLabels;
+
+ // Ensure Vulkan runtime is initialised. Renderer boot happens elsewhere,
+ // but we force creation of the singleton so later calls don't explode.
+ Renderer.getInstance();
+ }
+
+ public long getWindowHandle() {
+ return windowHandle;
+ }
+
+ public boolean isDebugSyncEnabled() {
+ return debugSync;
+ }
+
+ public boolean isDebugLabelsEnabled() {
+ return debugLabels;
+ }
+
+ public BiFunction shaderSourceProvider() {
+ return shaderSourceProvider;
+ }
+
+ @Override
+ public CommandEncoder createCommandEncoder() {
+ return new VulkanCommandEncoder(this);
+ }
+
+ @Override
+ public GpuTexture createTexture(java.util.function.Supplier label,
+ int usage,
+ TextureFormat format,
+ int width,
+ int height,
+ int depthOrLayers,
+ int mipLevels) {
+ String name = label != null ? label.get() : "unnamed";
+ return createTextureInternal(name, usage, format, width, height, depthOrLayers, mipLevels);
+ }
+
+ @Override
+ public GpuTexture createTexture(String label,
+ int usage,
+ TextureFormat format,
+ int width,
+ int height,
+ int depthOrLayers,
+ int mipLevels) {
+ String name = Objects.requireNonNullElse(label, "unnamed");
+ return createTextureInternal(name, usage, format, width, height, depthOrLayers, mipLevels);
+ }
+
+ private VulkanGpuTexture createTextureInternal(String label,
+ int usage,
+ TextureFormat format,
+ int width,
+ int height,
+ int depthOrLayers,
+ int mipLevels) {
+ if (depthOrLayers > 1) {
+ throw new UnsupportedOperationException("Array/3D textures are not implemented yet");
+ }
+
+ VulkanGpuTexture texture = new VulkanGpuTexture(this, usage, label, format, width, height, depthOrLayers, mipLevels);
+
+ int vkFormat = mapFormat(format);
+ int vkUsage = resolveUsage(usage, format);
+
+ VulkanImage image = VulkanImage.builder(width, height)
+ .setName(label)
+ .setFormat(vkFormat)
+ .setMipLevels(mipLevels)
+ .setUsage(vkUsage)
+ .createVulkanImage();
+
+ texture.attachImage(image);
+ texture.setUseMipmaps(mipLevels > 1);
+ return texture;
+ }
+
+ private static int mapFormat(TextureFormat format) {
+ return switch (format) {
+ case RGBA8 -> VK_FORMAT_R8G8B8A8_UNORM;
+ case RED8 -> VK_FORMAT_R8_UNORM;
+ case RED8I -> VK_FORMAT_R8_SINT;
+ case DEPTH32 -> VK_FORMAT_D32_SFLOAT;
+ };
+ }
+
+ private static int resolveUsage(int textureUsage, TextureFormat format) {
+ int flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
+ if ((textureUsage & GpuTexture.USAGE_TEXTURE_BINDING) != 0) {
+ flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ }
+ if ((textureUsage & GpuTexture.USAGE_RENDER_ATTACHMENT) != 0) {
+ if (format.hasDepthAspect()) {
+ flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ } else {
+ flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+ }
+
+ return flags;
+ }
+
+ @Override
+ public GpuTextureView createTextureView(GpuTexture texture) {
+ return new VulkanGpuTextureView((VulkanGpuTexture) texture, 0, texture.getMipLevels());
+ }
+
+ @Override
+ public GpuTextureView createTextureView(GpuTexture texture, int baseMipLevel, int levelCount) {
+ return new VulkanGpuTextureView((VulkanGpuTexture) texture, baseMipLevel, levelCount);
+ }
+
+ @Override
+ public VulkanGpuBuffer createBuffer(java.util.function.Supplier label,
+ int usage,
+ int size) {
+ String name = label != null ? label.get() : "unnamed-buffer";
+ return new VulkanGpuBuffer(this, name, usage, size);
+ }
+
+ @Override
+ public VulkanGpuBuffer createBuffer(java.util.function.Supplier label,
+ int usage,
+ java.nio.ByteBuffer initialData) {
+ String name = label != null ? label.get() : "unnamed-buffer";
+ VulkanGpuBuffer buffer = new VulkanGpuBuffer(this, name, usage, initialData.remaining());
+ buffer.upload(initialData);
+ return buffer;
+ }
+
+ @Override
+ public String getImplementationInformation() {
+ return "VulkanMod Vulkan backend (WIP)";
+ }
+
+ @Override
+ public List getLastDebugMessages() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean isDebuggingEnabled() {
+ return debugVerbosity > 0 || debugSync || debugLabels;
+ }
+
+ @Override
+ public String getVendor() {
+ return DeviceManager.deviceProperties != null
+ ? Integer.toUnsignedString(DeviceManager.deviceProperties.vendorID(), 16)
+ : "unknown";
+ }
+
+ @Override
+ public String getBackendName() {
+ return "Vulkan";
+ }
+
+ @Override
+ public String getVersion() {
+ return "1.2";
+ }
+
+ @Override
+ public String getRenderer() {
+ return DeviceManager.deviceProperties != null
+ ? DeviceManager.deviceProperties.deviceNameString()
+ : "unknown";
+ }
+
+ @Override
+ public int getMaxTextureSize() {
+ return DeviceManager.deviceProperties != null
+ ? DeviceManager.deviceProperties.limits().maxImageDimension2D()
+ : 0;
+ }
+
+ @Override
+ public int getUniformOffsetAlignment() {
+ return DeviceManager.deviceProperties != null
+ ? (int) DeviceManager.deviceProperties.limits().minUniformBufferOffsetAlignment()
+ : 256;
+ }
+
+ @Override
+ public CompiledRenderPipeline precompilePipeline(RenderPipeline pipeline) {
+ throw new UnsupportedOperationException("precompilePipeline is not implemented yet");
+ }
+
+ @Override
+ public CompiledRenderPipeline precompilePipeline(RenderPipeline pipeline,
+ BiFunction shaderSourceGetter) {
+ throw new UnsupportedOperationException("precompilePipeline is not implemented yet");
+ }
+
+ @Override
+ public void clearPipelineCache() {
+ // TODO: integrate with PipelineManager once the Vulkan pipeline cache is hooked up.
+ }
+
+ @Override
+ public List getEnabledExtensions() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void close() {
+ Renderer.getInstance().cleanUpResources();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuFence.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuFence.java
new file mode 100644
index 000000000..fb5d3fb85
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuFence.java
@@ -0,0 +1,50 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.buffers.GpuFence;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Lightweight fence placeholder backed by a {@link CompletableFuture}. The
+ * implementation will be updated to use Vulkan timeline semaphores once the
+ * command encoder is fully functional.
+ */
+public final class VulkanGpuFence implements GpuFence {
+
+ private final CompletableFuture signal = new CompletableFuture<>();
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ public void signal() {
+ signal.complete(null);
+ }
+
+ @Override
+ public void close() {
+ if (closed.compareAndSet(false, true)) {
+ signal.complete(null);
+ }
+ }
+
+ @Override
+ public boolean awaitCompletion(long nanosTimeout) {
+ if (signal.isDone()) {
+ return true;
+ }
+
+ if (nanosTimeout == 0L) {
+ return signal.isDone();
+ }
+
+ try {
+ if (nanosTimeout < 0L) {
+ signal.get();
+ } else {
+ signal.get(nanosTimeout, java.util.concurrent.TimeUnit.NANOSECONDS);
+ }
+ return true;
+ } catch (Exception ignored) {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTexture.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTexture.java
new file mode 100644
index 000000000..fb389a049
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTexture.java
@@ -0,0 +1,54 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.textures.GpuTexture;
+import com.mojang.blaze3d.textures.TextureFormat;
+import net.vulkanmod.vulkan.texture.VulkanImage;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * WIP texture wrapper. The actual Vulkan image creation and upload code will be
+ * connected once the command encoder is capable of recording the necessary operations.
+ */
+public final class VulkanGpuTexture extends GpuTexture {
+
+ private final VulkanGpuDevice device;
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+ private VulkanImage image;
+
+ VulkanGpuTexture(VulkanGpuDevice device,
+ int usage,
+ String label,
+ TextureFormat format,
+ int width,
+ int height,
+ int depthOrLayers,
+ int mipLevels) {
+ super(usage, label, format, width, height, depthOrLayers, mipLevels);
+ this.device = device;
+ }
+
+ public VulkanGpuDevice device() {
+ return device;
+ }
+
+ public void attachImage(VulkanImage image) {
+ this.image = image;
+ }
+
+ public VulkanImage image() {
+ return image;
+ }
+
+ @Override
+ public void close() {
+ if (closed.compareAndSet(false, true) && image != null) {
+ image.free();
+ }
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed.get();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTextureView.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTextureView.java
new file mode 100644
index 000000000..20b69cbfb
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanGpuTextureView.java
@@ -0,0 +1,35 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.textures.GpuTexture;
+import com.mojang.blaze3d.textures.GpuTextureView;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Placeholder texture view implementation. Once the backing command encoder
+ * supports render pass creation we will expose the actual Vulkan image view.
+ */
+public final class VulkanGpuTextureView extends GpuTextureView {
+
+ private final VulkanGpuTexture texture;
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ VulkanGpuTextureView(VulkanGpuTexture texture, int baseMip, int mipLevels) {
+ super(texture, baseMip, mipLevels);
+ this.texture = texture;
+ }
+
+ public VulkanGpuTexture textureHandle() {
+ return texture;
+ }
+
+ @Override
+ public void close() {
+ closed.set(true);
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed.get();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPass.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPass.java
new file mode 100644
index 000000000..6cde65938
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPass.java
@@ -0,0 +1,129 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.buffers.GpuBuffer;
+import com.mojang.blaze3d.buffers.GpuBufferSlice;
+import com.mojang.blaze3d.pipeline.RenderPipeline;
+import com.mojang.blaze3d.systems.RenderPass;
+import com.mojang.blaze3d.textures.GpuTextureView;
+import com.mojang.blaze3d.vertex.VertexFormat;
+import net.vulkanmod.vulkan.Renderer;
+import net.vulkanmod.vulkan.framebuffer.Framebuffer;
+import net.vulkanmod.vulkan.framebuffer.RenderPass.Builder;
+import org.lwjgl.vulkan.VkCommandBuffer;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * Vulkan-backed RenderPass driven by the existing {@link Builder}. Many draw
+ * operations are still pending; for now we only set up descriptor bindings and
+ * keep track of state.
+ */
+final class VulkanRenderPass implements RenderPass {
+
+ private final VulkanCommandEncoder encoder;
+ private final VulkanRenderPassState state;
+
+ private boolean closed = false;
+
+ VulkanRenderPass(VulkanCommandEncoder encoder, VulkanRenderPassState state) {
+ this.encoder = encoder;
+ this.state = state;
+ state.begin(Renderer.getCommandBuffer());
+ }
+
+ private static UnsupportedOperationException nyi(String method) {
+ return new UnsupportedOperationException("RenderPass#" + method + " is not implemented yet");
+ }
+
+ VulkanRenderPassState state() {
+ return state;
+ }
+
+ void begin(VkCommandBuffer commandBuffer) {
+ state.begin(commandBuffer);
+ }
+
+ void end(VkCommandBuffer commandBuffer) {
+ if (!closed) {
+ Renderer.getInstance().endRenderPass(commandBuffer);
+ closed = true;
+ }
+ }
+
+ @Override
+ public void pushDebugGroup(Supplier messageFactory) {
+ // TODO integrate with VK_EXT_debug_utils
+ }
+
+ @Override
+ public void popDebugGroup() {
+ }
+
+ @Override
+ public void setPipeline(RenderPipeline pipeline) {
+ throw nyi("setPipeline");
+ }
+
+ @Override
+ public void bindSampler(String name, GpuTextureView view) {
+ // descriptor binding will be implemented later
+ }
+
+ @Override
+ public void setUniform(String name, GpuBuffer buffer) {
+ // descriptor binding will be implemented later
+ }
+
+ @Override
+ public void setUniform(String name, GpuBufferSlice slice) {
+ // descriptor binding will be implemented later
+ }
+
+ @Override
+ public void enableScissor(int x, int y, int width, int height) {
+ Renderer.setScissor(x, y, width, height);
+ }
+
+ @Override
+ public void disableScissor() {
+ Framebuffer framebuffer = state.framebuffer.handle();
+ Renderer.setScissor(0, 0, framebuffer.getWidth(), framebuffer.getHeight());
+ }
+
+ @Override
+ public void setVertexBuffer(int slot, GpuBuffer buffer) {
+ throw nyi("setVertexBuffer");
+ }
+
+ @Override
+ public void setIndexBuffer(GpuBuffer buffer, VertexFormat.IndexType type) {
+ throw nyi("setIndexBuffer");
+ }
+
+ @Override
+ public void drawIndexed(int indexCount, int instanceCount, int firstIndex, int baseVertex) {
+ throw nyi("drawIndexed");
+ }
+
+ @Override
+ public void drawMultipleIndexed(Collection> draws,
+ GpuBuffer indirectBuffer,
+ VertexFormat.IndexType type,
+ Collection boundSamplers,
+ T shaderState) {
+ throw nyi("drawMultipleIndexed");
+ }
+
+ @Override
+ public void draw(int vertexCount, int instanceCount) {
+ throw nyi("draw");
+ }
+
+ @Override
+ public void close() {
+ end(Renderer.getCommandBuffer());
+ encoder.onRenderPassClosed();
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPassState.java b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPassState.java
new file mode 100644
index 000000000..cae7fab8b
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/blaze/VulkanRenderPassState.java
@@ -0,0 +1,104 @@
+package net.vulkanmod.vulkan.blaze;
+
+import com.mojang.blaze3d.textures.GpuTextureView;
+import net.minecraft.util.ARGB;
+import net.vulkanmod.vulkan.framebuffer.Framebuffer;
+import net.vulkanmod.vulkan.framebuffer.RenderPass;
+import net.vulkanmod.vulkan.util.VUtil;
+import org.lwjgl.vulkan.VkClearAttachment;
+import org.lwjgl.vulkan.VkClearRect;
+import org.lwjgl.vulkan.VkCommandBuffer;
+
+import java.lang.foreign.Arena;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+
+import static org.lwjgl.vulkan.VK10.VK_ATTACHMENT_LOAD_OP_CLEAR;
+import static org.lwjgl.vulkan.VK10.VK_ATTACHMENT_LOAD_OP_LOAD;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_ASPECT_COLOR_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_ASPECT_DEPTH_BIT;
+import static org.lwjgl.vulkan.VK10.vkCmdClearAttachments;
+
+final class VulkanRenderPassState {
+ final VulkanFramebuffer framebuffer;
+ final RenderPass renderPass;
+
+ private final OptionalInt colorClear;
+ private final OptionalDouble depthClear;
+
+ private VulkanRenderPassState(VulkanFramebuffer framebuffer, RenderPass renderPass,
+ OptionalInt colorClear, OptionalDouble depthClear) {
+ this.framebuffer = framebuffer;
+ this.renderPass = renderPass;
+ this.colorClear = colorClear;
+ this.depthClear = depthClear;
+ }
+
+ static VulkanRenderPassState create(VulkanFramebuffer framebuffer,
+ GpuTextureView colorView,
+ OptionalInt colorLevel,
+ GpuTextureView depthView,
+ OptionalDouble clearDepth) {
+ Framebuffer fb = framebuffer.handle();
+ RenderPass.Builder builder = RenderPass.builder(fb);
+
+ if (builder.getColorAttachmentInfo() != null) {
+ builder.getColorAttachmentInfo().setLoadOp(VK_ATTACHMENT_LOAD_OP_LOAD);
+ }
+ if (builder.getDepthAttachmentInfo() != null) {
+ builder.getDepthAttachmentInfo().setLoadOp(VK_ATTACHMENT_LOAD_OP_LOAD);
+ }
+
+ RenderPass renderPass = builder.build();
+ return new VulkanRenderPassState(framebuffer, renderPass, colorLevel, clearDepth);
+ }
+
+ void begin(VkCommandBuffer commandBuffer) {
+ framebuffer.handle().beginRenderPass(commandBuffer, renderPass);
+
+ if (colorClear.isPresent() || depthClear.isPresent()) {
+ try (Arena arena = Arena.ofConfined()) {
+ int attachmentCount = (colorClear.isPresent() ? 1 : 0) + (depthClear.isPresent() ? 1 : 0);
+ VkClearAttachment.Buffer attachments = VUtil.structBuffer(
+ arena,
+ VkClearAttachment.SIZEOF,
+ VkClearAttachment.ALIGNOF,
+ attachmentCount,
+ VkClearAttachment::create
+ );
+ int index = 0;
+
+ if (colorClear.isPresent()) {
+ VkClearAttachment colorAttachment = attachments.get(index++);
+ colorAttachment.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
+ colorAttachment.colorAttachment(0);
+ int argb = colorClear.getAsInt();
+ colorAttachment.clearValue().color().float32(0, ARGB.redFloat(argb));
+ colorAttachment.clearValue().color().float32(1, ARGB.greenFloat(argb));
+ colorAttachment.clearValue().color().float32(2, ARGB.blueFloat(argb));
+ colorAttachment.clearValue().color().float32(3, ARGB.alphaFloat(argb));
+ }
+
+ if (depthClear.isPresent()) {
+ VkClearAttachment depthAttachment = attachments.get(index);
+ depthAttachment.aspectMask(VK_IMAGE_ASPECT_DEPTH_BIT);
+ depthAttachment.clearValue().depthStencil().set((float) depthClear.getAsDouble(), 0);
+ }
+
+ VkClearRect.Buffer rect = VUtil.structBuffer(
+ arena,
+ VkClearRect.SIZEOF,
+ VkClearRect.ALIGNOF,
+ 1,
+ VkClearRect::create
+ );
+ rect.get(0).rect().offset().set(0, 0);
+ rect.get(0).rect().extent().set(framebuffer.handle().getWidth(), framebuffer.handle().getHeight());
+ rect.get(0).baseArrayLayer(0);
+ rect.get(0).layerCount(1);
+
+ vkCmdClearAttachments(commandBuffer, attachments, rect);
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/device/Device.java b/src/main/java/net/vulkanmod/vulkan/device/Device.java
index da850d3b9..9f2ae25db 100644
--- a/src/main/java/net/vulkanmod/vulkan/device/Device.java
+++ b/src/main/java/net/vulkanmod/vulkan/device/Device.java
@@ -1,10 +1,7 @@
package net.vulkanmod.vulkan.device;
-import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.*;
-import oshi.SystemInfo;
-import oshi.hardware.CentralProcessor;
import java.nio.IntBuffer;
import java.util.HashSet;
@@ -19,21 +16,18 @@
import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceFeatures2;
public class Device {
- final VkPhysicalDevice physicalDevice;
- final VkPhysicalDeviceProperties properties;
-
- private final int vendorId;
public final String vendorIdString;
public final String deviceName;
public final String driverVersion;
public final String vkVersion;
-
public final VkPhysicalDeviceFeatures2 availableFeatures;
public final VkPhysicalDeviceVulkan11Features availableFeatures11;
+ final VkPhysicalDevice physicalDevice;
+ final VkPhysicalDeviceProperties properties;
+ private final int vendorId;
// public final VkPhysicalDeviceVulkan13Features availableFeatures13;
// public final boolean vulkan13Support;
-
private boolean drawIndirectSupported;
public Device(VkPhysicalDevice device) {
diff --git a/src/main/java/net/vulkanmod/vulkan/device/DeviceManager.java b/src/main/java/net/vulkanmod/vulkan/device/DeviceManager.java
index 18fd202a0..62a493a04 100644
--- a/src/main/java/net/vulkanmod/vulkan/device/DeviceManager.java
+++ b/src/main/java/net/vulkanmod/vulkan/device/DeviceManager.java
@@ -171,6 +171,21 @@ public static void createLogicalDevice() {
deviceVulkan11Features.sType$Default();
deviceVulkan11Features.shaderDrawParameters(device.isDrawIndirectSupported());
+ VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddressFeatures = VkPhysicalDeviceBufferDeviceAddressFeatures.calloc(stack);
+ bufferDeviceAddressFeatures.sType$Default();
+ bufferDeviceAddressFeatures.bufferDeviceAddress(true);
+ deviceVulkan11Features.pNext(bufferDeviceAddressFeatures.address());
+
+ VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures = VkPhysicalDeviceAccelerationStructureFeaturesKHR.calloc(stack);
+ accelerationStructureFeatures.sType$Default();
+ accelerationStructureFeatures.accelerationStructure(true);
+ bufferDeviceAddressFeatures.pNext(accelerationStructureFeatures.address());
+
+ VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures = VkPhysicalDeviceRayTracingPipelineFeaturesKHR.calloc(stack);
+ rayTracingPipelineFeatures.sType$Default();
+ rayTracingPipelineFeatures.rayTracingPipeline(true);
+ accelerationStructureFeatures.pNext(rayTracingPipelineFeatures.address());
+
VkPhysicalDeviceFeatures2 deviceFeatures = VkPhysicalDeviceFeatures2.calloc(stack);
deviceFeatures.sType$Default();
deviceFeatures.features().samplerAnisotropy(device.availableFeatures.features().samplerAnisotropy());
@@ -196,7 +211,7 @@ public static void createLogicalDevice() {
dynamicRenderingFeaturesKHR.sType$Default();
dynamicRenderingFeaturesKHR.dynamicRendering(true);
- deviceVulkan11Features.pNext(dynamicRenderingFeaturesKHR.address());
+ rayTracingPipelineFeatures.pNext(dynamicRenderingFeaturesKHR.address());
// //Vulkan 1.3 dynamic rendering
// VkPhysicalDeviceVulkan13Features deviceVulkan13Features = VkPhysicalDeviceVulkan13Features.calloc(stack);
diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java
index 8a2d5ad09..d71f3e509 100644
--- a/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/Framebuffer.java
@@ -5,38 +5,48 @@
import net.vulkanmod.vulkan.Vulkan;
import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.texture.VulkanImage;
+import net.vulkanmod.vulkan.util.VUtil;
import org.apache.commons.lang3.Validate;
-import org.lwjgl.system.MemoryStack;
-import org.lwjgl.vulkan.*;
+import org.lwjgl.vulkan.VkCommandBuffer;
+import org.lwjgl.vulkan.VkFramebufferCreateInfo;
+import org.lwjgl.vulkan.VkRect2D;
+import org.lwjgl.vulkan.VkDevice;
+import org.lwjgl.vulkan.VkViewport;
+import java.lang.foreign.Arena;
import java.nio.LongBuffer;
import java.util.Arrays;
import static net.vulkanmod.vulkan.Vulkan.DYNAMIC_RENDERING;
-import static org.lwjgl.vulkan.VK10.*;
+import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_UNORM;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_SAMPLED_BIT;
+import static org.lwjgl.vulkan.VK10.VK_SUCCESS;
+import static org.lwjgl.vulkan.VK10.vkCmdSetScissor;
+import static org.lwjgl.vulkan.VK10.vkCmdSetViewport;
+import static org.lwjgl.vulkan.VK10.vkCreateFramebuffer;
+import static org.lwjgl.vulkan.VK10.vkDestroyFramebuffer;
public class Framebuffer {
public static final int DEFAULT_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
// private long id;
-
+ private final Reference2LongArrayMap renderpassToFramebufferMap = new Reference2LongArrayMap<>();
protected int format;
protected int depthFormat;
protected int width, height;
protected boolean linearFiltering;
protected boolean depthLinearFiltering;
protected int attachmentCount;
-
+ protected VulkanImage depthAttachment;
boolean hasColorAttachment;
boolean hasDepthAttachment;
-
private VulkanImage colorAttachment;
- protected VulkanImage depthAttachment;
-
- private final Reference2LongArrayMap renderpassToFramebufferMap = new Reference2LongArrayMap<>();
//SwapChain
- protected Framebuffer() {}
+ protected Framebuffer() {
+ }
public Framebuffer(Builder builder) {
this.format = builder.format;
@@ -56,6 +66,14 @@ public Framebuffer(Builder builder) {
}
}
+ public static Builder builder(int width, int height, int colorAttachments, boolean hasDepthAttachment) {
+ return new Builder(width, height, colorAttachments, hasDepthAttachment);
+ }
+
+ public static Builder builder(VulkanImage colorAttachment, VulkanImage depthAttachment) {
+ return new Builder(colorAttachment, depthAttachment);
+ }
+
public void createImages() {
if (this.hasColorAttachment) {
this.colorAttachment = VulkanImage.builder(this.width, this.height)
@@ -85,21 +103,25 @@ public void resize(int newWidth, int newHeight) {
}
private long createFramebuffer(RenderPass renderPass) {
-
- try (MemoryStack stack = MemoryStack.stackPush()) {
-
- LongBuffer attachments;
- if (colorAttachment != null && depthAttachment != null) {
- attachments = stack.longs(colorAttachment.getImageView(), depthAttachment.getImageView());
- } else if (colorAttachment != null) {
- attachments = stack.longs(colorAttachment.getImageView());
- } else {
- throw new IllegalStateException();
+ try (Arena arena = Arena.ofConfined()) {
+ LongBuffer attachments = colorAttachment != null && depthAttachment != null
+ ? VUtil.longBuffer(arena, colorAttachment.getImageView(), depthAttachment.getImageView())
+ : colorAttachment != null
+ ? VUtil.longBuffer(arena, colorAttachment.getImageView())
+ : null;
+
+ if (attachments == null) {
+ throw new IllegalStateException("Framebuffer must have at least one attachment");
}
- LongBuffer pFramebuffer = stack.mallocLong(1);
+ LongBuffer pFramebuffer = VUtil.allocateLongBuffer(arena, 1);
- VkFramebufferCreateInfo framebufferInfo = VkFramebufferCreateInfo.calloc(stack);
+ VkFramebufferCreateInfo framebufferInfo = VUtil.struct(
+ arena,
+ VkFramebufferCreateInfo.SIZEOF,
+ VkFramebufferCreateInfo.ALIGNOF,
+ VkFramebufferCreateInfo::create
+ );
framebufferInfo.sType$Default();
framebufferInfo.renderPass(renderPass.getId());
framebufferInfo.width(this.width);
@@ -107,7 +129,7 @@ private long createFramebuffer(RenderPass renderPass) {
framebufferInfo.layers(1);
framebufferInfo.pAttachments(attachments);
- if (VK10.vkCreateFramebuffer(Vulkan.getVkDevice(), framebufferInfo, null, pFramebuffer) != VK_SUCCESS) {
+ if (vkCreateFramebuffer(Vulkan.getVkDevice(), framebufferInfo, null, pFramebuffer) != VK_SUCCESS) {
throw new RuntimeException("Failed to create framebuffer");
}
@@ -115,12 +137,16 @@ private long createFramebuffer(RenderPass renderPass) {
}
}
- public void beginRenderPass(VkCommandBuffer commandBuffer, RenderPass renderPass, MemoryStack stack) {
+ public void beginRenderPass(VkCommandBuffer commandBuffer, RenderPass renderPass) {
if (!DYNAMIC_RENDERING) {
long framebufferId = this.getFramebufferId(renderPass);
- renderPass.beginRenderPass(commandBuffer, framebufferId, stack);
+ try (Arena arena = Arena.ofConfined()) {
+ renderPass.beginRenderPass(commandBuffer, framebufferId, arena);
+ }
} else {
- renderPass.beginDynamicRendering(commandBuffer, stack);
+ try (Arena arena = Arena.ofConfined()) {
+ renderPass.beginDynamicRendering(commandBuffer, arena, this);
+ }
}
Renderer.getInstance().setBoundRenderPass(renderPass);
@@ -134,24 +160,40 @@ protected long getFramebufferId(RenderPass renderPass) {
return this.renderpassToFramebufferMap.computeIfAbsent(renderPass, renderPass1 -> createFramebuffer(renderPass));
}
- public VkViewport.Buffer viewport(MemoryStack stack) {
- VkViewport.Buffer viewport = VkViewport.malloc(1, stack);
- viewport.x(0.0f);
- viewport.y(this.height);
- viewport.width(this.width);
- viewport.height(-this.height);
- viewport.minDepth(0.0f);
- viewport.maxDepth(1.0f);
-
- return viewport;
+ public void applyViewport(VkCommandBuffer commandBuffer) {
+ try (Arena arena = Arena.ofConfined()) {
+ VkViewport.Buffer viewport = VUtil.structBuffer(
+ arena,
+ VkViewport.SIZEOF,
+ VkViewport.ALIGNOF,
+ 1,
+ VkViewport::create
+ );
+ viewport.x(0.0f);
+ viewport.y(this.height);
+ viewport.width(this.width);
+ viewport.height(-this.height);
+ viewport.minDepth(0.0f);
+ viewport.maxDepth(1.0f);
+
+ vkCmdSetViewport(commandBuffer, 0, viewport);
+ }
}
- public VkRect2D.Buffer scissor(MemoryStack stack) {
- VkRect2D.Buffer scissor = VkRect2D.malloc(1, stack);
- scissor.offset().set(0, 0);
- scissor.extent().set(this.width, this.height);
-
- return scissor;
+ public void applyScissor(VkCommandBuffer commandBuffer) {
+ try (Arena arena = Arena.ofConfined()) {
+ VkRect2D.Buffer scissor = VUtil.structBuffer(
+ arena,
+ VkRect2D.SIZEOF,
+ VkRect2D.ALIGNOF,
+ 1,
+ VkRect2D::create
+ );
+ scissor.offset().set(0, 0);
+ scissor.extent().set(this.width, this.height);
+
+ vkCmdSetScissor(commandBuffer, 0, scissor);
+ }
}
public void cleanUp() {
@@ -207,14 +249,6 @@ public int getDepthFormat() {
return this.depthFormat;
}
- public static Builder builder(int width, int height, int colorAttachments, boolean hasDepthAttachment) {
- return new Builder(width, height, colorAttachments, hasDepthAttachment);
- }
-
- public static Builder builder(VulkanImage colorAttachment, VulkanImage depthAttachment) {
- return new Builder(colorAttachment, depthAttachment);
- }
-
public static class Builder {
final boolean createImages;
final int width, height;
@@ -223,7 +257,7 @@ public static class Builder {
VulkanImage colorAttachment;
VulkanImage depthAttachment;
-// int colorAttachments;
+ // int colorAttachments;
boolean hasColorAttachment;
boolean hasDepthAttachment;
diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java
index 589f00c21..94985b3c5 100644
--- a/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java
+++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/RenderPass.java
@@ -4,19 +4,32 @@
import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.Vulkan;
import net.vulkanmod.vulkan.memory.MemoryManager;
-import org.lwjgl.system.MemoryStack;
-import org.lwjgl.vulkan.*;
-
+import net.vulkanmod.vulkan.texture.VulkanImage;
+import net.vulkanmod.vulkan.util.VUtil;
+import org.lwjgl.vulkan.KHRDynamicRendering;
+import org.lwjgl.vulkan.VkAttachmentDescription;
+import org.lwjgl.vulkan.VkAttachmentReference;
+import org.lwjgl.vulkan.VkClearValue;
+import org.lwjgl.vulkan.VkCommandBuffer;
+import org.lwjgl.vulkan.VkRect2D;
+import org.lwjgl.vulkan.VkRenderPassBeginInfo;
+import org.lwjgl.vulkan.VkRenderPassCreateInfo;
+import org.lwjgl.vulkan.VkRenderingAttachmentInfo;
+import org.lwjgl.vulkan.VkRenderingInfo;
+import org.lwjgl.vulkan.VkSubpassDependency;
+import org.lwjgl.vulkan.VkSubpassDescription;
+import org.lwjgl.vulkan.VkViewport;
+
+import java.lang.foreign.Arena;
import java.nio.LongBuffer;
import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
import static org.lwjgl.vulkan.VK10.*;
public class RenderPass {
+ final int attachmentCount;
Framebuffer framebuffer;
long id;
-
- final int attachmentCount;
AttachmentInfo colorAttachmentInfo;
AttachmentInfo depthAttachmentInfo;
@@ -39,92 +52,139 @@ public RenderPass(Framebuffer framebuffer, AttachmentInfo colorAttachmentInfo, A
}
- private void createRenderPass() {
-
- try (MemoryStack stack = MemoryStack.stackPush()) {
- VkAttachmentDescription.Buffer attachments = VkAttachmentDescription.calloc(attachmentCount, stack);
- VkAttachmentReference.Buffer attachmentRefs = VkAttachmentReference.calloc(attachmentCount, stack);
+ public static Builder builder(Framebuffer framebuffer) {
+ return new Builder(framebuffer);
+ }
- VkSubpassDescription.Buffer subpass = VkSubpassDescription.calloc(1, stack);
+ private void createRenderPass() {
+ try (Arena arena = Arena.ofConfined()) {
+ VkAttachmentDescription.Buffer attachments = VUtil.structBuffer(
+ arena,
+ VkAttachmentDescription.SIZEOF,
+ VkAttachmentDescription.ALIGNOF,
+ attachmentCount,
+ VkAttachmentDescription::create
+ );
+ VkAttachmentReference.Buffer attachmentRefs = attachmentCount > 0
+ ? VUtil.structBuffer(arena, VkAttachmentReference.SIZEOF, VkAttachmentReference.ALIGNOF, attachmentCount, VkAttachmentReference::create)
+ : null;
+
+ VkSubpassDescription.Buffer subpass = VUtil.structBuffer(
+ arena,
+ VkSubpassDescription.SIZEOF,
+ VkSubpassDescription.ALIGNOF,
+ 1,
+ VkSubpassDescription::create
+ );
subpass.pipelineBindPoint(VK_PIPELINE_BIND_POINT_GRAPHICS);
- int i = 0;
+ int attachmentIndex = 0;
- // Color attachment
if (colorAttachmentInfo != null) {
- VkAttachmentDescription colorAttachment = attachments.get(i);
+ VkAttachmentDescription colorAttachment = attachments.get(attachmentIndex);
colorAttachment.format(colorAttachmentInfo.format)
- .samples(VK_SAMPLE_COUNT_1_BIT)
- .loadOp(colorAttachmentInfo.loadOp)
- .storeOp(colorAttachmentInfo.storeOp)
- .stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE)
- .stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
- .initialLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
- .finalLayout(colorAttachmentInfo.finalLayout);
-
- VkAttachmentReference colorAttachmentRef = attachmentRefs.get(0)
- .attachment(0)
- .layout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ .samples(VK_SAMPLE_COUNT_1_BIT)
+ .loadOp(colorAttachmentInfo.loadOp)
+ .storeOp(colorAttachmentInfo.storeOp)
+ .stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+ .stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
+ .initialLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
+ .finalLayout(colorAttachmentInfo.finalLayout);
+
+ VkAttachmentReference.Buffer colorRef = VUtil.structBuffer(
+ arena,
+ VkAttachmentReference.SIZEOF,
+ VkAttachmentReference.ALIGNOF,
+ 1,
+ VkAttachmentReference::create
+ );
+ colorRef.get(0)
+ .attachment(attachmentIndex)
+ .layout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
subpass.colorAttachmentCount(1);
- subpass.pColorAttachments(VkAttachmentReference.calloc(1, stack).put(0, colorAttachmentRef));
-
- ++i;
+ subpass.pColorAttachments(colorRef);
+ attachmentIndex++;
}
- // Depth-Stencil attachment
if (depthAttachmentInfo != null) {
- VkAttachmentDescription depthAttachment = attachments.get(i);
+ VkAttachmentDescription depthAttachment = attachments.get(attachmentIndex);
depthAttachment.format(depthAttachmentInfo.format)
- .samples(VK_SAMPLE_COUNT_1_BIT)
- .loadOp(depthAttachmentInfo.loadOp)
- .storeOp(depthAttachmentInfo.storeOp)
- .stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE)
- .stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
- .initialLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
- .finalLayout(depthAttachmentInfo.finalLayout);
-
- VkAttachmentReference depthAttachmentRef = attachmentRefs.get(1)
- .attachment(1)
- .layout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-
- subpass.pDepthStencilAttachment(depthAttachmentRef);
+ .samples(VK_SAMPLE_COUNT_1_BIT)
+ .loadOp(depthAttachmentInfo.loadOp)
+ .storeOp(depthAttachmentInfo.storeOp)
+ .stencilLoadOp(VK_ATTACHMENT_LOAD_OP_DONT_CARE)
+ .stencilStoreOp(VK_ATTACHMENT_STORE_OP_DONT_CARE)
+ .initialLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
+ .finalLayout(depthAttachmentInfo.finalLayout);
+
+ VkAttachmentReference.Buffer depthRef = VUtil.structBuffer(
+ arena,
+ VkAttachmentReference.SIZEOF,
+ VkAttachmentReference.ALIGNOF,
+ 1,
+ VkAttachmentReference::create
+ );
+ depthRef.get(0)
+ .attachment(attachmentIndex)
+ .layout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
+ subpass.pDepthStencilAttachment(depthRef.get(0));
+ attachmentIndex++;
}
- VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.calloc(stack);
- renderPassInfo.sType$Default()
- .pAttachments(attachments)
- .pSubpasses(subpass);
+ VkRenderPassCreateInfo renderPassInfo = VUtil.struct(
+ arena,
+ VkRenderPassCreateInfo.SIZEOF,
+ VkRenderPassCreateInfo.ALIGNOF,
+ VkRenderPassCreateInfo::create
+ );
+ renderPassInfo.sType$Default();
+ renderPassInfo.pAttachments(attachments);
+ renderPassInfo.pSubpasses(subpass);
- //Layout transition subpass depency
- switch (colorAttachmentInfo.finalLayout) {
- case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR -> {
- VkSubpassDependency.Buffer subpassDependencies = VkSubpassDependency.calloc(1, stack);
- subpassDependencies.get(0)
+ if (colorAttachmentInfo != null) {
+ switch (colorAttachmentInfo.finalLayout) {
+ case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR -> {
+ VkSubpassDependency.Buffer dependency = VUtil.structBuffer(
+ arena,
+ VkSubpassDependency.SIZEOF,
+ VkSubpassDependency.ALIGNOF,
+ 1,
+ VkSubpassDependency::create
+ );
+ dependency.get(0)
.srcSubpass(VK_SUBPASS_EXTERNAL)
.dstSubpass(0)
.srcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
.dstStageMask(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT)
.srcAccessMask(0)
.dstAccessMask(0);
-
- renderPassInfo.pDependencies(subpassDependencies);
- }
- case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL -> {
- VkSubpassDependency.Buffer subpassDependencies = VkSubpassDependency.calloc(1, stack);
- subpassDependencies.get(0)
+ renderPassInfo.pDependencies(dependency);
+ }
+ case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL -> {
+ VkSubpassDependency.Buffer dependency = VUtil.structBuffer(
+ arena,
+ VkSubpassDependency.SIZEOF,
+ VkSubpassDependency.ALIGNOF,
+ 1,
+ VkSubpassDependency::create
+ );
+ dependency.get(0)
.srcSubpass(0)
.dstSubpass(VK_SUBPASS_EXTERNAL)
.srcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
.dstStageMask(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
.srcAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
.dstAccessMask(VK_ACCESS_SHADER_READ_BIT);
-
- renderPassInfo.pDependencies(subpassDependencies);
+ renderPassInfo.pDependencies(dependency);
+ }
+ default -> {
+ }
}
}
- LongBuffer pRenderPass = stack.mallocLong(1);
+ LongBuffer pRenderPass = VUtil.allocateLongBuffer(arena, 1);
if (vkCreateRenderPass(Vulkan.getVkDevice(), renderPassInfo, null, pRenderPass) != VK_SUCCESS) {
throw new RuntimeException("Failed to create render pass");
@@ -134,27 +194,52 @@ private void createRenderPass() {
}
}
- public void beginRenderPass(VkCommandBuffer commandBuffer, long framebufferId, MemoryStack stack) {
+ public void beginRenderPass(VkCommandBuffer commandBuffer, long framebufferId, Arena arena) {
if (colorAttachmentInfo != null
- && framebuffer.getColorAttachment().getCurrentLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
- framebuffer.getColorAttachment().transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ && framebuffer.getColorAttachment().getCurrentLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
+ VulkanImage.transitionImageLayout(arena, commandBuffer, framebuffer.getColorAttachment(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ }
if (depthAttachmentInfo != null
- && framebuffer.getDepthAttachment().getCurrentLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
- framebuffer.getDepthAttachment().transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ && framebuffer.getDepthAttachment().getCurrentLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
+ VulkanImage.transitionImageLayout(arena, commandBuffer, framebuffer.getDepthAttachment(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+ }
- VkRenderPassBeginInfo renderPassInfo = VkRenderPassBeginInfo.calloc(stack);
+ VkRenderPassBeginInfo renderPassInfo = VUtil.struct(
+ arena,
+ VkRenderPassBeginInfo.SIZEOF,
+ VkRenderPassBeginInfo.ALIGNOF,
+ VkRenderPassBeginInfo::create
+ );
renderPassInfo.sType$Default();
renderPassInfo.renderPass(this.id);
renderPassInfo.framebuffer(framebufferId);
- VkRect2D renderArea = VkRect2D.malloc(stack);
+ VkRect2D renderArea = VUtil.struct(
+ arena,
+ VkRect2D.SIZEOF,
+ VkRect2D.ALIGNOF,
+ VkRect2D::create
+ );
renderArea.offset().set(0, 0);
renderArea.extent().set(framebuffer.getWidth(), framebuffer.getHeight());
renderPassInfo.renderArea(renderArea);
- VkClearValue.Buffer clearValues = VkClearValue.malloc(2, stack);
- clearValues.get(0).color().float32(VRenderSystem.clearColor);
+ VkClearValue.Buffer clearValues = VUtil.structBuffer(
+ arena,
+ VkClearValue.SIZEOF,
+ VkClearValue.ALIGNOF,
+ 2,
+ VkClearValue::create
+ );
+ float clearR = VRenderSystem.clearColor.get(0);
+ float clearG = VRenderSystem.clearColor.get(1);
+ float clearB = VRenderSystem.clearColor.get(2);
+ float clearA = VRenderSystem.clearColor.get(3);
+ clearValues.get(0).color().float32(0, clearR);
+ clearValues.get(0).color().float32(1, clearG);
+ clearValues.get(0).color().float32(2, clearB);
+ clearValues.get(0).color().float32(3, clearA);
clearValues.get(1).depthStencil().set(1.0f, 0);
renderPassInfo.pClearValues(clearValues);
@@ -176,23 +261,48 @@ public void endRenderPass(VkCommandBuffer commandBuffer) {
Renderer.getInstance().setBoundRenderPass(null);
}
- public void beginDynamicRendering(VkCommandBuffer commandBuffer, MemoryStack stack) {
- VkRect2D renderArea = VkRect2D.malloc(stack);
+ public void beginDynamicRendering(VkCommandBuffer commandBuffer, Arena arena, Framebuffer framebuffer) {
+ VkRect2D renderArea = VUtil.struct(
+ arena,
+ VkRect2D.SIZEOF,
+ VkRect2D.ALIGNOF,
+ VkRect2D::create
+ );
renderArea.offset().set(0, 0);
renderArea.extent().set(framebuffer.getWidth(), framebuffer.getHeight());
- VkClearValue.Buffer clearValues = VkClearValue.malloc(2, stack);
- clearValues.get(0).color().float32(stack.floats(0.0f, 0.0f, 0.0f, 1.0f));
+ VkClearValue.Buffer clearValues = VUtil.structBuffer(
+ arena,
+ VkClearValue.SIZEOF,
+ VkClearValue.ALIGNOF,
+ 2,
+ VkClearValue::create
+ );
+ clearValues.get(0).color().float32(0, 0.0f);
+ clearValues.get(0).color().float32(1, 0.0f);
+ clearValues.get(0).color().float32(2, 0.0f);
+ clearValues.get(0).color().float32(3, 1.0f);
clearValues.get(1).depthStencil().set(1.0f, 0);
- VkRenderingInfo renderingInfo = VkRenderingInfo.calloc(stack);
+ VkRenderingInfo renderingInfo = VUtil.struct(
+ arena,
+ VkRenderingInfo.SIZEOF,
+ VkRenderingInfo.ALIGNOF,
+ VkRenderingInfo::create
+ );
renderingInfo.sType(KHRDynamicRendering.VK_STRUCTURE_TYPE_RENDERING_INFO_KHR);
renderingInfo.renderArea(renderArea);
renderingInfo.layerCount(1);
// Color attachment
if (colorAttachmentInfo != null) {
- VkRenderingAttachmentInfo.Buffer colorAttachment = VkRenderingAttachmentInfo.calloc(1, stack);
+ VkRenderingAttachmentInfo.Buffer colorAttachment = VUtil.structBuffer(
+ arena,
+ VkRenderingAttachmentInfo.SIZEOF,
+ VkRenderingAttachmentInfo.ALIGNOF,
+ 1,
+ VkRenderingAttachmentInfo::create
+ );
colorAttachment.sType(KHRDynamicRendering.VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR);
colorAttachment.imageView(framebuffer.getColorAttachment().getImageView());
colorAttachment.imageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@@ -205,7 +315,12 @@ public void beginDynamicRendering(VkCommandBuffer commandBuffer, MemoryStack sta
//Depth attachment
if (depthAttachmentInfo != null) {
- VkRenderingAttachmentInfo depthAttachment = VkRenderingAttachmentInfo.calloc(stack);
+ VkRenderingAttachmentInfo depthAttachment = VUtil.struct(
+ arena,
+ VkRenderingAttachmentInfo.SIZEOF,
+ VkRenderingAttachmentInfo.ALIGNOF,
+ VkRenderingAttachmentInfo::create
+ );
depthAttachment.sType(KHRDynamicRendering.VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR);
depthAttachment.imageView(framebuffer.getDepthAttachment().getImageView());
depthAttachment.imageLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
@@ -287,10 +402,6 @@ public enum Type {
}
}
- public static Builder builder(Framebuffer framebuffer) {
- return new Builder(framebuffer);
- }
-
public static class Builder {
Framebuffer framebuffer;
AttachmentInfo colorAttachmentInfo;
diff --git a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java
index 857a80123..6063c1355 100644
--- a/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java
+++ b/src/main/java/net/vulkanmod/vulkan/framebuffer/SwapChain.java
@@ -33,11 +33,10 @@ public class SwapChain extends Framebuffer {
private static final int defUncappedMode = checkPresentMode(VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR);
private final Long2ReferenceOpenHashMap FBO_map = new Long2ReferenceOpenHashMap<>();
-
+ public boolean isBGRAformat;
private long swapChainId = VK_NULL_HANDLE;
private List swapChainImages;
private VkExtent2D extent2D;
- public boolean isBGRAformat;
private boolean vsync = false;
public SwapChain() {
@@ -50,6 +49,43 @@ public SwapChain() {
recreate();
}
+ private static VkExtent2D getExtent(VkSurfaceCapabilitiesKHR capabilities) {
+
+ if (capabilities.currentExtent().width() != UINT32_MAX) {
+ return capabilities.currentExtent();
+ }
+
+ // Fallback
+ IntBuffer width = stackGet().ints(0);
+ IntBuffer height = stackGet().ints(0);
+
+ glfwGetFramebufferSize(window, width, height);
+
+ VkExtent2D actualExtent = VkExtent2D.mallocStack().set(width.get(0), height.get(0));
+
+ VkExtent2D minExtent = capabilities.minImageExtent();
+ VkExtent2D maxExtent = capabilities.maxImageExtent();
+
+ actualExtent.width(MathUtil.clamp(minExtent.width(), maxExtent.width(), actualExtent.width()));
+ actualExtent.height(MathUtil.clamp(minExtent.height(), maxExtent.height(), actualExtent.height()));
+
+ return actualExtent;
+ }
+
+ private static int checkPresentMode(int... requestedModes) {
+ try (MemoryStack stack = MemoryStack.stackPush()) {
+ var a = DeviceManager.querySurfaceProperties(vkDevice.getPhysicalDevice(), stack).presentModes;
+ for (int dMode : requestedModes) {
+ for (int i = 0; i < a.capacity(); i++) {
+ if (a.get(i) == dMode) {
+ return dMode;
+ }
+ }
+ }
+ return VK_PRESENT_MODE_FIFO_KHR; // If None of the request modes exist/are supported by Driver
+ }
+ }
+
public void recreate() {
if (this.depthAttachment != null) {
this.depthAttachment.free();
@@ -285,43 +321,6 @@ private String getDisplayModeString(int requestedMode) {
};
}
- private static VkExtent2D getExtent(VkSurfaceCapabilitiesKHR capabilities) {
-
- if (capabilities.currentExtent().width() != UINT32_MAX) {
- return capabilities.currentExtent();
- }
-
- // Fallback
- IntBuffer width = stackGet().ints(0);
- IntBuffer height = stackGet().ints(0);
-
- glfwGetFramebufferSize(window, width, height);
-
- VkExtent2D actualExtent = VkExtent2D.mallocStack().set(width.get(0), height.get(0));
-
- VkExtent2D minExtent = capabilities.minImageExtent();
- VkExtent2D maxExtent = capabilities.maxImageExtent();
-
- actualExtent.width(MathUtil.clamp(minExtent.width(), maxExtent.width(), actualExtent.width()));
- actualExtent.height(MathUtil.clamp(minExtent.height(), maxExtent.height(), actualExtent.height()));
-
- return actualExtent;
- }
-
- private static int checkPresentMode(int... requestedModes) {
- try (MemoryStack stack = MemoryStack.stackPush()) {
- var a = DeviceManager.querySurfaceProperties(vkDevice.getPhysicalDevice(), stack).presentModes;
- for (int dMode : requestedModes) {
- for (int i = 0; i < a.capacity(); i++) {
- if (a.get(i) == dMode) {
- return dMode;
- }
- }
- }
- return VK_PRESENT_MODE_FIFO_KHR; // If None of the request modes exist/are supported by Driver
- }
- }
-
public boolean isVsync() {
return this.vsync;
}
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/MemoryManager.java b/src/main/java/net/vulkanmod/vulkan/memory/MemoryManager.java
index 9e9ea353a..e2d11147c 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/MemoryManager.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/MemoryManager.java
@@ -29,41 +29,23 @@
import static org.lwjgl.vulkan.VK10.*;
public class MemoryManager {
- private static final boolean DEBUG = false;
public static final long BYTES_IN_MB = 1024 * 1024;
-
- private static MemoryManager INSTANCE;
+ private static final boolean DEBUG = false;
private static final long ALLOCATOR = Vulkan.getAllocator();
-
private static final Long2ReferenceOpenHashMap buffers = new Long2ReferenceOpenHashMap<>();
private static final Long2ReferenceOpenHashMap images = new Long2ReferenceOpenHashMap<>();
-
static int Frames;
-
+ private static MemoryManager INSTANCE;
private static long deviceMemory = 0;
private static long nativeMemory = 0;
-
- private int currentFrame = 0;
-
private final ObjectArrayList[] freeableBuffers = new ObjectArrayList[Frames];
private final ObjectArrayList[] freeableImages = new ObjectArrayList[Frames];
-
private final ObjectArrayList[] frameOps = new ObjectArrayList[Frames];
private final ObjectArrayList>[] segmentsToFree = new ObjectArrayList[Frames];
-
+ private int currentFrame = 0;
//debug
private ObjectArrayList[] stackTraces;
- public static MemoryManager getInstance() {
- return INSTANCE;
- }
-
- public static void createInstance(int frames) {
- Frames = frames;
-
- INSTANCE = new MemoryManager();
- }
-
MemoryManager() {
for (int i = 0; i < Frames; ++i) {
this.freeableBuffers[i] = new ObjectArrayList<>();
@@ -81,6 +63,57 @@ public static void createInstance(int frames) {
}
}
+ public static MemoryManager getInstance() {
+ return INSTANCE;
+ }
+
+ public static void createInstance(int frames) {
+ Frames = frames;
+
+ INSTANCE = new MemoryManager();
+ }
+
+ public static void addImage(VulkanImage image) {
+ images.putIfAbsent(image.getId(), image);
+
+ deviceMemory += image.size;
+ }
+
+ public static void MapAndCopy(long allocation, Consumer consumer) {
+ try (MemoryStack stack = stackPush()) {
+ PointerBuffer data = stack.mallocPointer(1);
+
+ vmaMapMemory(ALLOCATOR, allocation, data);
+ consumer.accept(data);
+ vmaUnmapMemory(ALLOCATOR, allocation);
+ }
+ }
+
+ public static void freeBuffer(long buffer, long allocation) {
+ vmaDestroyBuffer(ALLOCATOR, buffer, allocation);
+
+ buffers.remove(buffer);
+ }
+
+ private static void freeBuffer(Buffer.BufferInfo bufferInfo) {
+ vmaDestroyBuffer(ALLOCATOR, bufferInfo.id(), bufferInfo.allocation());
+
+ if (bufferInfo.type() == MemoryType.Type.DEVICE_LOCAL) {
+ deviceMemory -= bufferInfo.bufferSize();
+ } else {
+ nativeMemory -= bufferInfo.bufferSize();
+ }
+
+ buffers.remove(bufferInfo.id());
+ }
+
+ public static void freeImage(long imageId, long allocation) {
+ vmaDestroyImage(ALLOCATOR, imageId, allocation);
+
+ VulkanImage image = images.remove(imageId);
+ deviceMemory -= image.size;
+ }
+
public synchronized void initFrame(int frame) {
this.setCurrentFrame(frame);
this.freeBuffers(frame);
@@ -141,8 +174,7 @@ public synchronized void createBuffer(Buffer buffer, long size, int usage, int p
if ((properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) {
deviceMemory += size;
- }
- else {
+ } else {
nativeMemory += size;
}
@@ -151,8 +183,8 @@ public synchronized void createBuffer(Buffer buffer, long size, int usage, int p
}
public void createImage(int width, int height, int mipLevels, int format, int tiling, int usage,
- int memProperties,
- LongBuffer pTextureImage, PointerBuffer pTextureImageMemory) {
+ int memProperties,
+ LongBuffer pTextureImage, PointerBuffer pTextureImageMemory) {
try (MemoryStack stack = stackPush()) {
VkImageCreateInfo imageInfo = VkImageCreateInfo.calloc(stack);
@@ -185,22 +217,6 @@ public void createImage(int width, int height, int mipLevels, int format, int ti
}
}
- public static void addImage(VulkanImage image) {
- images.putIfAbsent(image.getId(), image);
-
- deviceMemory += image.size;
- }
-
- public static void MapAndCopy(long allocation, Consumer consumer) {
- try (MemoryStack stack = stackPush()) {
- PointerBuffer data = stack.mallocPointer(1);
-
- vmaMapMemory(ALLOCATOR, allocation, data);
- consumer.accept(data);
- vmaUnmapMemory(ALLOCATOR, allocation);
- }
- }
-
public PointerBuffer Map(long allocation) {
PointerBuffer data = MemoryUtil.memAllocPointer(1);
@@ -209,32 +225,6 @@ public PointerBuffer Map(long allocation) {
return data;
}
- public static void freeBuffer(long buffer, long allocation) {
- vmaDestroyBuffer(ALLOCATOR, buffer, allocation);
-
- buffers.remove(buffer);
- }
-
- private static void freeBuffer(Buffer.BufferInfo bufferInfo) {
- vmaDestroyBuffer(ALLOCATOR, bufferInfo.id(), bufferInfo.allocation());
-
- if (bufferInfo.type() == MemoryType.Type.DEVICE_LOCAL) {
- deviceMemory -= bufferInfo.bufferSize();
- }
- else {
- nativeMemory -= bufferInfo.bufferSize();
- }
-
- buffers.remove(bufferInfo.id());
- }
-
- public static void freeImage(long imageId, long allocation) {
- vmaDestroyImage(ALLOCATOR, imageId, allocation);
-
- VulkanImage image = images.remove(imageId);
- deviceMemory -= image.size;
- }
-
public synchronized void addToFreeable(Buffer buffer) {
Buffer.BufferInfo bufferInfo = buffer.getBufferInfo();
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/MemoryType.java b/src/main/java/net/vulkanmod/vulkan/memory/MemoryType.java
index 15bf8d6df..d751e28c5 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/MemoryType.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/MemoryType.java
@@ -7,9 +7,9 @@
import java.nio.ByteBuffer;
public abstract class MemoryType {
- final Type type;
public final VkMemoryType vkMemoryType;
public final VkMemoryHeap vkMemoryHeap;
+ final Type type;
MemoryType(Type type, VkMemoryType vkMemoryType, VkMemoryHeap vkMemoryHeap) {
this.type = type;
@@ -26,7 +26,7 @@ public abstract class MemoryType {
public abstract boolean mappable();
public Type getType() {
- return this.type;
+ return this.type;
}
public enum Type {
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/Buffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/Buffer.java
index ac8ac91e4..f13f2600c 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/Buffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/Buffer.java
@@ -68,6 +68,10 @@ public long getAllocation() {
return allocation;
}
+ public void setAllocation(long allocation) {
+ this.allocation = allocation;
+ }
+
public long getUsedBytes() {
return usedBytes;
}
@@ -80,24 +84,20 @@ public long getId() {
return id;
}
- public long getBufferSize() {
- return bufferSize;
+ public void setId(long id) {
+ this.id = id;
}
- public long getDataPtr() {
- return dataPtr;
+ public long getBufferSize() {
+ return bufferSize;
}
public void setBufferSize(long size) {
this.bufferSize = size;
}
- public void setId(long id) {
- this.id = id;
- }
-
- public void setAllocation(long allocation) {
- this.allocation = allocation;
+ public long getDataPtr() {
+ return dataPtr;
}
public BufferInfo getBufferInfo() {
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndexBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndexBuffer.java
index 1b2ad4c8b..fb57b9f64 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndexBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndexBuffer.java
@@ -33,4 +33,4 @@ public enum IndexType {
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndirectBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndirectBuffer.java
index 6b09cb0cb..b8ce2109f 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndirectBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/IndirectBuffer.java
@@ -3,7 +3,6 @@
import net.vulkanmod.vulkan.Synchronization;
import net.vulkanmod.vulkan.Vulkan;
import net.vulkanmod.vulkan.device.DeviceManager;
-import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.memory.MemoryType;
import net.vulkanmod.vulkan.queue.CommandPool;
import net.vulkanmod.vulkan.queue.TransferQueue;
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/StagingBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/StagingBuffer.java
index 03d764c5a..ecbec6252 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/StagingBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/StagingBuffer.java
@@ -10,7 +10,7 @@
import java.nio.ByteBuffer;
import static org.lwjgl.system.libc.LibCString.nmemcpy;
-import static org.lwjgl.vulkan.VK10.*;
+import static org.lwjgl.vulkan.VK10.VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
public class StagingBuffer extends Buffer {
private static final long DEFAULT_SIZE = 64 * 1024 * 1024;
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/UniformBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/UniformBuffer.java
index b9d102d18..804bb2c24 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/UniformBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/UniformBuffer.java
@@ -9,15 +9,15 @@
public class UniformBuffer extends Buffer {
private final static int MIN_OFFSET_ALIGNMENT = (int) DeviceManager.deviceProperties.limits().minUniformBufferOffsetAlignment();
- public static int getAlignedSize(int uploadSize) {
- return align(uploadSize, MIN_OFFSET_ALIGNMENT);
- }
-
public UniformBuffer(int size, MemoryType memoryType) {
super(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, memoryType);
this.createBuffer(size);
}
+ public static int getAlignedSize(int uploadSize) {
+ return align(uploadSize, MIN_OFFSET_ALIGNMENT);
+ }
+
public void checkCapacity(int size) {
if (size > this.bufferSize - this.usedBytes) {
resizeBuffer((this.bufferSize + size) * 2);
@@ -31,4 +31,4 @@ public void updateOffset(int alignedSize) {
public long getPointer() {
return this.dataPtr + usedBytes;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/VertexBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/VertexBuffer.java
index fb9858c9b..edd682414 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/VertexBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/VertexBuffer.java
@@ -16,4 +16,4 @@ public VertexBuffer(int size, MemoryType type) {
this.createBuffer(size);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/net/vulkanmod/vulkan/memory/buffer/index/AutoIndexBuffer.java b/src/main/java/net/vulkanmod/vulkan/memory/buffer/index/AutoIndexBuffer.java
index a05ae38cf..e1422fc1f 100644
--- a/src/main/java/net/vulkanmod/vulkan/memory/buffer/index/AutoIndexBuffer.java
+++ b/src/main/java/net/vulkanmod/vulkan/memory/buffer/index/AutoIndexBuffer.java
@@ -1,8 +1,8 @@
package net.vulkanmod.vulkan.memory.buffer.index;
import net.vulkanmod.Initializer;
-import net.vulkanmod.vulkan.memory.buffer.IndexBuffer;
import net.vulkanmod.vulkan.memory.MemoryTypes;
+import net.vulkanmod.vulkan.memory.buffer.IndexBuffer;
import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
@@ -23,59 +23,6 @@ public AutoIndexBuffer(int vertexCount, DrawType type) {
createIndexBuffer(vertexCount);
}
- private void createIndexBuffer(int vertexCount) {
- this.vertexCount = vertexCount;
- ByteBuffer buffer;
-
- IndexBuffer.IndexType indexType = IndexBuffer.IndexType.UINT16;
-
- if (vertexCount > U16_MAX_VERTEX_COUNT &&
- (this.drawType == DrawType.QUADS || this.drawType == DrawType.LINES))
- {
- indexType = IndexBuffer.IndexType.UINT32;
- }
-
- switch (this.drawType) {
- case QUADS -> {
- if (indexType == IndexBuffer.IndexType.UINT16)
- buffer = genQuadIndices(vertexCount);
- else {
- buffer = genIntQuadIndices(vertexCount);
- }
- }
- case TRIANGLE_FAN -> buffer = genTriangleFanIndices(vertexCount);
- case TRIANGLE_STRIP -> buffer = genTriangleStripIndices(vertexCount);
- case LINES -> buffer = genLinesIndices(vertexCount);
- case DEBUG_LINE_STRIP -> buffer = genDebugLineStripIndices(vertexCount);
- default -> throw new IllegalArgumentException("Unsupported drawType: %s".formatted(this.drawType));
- }
-
- int size = buffer.capacity();
- this.indexBuffer = new IndexBuffer(size, MemoryTypes.GPU_MEM, indexType);
- this.indexBuffer.copyBuffer(buffer, buffer.remaining());
-
- MemoryUtil.memFree(buffer);
- }
-
- public void checkCapacity(int vertexCount) {
- if(vertexCount > this.vertexCount) {
- int newVertexCount = this.vertexCount * 2;
- Initializer.LOGGER.info("Reallocating AutoIndexBuffer from {} to {}", this.vertexCount, newVertexCount);
-
- this.indexBuffer.scheduleFree();
- createIndexBuffer(newVertexCount);
- }
- }
-
- public IndexBuffer getIndexBuffer() { return this.indexBuffer; }
-
- public void freeBuffer() {
- this.indexBuffer.scheduleFree();
- }
- public int getIndexCount(int vertexCount) {
- return getIndexCount(this.drawType, vertexCount);
- }
-
public static int getIndexCount(DrawType drawType, int vertexCount) {
switch (drawType) {
case QUADS, LINES -> {
@@ -107,7 +54,7 @@ public static ByteBuffer genQuadIndices(int vertexCount) {
ShortBuffer idxs = buffer.asShortBuffer();
int j = 0;
- for(int i = 0; i < vertexCount; i += 4) {
+ for (int i = 0; i < vertexCount; i += 4) {
idxs.put(j + 0, (short) (i));
idxs.put(j + 1, (short) (i + 1));
idxs.put(j + 2, (short) (i + 2));
@@ -129,7 +76,7 @@ public static ByteBuffer genIntQuadIndices(int vertexCount) {
IntBuffer idxs = buffer.asIntBuffer();
int j = 0;
- for(int i = 0; i < vertexCount; i += 4) {
+ for (int i = 0; i < vertexCount; i += 4) {
idxs.put(j + 0, (i));
idxs.put(j + 1, (i + 1));
idxs.put(j + 2, (i + 2));
@@ -151,7 +98,7 @@ public static ByteBuffer genLinesIndices(int vertexCount) {
ShortBuffer idxs = buffer.asShortBuffer();
int j = 0;
- for(int i = 0; i < vertexCount; i += 4) {
+ for (int i = 0; i < vertexCount; i += 4) {
idxs.put(j + 0, (short) (i));
idxs.put(j + 1, (short) (i + 1));
idxs.put(j + 2, (short) (i + 2));
@@ -221,6 +168,61 @@ public static int roundUpToDivisible(int n, int d) {
return ((n + d - 1) / d) * d;
}
+ private void createIndexBuffer(int vertexCount) {
+ this.vertexCount = vertexCount;
+ ByteBuffer buffer;
+
+ IndexBuffer.IndexType indexType = IndexBuffer.IndexType.UINT16;
+
+ if (vertexCount > U16_MAX_VERTEX_COUNT &&
+ (this.drawType == DrawType.QUADS || this.drawType == DrawType.LINES)) {
+ indexType = IndexBuffer.IndexType.UINT32;
+ }
+
+ switch (this.drawType) {
+ case QUADS -> {
+ if (indexType == IndexBuffer.IndexType.UINT16)
+ buffer = genQuadIndices(vertexCount);
+ else {
+ buffer = genIntQuadIndices(vertexCount);
+ }
+ }
+ case TRIANGLE_FAN -> buffer = genTriangleFanIndices(vertexCount);
+ case TRIANGLE_STRIP -> buffer = genTriangleStripIndices(vertexCount);
+ case LINES -> buffer = genLinesIndices(vertexCount);
+ case DEBUG_LINE_STRIP -> buffer = genDebugLineStripIndices(vertexCount);
+ default -> throw new IllegalArgumentException("Unsupported drawType: %s".formatted(this.drawType));
+ }
+
+ int size = buffer.capacity();
+ this.indexBuffer = new IndexBuffer(size, MemoryTypes.GPU_MEM, indexType);
+ this.indexBuffer.copyBuffer(buffer, buffer.remaining());
+
+ MemoryUtil.memFree(buffer);
+ }
+
+ public void checkCapacity(int vertexCount) {
+ if (vertexCount > this.vertexCount) {
+ int newVertexCount = this.vertexCount * 2;
+ Initializer.LOGGER.info("Reallocating AutoIndexBuffer from {} to {}", this.vertexCount, newVertexCount);
+
+ this.indexBuffer.scheduleFree();
+ createIndexBuffer(newVertexCount);
+ }
+ }
+
+ public IndexBuffer getIndexBuffer() {
+ return this.indexBuffer;
+ }
+
+ public void freeBuffer() {
+ this.indexBuffer.scheduleFree();
+ }
+
+ public int getIndexCount(int vertexCount) {
+ return getIndexCount(this.drawType, vertexCount);
+ }
+
public enum DrawType {
QUADS(7),
TRIANGLE_FAN(6),
diff --git a/src/main/java/net/vulkanmod/vulkan/pass/DefaultMainPass.java b/src/main/java/net/vulkanmod/vulkan/pass/DefaultMainPass.java
index d063a42e6..66efe36b9 100644
--- a/src/main/java/net/vulkanmod/vulkan/pass/DefaultMainPass.java
+++ b/src/main/java/net/vulkanmod/vulkan/pass/DefaultMainPass.java
@@ -9,26 +9,19 @@
import net.vulkanmod.vulkan.framebuffer.SwapChain;
import net.vulkanmod.vulkan.texture.VTextureSelector;
import net.vulkanmod.vulkan.texture.VulkanImage;
-import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer;
-import org.lwjgl.vulkan.VkRect2D;
-import org.lwjgl.vulkan.VkViewport;
+
+import java.lang.foreign.Arena;
import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
import static org.lwjgl.vulkan.VK10.*;
public class DefaultMainPass implements MainPass {
- public static DefaultMainPass create() {
- return new DefaultMainPass();
- }
-
- private RenderTarget mainTarget;
private final Framebuffer mainFramebuffer;
-
+ private RenderTarget mainTarget;
private RenderPass mainRenderPass;
private RenderPass auxRenderPass;
-
private VkGlTexture[] colorAttachmentTextures;
DefaultMainPass() {
@@ -39,6 +32,10 @@ public static DefaultMainPass create() {
createSwapChainTextures();
}
+ public static DefaultMainPass create() {
+ return new DefaultMainPass();
+ }
+
private void createRenderPasses() {
RenderPass.Builder builder = RenderPass.builder(this.mainFramebuffer);
builder.getColorAttachmentInfo().setFinalLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@@ -57,28 +54,26 @@ private void createRenderPasses() {
}
@Override
- public void begin(VkCommandBuffer commandBuffer, MemoryStack stack) {
+ public void begin(VkCommandBuffer commandBuffer) {
SwapChain framebuffer = Renderer.getInstance().getSwapChain();
- VulkanImage colorAttachment = framebuffer.getColorAttachment();
- colorAttachment.transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
- framebuffer.beginRenderPass(commandBuffer, this.mainRenderPass, stack);
-
- VkViewport.Buffer pViewport = framebuffer.viewport(stack);
- vkCmdSetViewport(commandBuffer, 0, pViewport);
+ try (Arena arena = Arena.ofConfined()) {
+ VulkanImage colorAttachment = framebuffer.getColorAttachment();
+ VulkanImage.transitionImageLayout(arena, commandBuffer, colorAttachment, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ }
- VkRect2D.Buffer pScissor = framebuffer.scissor(stack);
- vkCmdSetScissor(commandBuffer, 0, pScissor);
+ framebuffer.beginRenderPass(commandBuffer, this.mainRenderPass);
+ framebuffer.applyViewport(commandBuffer);
+ framebuffer.applyScissor(commandBuffer);
}
@Override
public void end(VkCommandBuffer commandBuffer) {
Renderer.getInstance().endRenderPass(commandBuffer);
- try (MemoryStack stack = MemoryStack.stackPush()) {
+ try (Arena arena = Arena.ofConfined()) {
SwapChain framebuffer = Renderer.getInstance().getSwapChain();
- framebuffer.getColorAttachment().transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+ VulkanImage.transitionImageLayout(arena, commandBuffer, framebuffer.getColorAttachment(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
int result = vkEndCommandBuffer(commandBuffer);
@@ -109,10 +104,7 @@ public void rebindMainTarget() {
Renderer.getInstance().endRenderPass(commandBuffer);
- try (MemoryStack stack = MemoryStack.stackPush()) {
- swapChain.beginRenderPass(commandBuffer, this.auxRenderPass, stack);
- }
-
+ swapChain.beginRenderPass(commandBuffer, this.auxRenderPass);
}
@Override
@@ -125,8 +117,8 @@ public void bindAsTexture() {
if (boundRenderPass == this.mainRenderPass || boundRenderPass == this.auxRenderPass)
Renderer.getInstance().endRenderPass(commandBuffer);
- try (MemoryStack stack = MemoryStack.stackPush()) {
- swapChain.getColorAttachment().transitionImageLayout(stack, commandBuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ try (Arena arena = Arena.ofConfined()) {
+ VulkanImage.transitionImageLayout(arena, commandBuffer, swapChain.getColorAttachment(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
VTextureSelector.bindTexture(swapChain.getColorAttachment());
diff --git a/src/main/java/net/vulkanmod/vulkan/pass/MainPass.java b/src/main/java/net/vulkanmod/vulkan/pass/MainPass.java
index 7ce219748..aeb28a538 100644
--- a/src/main/java/net/vulkanmod/vulkan/pass/MainPass.java
+++ b/src/main/java/net/vulkanmod/vulkan/pass/MainPass.java
@@ -1,12 +1,11 @@
package net.vulkanmod.vulkan.pass;
import net.vulkanmod.gl.VkGlTexture;
-import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer;
public interface MainPass {
- void begin(VkCommandBuffer commandBuffer, MemoryStack stack);
+ void begin(VkCommandBuffer commandBuffer);
void end(VkCommandBuffer commandBuffer);
@@ -14,13 +13,17 @@ public interface MainPass {
void onResize();
- default void mainTargetBindWrite() {}
+ default void mainTargetBindWrite() {
+ }
- default void mainTargetUnbindWrite() {}
+ default void mainTargetUnbindWrite() {
+ }
- default void rebindMainTarget() {}
+ default void rebindMainTarget() {
+ }
- default void bindAsTexture() {}
+ default void bindAsTexture() {
+ }
default VkGlTexture getColorAttachment() {
throw new UnsupportedOperationException();
diff --git a/src/main/java/net/vulkanmod/vulkan/queue/CommandPool.java b/src/main/java/net/vulkanmod/vulkan/queue/CommandPool.java
index d6de2982e..70ae58396 100644
--- a/src/main/java/net/vulkanmod/vulkan/queue/CommandPool.java
+++ b/src/main/java/net/vulkanmod/vulkan/queue/CommandPool.java
@@ -14,10 +14,9 @@
import static org.lwjgl.vulkan.VK10.*;
public class CommandPool {
- long id;
-
private final List commandBuffers = new ObjectArrayList<>();
private final java.util.Queue availableCmdBuffers = new ArrayDeque<>();
+ long id;
CommandPool(int queueFamilyIndex) {
this.createCommandPool(queueFamilyIndex);
diff --git a/src/main/java/net/vulkanmod/vulkan/queue/GraphicsQueue.java b/src/main/java/net/vulkanmod/vulkan/queue/GraphicsQueue.java
index e449f617b..f7f25a411 100644
--- a/src/main/java/net/vulkanmod/vulkan/queue/GraphicsQueue.java
+++ b/src/main/java/net/vulkanmod/vulkan/queue/GraphicsQueue.java
@@ -1,13 +1,9 @@
package net.vulkanmod.vulkan.queue;
import net.vulkanmod.vulkan.Synchronization;
-import net.vulkanmod.vulkan.Vulkan;
-import net.vulkanmod.vulkan.memory.MemoryManager;
-import net.vulkanmod.vulkan.util.VUtil;
import org.lwjgl.system.MemoryStack;
-import org.lwjgl.vulkan.*;
-import static org.lwjgl.vulkan.VK10.*;
+import static org.lwjgl.vulkan.VK10.VK_NULL_HANDLE;
public class GraphicsQueue extends Queue {
public static GraphicsQueue INSTANCE;
diff --git a/src/main/java/net/vulkanmod/vulkan/queue/Queue.java b/src/main/java/net/vulkanmod/vulkan/queue/Queue.java
index c6bb61182..f548b7c27 100644
--- a/src/main/java/net/vulkanmod/vulkan/queue/Queue.java
+++ b/src/main/java/net/vulkanmod/vulkan/queue/Queue.java
@@ -25,15 +25,6 @@ public abstract class Queue {
protected CommandPool commandPool;
- public synchronized CommandPool.CommandBuffer beginCommands() {
- try (MemoryStack stack = stackPush()) {
- CommandPool.CommandBuffer commandBuffer = this.commandPool.getCommandBuffer(stack);
- commandBuffer.begin(stack);
-
- return commandBuffer;
- }
- }
-
Queue(MemoryStack stack, int familyIndex) {
this(stack, familyIndex, true);
}
@@ -47,35 +38,6 @@ public synchronized CommandPool.CommandBuffer beginCommands() {
this.commandPool = new CommandPool(familyIndex);
}
- public synchronized long submitCommands(CommandPool.CommandBuffer commandBuffer) {
- try (MemoryStack stack = stackPush()) {
- return commandBuffer.submitCommands(stack, queue, false);
- }
- }
-
- public VkQueue queue() {
- return this.queue;
- }
-
- public void cleanUp() {
- if (commandPool != null)
- commandPool.cleanUp();
- }
-
- public void waitIdle() {
- vkQueueWaitIdle(queue);
- }
-
- public CommandPool getCommandPool() {
- return commandPool;
- }
-
- public enum Family {
- Graphics,
- Transfer,
- Compute
- }
-
public static QueueFamilyIndices getQueueFamilies() {
if (device == null)
device = Vulkan.getVkDevice();
@@ -191,6 +153,44 @@ public static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
}
}
+ public synchronized CommandPool.CommandBuffer beginCommands() {
+ try (MemoryStack stack = stackPush()) {
+ CommandPool.CommandBuffer commandBuffer = this.commandPool.getCommandBuffer(stack);
+ commandBuffer.begin(stack);
+
+ return commandBuffer;
+ }
+ }
+
+ public synchronized long submitCommands(CommandPool.CommandBuffer commandBuffer) {
+ try (MemoryStack stack = stackPush()) {
+ return commandBuffer.submitCommands(stack, queue, false);
+ }
+ }
+
+ public VkQueue queue() {
+ return this.queue;
+ }
+
+ public void cleanUp() {
+ if (commandPool != null)
+ commandPool.cleanUp();
+ }
+
+ public void waitIdle() {
+ vkQueueWaitIdle(queue);
+ }
+
+ public CommandPool getCommandPool() {
+ return commandPool;
+ }
+
+ public enum Family {
+ Graphics,
+ Transfer,
+ Compute
+ }
+
public static class QueueFamilyIndices {
public int graphicsFamily = VK_QUEUE_FAMILY_IGNORED;
public int presentFamily = VK_QUEUE_FAMILY_IGNORED;
diff --git a/src/main/java/net/vulkanmod/vulkan/queue/TransferQueue.java b/src/main/java/net/vulkanmod/vulkan/queue/TransferQueue.java
index 4cd17c4d6..7f83744f2 100644
--- a/src/main/java/net/vulkanmod/vulkan/queue/TransferQueue.java
+++ b/src/main/java/net/vulkanmod/vulkan/queue/TransferQueue.java
@@ -19,6 +19,19 @@ public TransferQueue(MemoryStack stack, int familyIndex) {
super(stack, familyIndex);
}
+ public static void uploadBufferCmd(VkCommandBuffer commandBuffer, long srcBuffer, long srcOffset, long dstBuffer, long dstOffset, long size) {
+
+ try (MemoryStack stack = stackPush()) {
+
+ VkBufferCopy.Buffer copyRegion = VkBufferCopy.calloc(1, stack);
+ copyRegion.size(size);
+ copyRegion.srcOffset(srcOffset);
+ copyRegion.dstOffset(dstOffset);
+
+ vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, copyRegion);
+ }
+ }
+
public long copyBufferCmd(long srcBuffer, long srcOffset, long dstBuffer, long dstOffset, long size) {
try (MemoryStack stack = stackPush()) {
@@ -57,17 +70,4 @@ public void uploadBufferImmediate(long srcBuffer, long srcOffset, long dstBuffer
}
}
- public static void uploadBufferCmd(VkCommandBuffer commandBuffer, long srcBuffer, long srcOffset, long dstBuffer, long dstOffset, long size) {
-
- try (MemoryStack stack = stackPush()) {
-
- VkBufferCopy.Buffer copyRegion = VkBufferCopy.calloc(1, stack);
- copyRegion.size(size);
- copyRegion.srcOffset(srcOffset);
- copyRegion.dstOffset(dstOffset);
-
- vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, copyRegion);
- }
- }
-
}
diff --git a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java
index d94ad1b02..422bd82bd 100644
--- a/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java
+++ b/src/main/java/net/vulkanmod/vulkan/shader/GraphicsPipeline.java
@@ -16,7 +16,6 @@
import java.nio.LongBuffer;
import java.util.List;
-import static org.lwjgl.system.MemoryStack.stackGet;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.vulkan.VK10.*;
@@ -44,16 +43,147 @@ public class GraphicsPipeline extends Pipeline {
createShaderModules(builder.vertShaderSPIRV, builder.fragShaderSPIRV);
if (builder.renderPass != null)
- graphicsPipelines.computeIfAbsent(PipelineState.DEFAULT,
- this::createGraphicsPipeline);
+ graphicsPipelines.computeLongIfAbsent(PipelineState.DEFAULT, this::createGraphicsPipeline);
createDescriptorSets(Renderer.getFramesNum());
PIPELINES.add(this);
}
+ private static VkVertexInputBindingDescription.Buffer getBindingDescription(VertexFormat vertexFormat) {
+ VkVertexInputBindingDescription.Buffer bindingDescription = VkVertexInputBindingDescription.calloc(1);
+
+ bindingDescription.binding(0);
+ bindingDescription.stride(vertexFormat.getVertexSize());
+ bindingDescription.inputRate(VK_VERTEX_INPUT_RATE_VERTEX);
+
+ return bindingDescription;
+ }
+
+ private static VkVertexInputAttributeDescription.Buffer getAttributeDescriptions(VertexFormat vertexFormat) {
+ List elements = vertexFormat.getElements();
+
+ int size = elements.size();
+
+ VkVertexInputAttributeDescription.Buffer attributeDescriptions = VkVertexInputAttributeDescription.calloc(size);
+
+ int offset = 0;
+
+ for (int i = 0; i < size; ++i) {
+ VkVertexInputAttributeDescription posDescription = attributeDescriptions.get(i);
+ posDescription.binding(0);
+ posDescription.location(i);
+
+ VertexFormatElement formatElement = elements.get(i);
+ VertexFormatElement.Usage usage = formatElement.usage();
+ VertexFormatElement.Type type = formatElement.type();
+ int elementCount = formatElement.count();
+
+ switch (usage) {
+ case POSITION -> {
+ switch (type) {
+ case FLOAT -> {
+ posDescription.format(VK_FORMAT_R32G32B32_SFLOAT);
+ posDescription.offset(offset);
+
+ offset += 12;
+ }
+ case SHORT -> {
+ posDescription.format(VK_FORMAT_R16G16B16A16_SINT);
+ posDescription.offset(offset);
+
+ offset += 8;
+ }
+ case BYTE -> {
+ posDescription.format(VK_FORMAT_R8G8B8A8_SINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ }
+
+ }
+
+ case COLOR -> {
+ switch (type) {
+ case UBYTE -> {
+ posDescription.format(VK_FORMAT_R8G8B8A8_UNORM);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ case UINT -> {
+ posDescription.format(VK_FORMAT_R32_UINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ }
+ }
+
+ case UV -> {
+ switch (type) {
+ case FLOAT -> {
+ posDescription.format(VK_FORMAT_R32G32_SFLOAT);
+ posDescription.offset(offset);
+
+ offset += 8;
+ }
+ case SHORT -> {
+ posDescription.format(VK_FORMAT_R16G16_SINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ case USHORT -> {
+ posDescription.format(VK_FORMAT_R16G16_UINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ case UINT -> {
+ posDescription.format(VK_FORMAT_R32_UINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+ }
+ }
+
+ case NORMAL -> {
+ posDescription.format(VK_FORMAT_R8G8B8A8_SNORM);
+ posDescription.offset(offset);
+
+ offset += 4;
+ }
+
+ case GENERIC -> {
+ if (type == VertexFormatElement.Type.SHORT && elementCount == 1) {
+ posDescription.format(VK_FORMAT_R16_SINT);
+ posDescription.offset(offset);
+
+ offset += 2;
+ } else if (type == VertexFormatElement.Type.INT && elementCount == 1) {
+ posDescription.format(VK_FORMAT_R32_SINT);
+ posDescription.offset(offset);
+
+ offset += 4;
+ } else {
+ throw new RuntimeException(String.format("Unknown format: %s", usage));
+ }
+ }
+
+ default -> throw new RuntimeException(String.format("Unknown format: %s", usage));
+ }
+
+ posDescription.offset(((VertexFormatMixed) (vertexFormat)).getOffset(i));
+ }
+
+ return attributeDescriptions.rewind();
+ }
+
public long getHandle(PipelineState state) {
- return graphicsPipelines.computeIfAbsent(state, this::createGraphicsPipeline);
+ return graphicsPipelines.computeLongIfAbsent(state, this::createGraphicsPipeline);
}
private long createGraphicsPipeline(PipelineState state) {
@@ -147,8 +277,7 @@ private long createGraphicsPipeline(PipelineState state) {
colorBlendAttachment.srcAlphaBlendFactor(PipelineState.BlendState.getSrcAlphaFactor(state.blendState_i));
colorBlendAttachment.dstAlphaBlendFactor(PipelineState.BlendState.getDstAlphaFactor(state.blendState_i));
colorBlendAttachment.alphaBlendOp(PipelineState.BlendState.blendOp(state.blendState_i));
- }
- else {
+ } else {
colorBlendAttachment.blendEnable(false);
}
@@ -165,13 +294,9 @@ private long createGraphicsPipeline(PipelineState state) {
dynamicStates.sType(VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO);
if (topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST || polygonMode == VK_POLYGON_MODE_LINE) {
- dynamicStates.pDynamicStates(
- stack.ints(VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
- VK_DYNAMIC_STATE_LINE_WIDTH));
- }
- else {
- dynamicStates.pDynamicStates(
- stack.ints(VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR));
+ dynamicStates.pDynamicStates(stack.ints(VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_LINE_WIDTH));
+ } else {
+ dynamicStates.pDynamicStates(stack.ints(VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR));
}
VkGraphicsPipelineCreateInfo.Buffer pipelineInfo = VkGraphicsPipelineCreateInfo.calloc(1, stack);
@@ -192,8 +317,7 @@ private long createGraphicsPipeline(PipelineState state) {
if (!Vulkan.DYNAMIC_RENDERING) {
pipelineInfo.renderPass(state.renderPass.getId());
pipelineInfo.subpass(0);
- }
- else {
+ } else {
//dyn-rendering
VkPipelineRenderingCreateInfoKHR renderingInfo = VkPipelineRenderingCreateInfoKHR.calloc(stack);
renderingInfo.sType(KHRDynamicRendering.VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR);
@@ -204,8 +328,7 @@ private long createGraphicsPipeline(PipelineState state) {
LongBuffer pGraphicsPipeline = stack.mallocLong(1);
- Vulkan.checkResult(vkCreateGraphicsPipelines(DeviceManager.vkDevice, PIPELINE_CACHE, pipelineInfo, null, pGraphicsPipeline),
- "Failed to create graphics pipeline " + this.name);
+ Vulkan.checkResult(vkCreateGraphicsPipelines(DeviceManager.vkDevice, PIPELINE_CACHE, pipelineInfo, null, pGraphicsPipeline), "Failed to create graphics pipeline " + this.name);
return pGraphicsPipeline.get(0);
}
@@ -250,138 +373,4 @@ void cleanUp() {
MemoryUtil.memFree(this.attributeDescriptions);
}
}
-
- private static VkVertexInputBindingDescription.Buffer getBindingDescription(VertexFormat vertexFormat) {
- VkVertexInputBindingDescription.Buffer bindingDescription = VkVertexInputBindingDescription.calloc(1);
-
- bindingDescription.binding(0);
- bindingDescription.stride(vertexFormat.getVertexSize());
- bindingDescription.inputRate(VK_VERTEX_INPUT_RATE_VERTEX);
-
- return bindingDescription;
- }
-
- private static VkVertexInputAttributeDescription.Buffer getAttributeDescriptions(VertexFormat vertexFormat) {
- List elements = vertexFormat.getElements();
-
- int size = elements.size();
-
- VkVertexInputAttributeDescription.Buffer attributeDescriptions = VkVertexInputAttributeDescription.calloc(size);
-
- int offset = 0;
-
- for (int i = 0; i < size; ++i) {
- VkVertexInputAttributeDescription posDescription = attributeDescriptions.get(i);
- posDescription.binding(0);
- posDescription.location(i);
-
- VertexFormatElement formatElement = elements.get(i);
- VertexFormatElement.Usage usage = formatElement.usage();
- VertexFormatElement.Type type = formatElement.type();
- int elementCount = formatElement.count();
-
- switch (usage) {
- case POSITION -> {
- switch (type) {
- case FLOAT -> {
- posDescription.format(VK_FORMAT_R32G32B32_SFLOAT);
- posDescription.offset(offset);
-
- offset += 12;
- }
- case SHORT -> {
- posDescription.format(VK_FORMAT_R16G16B16A16_SINT);
- posDescription.offset(offset);
-
- offset += 8;
- }
- case BYTE -> {
- posDescription.format(VK_FORMAT_R8G8B8A8_SINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- }
-
- }
-
- case COLOR -> {
- switch (type) {
- case UBYTE -> {
- posDescription.format(VK_FORMAT_R8G8B8A8_UNORM);
- posDescription.offset(offset);
-
- offset += 4;
- }
- case UINT -> {
- posDescription.format(VK_FORMAT_R32_UINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- }
- }
-
- case UV -> {
- switch (type) {
- case FLOAT -> {
- posDescription.format(VK_FORMAT_R32G32_SFLOAT);
- posDescription.offset(offset);
-
- offset += 8;
- }
- case SHORT -> {
- posDescription.format(VK_FORMAT_R16G16_SINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- case USHORT -> {
- posDescription.format(VK_FORMAT_R16G16_UINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- case UINT -> {
- posDescription.format(VK_FORMAT_R32_UINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- }
- }
-
- case NORMAL -> {
- posDescription.format(VK_FORMAT_R8G8B8A8_SNORM);
- posDescription.offset(offset);
-
- offset += 4;
- }
-
- case GENERIC -> {
- if (type == VertexFormatElement.Type.SHORT && elementCount == 1) {
- posDescription.format(VK_FORMAT_R16_SINT);
- posDescription.offset(offset);
-
- offset += 2;
- }
- else if (type == VertexFormatElement.Type.INT && elementCount == 1) {
- posDescription.format(VK_FORMAT_R32_SINT);
- posDescription.offset(offset);
-
- offset += 4;
- }
- else {
- throw new RuntimeException(String.format("Unknown format: %s", usage));
- }
- }
-
- default -> throw new RuntimeException(String.format("Unknown format: %s", usage));
- }
-
- posDescription.offset(((VertexFormatMixed) (vertexFormat)).getOffset(i));
- }
-
- return attributeDescriptions.rewind();
- }
}
diff --git a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java
index 49d146cf2..8bb7347a5 100644
--- a/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java
+++ b/src/main/java/net/vulkanmod/vulkan/shader/Pipeline.java
@@ -42,9 +42,20 @@
public abstract class Pipeline {
+ protected static final List PIPELINES = new LinkedList<>();
private static final VkDevice DEVICE = Vulkan.getVkDevice();
protected static final long PIPELINE_CACHE = createPipelineCache();
- protected static final List PIPELINES = new LinkedList<>();
+ public final String name;
+ protected long descriptorSetLayout;
+ protected long pipelineLayout;
+ protected DescriptorSets[] descriptorSets;
+ protected List buffers;
+ protected ManualUBO manualUBO;
+ protected List imageDescriptors;
+ protected PushConstants pushConstants;
+ public Pipeline(String name) {
+ this.name = name;
+ }
private static long createPipelineCache() {
try (MemoryStack stack = stackPush()) {
@@ -73,19 +84,23 @@ public static void recreateDescriptorSets(int frames) {
});
}
- public final String name;
+ static long createShaderModule(ByteBuffer spirvCode) {
- protected long descriptorSetLayout;
- protected long pipelineLayout;
+ try (MemoryStack stack = stackPush()) {
- protected DescriptorSets[] descriptorSets;
- protected List buffers;
- protected ManualUBO manualUBO;
- protected List imageDescriptors;
- protected PushConstants pushConstants;
+ VkShaderModuleCreateInfo createInfo = VkShaderModuleCreateInfo.calloc(stack);
- public Pipeline(String name) {
- this.name = name;
+ createInfo.sType(VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);
+ createInfo.pCode(spirvCode);
+
+ LongBuffer pShaderModule = stack.mallocLong(1);
+
+ if (vkCreateShaderModule(DEVICE, createInfo, null, pShaderModule) != VK_SUCCESS) {
+ throw new RuntimeException("Failed to create shader module");
+ }
+
+ return pShaderModule.get(0);
+ }
}
protected void createDescriptorSetLayout() {
@@ -179,8 +194,7 @@ public ManualUBO getManualUBO() {
}
public void resetDescriptorPool(int i) {
- if (this.descriptorSets != null)
- this.descriptorSets[i].resetIdx();
+ if (this.descriptorSets != null) this.descriptorSets[i].resetIdx();
}
@@ -205,37 +219,17 @@ public void bindDescriptorSets(VkCommandBuffer commandBuffer, UniformBuffer unif
this.descriptorSets[frame].bindSets(commandBuffer, uniformBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS);
}
- static long createShaderModule(ByteBuffer spirvCode) {
-
- try (MemoryStack stack = stackPush()) {
-
- VkShaderModuleCreateInfo createInfo = VkShaderModuleCreateInfo.calloc(stack);
-
- createInfo.sType(VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);
- createInfo.pCode(spirvCode);
-
- LongBuffer pShaderModule = stack.mallocLong(1);
-
- if (vkCreateShaderModule(DEVICE, createInfo, null, pShaderModule) != VK_SUCCESS) {
- throw new RuntimeException("Failed to create shader module");
- }
-
- return pShaderModule.get(0);
- }
- }
-
protected static class DescriptorSets {
private final Pipeline pipeline;
+ private final long[] boundUBs;
+ private final ImageDescriptor.State[] boundTextures;
+ private final IntBuffer dynamicOffsets;
private int poolSize = 10;
private long descriptorPool;
private LongBuffer sets;
private long currentSet;
private int currentIdx = -1;
- private final long[] boundUBs;
- private final ImageDescriptor.State[] boundTextures;
- private final IntBuffer dynamicOffsets;
-
DescriptorSets(Pipeline pipeline) {
this.pipeline = pipeline;
this.boundTextures = new ImageDescriptor.State[pipeline.imageDescriptors.size()];
@@ -256,8 +250,7 @@ protected void bindSets(VkCommandBuffer commandBuffer, UniformBuffer uniformBuff
this.updateUniforms(uniformBuffer);
this.updateDescriptorSet(stack, uniformBuffer);
- vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipeline.pipelineLayout,
- 0, stack.longs(currentSet), dynamicOffsets);
+ vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipeline.pipelineLayout, 0, stack.longs(currentSet), dynamicOffsets);
}
}
@@ -285,8 +278,7 @@ private void updateUniforms(UniformBuffer globalUB) {
}
private boolean needsUpdate(UniformBuffer uniformBuffer) {
- if (currentIdx == -1)
- return true;
+ if (currentIdx == -1) return true;
for (int j = 0; j < pipeline.imageDescriptors.size(); ++j) {
ImageDescriptor imageDescriptor = pipeline.imageDescriptors.get(j);
@@ -294,8 +286,7 @@ private boolean needsUpdate(UniformBuffer uniformBuffer) {
long view = imageDescriptor.getImageView(image);
long sampler = image.getSampler();
- if (imageDescriptor.isReadOnlyLayout)
- image.readOnlyLayout();
+ if (imageDescriptor.isReadOnlyLayout) image.readOnlyLayout();
if (!this.boundTextures[j].isCurrentState(view, sampler)) {
return true;
@@ -306,8 +297,7 @@ private boolean needsUpdate(UniformBuffer uniformBuffer) {
UBO ubo = pipeline.buffers.get(j);
UniformBuffer uniformBufferI = ubo.getUniformBuffer();
- if (uniformBufferI == null)
- uniformBufferI = uniformBuffer;
+ if (uniformBufferI == null) uniformBufferI = uniformBuffer;
if (this.boundUBs[j] != uniformBufferI.getId()) {
return true;
@@ -333,8 +323,7 @@ private void checkPoolSize(MemoryStack stack) {
private void updateDescriptorSet(MemoryStack stack, UniformBuffer uniformBuffer) {
//Check if update is needed
- if (!needsUpdate(uniformBuffer))
- return;
+ if (!needsUpdate(uniformBuffer)) return;
this.currentIdx++;
@@ -350,8 +339,7 @@ private void updateDescriptorSet(MemoryStack stack, UniformBuffer uniformBuffer)
int i = 0;
for (UBO ubo : pipeline.buffers) {
UniformBuffer ub = ubo.getUniformBuffer();
- if (ub == null)
- ub = uniformBuffer;
+ if (ub == null) ub = uniformBuffer;
boundUBs[i] = ub.getId();
bufferInfos[i] = VkDescriptorBufferInfo.calloc(1, stack);
@@ -379,15 +367,13 @@ private void updateDescriptorSet(MemoryStack stack, UniformBuffer uniformBuffer)
long sampler = image.getSampler();
int layout = imageDescriptor.getLayout();
- if (imageDescriptor.isReadOnlyLayout)
- image.readOnlyLayout();
+ if (imageDescriptor.isReadOnlyLayout) image.readOnlyLayout();
imageInfo[j] = VkDescriptorImageInfo.calloc(1, stack);
imageInfo[j].imageLayout(layout);
imageInfo[j].imageView(view);
- if (imageDescriptor.useSampler)
- imageInfo[j].sampler(sampler);
+ if (imageDescriptor.useSampler) imageInfo[j].sampler(sampler);
VkWriteDescriptorSet samplerDescriptorWrite = descriptorWrites.get(i);
samplerDescriptorWrite.sType(VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET);
@@ -508,13 +494,21 @@ public Builder() {
this(null, null);
}
+ public static int getStageFromString(String s) {
+ return switch (s) {
+ case "vertex" -> VK_SHADER_STAGE_VERTEX_BIT;
+ case "fragment" -> VK_SHADER_STAGE_FRAGMENT_BIT;
+ case "all" -> VK_SHADER_STAGE_ALL_GRAPHICS;
+ case "compute" -> VK_SHADER_STAGE_COMPUTE_BIT;
+
+ default -> throw new RuntimeException("cannot identify type..");
+ };
+ }
+
public GraphicsPipeline createGraphicsPipeline() {
- Validate.isTrue(this.imageDescriptors != null && this.UBOs != null
- && this.vertShaderSPIRV != null && this.fragShaderSPIRV != null,
- "Cannot create Pipeline: resources missing");
+ Validate.isTrue(this.imageDescriptors != null && this.UBOs != null && this.vertShaderSPIRV != null && this.fragShaderSPIRV != null, "Cannot create Pipeline: resources missing");
- if (this.manualUBO != null)
- this.UBOs.add(this.manualUBO);
+ if (this.manualUBO != null) this.UBOs.add(this.manualUBO);
return new GraphicsPipeline(this);
}
@@ -603,8 +597,7 @@ private void parseUboNode(JsonElement jsonelement) {
}
uniformInfo.setBufferSupplier(uniformSupplier);
- }
- else {
+ } else {
throw new IllegalStateException("No uniform supplier found for uniform: (%s:%s)".formatted(type2, name));
}
}
@@ -614,8 +607,7 @@ private void parseUboNode(JsonElement jsonelement) {
UBO ubo = builder.buildUBO(binding, type);
- if (binding >= this.nextBinding)
- this.nextBinding = binding + 1;
+ if (binding >= this.nextBinding) this.nextBinding = binding + 1;
this.UBOs.add(ubo);
}
@@ -626,8 +618,7 @@ private void parseManualUboNode(JsonElement jsonelement) {
int stage = getStageFromString(GsonHelper.getAsString(jsonobject, "type"));
int size = GsonHelper.getAsInt(jsonobject, "size");
- if (binding >= this.nextBinding)
- this.nextBinding = binding + 1;
+ if (binding >= this.nextBinding) this.nextBinding = binding + 1;
this.manualUBO = new ManualUBO(binding, stage, size);
}
@@ -659,16 +650,5 @@ private void parsePushConstantNode(JsonArray jsonArray) {
this.pushConstants = builder.buildPushConstant();
}
-
- public static int getStageFromString(String s) {
- return switch (s) {
- case "vertex" -> VK_SHADER_STAGE_VERTEX_BIT;
- case "fragment" -> VK_SHADER_STAGE_FRAGMENT_BIT;
- case "all" -> VK_SHADER_STAGE_ALL_GRAPHICS;
- case "compute" -> VK_SHADER_STAGE_COMPUTE_BIT;
-
- default -> throw new RuntimeException("cannot identify type..");
- };
- }
}
}
diff --git a/src/main/java/net/vulkanmod/vulkan/shader/PipelineState.java b/src/main/java/net/vulkanmod/vulkan/shader/PipelineState.java
index 8015cbf1b..cc651410e 100644
--- a/src/main/java/net/vulkanmod/vulkan/shader/PipelineState.java
+++ b/src/main/java/net/vulkanmod/vulkan/shader/PipelineState.java
@@ -1,6 +1,8 @@
package net.vulkanmod.vulkan.shader;
-import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.opengl.GlConst;
+import com.mojang.blaze3d.platform.DestFactor;
+import com.mojang.blaze3d.platform.SourceFactor;
import net.vulkanmod.vulkan.VRenderSystem;
import net.vulkanmod.vulkan.framebuffer.RenderPass;
@@ -17,6 +19,22 @@ public class PipelineState {
public static final PipelineState DEFAULT = new PipelineState(getAssemblyRasterState(), getBlendState(), getDepthState(), getLogicOpState(), VRenderSystem.getColorMask(), null);
public static PipelineState currentState = DEFAULT;
+ final RenderPass renderPass;
+ int assemblyRasterState;
+ int blendState_i;
+ int depthState_i;
+ int colorMask_i;
+ int logicOp_i;
+
+ public PipelineState(int assemblyRasterState, int blendState, int depthState, int logicOp, int colorMask, RenderPass renderPass) {
+ this.renderPass = renderPass;
+
+ this.assemblyRasterState = assemblyRasterState;
+ this.blendState_i = blendState;
+ this.depthState_i = depthState;
+ this.colorMask_i = colorMask;
+ this.logicOp_i = logicOp;
+ }
public static PipelineState getCurrentPipelineState(RenderPass renderPass) {
int assemblyRasterState = getAssemblyRasterState();
@@ -60,45 +78,21 @@ public static int getLogicOpState() {
return logicOpState;
}
- final RenderPass renderPass;
-
- int assemblyRasterState;
- int blendState_i;
- int depthState_i;
- int colorMask_i;
- int logicOp_i;
-
- public PipelineState(int assemblyRasterState, int blendState, int depthState, int logicOp, int colorMask,
- RenderPass renderPass) {
- this.renderPass = renderPass;
-
- this.assemblyRasterState = assemblyRasterState;
- this.blendState_i = blendState;
- this.depthState_i = depthState;
- this.colorMask_i = colorMask;
- this.logicOp_i = logicOp;
+ public static BlendInfo defaultBlendInfo() {
+ return new BlendInfo(true, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD);
}
- private boolean checkEquals(int assemblyRasterState, int blendState, int depthState, int logicOp, int colorMask,
- RenderPass renderPass) {
- return (blendState == this.blendState_i) && (depthState == this.depthState_i)
- && renderPass == this.renderPass && logicOp == this.logicOp_i
- && (assemblyRasterState == this.assemblyRasterState)
- && colorMask == this.colorMask_i;
+ private boolean checkEquals(int assemblyRasterState, int blendState, int depthState, int logicOp, int colorMask, RenderPass renderPass) {
+ return (blendState == this.blendState_i) && (depthState == this.depthState_i) && renderPass == this.renderPass && logicOp == this.logicOp_i && (assemblyRasterState == this.assemblyRasterState) && colorMask == this.colorMask_i;
}
@Override
public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
PipelineState that = (PipelineState) o;
- return (blendState_i == that.blendState_i) && (depthState_i == that.depthState_i)
- && this.renderPass == that.renderPass && logicOp_i == that.logicOp_i
- && this.assemblyRasterState == that.assemblyRasterState
- && this.colorMask_i == that.colorMask_i;
+ return (blendState_i == that.blendState_i) && (depthState_i == that.depthState_i) && this.renderPass == that.renderPass && logicOp_i == that.logicOp_i && this.assemblyRasterState == that.assemblyRasterState && this.colorMask_i == that.colorMask_i;
}
@Override
@@ -106,11 +100,6 @@ public int hashCode() {
return Objects.hash(blendState_i, depthState_i, logicOp_i, assemblyRasterState, colorMask_i, renderPass);
}
- public static BlendInfo defaultBlendInfo() {
- return new BlendInfo(true, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
- VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD);
- }
-
public static class BlendInfo {
public boolean enabled;
public int srcRgbFactor;
@@ -119,8 +108,7 @@ public static class BlendInfo {
public int dstAlphaFactor;
public int blendOp;
- public BlendInfo(boolean enabled, int srcRgbFactor, int dstRgbFactor, int srcAlphaFactor, int dstAlphaFactor,
- int blendOp) {
+ public BlendInfo(boolean enabled, int srcRgbFactor, int dstRgbFactor, int srcAlphaFactor, int dstAlphaFactor, int blendOp) {
this.enabled = enabled;
this.srcRgbFactor = srcRgbFactor;
this.dstRgbFactor = dstRgbFactor;
@@ -129,46 +117,6 @@ public BlendInfo(boolean enabled, int srcRgbFactor, int dstRgbFactor, int srcAlp
this.blendOp = blendOp;
}
- public void setBlendFunction(GlStateManager.SourceFactor sourceFactor, GlStateManager.DestFactor destFactor) {
- this.srcRgbFactor = glToVulkanBlendFactor(sourceFactor.value);
- this.srcAlphaFactor = glToVulkanBlendFactor(sourceFactor.value);
- this.dstRgbFactor = glToVulkanBlendFactor(destFactor.value);
- this.dstAlphaFactor = glToVulkanBlendFactor(destFactor.value);
- }
-
- public void setBlendFuncSeparate(GlStateManager.SourceFactor srcRgb, GlStateManager.DestFactor dstRgb,
- GlStateManager.SourceFactor srcAlpha, GlStateManager.DestFactor dstAlpha) {
- this.srcRgbFactor = glToVulkanBlendFactor(srcRgb.value);
- this.srcAlphaFactor = glToVulkanBlendFactor(srcAlpha.value);
- this.dstRgbFactor = glToVulkanBlendFactor(dstRgb.value);
- this.dstAlphaFactor = glToVulkanBlendFactor(dstAlpha.value);
- }
-
- /* gl to Vulkan conversion */
- public void setBlendFunction(int sourceFactor, int destFactor) {
- this.srcRgbFactor = glToVulkanBlendFactor(sourceFactor);
- this.srcAlphaFactor = glToVulkanBlendFactor(sourceFactor);
- this.dstRgbFactor = glToVulkanBlendFactor(destFactor);
- this.dstAlphaFactor = glToVulkanBlendFactor(destFactor);
- }
-
- /* gl to Vulkan conversion */
- public void setBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
- this.srcRgbFactor = glToVulkanBlendFactor(srcRgb);
- this.srcAlphaFactor = glToVulkanBlendFactor(srcAlpha);
- this.dstRgbFactor = glToVulkanBlendFactor(dstRgb);
- this.dstAlphaFactor = glToVulkanBlendFactor(dstAlpha);
- }
-
- public void setBlendOp(int i) {
- this.blendOp = glToVulkanBlendOp(i);
- }
-
-
- public int createBlendState() {
- return BlendState.getState(this);
- }
-
private static int glToVulkanBlendOp(int value) {
return switch (value) {
case 0x8006 -> VK_BLEND_OP_ADD;
@@ -217,6 +165,46 @@ private static int glToVulkanBlendFactor(int value) {
// ZERO(0);
};
}
+
+ public void setBlendFunction(SourceFactor sourceFactor, DestFactor destFactor) {
+ int src = GlConst.toGl(sourceFactor);
+ int dst = GlConst.toGl(destFactor);
+ this.srcRgbFactor = glToVulkanBlendFactor(src);
+ this.srcAlphaFactor = glToVulkanBlendFactor(src);
+ this.dstRgbFactor = glToVulkanBlendFactor(dst);
+ this.dstAlphaFactor = glToVulkanBlendFactor(dst);
+ }
+
+ public void setBlendFuncSeparate(SourceFactor srcRgb, DestFactor dstRgb, SourceFactor srcAlpha, DestFactor dstAlpha) {
+ this.srcRgbFactor = glToVulkanBlendFactor(GlConst.toGl(srcRgb));
+ this.srcAlphaFactor = glToVulkanBlendFactor(GlConst.toGl(srcAlpha));
+ this.dstRgbFactor = glToVulkanBlendFactor(GlConst.toGl(dstRgb));
+ this.dstAlphaFactor = glToVulkanBlendFactor(GlConst.toGl(dstAlpha));
+ }
+
+ /* gl to Vulkan conversion */
+ public void setBlendFunction(int sourceFactor, int destFactor) {
+ this.srcRgbFactor = glToVulkanBlendFactor(sourceFactor);
+ this.srcAlphaFactor = glToVulkanBlendFactor(sourceFactor);
+ this.dstRgbFactor = glToVulkanBlendFactor(destFactor);
+ this.dstAlphaFactor = glToVulkanBlendFactor(destFactor);
+ }
+
+ /* gl to Vulkan conversion */
+ public void setBlendFuncSeparate(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
+ this.srcRgbFactor = glToVulkanBlendFactor(srcRgb);
+ this.srcAlphaFactor = glToVulkanBlendFactor(srcAlpha);
+ this.dstRgbFactor = glToVulkanBlendFactor(dstRgb);
+ this.dstAlphaFactor = glToVulkanBlendFactor(dstAlpha);
+ }
+
+ public void setBlendOp(int i) {
+ this.blendOp = glToVulkanBlendOp(i);
+ }
+
+ public int createBlendState() {
+ return BlendState.getState(this);
+ }
}
public static class BlendState {
@@ -342,10 +330,7 @@ public static int decodeCullMode(int state) {
public static abstract class ColorMask {
public static int getColorMask(boolean r, boolean g, boolean b, boolean a) {
- return (r ? VK_COLOR_COMPONENT_R_BIT : 0)
- | (g ? VK_COLOR_COMPONENT_G_BIT : 0)
- | (b ? VK_COLOR_COMPONENT_B_BIT : 0)
- | (a ? VK_COLOR_COMPONENT_A_BIT : 0);
+ return (r ? VK_COLOR_COMPONENT_R_BIT : 0) | (g ? VK_COLOR_COMPONENT_G_BIT : 0) | (b ? VK_COLOR_COMPONENT_B_BIT : 0) | (a ? VK_COLOR_COMPONENT_A_BIT : 0);
}
}
diff --git a/src/main/java/net/vulkanmod/vulkan/shader/RayTracingPipeline.java b/src/main/java/net/vulkanmod/vulkan/shader/RayTracingPipeline.java
new file mode 100644
index 000000000..212ea901f
--- /dev/null
+++ b/src/main/java/net/vulkanmod/vulkan/shader/RayTracingPipeline.java
@@ -0,0 +1,229 @@
+package net.vulkanmod.vulkan.shader;
+
+import net.vulkanmod.vulkan.device.DeviceManager;
+import net.vulkanmod.vulkan.memory.MemoryTypes;
+import net.vulkanmod.vulkan.memory.buffer.Buffer;
+import org.lwjgl.system.MemoryStack;
+import org.lwjgl.system.MemoryUtil;
+import org.lwjgl.vulkan.*;
+
+import java.nio.ByteBuffer;
+import java.nio.LongBuffer;
+
+import static org.lwjgl.system.MemoryStack.stackPush;
+import static org.lwjgl.vulkan.KHRRayTracingPipeline.*;
+import static org.lwjgl.vulkan.VK10.*;
+import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceProperties2;
+import static org.lwjgl.vulkan.VK12.VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+import static org.lwjgl.vulkan.VK12.vkGetBufferDeviceAddress;
+
+public class RayTracingPipeline extends Pipeline {
+
+ private static final int VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400;
+
+ private long pipelineHandle;
+
+ private long raygenShaderModule = 0;
+ private long missShaderModule = 0;
+ private long chitShaderModule = 0;
+
+ private Buffer shaderBindingTable;
+ private long sbtBufferAddress;
+ private int sbtStride;
+
+ RayTracingPipeline(Builder builder) {
+ super(builder.shaderPath);
+ this.buffers = builder.UBOs;
+ this.manualUBO = builder.manualUBO;
+ this.imageDescriptors = builder.imageDescriptors;
+ this.pushConstants = builder.pushConstants;
+
+ createDescriptorSetLayout();
+ createPipelineLayout();
+ createShaderModules(builder.raygenShaderSPIRV, builder.missShaderSPIRV, builder.chitShaderSPIRV);
+
+ createRayTracingPipeline();
+
+ createDescriptorSets(3); //Renderer.getFramesNum());
+
+ PIPELINES.add(this);
+ }
+
+ private static int alignUp(int value, int alignment) {
+ long aligned = ((long) value + alignment - 1L) / alignment * alignment;
+ return (int) aligned;
+ }
+
+ private void createShaderModules(SPIRVUtils.SPIRV raygenShaderSPIRV, SPIRVUtils.SPIRV missShaderSPIRV, SPIRVUtils.SPIRV chitShaderSPIRV) {
+ this.raygenShaderModule = createShaderModule(raygenShaderSPIRV.bytecode());
+ this.missShaderModule = createShaderModule(missShaderSPIRV.bytecode());
+ this.chitShaderModule = createShaderModule(chitShaderSPIRV.bytecode());
+ }
+
+ private void createRayTracingPipeline() {
+ try (MemoryStack stack = stackPush()) {
+ VkPipelineShaderStageCreateInfo.Buffer shaderStages = VkPipelineShaderStageCreateInfo.calloc(3, stack);
+
+ // Ray Generation Shader
+ shaderStages.get(0).sType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+ shaderStages.get(0).stage(VK_SHADER_STAGE_RAYGEN_BIT_KHR);
+ shaderStages.get(0).module(raygenShaderModule);
+ shaderStages.get(0).pName(stack.UTF8("main"));
+
+ // Miss Shader
+ shaderStages.get(1).sType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+ shaderStages.get(1).stage(VK_SHADER_STAGE_MISS_BIT_KHR);
+ shaderStages.get(1).module(missShaderModule);
+ shaderStages.get(1).pName(stack.UTF8("main"));
+
+ // Closest Hit Shader
+ shaderStages.get(2).sType(VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO);
+ shaderStages.get(2).stage(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
+ shaderStages.get(2).module(chitShaderModule);
+ shaderStages.get(2).pName(stack.UTF8("main"));
+
+ VkRayTracingShaderGroupCreateInfoKHR.Buffer shaderGroups = VkRayTracingShaderGroupCreateInfoKHR.calloc(3, stack);
+
+ // Ray Generation Shader Group
+ shaderGroups.get(0).sType(VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR);
+ shaderGroups.get(0).type(VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR);
+ shaderGroups.get(0).generalShader(0);
+ shaderGroups.get(0).closestHitShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(0).anyHitShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(0).intersectionShader(VK_SHADER_UNUSED_KHR);
+
+ // Miss Shader Group
+ shaderGroups.get(1).sType(VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR);
+ shaderGroups.get(1).type(VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR);
+ shaderGroups.get(1).generalShader(1);
+ shaderGroups.get(1).closestHitShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(1).anyHitShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(1).intersectionShader(VK_SHADER_UNUSED_KHR);
+
+ // Closest Hit Shader Group
+ shaderGroups.get(2).sType(VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR);
+ shaderGroups.get(2).type(VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR);
+ shaderGroups.get(2).generalShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(2).closestHitShader(2);
+ shaderGroups.get(2).anyHitShader(VK_SHADER_UNUSED_KHR);
+ shaderGroups.get(2).intersectionShader(VK_SHADER_UNUSED_KHR);
+
+ VkRayTracingPipelineCreateInfoKHR.Buffer pipelineInfo = VkRayTracingPipelineCreateInfoKHR.calloc(1, stack);
+ pipelineInfo.sType(VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR);
+ pipelineInfo.pStages(shaderStages);
+ pipelineInfo.pGroups(shaderGroups);
+ pipelineInfo.maxPipelineRayRecursionDepth(1);
+ pipelineInfo.layout(pipelineLayout);
+
+ LongBuffer pPipeline = stack.mallocLong(1);
+ if (vkCreateRayTracingPipelinesKHR(DeviceManager.vkDevice, VK_NULL_HANDLE, VK_NULL_HANDLE, pipelineInfo, null, pPipeline) != VK_SUCCESS) {
+ throw new RuntimeException("Failed to create ray tracing pipeline");
+ }
+ pipelineHandle = pPipeline.get(0);
+
+ createShaderBindingTable();
+ }
+ }
+
+ private void createShaderBindingTable() {
+ try (MemoryStack stack = stackPush()) {
+ VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingProperties = VkPhysicalDeviceRayTracingPipelinePropertiesKHR.calloc(stack);
+ rayTracingProperties.sType$Default();
+
+ VkPhysicalDeviceProperties2 deviceProps2 = VkPhysicalDeviceProperties2.calloc(stack);
+ deviceProps2.sType$Default();
+ deviceProps2.pNext(rayTracingProperties.address());
+ vkGetPhysicalDeviceProperties2(DeviceManager.physicalDevice, deviceProps2);
+
+ int groupCount = 3;
+ int handleSize = rayTracingProperties.shaderGroupHandleSize();
+ int handleAlignment = Math.max(1, rayTracingProperties.shaderGroupHandleAlignment());
+ int baseAlignment = Math.max(1, rayTracingProperties.shaderGroupBaseAlignment());
+
+ int alignedHandleSize = alignUp(handleSize, handleAlignment);
+ this.sbtStride = alignUp(alignedHandleSize, baseAlignment);
+ int sbtSize = this.sbtStride * groupCount;
+
+ ByteBuffer handles = MemoryUtil.memAlloc(handleSize * groupCount);
+ if (vkGetRayTracingShaderGroupHandlesKHR(DeviceManager.vkDevice, pipelineHandle, 0, groupCount, handles) != VK_SUCCESS) {
+ MemoryUtil.memFree(handles);
+ throw new RuntimeException("Failed to get ray tracing shader group handles");
+ }
+
+ ByteBuffer sbtData = MemoryUtil.memAlloc(sbtSize);
+ MemoryUtil.memSet(MemoryUtil.memAddress(sbtData), (byte) 0, sbtSize);
+ for (int i = 0; i < groupCount; i++) {
+ long src = MemoryUtil.memAddress(handles) + (long) i * handleSize;
+ long dst = MemoryUtil.memAddress(sbtData) + (long) i * this.sbtStride;
+ MemoryUtil.memCopy(src, dst, handleSize);
+ }
+ MemoryUtil.memFree(handles);
+
+ this.shaderBindingTable = new Buffer(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, MemoryTypes.HOST_MEM);
+ this.shaderBindingTable.createBuffer(sbtSize);
+ this.shaderBindingTable.copyBuffer(sbtData, sbtSize);
+ MemoryUtil.memFree(sbtData);
+
+ VkBufferDeviceAddressInfo bufferDeviceAddressInfo = VkBufferDeviceAddressInfo.calloc(stack);
+ bufferDeviceAddressInfo.sType$Default();
+ bufferDeviceAddressInfo.buffer(this.shaderBindingTable.getId());
+ this.sbtBufferAddress = vkGetBufferDeviceAddress(DeviceManager.vkDevice, bufferDeviceAddressInfo);
+ }
+ }
+
+ public long getHandle() {
+ return this.pipelineHandle;
+ }
+
+ public long getSbtBufferAddress() {
+ return sbtBufferAddress;
+ }
+
+ public int getSbtStride() {
+ return sbtStride;
+ }
+
+ @Override
+ public void cleanUp() {
+ vkDestroyShaderModule(DeviceManager.vkDevice, raygenShaderModule, null);
+ vkDestroyShaderModule(DeviceManager.vkDevice, missShaderModule, null);
+ vkDestroyShaderModule(DeviceManager.vkDevice, chitShaderModule, null);
+
+ destroyDescriptorSets();
+ vkDestroyPipeline(DeviceManager.vkDevice, pipelineHandle, null);
+ vkDestroyDescriptorSetLayout(DeviceManager.vkDevice, descriptorSetLayout, null);
+ vkDestroyPipelineLayout(DeviceManager.vkDevice, pipelineLayout, null);
+
+ this.shaderBindingTable.scheduleFree();
+
+ PIPELINES.remove(this);
+ //Renderer.getInstance().removeUsedPipeline(this);
+ }
+
+ public static class Builder extends Pipeline.Builder {
+ SPIRVUtils.SPIRV raygenShaderSPIRV, missShaderSPIRV, chitShaderSPIRV;
+
+ public Builder(String shaderPath) {
+ super(null, shaderPath);
+ }
+
+ public Builder setRaygenShaderSPIRV(SPIRVUtils.SPIRV spirv) {
+ this.raygenShaderSPIRV = spirv;
+ return this;
+ }
+
+ public Builder setMissShaderSPIRV(SPIRVUtils.SPIRV spirv) {
+ this.missShaderSPIRV = spirv;
+ return this;
+ }
+
+ public Builder setChitShaderSPIRV(SPIRVUtils.SPIRV spirv) {
+ this.chitShaderSPIRV = spirv;
+ return this;
+ }
+
+ public RayTracingPipeline createRayTracingPipeline() {
+ return new RayTracingPipeline(this);
+ }
+ }
+}
diff --git a/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java b/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java
index 05c95e547..d27eadda1 100644
--- a/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java
+++ b/src/main/java/net/vulkanmod/vulkan/shader/SPIRVUtils.java
@@ -24,15 +24,12 @@
public class SPIRVUtils {
private static final boolean DEBUG = false;
private static final boolean OPTIMIZATIONS = true;
-
- private static long compiler;
- private static long options;
-
//The dedicated Includer and Releaser Inner Classes used to Initialise #include Support for ShaderC
private static final ShaderIncluder SHADER_INCLUDER = new ShaderIncluder();
private static final ShaderReleaser SHADER_RELEASER = new ShaderReleaser();
private static final long pUserData = 0;
-
+ private static long compiler;
+ private static long options;
private static ObjectArrayList