diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/InstanceType.java b/src/main/java/com/jozufozu/flywheel/api/instance/InstanceType.java index 5ebab055a..4d317da01 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/InstanceType.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/InstanceType.java @@ -26,11 +26,11 @@ public interface InstanceType { * @deprecated Use {@link #layout()} instead. */ @Deprecated - BufferLayout getLayout(); + BufferLayout oldLayout(); Layout layout(); - InstanceWriter getWriter(); + InstanceWriter writer(); ResourceLocation vertexShader(); diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/Element.java b/src/main/java/com/jozufozu/flywheel/api/layout/Element.java deleted file mode 100644 index 4332c8295..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/layout/Element.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.jozufozu.flywheel.api.layout; - -/** - * A single element in a {@link Layout}. - */ -public sealed interface Element { - String name(); - - /** - * A simple vector of floats, i.e. {@code vec3}, {@code dvec2}. - *
- * If {@link #type} is an integral type, the shader will implicitly convert it to a float without normalization. - * If you want normalization, use {@link NormalizedVector}. - * - * @param name The name of the element to be used in the shader. - * @param type The backing type of the element. - * @param size The number of components in the vector. - */ - record Vector(String name, FloatType type, VectorSize size) implements Element { - } - - /** - * A vector of integers, i.e. {@code ivec3}, {@code uvec2}. - *
- * All backing types will be presented as either {@code int} or {@code uint} in the shader, - * depending on the signedness of the type. - * - * @param name The name of the element to be used in the shader. - * @param type The backing type of the element. - * @param size The number of components in the vector. - */ - record IntegerVector(String name, IntegerType type, VectorSize size) implements Element { - } - - /** - * A vector of integers, normalized and presented as a float in the shader. - * - * @param name The name of the element to be used in the shader. - * @param type The backing type of the element. - * @param size The number of components in the vector. - */ - record NormalizedVector(String name, IntegerType type, VectorSize size) implements Element { - } - - /** - * A matrix of 32-bit floating point numbers, i.e. {@code mat3}, {@code mat2x4}. - * - * @param name The name of the element to be used in the shader. - * @param rows The number of rows in the matrix. - * @param cols The number of columns in the matrix. - */ - record Matrix(String name, MatrixSize rows, MatrixSize cols) implements Element { - } -} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/ElementType.java b/src/main/java/com/jozufozu/flywheel/api/layout/ElementType.java new file mode 100644 index 000000000..333bfddb6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/ElementType.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.api.layout; + +public sealed interface ElementType permits ScalarElementType, VectorElementType, MatrixElementType { + int byteSize(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/FloatRepr.java b/src/main/java/com/jozufozu/flywheel/api/layout/FloatRepr.java new file mode 100644 index 000000000..63b82130a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/FloatRepr.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.api.layout; + +public enum FloatRepr implements ValueRepr { + BYTE(Byte.BYTES), + NORMALIZED_BYTE(Byte.BYTES), + UNSIGNED_BYTE(Byte.BYTES), + NORMALIZED_UNSIGNED_BYTE(Byte.BYTES), + SHORT(Short.BYTES), + NORMALIZED_SHORT(Short.BYTES), + UNSIGNED_SHORT(Short.BYTES), + NORMALIZED_UNSIGNED_SHORT(Short.BYTES), + INT(Integer.BYTES), + NORMALIZED_INT(Integer.BYTES), + UNSIGNED_INT(Integer.BYTES), + NORMALIZED_UNSIGNED_INT(Integer.BYTES), + FLOAT(Float.BYTES); + + private final int byteSize; + + FloatRepr(int byteSize) { + this.byteSize = byteSize; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/FloatType.java b/src/main/java/com/jozufozu/flywheel/api/layout/FloatType.java deleted file mode 100644 index 8b7eb0939..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/layout/FloatType.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jozufozu.flywheel.api.layout; - -/** - * The backing type of traditional floating point vertex attributes. - *
- * Integral types are implicitly converted to floats in the shader. - */ -public enum FloatType { - BYTE, - UNSIGNED_BYTE, - SHORT, - UNSIGNED_SHORT, - INT, - UNSIGNED_INT, - HALF_FLOAT, - FLOAT, - DOUBLE, - FIXED, -} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/IntegerRepr.java b/src/main/java/com/jozufozu/flywheel/api/layout/IntegerRepr.java new file mode 100644 index 000000000..c8b1c18e3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/IntegerRepr.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.api.layout; + +public enum IntegerRepr implements ValueRepr { + BYTE(Byte.BYTES), + SHORT(Short.BYTES), + INT(Integer.BYTES); + + private final int byteSize; + + IntegerRepr(int byteSize) { + this.byteSize = byteSize; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/IntegerType.java b/src/main/java/com/jozufozu/flywheel/api/layout/IntegerType.java deleted file mode 100644 index 7ebd9e640..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/layout/IntegerType.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.api.layout; - -/** - * Integral types backing layout elements. - */ -public enum IntegerType { - BYTE, - UNSIGNED_BYTE, - SHORT, - UNSIGNED_SHORT, - INT, - UNSIGNED_INT -} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/Layout.java b/src/main/java/com/jozufozu/flywheel/api/layout/Layout.java index 24f54c6be..3c4d1e83e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/layout/Layout.java +++ b/src/main/java/com/jozufozu/flywheel/api/layout/Layout.java @@ -1,6 +1,27 @@ package com.jozufozu.flywheel.api.layout; import java.util.List; +import java.util.Map; -public record Layout(List elements) { +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Unmodifiable; + +@ApiStatus.NonExtendable +public interface Layout { + int MAX_ELEMENT_NAME_LENGTH = 896; + + @Unmodifiable + List elements(); + + @Unmodifiable + Map asMap(); + + int byteSize(); + + @ApiStatus.NonExtendable + interface Element { + String name(); + + ElementType type(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/LayoutBuilder.java b/src/main/java/com/jozufozu/flywheel/api/layout/LayoutBuilder.java new file mode 100644 index 000000000..30bd44069 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/LayoutBuilder.java @@ -0,0 +1,23 @@ +package com.jozufozu.flywheel.api.layout; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Range; + +import com.jozufozu.flywheel.impl.layout.LayoutBuilderImpl; + +@ApiStatus.NonExtendable +public interface LayoutBuilder { + LayoutBuilder scalar(String name, ValueRepr repr); + + LayoutBuilder vector(String name, ValueRepr repr, @Range(from = 2, to = 4) int size); + + LayoutBuilder matrix(String name, FloatRepr repr, @Range(from = 2, to = 4) int rows, @Range(from = 2, to = 4) int columns); + + LayoutBuilder matrix(String name, FloatRepr repr, @Range(from = 2, to = 4) int size); + + Layout build(); + + static LayoutBuilder create() { + return new LayoutBuilderImpl(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/MatrixElementType.java b/src/main/java/com/jozufozu/flywheel/api/layout/MatrixElementType.java new file mode 100644 index 000000000..fcead2081 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/MatrixElementType.java @@ -0,0 +1,15 @@ +package com.jozufozu.flywheel.api.layout; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Range; + +@ApiStatus.NonExtendable +public non-sealed interface MatrixElementType extends ElementType { + FloatRepr repr(); + + @Range(from = 2, to = 4) + int rows(); + + @Range(from = 2, to = 4) + int columns(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/MatrixSize.java b/src/main/java/com/jozufozu/flywheel/api/layout/MatrixSize.java deleted file mode 100644 index e1515aa35..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/layout/MatrixSize.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.jozufozu.flywheel.api.layout; - -/** - * The size of a single dimension in a matrix. - */ -public enum MatrixSize { - TWO, - THREE, - FOUR, -} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/ScalarElementType.java b/src/main/java/com/jozufozu/flywheel/api/layout/ScalarElementType.java new file mode 100644 index 000000000..1af958585 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/ScalarElementType.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.api.layout; + +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable +public non-sealed interface ScalarElementType extends ElementType { + ValueRepr repr(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/UnsignedIntegerRepr.java b/src/main/java/com/jozufozu/flywheel/api/layout/UnsignedIntegerRepr.java new file mode 100644 index 000000000..8676bd482 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/UnsignedIntegerRepr.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.api.layout; + +public enum UnsignedIntegerRepr implements ValueRepr { + UNSIGNED_BYTE(Byte.BYTES), + UNSIGNED_SHORT(Short.BYTES), + UNSIGNED_INT(Integer.BYTES); + + private final int byteSize; + + UnsignedIntegerRepr(int byteSize) { + this.byteSize = byteSize; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/ValueRepr.java b/src/main/java/com/jozufozu/flywheel/api/layout/ValueRepr.java new file mode 100644 index 000000000..1dcff5001 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/ValueRepr.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.api.layout; + +public sealed interface ValueRepr permits IntegerRepr, UnsignedIntegerRepr, FloatRepr { + int byteSize(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/VectorElementType.java b/src/main/java/com/jozufozu/flywheel/api/layout/VectorElementType.java new file mode 100644 index 000000000..bc13d6bf5 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/layout/VectorElementType.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.api.layout; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Range; + +@ApiStatus.NonExtendable +public non-sealed interface VectorElementType extends ElementType { + ValueRepr repr(); + + @Range(from = 2, to = 4) + int size(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/layout/VectorSize.java b/src/main/java/com/jozufozu/flywheel/api/layout/VectorSize.java deleted file mode 100644 index d4a3152ba..000000000 --- a/src/main/java/com/jozufozu/flywheel/api/layout/VectorSize.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jozufozu.flywheel.api.layout; - -/** - * The number of components in a vector. - *
- * If the vector size is 1, the attribute is presented as a scalar. - */ -public enum VectorSize { - ONE, - TWO, - THREE, - FOUR, -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java b/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java index 9ff9d0e94..ca02a78b8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/component/IndirectComponent.java @@ -34,7 +34,7 @@ public class IndirectComponent implements SourceComponent { } public static IndirectComponent create(InstanceType instanceType) { - return new IndirectComponent(instanceType.getLayout().layoutItems); + return new IndirectComponent(instanceType.oldLayout().layoutItems); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java b/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java index 4e1dffdaa..cd82b2024 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/component/InstancedArraysComponent.java @@ -25,7 +25,7 @@ public class InstancedArraysComponent implements SourceComponent { public InstancedArraysComponent(Pipeline.InstanceAssemblerContext ctx) { this.layoutItems = ctx.instanceType() - .getLayout().layoutItems; + .oldLayout().layoutItems; this.baseIndex = ctx.baseAttribute(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java index 99609b419..371bb3b82 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java @@ -58,7 +58,7 @@ public class IndirectCullingGroup { applyProgram = programs.getApplyProgram(); drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT); - objectStride = instanceType.getLayout() + objectStride = instanceType.oldLayout() .getStride() + IndirectBuffers.INT_SIZE; buffers = new IndirectBuffers(objectStride); diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java index ded8946ce..2b3dbb543 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java @@ -20,10 +20,10 @@ public class IndirectInstancer extends AbstractInstancer public IndirectInstancer(InstanceType type) { super(type); - long instanceStride = type.getLayout() + long instanceStride = type.oldLayout() .getStride(); this.objectStride = instanceStride + IndirectBuffers.INT_SIZE; - writer = this.type.getWriter(); + writer = this.type.writer(); } public void addDraw(IndirectDraw draw) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java index 6ccf510f4..998561485 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java @@ -28,9 +28,9 @@ public class InstancedInstancer extends AbstractInstancer public InstancedInstancer(InstanceType type) { super(type); - instanceFormat = type.getLayout(); + instanceFormat = type.oldLayout(); instanceStride = instanceFormat.getStride(); - writer = type.getWriter(); + writer = type.writer(); } public int getAttributeCount() { diff --git a/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutBuilderImpl.java b/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutBuilderImpl.java new file mode 100644 index 000000000..5784b19f3 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutBuilderImpl.java @@ -0,0 +1,179 @@ +package com.jozufozu.flywheel.impl.layout; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.jetbrains.annotations.Range; + +import com.jozufozu.flywheel.api.layout.FloatRepr; +import com.jozufozu.flywheel.api.layout.Layout; +import com.jozufozu.flywheel.api.layout.Layout.Element; +import com.jozufozu.flywheel.api.layout.LayoutBuilder; +import com.jozufozu.flywheel.api.layout.ValueRepr; +import com.jozufozu.flywheel.impl.layout.LayoutImpl.ElementImpl; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; + +public class LayoutBuilderImpl implements LayoutBuilder { + private static final Set GLSL_KEYWORDS = Set.of( + // standard keywords + "const", "uniform", "buffer", "shared", "attribute", "varying", + "coherent", "volatile", "restrict", "readonly", "writeonly", + "atomic_uint", + "layout", + "centroid", "flat", "smooth", "noperspective", + "patch", "sample", + "invariant", "precise", + "break", "continue", "do", "for", "while", "switch", "case", "default", + "if", "else", + "subroutine", + "in", "out", "inout", + "int", "void", "bool", "true", "false", "float", "double", + "discard", "return", + "vec2", "vec3", "vec4", "ivec2", "ivec3", "ivec4", "bvec2", "bvec3", "bvec4", + "uint", "uvec2", "uvec3", "uvec4", + "dvec2", "dvec3", "dvec4", + "mat2", "mat3", "mat4", + "mat2x2", "mat2x3", "mat2x4", + "mat3x2", "mat3x3", "mat3x4", + "mat4x2", "mat4x3", "mat4x4", + "dmat2", "dmat3", "dmat4", + "dmat2x2", "dmat2x3", "dmat2x4", + "dmat3x2", "dmat3x3", "dmat3x4", + "dmat4x2", "dmat4x3", "dmat4x4", + "lowp", "mediump", "highp", "precision", + "sampler1D", "sampler1DShadow", "sampler1DArray", "sampler1DArrayShadow", + "isampler1D", "isampler1DArray", "usampler1D", "usampler1DArray", + "sampler2D", "sampler2DShadow", "sampler2DArray", "sampler2DArrayShadow", + "isampler2D", "isampler2DArray", "usampler2D", "usampler2DArray", + "sampler2DRect", "sampler2DRectShadow", "isampler2DRect", "usampler2DRect", + "sampler2DMS", "isampler2DMS", "usampler2DMS", + "sampler2DMSArray", "isampler2DMSArray", "usampler2DMSArray", + "sampler3D", "isampler3D", "usampler3D", + "samplerCube", "samplerCubeShadow", "isamplerCube", "usamplerCube", + "samplerCubeArray", "samplerCubeArrayShadow", + "isamplerCubeArray", "usamplerCubeArray", + "samplerBuffer", "isamplerBuffer", "usamplerBuffer", + "image1D", "iimage1D", "uimage1D", + "image1DArray", "iimage1DArray", "uimage1DArray", + "image2D", "iimage2D", "uimage2D", + "image2DArray", "iimage2DArray", "uimage2DArray", + "image2DRect", "iimage2DRect", "uimage2DRect", + "image2DMS", "iimage2DMS", "uimage2DMS", + "image2DMSArray", "iimage2DMSArray", "uimage2DMSArray", + "image3D", "iimage3D", "uimage3D", + "imageCube", "iimageCube", "uimageCube", + "imageCubeArray", "iimageCubeArray", "uimageCubeArray", + "imageBuffer", "iimageBuffer", "uimageBuffer", + "struct", + // Vulkan keywords + "texture1D", "texture1DArray", + "itexture1D", "itexture1DArray", "utexture1D", "utexture1DArray", + "texture2D", "texture2DArray", + "itexture2D", "itexture2DArray", "utexture2D", "utexture2DArray", + "texture2DRect", "itexture2DRect", "utexture2DRect", + "texture2DMS", "itexture2DMS", "utexture2DMS", + "texture2DMSArray", "itexture2DMSArray", "utexture2DMSArray", + "texture3D", "itexture3D", "utexture3D", + "textureCube", "itextureCube", "utextureCube", + "textureCubeArray", "itextureCubeArray", "utextureCubeArray", + "textureBuffer", "itextureBuffer", "utextureBuffer", + "sampler", "samplerShadow", + "subpassInput", "isubpassInput", "usubpassInput", + "subpassInputMS", "isubpassInputMS", "usubpassInputMS", + // reserved keywords + "common", "partition", "active", + "asm", + "class", "union", "enum", "typedef", "template", "this", + "resource", + "goto", + "inline", "noinline", "public", "static", "extern", "external", "interface", + "long", "short", "half", "fixed", "unsigned", "superp", + "input", "output", + "hvec2", "hvec3", "hvec4", "fvec2", "fvec3", "fvec4", + "filter", + "sizeof", "cast", + "namespace", "using", + "sampler3DRect" + ); + + private final List elements = new ArrayList<>(); + + @Override + public LayoutBuilder scalar(String name, ValueRepr repr) { + elements.add(new ElementImpl(name, new ScalarElementTypeImpl(repr))); + return this; + } + + @Override + public LayoutBuilder vector(String name, ValueRepr repr, @Range(from = 2, to = 4) int size) { + elements.add(new ElementImpl(name, new VectorElementTypeImpl(repr, size))); + return this; + } + + @Override + public LayoutBuilder matrix(String name, FloatRepr repr, @Range(from = 2, to = 4) int rows, @Range(from = 2, to = 4) int columns) { + elements.add(new ElementImpl(name, new MatrixElementTypeImpl(repr, rows, columns))); + return this; + } + + @Override + public LayoutBuilder matrix(String name, FloatRepr repr, @Range(from = 2, to = 4) int size) { + return matrix(name, repr, size, size); + } + + @Override + public Layout build() { + Object2IntMap name2IndexMap = new Object2IntOpenHashMap<>(); + name2IndexMap.defaultReturnValue(-1); + + for (int i = 0; i < elements.size(); i++) { + Element element = elements.get(i); + String name = element.name(); + + if (GLSL_KEYWORDS.contains(name)) { + throw new IllegalStateException("Element at index " + i + " has invalid name '" + name + "'; this is a GLSL keyword!"); + } + + for (int j = 0; j < name.length(); j++) { + char c = name.charAt(j); + if (j == 0) { + if (!isLetter(c)) { + throw new IllegalStateException("Element at index " + i + " has invalid name '" + name + "'! Names must start with a letter."); + } + } else { + if (!isValidNameCharacter(c)) { + throw new IllegalStateException("Element at index " + i + " has invalid name '" + name + "'! Names must only contain letters, digits, and underscores."); + } + } + } + + String lowerCaseName = name.toLowerCase(Locale.ROOT); + if (lowerCaseName.startsWith("gl") || lowerCaseName.startsWith("flw")) { + throw new IllegalStateException("Element at index " + i + " has invalid name '" + name + "'! Names must not start with 'gl' or 'flw' (case-insensitive)."); + } + + if (name.length() > Layout.MAX_ELEMENT_NAME_LENGTH) { + throw new IllegalStateException("Element at index " + i + " has invalid name '" + name + "'! Names must not be longer than " + Layout.MAX_ELEMENT_NAME_LENGTH + " characters."); + } + + int prevIndex = name2IndexMap.putIfAbsent(name, i); + if (prevIndex != -1) { + throw new IllegalStateException("Elements at indices " + prevIndex + " and " + i + " have the same name; this is not valid!"); + } + } + + return new LayoutImpl(List.copyOf(elements)); + } + + private static boolean isValidNameCharacter(char c) { + return isLetter(c) || c >= '0' && c <= '9' || c == '_'; + } + + private static boolean isLetter(char c) { + return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutImpl.java b/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutImpl.java new file mode 100644 index 000000000..0b223d1b6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/layout/LayoutImpl.java @@ -0,0 +1,48 @@ +package com.jozufozu.flywheel.impl.layout; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jetbrains.annotations.Unmodifiable; + +import com.jozufozu.flywheel.api.layout.ElementType; +import com.jozufozu.flywheel.api.layout.Layout; + +final class LayoutImpl implements Layout { + private final List elements; + private final Map map; + private final int byteSize; + + LayoutImpl(List elements) { + this.elements = elements; + + map = new HashMap<>(); + int byteSize = 0; + for (Element element : this.elements) { + map.put(element.name(), element.type()); + byteSize += element.type().byteSize(); + } + this.byteSize = byteSize; + } + + @Override + @Unmodifiable + public List elements() { + return elements; + } + + @Override + @Unmodifiable + public Map asMap() { + return map; + } + + @Override + public int byteSize() { + return byteSize; + } + + record ElementImpl(String name, ElementType type) implements Element { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/layout/MatrixElementTypeImpl.java b/src/main/java/com/jozufozu/flywheel/impl/layout/MatrixElementTypeImpl.java new file mode 100644 index 000000000..d70be1f2a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/layout/MatrixElementTypeImpl.java @@ -0,0 +1,51 @@ +package com.jozufozu.flywheel.impl.layout; + +import org.jetbrains.annotations.Range; + +import com.jozufozu.flywheel.api.layout.FloatRepr; +import com.jozufozu.flywheel.api.layout.MatrixElementType; + +final class MatrixElementTypeImpl implements MatrixElementType { + private final FloatRepr repr; + @Range(from = 2, to = 4) + private final int rows; + @Range(from = 2, to = 4) + private final int columns; + private final int byteSize; + + MatrixElementTypeImpl(FloatRepr repr, @Range(from = 2, to = 4) int rows, @Range(from = 2, to = 4) int columns) { + if (rows < 2 || rows > 4) { + throw new IllegalArgumentException("Matrix element row count must be in range [2, 4]!"); + } + if (columns < 2 || columns > 4) { + throw new IllegalArgumentException("Matrix element column count must be in range [2, 4]!"); + } + + this.repr = repr; + this.rows = rows; + this.columns = columns; + byteSize = repr.byteSize() * rows * columns; + } + + @Override + public FloatRepr repr() { + return repr; + } + + @Override + @Range(from = 2, to = 4) + public int rows() { + return rows; + } + + @Override + @Range(from = 2, to = 4) + public int columns() { + return columns; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/layout/ScalarElementTypeImpl.java b/src/main/java/com/jozufozu/flywheel/impl/layout/ScalarElementTypeImpl.java new file mode 100644 index 000000000..d39aaac84 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/layout/ScalarElementTypeImpl.java @@ -0,0 +1,24 @@ +package com.jozufozu.flywheel.impl.layout; + +import com.jozufozu.flywheel.api.layout.ScalarElementType; +import com.jozufozu.flywheel.api.layout.ValueRepr; + +final class ScalarElementTypeImpl implements ScalarElementType { + private final ValueRepr repr; + private final int byteSize; + + ScalarElementTypeImpl(ValueRepr repr) { + this.repr = repr; + byteSize = repr.byteSize(); + } + + @Override + public ValueRepr repr() { + return repr; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/layout/VectorElementTypeImpl.java b/src/main/java/com/jozufozu/flywheel/impl/layout/VectorElementTypeImpl.java new file mode 100644 index 000000000..7d9bb5fb2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/layout/VectorElementTypeImpl.java @@ -0,0 +1,39 @@ +package com.jozufozu.flywheel.impl.layout; + +import org.jetbrains.annotations.Range; + +import com.jozufozu.flywheel.api.layout.ValueRepr; +import com.jozufozu.flywheel.api.layout.VectorElementType; + +final class VectorElementTypeImpl implements VectorElementType { + private final ValueRepr repr; + @Range(from = 2, to = 4) + private final int size; + private final int byteSize; + + VectorElementTypeImpl(ValueRepr repr, @Range(from = 2, to = 4) int size) { + if (size < 2 || size > 4) { + throw new IllegalArgumentException("Vector element size must be in range [2, 4]!"); + } + + this.repr = repr; + this.size = size; + byteSize = repr.byteSize() * size; + } + + @Override + public ValueRepr repr() { + return repr; + } + + @Override + @Range(from = 2, to = 4) + public int size() { + return size; + } + + @Override + public int byteSize() { + return byteSize; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedType.java b/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedType.java index fbc28950d..86846dba5 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/OrientedType.java @@ -4,17 +4,17 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instance.InstanceHandle; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceWriter; -import com.jozufozu.flywheel.api.layout.FloatType; -import com.jozufozu.flywheel.api.layout.IntegerType; +import com.jozufozu.flywheel.api.layout.FloatRepr; +import com.jozufozu.flywheel.api.layout.IntegerRepr; import com.jozufozu.flywheel.api.layout.Layout; -import com.jozufozu.flywheel.api.layout.VectorSize; +import com.jozufozu.flywheel.api.layout.LayoutBuilder; import com.jozufozu.flywheel.lib.layout.BufferLayout; import com.jozufozu.flywheel.lib.layout.CommonItems; -import com.jozufozu.flywheel.lib.layout.LayoutBuilder; import net.minecraft.resources.ResourceLocation; public class OrientedType implements InstanceType { + @Deprecated private static final BufferLayout OLD_LAYOUT = BufferLayout.builder() .addItem(CommonItems.LIGHT_COORD, "light") .addItem(CommonItems.UNORM_4x8, "color") @@ -23,12 +23,12 @@ public class OrientedType implements InstanceType { .addItem(CommonItems.VEC4, "rotation") .build(); - private static final Layout LAYOUT = LayoutBuilder.of() - .integer("light", IntegerType.SHORT, VectorSize.TWO) - .normalized("color", IntegerType.BYTE, VectorSize.FOUR) - .vector("position", FloatType.FLOAT, VectorSize.THREE) - .vector("pivot", FloatType.FLOAT, VectorSize.THREE) - .vector("rotation", FloatType.FLOAT, VectorSize.FOUR) + private static final Layout LAYOUT = LayoutBuilder.create() + .vector("light", IntegerRepr.SHORT, 2) + .vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4) + .vector("position", FloatRepr.FLOAT, 3) + .vector("pivot", FloatRepr.FLOAT, 3) + .vector("rotation", FloatRepr.FLOAT, 4) .build(); private static final ResourceLocation VERTEX_SHADER = Flywheel.rl("instance/oriented.vert"); @@ -40,7 +40,8 @@ public class OrientedType implements InstanceType { } @Override - public BufferLayout getLayout() { + @Deprecated + public BufferLayout oldLayout() { return OLD_LAYOUT; } @@ -50,7 +51,7 @@ public class OrientedType implements InstanceType { } @Override - public InstanceWriter getWriter() { + public InstanceWriter writer() { return OrientedWriter.INSTANCE; } @@ -63,5 +64,4 @@ public class OrientedType implements InstanceType { public ResourceLocation cullShader() { return CULL_SHADER; } - } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedType.java b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedType.java index 120efbeae..393ea11b0 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedType.java @@ -4,17 +4,17 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instance.InstanceHandle; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceWriter; -import com.jozufozu.flywheel.api.layout.IntegerType; +import com.jozufozu.flywheel.api.layout.FloatRepr; +import com.jozufozu.flywheel.api.layout.IntegerRepr; import com.jozufozu.flywheel.api.layout.Layout; -import com.jozufozu.flywheel.api.layout.MatrixSize; -import com.jozufozu.flywheel.api.layout.VectorSize; +import com.jozufozu.flywheel.api.layout.LayoutBuilder; import com.jozufozu.flywheel.lib.layout.BufferLayout; import com.jozufozu.flywheel.lib.layout.CommonItems; -import com.jozufozu.flywheel.lib.layout.LayoutBuilder; import net.minecraft.resources.ResourceLocation; public class TransformedType implements InstanceType { + @Deprecated private static final BufferLayout OLD_LAYOUT = BufferLayout.builder() .addItem(CommonItems.LIGHT_COORD, "light") .addItem(CommonItems.UNORM_4x8, "color") @@ -22,11 +22,11 @@ public class TransformedType implements InstanceType { .addItem(CommonItems.MAT3, "normal") .build(); - public static final Layout LAYOUT = LayoutBuilder.of() - .integer("light", IntegerType.SHORT, VectorSize.TWO) - .normalized("color", IntegerType.BYTE, VectorSize.FOUR) - .mat("pose", MatrixSize.FOUR) - .mat("normal", MatrixSize.THREE) + private static final Layout LAYOUT = LayoutBuilder.create() + .vector("light", IntegerRepr.SHORT, 2) + .vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4) + .matrix("pose", FloatRepr.FLOAT, 4) + .matrix("normal", FloatRepr.FLOAT, 3) .build(); private static final ResourceLocation VERTEX_SHADER = Flywheel.rl("instance/transformed.vert"); @@ -38,7 +38,8 @@ public class TransformedType implements InstanceType { } @Override - public BufferLayout getLayout() { + @Deprecated + public BufferLayout oldLayout() { return OLD_LAYOUT; } @@ -48,7 +49,7 @@ public class TransformedType implements InstanceType { } @Override - public InstanceWriter getWriter() { + public InstanceWriter writer() { return TransformedWriter.INSTANCE; } @@ -61,5 +62,4 @@ public class TransformedType implements InstanceType { public ResourceLocation cullShader() { return CULL_SHADER; } - } diff --git a/src/main/java/com/jozufozu/flywheel/lib/layout/LayoutBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/layout/LayoutBuilder.java deleted file mode 100644 index 8e11bf90c..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/layout/LayoutBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jozufozu.flywheel.lib.layout; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.layout.Element; -import com.jozufozu.flywheel.api.layout.FloatType; -import com.jozufozu.flywheel.api.layout.IntegerType; -import com.jozufozu.flywheel.api.layout.Layout; -import com.jozufozu.flywheel.api.layout.MatrixSize; -import com.jozufozu.flywheel.api.layout.VectorSize; - -public class LayoutBuilder { - private final List elements = new ArrayList<>(); - - public static LayoutBuilder of() { - return new LayoutBuilder(); - } - - public Layout build() { - return new Layout(ImmutableList.copyOf(elements)); - } - - public LayoutBuilder element(Element element) { - elements.add(element); - return this; - } - - public LayoutBuilder integer(String name, IntegerType type, VectorSize size) { - return element(new Element.IntegerVector(name, type, size)); - } - - public LayoutBuilder normalized(String name, IntegerType type, VectorSize size) { - return element(new Element.NormalizedVector(name, type, size)); - } - - public LayoutBuilder vector(String name, FloatType type, VectorSize size) { - return element(new Element.Vector(name, type, size)); - } - - public LayoutBuilder mat(String name, MatrixSize rows, MatrixSize cols) { - return element(new Element.Matrix(name, rows, cols)); - } - - public LayoutBuilder mat(String name, MatrixSize size) { - return mat(name, size, size); - } -}