diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RenderContext.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RenderContext.java deleted file mode 100644 index f4e8a8f4b..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RenderContext.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.modificationstation.stationapi.api.client.render; - -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.MeshBuilder; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; -import net.modificationstation.stationapi.api.client.render.model.BakedModel; - -import java.util.function.Consumer; - -/** - * This defines the instance made available to models for buffering vertex data at render time. - * - *

Only the renderer should implement or extend this interface. - */ -public interface RenderContext { - /** - * Used by models to send vertex data previously baked via {@link MeshBuilder}. - * The fastest option and preferred whenever feasible. - */ - Consumer meshConsumer(); - - /** - * Fabric causes vanilla baked models to send themselves - * via this interface. Can also be used by compound models that contain a mix - * of vanilla baked models, packaged quads and/or dynamic elements. - */ - Consumer fallbackConsumer(); - - /** - * Returns a {@link QuadEmitter} instance that emits directly to the render buffer. - * It remains necessary to call {@link QuadEmitter#emit()} to output the quad. - * - *

This method will always be less performant than passing pre-baked meshes - * via {@link #meshConsumer()}. It should be used sparingly for model components that - * demand it - text, icons, dynamic indicators, or other elements that vary too - * much for static baking to be feasible. - * - *

Calling this method invalidates any {@link QuadEmitter} returned earlier. - * Will be threadlocal/re-used - do not retain references. - */ - QuadEmitter getEmitter(); - - /** - * Causes all models/quads/meshes sent to this consumer to be transformed by the provided - * {@link QuadTransform} that edits each quad before buffering. Quads in the mesh will - * be passed to the {@link QuadTransform} for modification before offsets, face culling or lighting are applied. - * Meant for animation and mesh customization. - * - *

You MUST call {@link #popTransform()} after model is done outputting quads. - * - *

More than one transformer can be added to the context. Transformers are applied in reverse order. - * (Last pushed is applied first.) - * - *

Meshes are never mutated by the transformer - only buffered quads. This ensures thread-safe - * use of meshes/models across multiple chunk builders. - */ - void pushTransform(QuadTransform transform); - - /** - * Removes the transformation added by the last call to {@link #pushTransform(QuadTransform)}. - * MUST be called before exiting from {@link BakedModel} .emit... methods. - */ - void popTransform(); - - @FunctionalInterface - interface QuadTransform { - - /** - * Return false to filter out quads from rendering. When more than one transform - * is in effect, returning false means unapplied transforms will not receive the quad. - */ - boolean transform(MutableQuadView quad); - } -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java index 796d07013..0b6259d94 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java @@ -1,11 +1,6 @@ package net.modificationstation.stationapi.api.client.render; -import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.render.mesh.MeshBuilder; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; -import net.modificationstation.stationapi.api.util.Identifier; -import org.jetbrains.annotations.Nullable; /** * Interface for rendering plug-ins that provide enhanced capabilities @@ -13,41 +8,6 @@ * enhanced model rendering interfaces specified by the Fabric API. */ public interface Renderer { - /** - * Obtain a new {@link MeshBuilder} instance used to create - * baked models with enhanced features. - * - *

Renderer does not retain a reference to returned instances and they should be re-used for - * multiple models when possible to avoid memory allocation overhead. - */ - MeshBuilder meshBuilder(); - - /** - * Obtain a new {@link MaterialFinder} instance used to retrieve - * standard {@link RenderMaterial} instances. - * - *

Renderer does not retain a reference to returned instances and they should be re-used for - * multiple materials when possible to avoid memory allocation overhead. - */ - MaterialFinder materialFinder(); - - /** - * Return a material previously registered via {@link #registerMaterial(Identifier, RenderMaterial)}. - * Will return null if no material was found matching the given identifier. - */ - @Nullable - RenderMaterial materialById(Identifier id); - - /** - * Register a material for re-use by other mods or models within a mod. - * The registry does not persist registrations - mods must create and register - * all materials at game initialization. - * - *

Returns false if a material with the given identifier is already present, - * leaving the existing material intact. - */ - boolean registerMaterial(Identifier id, RenderMaterial material); - /** * Obtain a new {@link BakedModelRenderer} instance used to render * baked models. diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/BlendMode.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/BlendMode.java deleted file mode 100644 index 68db3ee17..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/BlendMode.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.material; - -/** - * Defines how sprite pixels will be blended with the scene. - */ -public enum BlendMode { - - /** - * Emulate blending behavior of {@code BlockRenderLayer} associated with the block. - */ - DEFAULT(-1), - - /** - * Fully opaque with depth test, no blending. Used for most normal blocks. - */ - SOLID(0), - - /** - * Pixels are blended with the background according to alpha colour values. Some performance cost, - * use in moderation. Texture mip-map enabled. Used for ice. - */ - TRANSLUCENT(1); - - public final int blockRenderPass; - - BlendMode(int blockRenderPass) { - this.blockRenderPass = blockRenderPass; - } - - public static BlendMode fromRenderPass(int renderPass) { - return switch (renderPass) { - case 0 -> SOLID; - case 1 -> TRANSLUCENT; - default -> DEFAULT; - }; - } -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java deleted file mode 100644 index 7b0845d5c..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.material; - -import net.modificationstation.stationapi.api.client.render.RenderContext; -import net.modificationstation.stationapi.api.client.render.Renderer; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; - -/** - * Finds standard {@link RenderMaterial} instances used to communicate - * quad rendering characteristics to a {@link RenderContext}. - * - *

Must be obtained via {@link Renderer#materialFinder()}. - */ -public interface MaterialFinder { - /** - * Returns the standard material encoding all - * of the current settings in this finder. The settings in - * this finder are not changed. - * - *

Resulting instances can and should be re-used to prevent - * needless memory allocation. {@link Renderer} implementations - * may or may not cache standard material instances. - */ - RenderMaterial find(); - - /** - * Resets this instance to default values. Values will match those - * in effect when an instance is newly obtained via {@link Renderer#materialFinder()}. - */ - MaterialFinder clear(); - - /** - * Reserved for future use. Behavior for values > 1 is currently undefined. - */ - MaterialFinder spriteDepth(int depth); - - /** - * Defines how sprite pixels will be blended with the scene. - * - *

See {@link BlendMode} for more information. - */ - MaterialFinder blendMode(int spriteIndex, BlendMode blendMode); - - /** - * Vertex color(s) will be modified for quad color index unless disabled. - */ - MaterialFinder disableColorIndex(int spriteIndex, boolean disable); - - /** - * Vertex color(s) will be modified for diffuse shading unless disabled. - */ - MaterialFinder disableDiffuse(int spriteIndex, boolean disable); - - /** - * Vertex color(s) will be modified for ambient occlusion unless disabled. - */ - MaterialFinder disableAo(int spriteIndex, boolean disable); - - /** - * When true, sprite texture and color will be rendered at full brightness. - * Lightmap values provided via {@link QuadEmitter#lightmap(int)} will be ignored. - * False by default - * - *

This is the preferred method for emissive lighting effects. Some renderers - * with advanced lighting models may not use block lightmaps and this method will - * allow per-sprite emissive lighting in future extensions that support overlay sprites. - * - *

Note that color will still be modified by diffuse shading and ambient occlusion, - * unless disabled via {@link #disableAo(int, boolean)} and {@link #disableDiffuse(int, boolean)}. - */ - MaterialFinder emissive(int spriteIndex, boolean isEmissive); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java deleted file mode 100644 index 20935c16b..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.material; - -import net.modificationstation.stationapi.api.client.render.Renderer; -import net.modificationstation.stationapi.api.client.render.mesh.MeshBuilder; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.util.Identifier; - -import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; -import static net.modificationstation.stationapi.api.util.Identifier.of; - -import net.minecraft.block.Block; - -/** - * All model quads have an associated render material governing - * how the quad will be rendered. - * - *

A material instance is always immutable and thread-safe. References to a material - * remain valid until the end of the current game session. - * - *

Materials can be registered and shared between mods using {@link Renderer#registerMaterial(Identifier, RenderMaterial)}. - * The registering mod is responsible for creating each registered material at startup. - * - *

Materials are not required to know their registration identity, and two materials - * with the same attributes may or may not satisfy equality and identity tests. Model - * implementations should never attempt to analyze materials or implement control logic based on them. - * They are only tokens for communicating quad attributes to the ModelRenderer. - * - *

There are three classes of materials... - * - *

STANDARD MATERIALS - * - *

Standard materials have "normal" rendering with control over lighting, - * color, and texture blending. In the default renderer, "normal" rendering - * emulates unmodified Minecraft. Other renderers may offer a different aesthetic. - * - *

The number of standard materials is finite, but not necessarily small. - * To find a standard material, use {@link Renderer#materialFinder()}. - * - *

All renderer implementations should support standard materials. - * - *

SPECIAL MATERIALS - * - *

Special materials are implemented directly by the Renderer implementation, typically - * with the aim of providing advanced/extended features. Such materials may offer additional - * vertex attributes via extensions to {@link MeshBuilder} and {@link MutableQuadView}. - * - *

Special materials can be obtained using {@link Renderer#materialById(Identifier)} - * with a known identifier. Renderers may provide other means of access. Popular - * special materials could be implemented by multiple renderers, however there is - * no requirement that special materials be cross-compatible. - */ -public interface RenderMaterial { - /** - * This will be identical to the material that would be obtained by calling {@link MaterialFinder#find()} - * on a new, unaltered, {@link MaterialFinder} instance. It is defined here for clarity and convenience. - * - *

Quads using this material use {@link Block#getRenderLayer()} of - * the associated block to determine texture blending, honor block color index, are non-emissive, and apply both - * diffuse and ambient occlusion shading to vertex colors. - * - *

All standard, non-fluid baked models are rendered using this material. - */ - Identifier MATERIAL_STANDARD = of(NAMESPACE, "standard"); - - /** - * How many sprite color/uv coordinates are in the material. - * Behavior for values > 1 is currently undefined. - * See {@link MaterialFinder#spriteDepth(int)} - */ - int spriteDepth(); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java deleted file mode 100644 index ce536f373..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.mesh; - -import net.modificationstation.stationapi.api.client.render.Renderer; - -import java.util.function.Consumer; - -/** - * A bundle of one or more {@link QuadView} instances encoded by the renderer, - * typically via {@link Renderer#meshBuilder()}. - * - *

Similar in purpose to the {@code List} instances returned by BakedModel, but - * affords the renderer the ability to optimize the format for performance - * and memory allocation. - * - *

Only the renderer should implement or extend this interface. - */ -public interface Mesh { - /** - * Use to access all of the quads encoded in this mesh. The quad instances - * sent to the consumer will likely be threadlocal/reused and should never - * be retained by the consumer. - */ - void forEach(Consumer consumer); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshBuilder.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshBuilder.java deleted file mode 100644 index b7943de07..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshBuilder.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.mesh; - -/** - * Decouples models from the vertex format(s) used by - * ModelRenderer to allow compatibility across diverse implementations. - */ -public interface MeshBuilder { - - /** - * Returns the {@link QuadEmitter} used to append quad to this mesh. - * Calling this method a second time invalidates any prior result. - * Do not retain references outside the context of building the mesh. - */ - QuadEmitter getEmitter(); - - /** - * Returns a new {@link Mesh} instance containing all - * quads added to this builder and resets the builder to an empty state. - */ - Mesh build(); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java deleted file mode 100644 index cede9400c..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java +++ /dev/null @@ -1,214 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.mesh; - -import net.modificationstation.stationapi.api.client.render.Renderer; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.render.model.BakedQuad; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.api.util.math.Vector2f; -import org.jetbrains.annotations.Nullable; - -/** - * A mutable {@link QuadView} instance. The base interface for - * {@link QuadEmitter} and for dynamic renders/mesh transforms. - * - *

Instances of {@link MutableQuadView} will practically always be - * threadlocal and/or reused - do not retain references. - * - *

Only the renderer should implement or extend this interface. - */ -public interface MutableQuadView extends QuadView { - /** - * Causes texture to appear with no rotation. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_ROTATE_NONE = 0; - - /** - * Causes texture to appear rotated 90 deg. clockwise relative to nominal face. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_ROTATE_90 = 1; - - /** - * Causes texture to appear rotated 180 deg. relative to nominal face. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_ROTATE_180 = 2; - - /** - * Causes texture to appear rotated 270 deg. clockwise relative to nominal face. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_ROTATE_270 = 3; - - /** - * When enabled, texture coordinate are assigned based on vertex position. - * Any existing uv coordinates will be replaced. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - * - *

UV lock always derives texture coordinates based on nominal face, even - * when the quad is not co-planar with that face, and the result is - * the same as if the quad were projected onto the nominal face, which - * is usually the desired result. - */ - int BAKE_LOCK_UV = 4; - - /** - * When set, U texture coordinates for the given sprite are - * flipped as part of baking. Can be useful for some randomization - * and texture mapping scenarios. Results are different than what - * can be obtained via rotation and both can be applied. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_FLIP_U = 8; - - /** - * Same as {@link MutableQuadView#BAKE_FLIP_U} but for V coordinate. - */ - int BAKE_FLIP_V = 16; - - /** - * UV coordinates by default are assumed to be 0-16 scale for consistency - * with conventional Minecraft model format. This is scaled to 0-1 during - * baking before interpolation. Model loaders that already have 0-1 coordinates - * can avoid wasteful multiplication/division by passing 0-1 coordinates directly. - * Pass in bakeFlags parameter to {@link #spriteBake(int, Sprite, int)}. - */ - int BAKE_NORMALIZED = 32; - - /** - * Assigns a different material to this quad. Useful for transformation of - * existing meshes because lighting and texture blending are controlled by material. - */ - MutableQuadView material(RenderMaterial material); - - /** - * If non-null, quad is coplanar with a block face which, if known, simplifies - * or shortcuts geometric analysis that might otherwise be needed. - * Set to null if quad is not coplanar or if this is not known. - * Also controls face culling during block rendering. - * - *

Null by default. - * - *

When called with a non-null value, also sets {@link #nominalFace(Direction)} - * to the same value. - * - *

This is different than the value reported by {@link BakedQuad#getFace()}. That value - * is computed based on face geometry and must be non-null in vanilla quads. - * That computed value is returned by {@link #lightFace()}. - */ - @Nullable - MutableQuadView cullFace(@Nullable Direction face); - - /** - * Provides a hint to renderer about the facing of this quad. Not required, - * but if provided can shortcut some geometric analysis if the quad is parallel to a block face. - * Should be the expected value of {@link #lightFace()}. Value will be confirmed - * and if invalid the correct light face will be calculated. - * - *

Null by default, and set automatically by {@link #cullFace()}. - * - *

Models may also find this useful as the face for texture UV locking and rotation semantics. - * - *

Note: This value is not persisted independently when the quad is encoded. - * When reading encoded quads, this value will always be the same as {@link #lightFace()}. - */ - @Nullable - MutableQuadView nominalFace(Direction face); - - /** - * Value functions identically to {@link BakedQuad#getColorIndex()} and is - * used by renderer / model builder in same way. Default value is -1. - */ - MutableQuadView colorIndex(int colourIndex); - - /** - * Enables bulk vertex data transfer using the standard Minecraft vertex formats. - * This method should be performant whenever caller's vertex representation makes it feasible. - * - *

Calling this method does not emit the quad. - */ - MutableQuadView fromVanilla(BakedQuad quad, RenderMaterial material, Direction cullFace); - - /** - * Encodes an integer tag with this quad that can later be retrieved via - * {@link QuadView#tag()}. Useful for models that want to perform conditional - * transformation or filtering on static meshes. - */ - MutableQuadView tag(int tag); - - /** - * Sets the geometric vertex position for the given vertex, - * relative to block origin. (0,0,0). Minecraft rendering is designed - * for models that fit within a single block space and is recommended - * that coordinates remain in the 0-1 range, with multi-block meshes - * split into multiple per-block models. - */ - MutableQuadView pos(int vertexIndex, float x, float y, float z); - - /** - * Same as {@link #pos(int, float, float, float)} but accepts vector type. - */ - default MutableQuadView pos(int vertexIndex, Vec3f vec) { - return pos(vertexIndex, vec.getX(), vec.getY(), vec.getZ()); - } - - /** - * Adds a vertex normal. Models that have per-vertex - * normals should include them to get correct lighting when it matters. - * Computed face normal is used when no vertex normal is provided. - * - *

{@link Renderer} implementations should honor vertex normals for - * diffuse lighting - modifying vertex color(s) or packing normals in the vertex - * buffer as appropriate for the rendering method/vertex format in effect. - */ - MutableQuadView normal(int vertexIndex, float x, float y, float z); - - /** - * Same as {@link #normal(int, float, float, float)} but accepts vector type. - */ - default MutableQuadView normal(int vertexIndex, Vec3f vec) { - return normal(vertexIndex, vec.getX(), vec.getY(), vec.getZ()); - } - - /** - * Set sprite color. Behavior for {@code spriteIndex > 0} is currently undefined. - */ - MutableQuadView spriteColor(int vertexIndex, int spriteIndex, int color); - - /** - * Convenience: set sprite color for all vertices at once. Behavior for {@code spriteIndex > 0} is currently undefined. - */ - default MutableQuadView spriteColor(int spriteIndex, int c0, int c1, int c2, int c3) { - spriteColor(0, spriteIndex, c0); - spriteColor(1, spriteIndex, c1); - spriteColor(2, spriteIndex, c2); - spriteColor(3, spriteIndex, c3); - return this; - } - - /** - * Set sprite atlas coordinates. Behavior for {@code spriteIndex > 0} is currently undefined. - */ - MutableQuadView sprite(int vertexIndex, int spriteIndex, float u, float v); - - /** - * Set sprite atlas coordinates. Behavior for {@code spriteIndex > 0} is currently undefined. - * - *

Only use this function if you already have a {@link Vector2f}. - * Otherwise, see {@link MutableQuadView#sprite(int, int, float, float)}. - */ - default MutableQuadView sprite(int vertexIndex, int spriteIndex, Vector2f uv) { - return sprite(vertexIndex, spriteIndex, uv.x, uv.y); - } - - /** - * Assigns sprite atlas u,v coordinates to this quad for the given sprite. - * Can handle UV locking, rotation, interpolation, etc. Control this behavior - * by passing additive combinations of the BAKE_ flags defined in this interface. - * Behavior for {@code spriteIndex > 0} is currently undefined. - */ - MutableQuadView spriteBake(int spriteIndex, Sprite sprite, int bakeFlags); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java deleted file mode 100644 index e00a46190..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.mesh; - -import net.modificationstation.stationapi.api.client.render.RenderContext; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.api.util.math.Vector2f; - -/** - * Specialized {@link MutableQuadView} obtained via {@link MeshBuilder#getEmitter()} - * to append quads during mesh building. - * - *

Also obtained from {@link RenderContext#getEmitter()} to submit - * dynamic quads one-by-one at render time. - * - *

Instances of {@link QuadEmitter} will practically always be - * threadlocal and/or reused - do not retain references. - * - *

Only the renderer should implement or extend this interface. - */ -public interface QuadEmitter extends MutableQuadView { - @Override - QuadEmitter material(RenderMaterial material); - - @Override - QuadEmitter cullFace(Direction face); - - @Override - QuadEmitter nominalFace(Direction face); - - @Override - QuadEmitter colorIndex(int colourIndex); - - @Override - QuadEmitter tag(int tag); - - @Override - QuadEmitter pos(int vertexIndex, float x, float y, float z); - - @Override - default QuadEmitter pos(int vertexIndex, Vec3f vec) { - MutableQuadView.super.pos(vertexIndex, vec); - return this; - } - - @Override - default QuadEmitter normal(int vertexIndex, Vec3f vec) { - MutableQuadView.super.normal(vertexIndex, vec); - return this; - } - - @Override - QuadEmitter spriteColor(int vertexIndex, int spriteIndex, int color); - - @Override - default QuadEmitter spriteColor(int spriteIndex, int c0, int c1, int c2, int c3) { - MutableQuadView.super.spriteColor(spriteIndex, c0, c1, c2, c3); - return this; - } - - @Override - QuadEmitter sprite(int vertexIndex, int spriteIndex, float u, float v); - - /** - * Set sprite atlas coordinates. Behavior for {@code spriteIndex > 0} is currently undefined. - * - *

Only use this function if you already have a {@link Vector2f}. - * Otherwise, see {@link QuadEmitter#sprite(int, int, float, float)}. - */ - default QuadEmitter sprite(int vertexIndex, int spriteIndex, Vector2f uv) { - return sprite(vertexIndex, spriteIndex, uv.x, uv.y); - } - - default QuadEmitter spriteUnitSquare(int spriteIndex) { - sprite(0, spriteIndex, 0, 0); - sprite(1, spriteIndex, 0, 1); - sprite(2, spriteIndex, 1, 1); - sprite(3, spriteIndex, 1, 0); - return this; - } - - @Override - QuadEmitter spriteBake(int spriteIndex, Sprite sprite, int bakeFlags); - - /** - * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} - * is effectively zero - meaning the face is a cull face. - */ - float CULL_FACE_EPSILON = 0.00001f; - - /** - * Helper method to assign vertex coordinates for a square aligned with the given face. - * Ensures that vertex order is consistent with vanilla convention. (Incorrect order can - * lead to bad AO lighting unless enhanced lighting logic is available/enabled.) - * - *

Square will be parallel to the given face and coplanar with the face (and culled if the - * face is occluded) if the depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. - * - *

All coordinates should be normalized (0-1). - */ - default QuadEmitter square(Direction nominalFace, float left, float bottom, float right, float top, float depth) { - if (Math.abs(depth) < CULL_FACE_EPSILON) { - cullFace(nominalFace); - depth = 0; // avoid any inconsistency for face quads - } else { - cullFace(null); - } - - nominalFace(nominalFace); - switch (nominalFace) { - case UP: - depth = 1 - depth; - top = 1 - top; - bottom = 1 - bottom; - - case DOWN: - pos(0, left, depth, top); - pos(1, left, depth, bottom); - pos(2, right, depth, bottom); - pos(3, right, depth, top); - break; - - case WEST: - depth = 1 - depth; - left = 1 - left; - right = 1 - right; - - case EAST: - pos(0, 1 - left, top, depth); - pos(1, 1 - left, bottom, depth); - pos(2, 1 - right, bottom, depth); - pos(3, 1 - right, top, depth); - break; - - case SOUTH: - depth = 1 - depth; - left = 1 - left; - right = 1 - right; - - case NORTH: - pos(0, depth, top, left); - pos(1, depth, bottom, left); - pos(2, depth, bottom, right); - pos(3, depth, top, right); - break; - } - - return this; - } - - /** - * In static mesh building, causes quad to be appended to the mesh being built. - * In a dynamic render context, create a new quad to be output to rendering. - * In both cases, current instance is reset to default values. - */ - QuadEmitter emit(); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java deleted file mode 100644 index 7cb7c8126..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java +++ /dev/null @@ -1,187 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.mesh; - -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.render.model.BakedQuad; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Interface for reading quad data encoded by {@link MeshBuilder}. - * Enables models to do analysis, re-texturing or translation without knowing the - * renderer's vertex formats and without retaining redundant information. - * - *

Only the renderer should implement or extend this interface. - */ -public interface QuadView { - /** Count of integers in a conventional (un-modded) block or item vertex. */ - int VANILLA_VERTEX_STRIDE = 8; - - /** Count of integers in a conventional (un-modded) block or item quad. */ - int VANILLA_QUAD_STRIDE = VANILLA_VERTEX_STRIDE * 4; - - /** - * Reads baked vertex data and outputs standard baked quad - * vertex data in the given array and location. - * - * @param spriteIndex The sprite to be used for the quad. - * Behavior for values > 0 is currently undefined. - * - * @param target Target array for the baked quad data. - * - * @param targetIndex Starting position in target array - array must have - * at least 28 elements available at this index. - * - * @param isItem If true, will output vertex normals. Otherwise will output - * lightmaps, per Minecraft vertex formats for baked models. - */ - void toVanilla(int spriteIndex, int[] target, int targetIndex, boolean isItem); - - /** - * Extracts all quad properties except material to the given {@link MutableQuadView} instance. - * Must be used before calling {link QuadEmitter#emit()} on the target instance. - * Meant for re-texturing, analysis and static transformation use cases. - */ - void copyTo(MutableQuadView target); - - /** - * Retrieves the material serialized with the quad. - */ - RenderMaterial material(); - - /** - * Retrieves the quad color index serialized with the quad. - */ - int colorIndex(); - - /** - * Equivalent to {@link BakedQuad#getFace()}. This is the face used for vanilla lighting - * calculations and will be the block face to which the quad is most closely aligned. Always - * the same as cull face for quads that are on a block face, but never null. - */ - @NotNull - Direction lightFace(); - - /** - * If non-null, quad should not be rendered in-world if the - * opposite face of a neighbor block occludes it. - * - * @see MutableQuadView#cullFace(Direction) - */ - @Nullable Direction cullFace(); - - /** - * See {@link MutableQuadView#nominalFace(Direction)}. - */ - Direction nominalFace(); - - /** - * Normal of the quad as implied by geometry. Will be invalid - * if quad vertices are not co-planar. Typically computed lazily - * on demand and not encoded. - * - *

Not typically needed by models. Exposed to enable standard lighting - * utility functions for use by renderers. - */ - Vec3f faceNormal(); - - /** - * Generates a new BakedQuad instance with texture - * coordinates and colors from the given sprite. - * - * @param spriteIndex The sprite to be used for the quad. - * Behavior for {@code spriteIndex > 0} is currently undefined. - * - * @param sprite {@link MutableQuadView} does not serialize sprites - * so the sprite must be provided by the caller. - * - * @param isItem If true, will output vertex normals. Otherwise will output - * lightmaps, per Minecraft vertex formats for baked models. - * - * @return A new baked quad instance with the closest-available appearance - * supported by vanilla features. Will retain emissive light maps, for example, - * but the standard Minecraft renderer will not use them. - */ - default BakedQuad toBakedQuad(int spriteIndex, Sprite sprite, boolean isItem) { - int[] vertexData = new int[VANILLA_QUAD_STRIDE]; - toVanilla(spriteIndex, vertexData, 0, isItem); - return new BakedQuad(vertexData, colorIndex(), lightFace(), sprite, true); - } - - /** - * Retrieves the integer tag encoded with this quad via {@link MutableQuadView#tag(int)}. - * Will return zero if no tag was set. For use by models. - */ - int tag(); - - /** - * Pass a non-null target to avoid allocation - will be returned with values. - * Otherwise returns a new instance. - */ - Vec3f copyPos(int vertexIndex, @Nullable Vec3f target); - - /** - * Convenience: access x, y, z by index 0-2. - */ - float posByIndex(int vertexIndex, int coordinateIndex); - - /** - * Geometric position, x coordinate. - */ - float x(int vertexIndex); - - /** - * Geometric position, y coordinate. - */ - float y(int vertexIndex); - - /** - * Geometric position, z coordinate. - */ - float z(int vertexIndex); - - /** - * If false, no vertex normal was provided. - * Lighting should use face normal in that case. - */ - boolean hasNormal(int vertexIndex); - - /** - * Pass a non-null target to avoid allocation - will be returned with values. - * Otherwise returns a new instance. Returns null if normal not present. - */ - @Nullable - Vec3f copyNormal(int vertexIndex, @Nullable Vec3f target); - - /** - * Will return {@link Float#NaN} if normal not present. - */ - float normalX(int vertexIndex); - - /** - * Will return {@link Float#NaN} if normal not present. - */ - float normalY(int vertexIndex); - - /** - * Will return {@link Float#NaN} if normal not present. - */ - float normalZ(int vertexIndex); - - /** - * Retrieve vertex color. - */ - int spriteColor(int vertexIndex, int spriteIndex); - - /** - * Retrieve horizontal sprite atlas coordinates. - */ - float spriteU(int vertexIndex, int spriteIndex); - - /** - * Retrieve vertical sprite atlas coordinates. - */ - float spriteV(int vertexIndex, int spriteIndex); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java index da510c4b1..175a1647c 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java @@ -1,20 +1,14 @@ package net.modificationstation.stationapi.api.client.render.model; import com.google.common.collect.ImmutableList; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.render.RenderContext; import net.modificationstation.stationapi.api.client.render.model.json.ModelOverrideList; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; import net.modificationstation.stationapi.api.client.texture.Sprite; import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.MatrixStack; import org.jetbrains.annotations.Nullable; import java.util.Random; -import java.util.function.Supplier; public interface BakedModel { @@ -41,94 +35,4 @@ public interface BakedModel { ModelTransformation getTransformation(); ModelOverrideList getOverrides(); - - /** - * When true, signals renderer this producer is implemented through {@link BakedModel#getQuads(BlockState, Direction, Random)}. - * Also means the model does not rely on any non-vanilla features. - * Allows the renderer to optimize or route vanilla models through the unmodified vanilla pipeline if desired. - * - *

Fabric overrides to true for vanilla baked models. - * Enhanced models that use this API should return false, - * otherwise the API will not recognize the model. - */ - default boolean isVanillaAdapter() { - return true; - } - - /** - * This method will be called during chunk rebuilds to generate both the static and - * dynamic portions of a block model when the model implements this interface and - * {@link #isVanillaAdapter()} returns false. - * - *

During chunk rebuild, this method will always be called exactly one time per block - * position, irrespective of which or how many faces or block render layers are included - * in the model. Models must output all quads/meshes in a single pass. - * - *

Also called to render block models outside of chunk rebuild or block entity rendering. - * Typically this happens when the block is being rendered as an entity, not as a block placed in the world. - * Currently this happens for falling blocks and blocks being pushed by a piston, but renderers - * should invoke this for all calls to {@link BlockModelRenderer#render(BlockView, BakedModel, BlockState, TilePos, MatrixStack, VertexConsumer, boolean, Random, long, int)} - * that occur outside of chunk rebuilds to allow for features added by mods, unless - * {@link #isVanillaAdapter()} returns true. - * - *

Outside of chunk rebuilds, this method will be called every frame. Model implementations should - * rely on pre-baked meshes as much as possible and keep transformation to a minimum. The provided - * block position may be the nearest block position and not actual. For this reason, neighbor - * state lookups are best avoided or will require special handling. Block entity lookups are - * likely to fail and/or give meaningless results. - * - *

In all cases, renderer will handle face occlusion and filter quads on faces obscured by - * neighboring blocks (if appropriate). Models only need to consider "sides" to the - * extent the model is driven by connection with neighbor blocks or other world state. - * - *

Note: with {@link BakedModel#getQuads(BlockState, Direction, Random)}, the random - * parameter is normally initialized with the same seed prior to each face layer. - * Model authors should note this method is called only once per block, and call the provided - * Random supplier multiple times if re-seeding is necessary. For wrapped vanilla baked models, - * it will probably be easier to use {@link RenderContext#fallbackConsumer} which handles - * re-seeding per face automatically. - * - * @param blockView Access to world state. Using {@link net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView#getBlockEntityRenderAttachment(BlockPos)} to - * retrieve block entity state unless thread safety can be guaranteed. - * param safeBlockEntityAccessor Thread-safe access to block entity data - * @param state Block state for model being rendered. - * @param pos Position of block for model being rendered. - * @param randomSupplier Random object seeded per vanilla conventions. Call multiple times to re-seed. - * Will not be thread-safe. Do not cache or retain a reference. - * @param context Accepts model output. - */ - default void emitBlockQuads(BlockView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - context.fallbackConsumer().accept(this); - } - - /** - * This method will be called during item rendering to generate both the static and - * dynamic portions of an item model when the model implements this interface and - * {@link #isVanillaAdapter()} returns false. - * - *

Vanilla item rendering is normally very limited. It ignores lightmaps, vertex colors, - * and vertex normals. Renderers are expected to implement enhanced features for item - * models. If a feature is impractical due to performance or other concerns, then the - * renderer must at least give acceptable visual results without the need for special- - * case handling in model implementations. - * - *

Calls to this method will generally happen on the main client thread but nothing - * prevents a mod or renderer from calling this method concurrently. Implementations - * should not mutate the ItemStack parameter, and best practice will be to make the - * method thread-safe. - * - *

Implementing this method does NOT mitigate the need to implement a functional - * {@link BakedModel#getOverrides()} method, because this method will be called - * on the result of {@link BakedModel#getOverrides}. However, that - * method can simply return the base model because the output from this method will - * be used for rendering. - * - *

Renderer implementations should also use this method to obtain the quads used - * for item enchantment glint rendering. This means models can put geometric variation - * logic here, instead of returning every possible shape from {@link BakedModel#getOverrides} - * as vanilla baked models. - */ - default void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { - context.fallbackConsumer().accept(this); - } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java index 164e74a79..8c90d6fcd 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java @@ -1,18 +1,13 @@ package net.modificationstation.stationapi.api.client.render.model; import com.google.common.collect.ImmutableList; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.render.RenderContext; import net.modificationstation.stationapi.api.client.render.model.json.ModelOverrideList; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; import net.modificationstation.stationapi.api.client.texture.Sprite; import net.modificationstation.stationapi.api.util.math.Direction; import java.util.Random; -import java.util.function.Supplier; /** * Base class for specialized model implementations that need to wrap other baked models. @@ -23,18 +18,6 @@ public abstract class ForwardingBakedModel implements BakedModel { /** implementations must set this somehow. */ protected BakedModel wrapped; - public void emitBlockQuads(BlockView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - wrapped.emitBlockQuads(blockView, state, pos, randomSupplier, context); - } - - public boolean isVanillaAdapter() { - return wrapped.isVanillaAdapter(); - } - - public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { - wrapped.emitItemQuads(stack, randomSupplier, context); - } - @Override public ImmutableList getQuads(BlockState blockState, Direction face, Random rand) { return wrapped.getQuads(blockState, face, rand); diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java deleted file mode 100644 index 9021a87ed..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java +++ /dev/null @@ -1,113 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.model; - -import com.google.common.collect.ImmutableList; -import net.modificationstation.stationapi.api.client.StationRenderAPI; -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; -import net.modificationstation.stationapi.api.client.render.model.json.Transformation; -import net.modificationstation.stationapi.api.client.texture.atlas.Atlases; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; - -/** - * Collection of utilities for model implementations. - */ -public abstract class ModelHelper { - private ModelHelper() { } - - /** Result from {@link #toFaceIndex(Direction)} for null values. */ - public static final int NULL_FACE_ID = 6; - - /** - * Convenient way to encode faces that may be null. - * Null is returned as {@link #NULL_FACE_ID}. - * Use {@link #faceFromIndex(int)} to retrieve encoded face. - */ - public static int toFaceIndex(Direction face) { - return face == null ? NULL_FACE_ID : face.getId(); - } - - /** - * Use to decode a result from {@link #toFaceIndex(Direction)}. - * Return value will be null if encoded value was null. - * Can also be used for no-allocation iteration of {@link Direction#values()}, - * optionally including the null face. (Use < or <= {@link #NULL_FACE_ID} - * to exclude or include the null value, respectively.) - */ - @Nullable - public static Direction faceFromIndex(int faceIndex) { - return FACES[faceIndex]; - } - - /** @see #faceFromIndex(int) */ - private static final Direction[] FACES = Arrays.copyOf(Direction.values(), 7); - - /** - * Converts a mesh into an array of lists of vanilla baked quads. - * Useful for creating vanilla baked models when required for compatibility. - * The array indexes correspond to {@link Direction#getId()} with the - * addition of {@link #NULL_FACE_ID}. - * - *

Retrieves sprites from the block texture atlas via {@link SpriteFinder}. - */ - public static List[] toQuadLists(Mesh mesh) { - SpriteFinder finder = SpriteFinder.get(StationRenderAPI.getBakedModelManager().getAtlas(Atlases.GAME_ATLAS_TEXTURE)); - - @SuppressWarnings("unchecked") - final ImmutableList.Builder[] builders = new ImmutableList.Builder[7]; - - for (int i = 0; i < 7; i++) { - builders[i] = ImmutableList.builder(); - } - - if (mesh != null) { - mesh.forEach(q -> { - final int limit = q.material().spriteDepth(); - - for (int l = 0; l < limit; l++) { - Direction face = q.cullFace(); - builders[face == null ? 6 : face.getId()].add(q.toBakedQuad(l, finder.find(q, l), false)); - } - }); - } - - @SuppressWarnings("unchecked") - List[] result = new List[7]; - - for (int i = 0; i < 7; i++) { - result[i] = builders[i].build(); - } - - return result; - } - - /** - * The vanilla model transformation logic is closely coupled with model deserialization. - * That does little good for modded model loaders and procedurally generated models. - * This convenient construction method applies the same scaling factors used for vanilla models. - * This means you can use values from a vanilla JSON file as inputs to this method. - */ - private static Transformation makeTransform(float rotationX, float rotationY, @SuppressWarnings("SameParameterValue") float rotationZ, @SuppressWarnings("SameParameterValue") float translationX, float translationY, @SuppressWarnings("SameParameterValue") float translationZ, float scaleX, float scaleY, float scaleZ) { - Vec3f translation = new Vec3f(translationX, translationY, translationZ); - translation.scale(0.0625f); - translation.clamp(-5.0F, 5.0F); - return new Transformation(new Vec3f(rotationX, rotationY, rotationZ), translation, new Vec3f(scaleX, scaleY, scaleZ)); - } - - public static final Transformation TRANSFORM_BLOCK_GUI = makeTransform(30, 225, 0, 0, 0, 0, 0.625f, 0.625f, 0.625f); - public static final Transformation TRANSFORM_BLOCK_GROUND = makeTransform(0, 0, 0, 0, 3, 0, 0.25f, 0.25f, 0.25f); - public static final Transformation TRANSFORM_BLOCK_FIXED = makeTransform(0, 0, 0, 0, 0, 0, 0.5f, 0.5f, 0.5f); - public static final Transformation TRANSFORM_BLOCK_3RD_PERSON_RIGHT = makeTransform(75, 45, 0, 0, 2.5f, 0, 0.375f, 0.375f, 0.375f); - public static final Transformation TRANSFORM_BLOCK_1ST_PERSON_RIGHT = makeTransform(0, 45, 0, 0, 0, 0, 0.4f, 0.4f, 0.4f); - public static final Transformation TRANSFORM_BLOCK_1ST_PERSON_LEFT = makeTransform(0, 225, 0, 0, 0, 0, 0.4f, 0.4f, 0.4f); - - /** - * Mimics the vanilla model transformation used for most vanilla blocks, - * and should be suitable for most custom block-like models. - */ - public static final ModelTransformation MODEL_TRANSFORM_BLOCK = new ModelTransformation(TRANSFORM_BLOCK_3RD_PERSON_RIGHT, TRANSFORM_BLOCK_3RD_PERSON_RIGHT, TRANSFORM_BLOCK_1ST_PERSON_LEFT, TRANSFORM_BLOCK_1ST_PERSON_RIGHT, Transformation.IDENTITY, TRANSFORM_BLOCK_GUI, TRANSFORM_BLOCK_GROUND, TRANSFORM_BLOCK_FIXED); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java index c973f0337..60cbbb154 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java @@ -5,11 +5,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.render.RenderContext; import net.modificationstation.stationapi.api.client.render.model.json.ModelOverrideList; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; import net.modificationstation.stationapi.api.client.texture.Sprite; @@ -23,7 +19,6 @@ import java.util.Map; import java.util.Random; import java.util.function.Predicate; -import java.util.function.Supplier; @Environment(EnvType.CLIENT) public class MultipartBakedModel implements BakedModel { @@ -35,7 +30,6 @@ public class MultipartBakedModel implements BakedModel { protected final ModelTransformation transformations; protected final ModelOverrideList itemPropertyOverrides; private final Map stateCache = new Object2ObjectOpenCustomHashMap<>(Util.identityHashStrategy()); - private final boolean isVanilla; public MultipartBakedModel(List, BakedModel>> components) { this.components = components; @@ -46,46 +40,6 @@ public MultipartBakedModel(List, BakedModel>> compone this.sprite = bakedModel.getSprite(); this.transformations = bakedModel.getTransformation(); this.itemPropertyOverrides = bakedModel.getOverrides(); - boolean isVanilla = true; - for (Pair, BakedModel> component : components) - if (!component.getRight().isVanillaAdapter()) { - isVanilla = false; - break; - } - this.isVanilla = isVanilla; - } - - @Override - public boolean isVanillaAdapter() { - return isVanilla; - } - - @Override - public void emitBlockQuads(BlockView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - BitSet bitSet = this.stateCache.get(state); - - if (bitSet == null) { - bitSet = new BitSet(); - - for (int i = 0; i < this.components.size(); i++) { - Pair, BakedModel> pair = components.get(i); - - if (pair.getLeft().test(state)) { - pair.getRight().emitBlockQuads(blockView, state, pos, randomSupplier, context); - bitSet.set(i); - } - } - - stateCache.put(state, bitSet); - } else - for (int i = 0; i < this.components.size(); i++) - if (bitSet.get(i)) - components.get(i).getRight().emitBlockQuads(blockView, state, pos, randomSupplier, context); - } - - @Override - public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { - // Vanilla doesn't use MultipartBakedModel for items. } @Override diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java deleted file mode 100644 index dd0b9d678..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.model; - -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; -import net.modificationstation.stationapi.impl.client.render.SpriteFinderImpl; - -/** - * Indexes a texture atlas to allow fast lookup of Sprites from - * baked vertex coordinates. Main use is for {@link Mesh}-based models - * to generate vanilla quads on demand without tracking and retaining - * the sprites that were baked into the mesh. In other words, this class - * supplies the sprite parameter for {@link QuadView#toBakedQuad(int, Sprite, boolean)}. - */ -public interface SpriteFinder { - /** - * Retrieves or creates the finder for the given atlas. - * Instances should not be retained as fields or they must be - * refreshed whenever there is a resource reload or other event - * that causes atlas textures to be re-stitched. - */ - static SpriteFinder get(SpriteAtlasTexture atlas) { - return SpriteFinderImpl.get(atlas); - } - - /** - * Finds the atlas sprite containing the vertex centroid of the quad. - * Vertex centroid is essentially the mean u,v coordinate - the intent being - * to find a point that is unambiguously inside the sprite (vs on an edge.) - * - *

Should be reliable for any convex quad or triangle. May fail for non-convex quads. - * Note that all the above refers to u,v coordinates. Geometric vertex does not matter, - * except to the extent it was used to determine u,v. - */ - Sprite find(QuadView quad, int textureIndex); - - /** - * Alternative to {@link #find(QuadView, int)} when vertex centroid is already - * known or unsuitable. Expects normalized (0-1) coordinates on the atlas texture, - * which should already be the case for u,v values in vanilla baked quads and in - * {@link QuadView} after calling {@link MutableQuadView#spriteBake(int, Sprite, int)}. - * - *

Coordinates must be in the sprite interior for reliable results. Generally will - * be easier to use {@link #find(QuadView, int)} unless you know the vertex - * centroid will somehow not be in the quad interior. This method will be slightly - * faster if you already have the centroid or another appropriate value. - */ - Sprite find(float u, float v); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java index a876640f9..a9059606f 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java @@ -4,11 +4,7 @@ import com.google.common.collect.Lists; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.render.RenderContext; import net.modificationstation.stationapi.api.client.render.model.json.ModelOverrideList; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; import net.modificationstation.stationapi.api.client.texture.Sprite; @@ -19,45 +15,17 @@ import java.util.List; import java.util.Objects; import java.util.Random; -import java.util.function.Supplier; @Environment(EnvType.CLIENT) public class WeightedBakedModel implements BakedModel { private final int totalWeight; private final List models; private final BakedModel defaultModel; - private final boolean isVanilla; public WeightedBakedModel(List models) { this.models = models; this.totalWeight = WeightedPicker.getWeightSum(models); this.defaultModel = models.get(0).model; - boolean isVanilla = true; - for (Entry model : models) - if (!model.model.isVanillaAdapter()) { - isVanilla = false; - break; - } - this.isVanilla = isVanilla; - } - - @Override - public boolean isVanillaAdapter() { - return isVanilla; - } - - @Override - public void emitBlockQuads(BlockView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - Entry entry = WeightedPicker.getAt(this.models, Math.abs((int) randomSupplier.get().nextLong()) % this.totalWeight); - if (entry != null) - entry.model.emitBlockQuads(blockView, state, pos, randomSupplier, context); - } - - @Override - public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { - Entry entry = WeightedPicker.getAt(this.models, Math.abs((int) randomSupplier.get().nextLong()) % this.totalWeight); - if (entry != null) - entry.model.emitItemQuads(stack, randomSupplier, context); } @Override diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java index 0b9db1805..24794cabb 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java @@ -1,12 +1,11 @@ package net.modificationstation.stationapi.api.client.texture; import lombok.Getter; -import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.resource.ResourceManager; +import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.util.crash.CrashException; import net.modificationstation.stationapi.api.util.crash.CrashReport; import net.modificationstation.stationapi.api.util.crash.CrashReportSection; -import net.modificationstation.stationapi.impl.client.render.SpriteFinderImpl; import java.io.BufferedWriter; import java.io.IOException; @@ -29,7 +28,6 @@ public class SpriteAtlasTexture extends AbstractTexture implements DynamicTextur private int width; @Getter private int height; - private SpriteFinderImpl spriteFinder = null; public SpriteAtlasTexture(Identifier id) { this.id = id; @@ -65,7 +63,6 @@ public void upload(SpriteLoader.StitchResult stitchResult) { } this.spritesToLoad = List.copyOf(list); this.animatedSprites = List.copyOf(list2); - spriteFinder = null; } @Override @@ -118,14 +115,5 @@ public int getMaxTextureSize() { public void applyTextureFilter(SpriteLoader.StitchResult data) { this.setFilter(false, false); } - - public SpriteFinderImpl spriteFinder() { - SpriteFinderImpl result = spriteFinder; - if (result == null) { - result = new SpriteFinderImpl(sprites, this); - spriteFinder = result; - } - return result; - } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/SpriteFinderImpl.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/SpriteFinderImpl.java deleted file mode 100644 index 0b7d1835e..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/SpriteFinderImpl.java +++ /dev/null @@ -1,130 +0,0 @@ -package net.modificationstation.stationapi.impl.client.render; - -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.client.render.model.SpriteFinder; -import net.modificationstation.stationapi.api.client.texture.MissingSprite; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; -import net.modificationstation.stationapi.api.util.Identifier; - -import java.util.Map; -import java.util.function.Consumer; - -/** - * Indexes an atlas sprite to allow fast lookup of Sprites from - * baked vertex coordinates. Implementation is a straightforward - * quad tree. Other options that were considered were linear search - * (slow) and direct indexing of fixed-size cells. Direct indexing - * would be fastest but would be memory-intensive for large atlases - * and unsuitable for any atlas that isn't consistently aligned to - * a fixed cell size. - */ -public class SpriteFinderImpl implements SpriteFinder { - - private final Node root; - private final SpriteAtlasTexture spriteAtlasTexture; - - public SpriteFinderImpl(Map sprites, SpriteAtlasTexture spriteAtlasTexture) { - root = new Node(0.5f, 0.5f, 0.25f); - this.spriteAtlasTexture = spriteAtlasTexture; - sprites.values().forEach(root::add); - } - - @Override - public Sprite find(QuadView quad, int textureIndex) { - float u = 0; - float v = 0; - - for (int i = 0; i < 4; i++) { - u += quad.spriteU(i, textureIndex); - v += quad.spriteV(i, textureIndex); - } - - return find(u * 0.25f, v * 0.25f); - } - - @Override - public Sprite find(float u, float v) { - return root.find(u, v); - } - - private class Node { - final float midU; - final float midV; - final float cellRadius; - Object lowLow = null; - Object lowHigh = null; - Object highLow = null; - Object highHigh = null; - - Node(float midU, float midV, float radius) { - this.midU = midU; - this.midV = midV; - cellRadius = radius; - } - - static final float EPS = 0.00001f; - - void add(Sprite sprite) { - final boolean lowU = sprite.getMinU() < midU - EPS; - final boolean highU = sprite.getMaxU() > midU + EPS; - final boolean lowV = sprite.getMinV() < midV - EPS; - final boolean highV = sprite.getMaxV() > midV + EPS; - - if (lowU && lowV) { - addInner(sprite, lowLow, -1, -1, q -> lowLow = q); - } - - if (lowU && highV) { - addInner(sprite, lowHigh, -1, 1, q -> lowHigh = q); - } - - if (highU && lowV) { - addInner(sprite, highLow, 1, -1, q -> highLow = q); - } - - if (highU && highV) { - addInner(sprite, highHigh, 1, 1, q -> highHigh = q); - } - } - - private void addInner(Sprite sprite, Object quadrant, int uStep, int vStep, Consumer setter) { - if (quadrant == null) { - setter.accept(sprite); - } else if (quadrant instanceof Node) { - ((Node) quadrant).add(sprite); - } else { - Node n = new Node(midU + cellRadius * uStep, midV + cellRadius * vStep, cellRadius * 0.5f); - - if (quadrant instanceof Sprite) { - n.add((Sprite) quadrant); - } - - n.add(sprite); - setter.accept(n); - } - } - - private Sprite find(float u, float v) { - if (u < midU) { - return v < midV ? findInner(lowLow, u, v) : findInner(lowHigh, u, v); - } else { - return v < midV ? findInner(highLow, u, v) : findInner(highHigh, u, v); - } - } - - private Sprite findInner(Object quadrant, float u, float v) { - if (quadrant instanceof Sprite) { - return (Sprite) quadrant; - } else if (quadrant instanceof Node) { - return ((Node) quadrant).find(u, v); - } else { - return spriteAtlasTexture.getSprite(MissingSprite.getMissingSpriteId()); - } - } - } - - public static SpriteFinderImpl get(SpriteAtlasTexture atlas) { - return atlas.spriteFinder(); - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/ArsenicRenderer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/ArsenicRenderer.java index ef4923047..a047304dd 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/ArsenicRenderer.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/ArsenicRenderer.java @@ -4,16 +4,9 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import net.modificationstation.stationapi.api.client.render.Renderer; -import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.render.mesh.MeshBuilder; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; -import net.modificationstation.stationapi.api.util.Identifier; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MeshBuilderImpl; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.BakedModelRendererImpl; -import java.util.IdentityHashMap; -import java.util.Map; import java.util.function.Supplier; @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -21,38 +14,6 @@ public final class ArsenicRenderer implements Renderer { public static final ArsenicRenderer INSTANCE = new ArsenicRenderer(); - public static final RenderMaterialImpl.Value MATERIAL_STANDARD = (RenderMaterialImpl.Value) INSTANCE.materialFinder().find(); - - static { - INSTANCE.registerMaterial(RenderMaterial.MATERIAL_STANDARD, MATERIAL_STANDARD); - } - - private final Map materialMap = new IdentityHashMap<>(); - - @Override - public MeshBuilder meshBuilder() { - return new MeshBuilderImpl(); - } - - @Override - public MaterialFinder materialFinder() { - return new RenderMaterialImpl.Finder(); - } - - @Override - public RenderMaterial materialById(Identifier id) { - return materialMap.get(id); - } - - @Override - public boolean registerMaterial(Identifier id, RenderMaterial material) { - if (materialMap.containsKey(id)) return false; - - // cast to prevent acceptance of impostor implementations - materialMap.put(id, material); - return true; - } - @Override public BakedModelRenderer bakedModelRenderer() { return bakedModelRenderer.get(); diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/RenderMaterialImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/RenderMaterialImpl.java deleted file mode 100644 index 519391ed2..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/RenderMaterialImpl.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer; - -import com.google.common.base.Preconditions; -import net.modificationstation.stationapi.api.client.render.material.BlendMode; -import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.util.math.MathHelper; - -/** - * 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 abstract class RenderMaterialImpl { - private static final BlendMode[] BLEND_MODES = BlendMode.values(); - - private static final int BLEND_MODE_MASK = MathHelper.smallestEncompassingPowerOfTwo(BlendMode.values().length) - 1; - private static final int COLOR_DISABLE_FLAG = BLEND_MODE_MASK + 1; - private static final int EMISSIVE_FLAG = COLOR_DISABLE_FLAG << 1; - private static final int DIFFUSE_FLAG = EMISSIVE_FLAG << 1; - private static final int AO_FLAG = DIFFUSE_FLAG << 1; - public static final int VALUE_COUNT = (AO_FLAG << 1); - - private static final Value[] VALUES = new Value[VALUE_COUNT]; - - static { - for (int i = 0; i < VALUE_COUNT; i++) { - VALUES[i] = new Value(i); - } - } - - public static RenderMaterialImpl.Value byIndex(int index) { - return VALUES[index]; - } - - protected int bits; - - public BlendMode blendMode(int textureIndex) { - return BLEND_MODES[bits & BLEND_MODE_MASK]; - } - - public boolean disableColorIndex(int textureIndex) { - return (bits & COLOR_DISABLE_FLAG) != 0; - } - - public int spriteDepth() { - return 1; - } - - public boolean emissive(int textureIndex) { - return (bits & EMISSIVE_FLAG) != 0; - } - - public boolean disableDiffuse(int textureIndex) { - return (bits & DIFFUSE_FLAG) != 0; - } - - public boolean disableAo(int textureIndex) { - return (bits & AO_FLAG) != 0; - } - - public static class Value extends RenderMaterialImpl implements RenderMaterial { - private Value(int bits) { - this.bits = bits; - } - - public int index() { - return bits; - } - } - - public static class Finder extends RenderMaterialImpl implements MaterialFinder { - @Override - public RenderMaterial find() { - return VALUES[bits]; - } - - @Override - public MaterialFinder clear() { - bits = 0; - return this; - } - - @Override - public MaterialFinder blendMode(int textureIndex, BlendMode blendMode) { - if (blendMode == null) { - blendMode = BlendMode.DEFAULT; - } - - bits = (bits & ~BLEND_MODE_MASK) | blendMode.ordinal(); - return this; - } - - @Override - public MaterialFinder disableColorIndex(int textureIndex, boolean disable) { - bits = disable ? (bits | COLOR_DISABLE_FLAG) : (bits & ~COLOR_DISABLE_FLAG); - return this; - } - - @Override - public MaterialFinder spriteDepth(int depth) { - Preconditions.checkArgument(depth == 1, "Unsupported sprite depth: %s", depth); - - return this; - } - - @Override - public MaterialFinder emissive(int textureIndex, boolean isEmissive) { - bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG); - return this; - } - - @Override - public MaterialFinder disableDiffuse(int textureIndex, boolean disable) { - bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG); - return this; - } - - @Override - public MaterialFinder disableAo(int textureIndex, boolean disable) { - bits = disable ? (bits | AO_FLAG) : (bits & ~AO_FLAG); - return this; - } - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/aocalc/LightingCalculatorImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/aocalc/LightingCalculatorImpl.java index 4c3ec343e..c79d428d2 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/aocalc/LightingCalculatorImpl.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/aocalc/LightingCalculatorImpl.java @@ -2,11 +2,9 @@ import net.minecraft.block.Block; import net.minecraft.world.BlockView; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; import net.modificationstation.stationapi.api.client.render.model.BakedQuad; import net.modificationstation.stationapi.api.util.math.Direction; import net.modificationstation.stationapi.api.util.math.MathHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MutableQuadViewImpl; import java.util.Arrays; @@ -114,17 +112,6 @@ public void calculateForQuad(BakedQuad q) { light[3] = MathHelper.lerp(emission, light[3], 1F); } - public void calculateForQuad(MutableQuadViewImpl q) { - calculateForQuad( - q.lightFace(), - x + q.x(0), y + q.y(0), z + q.z(0), - x + q.x(1), y + q.y(1), z + q.z(1), - x + q.x(2), y + q.y(2), z + q.z(2), - x + q.x(3), y + q.y(3), z + q.z(3), - q.hasShade() - ); - } - private void calculateForQuad( Direction face, double v00x, double v00y, double v00z, @@ -458,7 +445,7 @@ private void quadFast( case X -> Math.abs(mX - x); case Y -> Math.abs(mY - y); case Z -> Math.abs(mZ - z); - } < QuadEmitter.CULL_FACE_EPSILON ? + } < 0.00001f ? light(floor(mX) + face.getOffsetX(), floor(mY) + face.getOffsetY(), floor(mZ) + face.getOffsetZ()) : light(floor(mX), floor(mY), floor(mZ)); } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/ColorHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/ColorHelper.java deleted file mode 100644 index 394015844..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/ColorHelper.java +++ /dev/null @@ -1,59 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.helper; - -import it.unimi.dsi.fastutil.ints.Int2IntFunction; - -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 Int2IntFunction colorSwapper = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? color -> ((color & 0xFF00FF00) | ((color & 0x00FF0000) >> 16) | ((color & 0xFF) << 16)) : color -> color; - - /** - * Swaps red blue order if needed to match GPU expectations for color component order. - */ - public static int swapRedBlueIfNeeded(int color) { - return colorSwapper.applyAsInt(color); - } - - /** Component-wise multiply. Components need to be in same order in both inputs! */ - public static int multiplyColour(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); - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/GeometryHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/GeometryHelper.java deleted file mode 100644 index 0b181c71c..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/GeometryHelper.java +++ /dev/null @@ -1,222 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.helper; - -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.client.render.model.BakedQuad; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import org.jetbrains.annotations.NotNull; - -import static net.modificationstation.stationapi.api.util.math.MathHelper.approximatelyEquals; - -/** - * 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) { - if (face == null) { - return false; - } - - int i = face.getAxis().ordinal(); - final float val = quad.posByIndex(0, i); - return approximatelyEquals(val, quad.posByIndex(1, i)) && approximatelyEquals(val, quad.posByIndex(2, i)) && approximatelyEquals(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) { - if (lightFace == null) return false; - - final float x = quad.posByIndex(0, lightFace.getAxis().ordinal()); - return lightFace.getDirection() == Direction.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. - * - * @param lightFace MUST be non-null. - */ - public static boolean isQuadCubic(@NotNull 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#getFace()} 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 Vec3f normal = quad.faceNormal(); - return switch (GeometryHelper.longestAxis(normal)) { - case X -> normal.getX() > 0 ? Direction.EAST : Direction.WEST; - case Y -> normal.getY() > 0 ? Direction.UP : Direction.DOWN; - case Z -> normal.getZ() > 0 ? Direction.SOUTH : Direction.NORTH; - }; - } - - /** - * Simple 4-way compare, doesn't handle NaN values. - */ - public static float min(float a, float b, float c, float d) { - final float x = Math.min(a, b); - final float y = Math.min(c, d); - return Math.min(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 = Math.max(a, b); - final float y = Math.max(c, d); - return Math.max(x, y); - } - - /** - * @see #longestAxis(float, float, float) - */ - public static Direction.Axis longestAxis(Vec3f vec) { - return longestAxis(vec.getX(), vec.getY(), vec.getZ()); - } - - /** - * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector. - */ - public static Direction.Axis longestAxis(float normalX, float normalY, float normalZ) { - Direction.Axis result = Direction.Axis.Y; - float longest = Math.abs(normalY); - float a = Math.abs(normalX); - - if (a > longest) { - result = Direction.Axis.X; - longest = a; - } - - return Math.abs(normalZ) > longest - ? Direction.Axis.Z : result; - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/NormalHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/NormalHelper.java deleted file mode 100644 index 417c74e9f..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/NormalHelper.java +++ /dev/null @@ -1,99 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.helper; - -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.MathHelper; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.api.util.math.Vec3i; -import org.jetbrains.annotations.NotNull; - -/** - * 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() { } - - /** - * Stores a normal plus an extra value as a quartet of signed bytes. - * This is the same normal format that vanilla item rendering expects. - * The extra value is for use by shaders. - */ - public static int packNormal(float x, float y, float z, float w) { - x = MathHelper.clamp(x, -1, 1); - y = MathHelper.clamp(y, -1, 1); - z = MathHelper.clamp(z, -1, 1); - w = MathHelper.clamp(w, -1, 1); - - return ((int) (x * 127) & 255) | (((int) (y * 127) & 255) << 8) | (((int) (z * 127) & 255) << 16) | (((int) (w * 127) & 255) << 24); - } - - /** - * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type. - */ - public static int packNormal(Vec3f normal, float w) { - return packNormal(normal.getX(), normal.getY(), normal.getZ(), w); - } - - /** - * Retrieves values packed by {@link #packNormal(float, float, float, float)}. - * - *

Components are x, y, z, w - zero based. - */ - public static float getPackedNormalComponent(int packedNormal, int component) { - return ((byte) (packedNormal >> (8 * component))) / 127f; - } - - /** - * 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 Vec3f saveTo, QuadView q) { - final Direction nominalFace = q.nominalFace(); - - if (GeometryHelper.isQuadParallelToFace(nominalFace, q)) { - Vec3i vec = nominalFace.getVector(); - 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); - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/TextureHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/TextureHelper.java deleted file mode 100644 index 7eebdcfae..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/helper/TextureHelper.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.helper; - -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; - -/** - * Handles most texture-baking use cases for model loaders and model libraries - * via {@link #bakeSprite(MutableQuadView, int, Sprite, 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, int spriteIndex, Sprite sprite, int bakeFlags) { - if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) { - // Assigns normalized UV coordinates based on vertex positions - applyModifier(quad, spriteIndex, UVLOCKERS[quad.nominalFace().getId()]); - } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { - // Scales from 0-16 to 0-1 - applyModifier(quad, spriteIndex, (q, i, t) -> q.sprite(i, t, q.spriteU(i, t) * NORMALIZER, q.spriteV(i, t) * NORMALIZER)); - } - - final int rotation = bakeFlags & 3; - - if (rotation != 0) { - // Rotates texture around the center of sprite. - // Assumes normalized coordinates. - applyModifier(quad, spriteIndex, ROTATIONS[rotation]); - } - - if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) { - // Inverts U coordinates. Assumes normalized (0-1) values. - applyModifier(quad, spriteIndex, (q, i, t) -> q.sprite(i, t, 1 - q.spriteU(i, t), q.spriteV(i, t))); - } - - if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) { - // Inverts V coordinates. Assumes normalized (0-1) values. - applyModifier(quad, spriteIndex, (q, i, t) -> q.sprite(i, t, q.spriteU(i, t), 1 - q.spriteV(i, t))); - } - - interpolate(quad, spriteIndex, 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, int spriteIndex, Sprite sprite) { - final float uMin = sprite.getMinU(); - final float uSpan = sprite.getMaxU() - uMin; - final float vMin = sprite.getMinV(); - final float vSpan = sprite.getMaxV() - vMin; - - for (int i = 0; i < 4; i++) { - q.sprite(i, spriteIndex, uMin + q.spriteU(i, spriteIndex) * uSpan, vMin + q.spriteV(i, spriteIndex) * vSpan); - } - } - - @FunctionalInterface - private interface VertexModifier { - void apply(MutableQuadView quad, int vertexIndex, int spriteIndex); - } - - private static void applyModifier(MutableQuadView quad, int spriteIndex, VertexModifier modifier) { - for (int i = 0; i < 4; i++) { - modifier.apply(quad, i, spriteIndex); - } - } - - private static final VertexModifier[] ROTATIONS = new VertexModifier[] { - null, - (q, i, t) -> q.sprite(i, t, q.spriteV(i, t), 1 - q.spriteU(i, t)), //90 - (q, i, t) -> q.sprite(i, t, 1 - q.spriteU(i, t), 1 - q.spriteV(i, t)), //180 - (q, i, t) -> q.sprite(i, t, 1 - q.spriteV(i, t), q.spriteU(i, t)) // 270 - }; - - private static final VertexModifier[] UVLOCKERS = new VertexModifier[6]; - - static { - UVLOCKERS[Direction.SOUTH.getId()] = (q, i, t) -> q.sprite(i, t, 1 - q.z(i), 1 - q.y(i)); - UVLOCKERS[Direction.NORTH.getId()] = (q, i, t) -> q.sprite(i, t, q.z(i), 1 - q.y(i)); - UVLOCKERS[Direction.EAST.getId()] = (q, i, t) -> q.sprite(i, t, 1 - q.x(i), 1 - q.y(i)); - UVLOCKERS[Direction.WEST.getId()] = (q, i, t) -> q.sprite(i, t, q.x(i), 1 - q.y(i)); - UVLOCKERS[Direction.DOWN.getId()] = (q, i, t) -> q.sprite(i, t, q.x(i), 1 - q.z(i)); - UVLOCKERS[Direction.UP.getId()] = (q, i, t) -> q.sprite(i, t, q.x(i), q.z(i)); - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/EncodingFormat.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/EncodingFormat.java deleted file mode 100644 index 9829bfe77..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/EncodingFormat.java +++ /dev/null @@ -1,121 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh; - -import com.google.common.base.Preconditions; -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.client.render.model.ModelHelper; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.MathHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.RenderMaterialImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.GeometryHelper; - -/** - * 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_COLOR_INDEX = 1; - static final int HEADER_TAG = 2; - public static final int HEADER_STRIDE = 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_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 { - VERTEX_X = HEADER_STRIDE; - VERTEX_Y = HEADER_STRIDE + 1; - VERTEX_Z = HEADER_STRIDE + 2; - VERTEX_U = HEADER_STRIDE + 4; - VERTEX_V = VERTEX_U + 1; - VERTEX_COLOR = HEADER_STRIDE + 6; - VERTEX_NORMAL = HEADER_STRIDE + 7; - VERTEX_STRIDE = 8; - QUAD_STRIDE = VERTEX_STRIDE * 4; - QUAD_STRIDE_BYTES = QUAD_STRIDE * 4; - TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE; - - //noinspection ConstantValue - Preconditions.checkState(VERTEX_STRIDE == QuadView.VANILLA_VERTEX_STRIDE, "Indigo vertex stride (%s) mismatched with rendering API (%s)", VERTEX_STRIDE, QuadView.VANILLA_VERTEX_STRIDE); - //noinspection ConstantValue - 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_MASK = MathHelper.smallestEncompassingPowerOfTwo(ModelHelper.NULL_FACE_ID) - 1; - private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK); - private static final int CULL_SHIFT = 0; - private static final int CULL_INVERSE_MASK = ~(DIRECTION_MASK << CULL_SHIFT); - private static final int LIGHT_SHIFT = CULL_SHIFT + DIRECTION_BIT_COUNT; - private static final int LIGHT_INVERSE_MASK = ~(DIRECTION_MASK << LIGHT_SHIFT); - private static final int NORMALS_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT; - private static final int NORMALS_COUNT = 4; - private static final int NORMALS_MASK = (1 << NORMALS_COUNT) - 1; - private static final int NORMALS_INVERSE_MASK = ~(NORMALS_MASK << NORMALS_SHIFT); - private static final int GEOMETRY_SHIFT = NORMALS_SHIFT + NORMALS_COUNT; - private static final int GEOMETRY_MASK = (1 << GeometryHelper.FLAG_BIT_COUNT) - 1; - private static final int GEOMETRY_INVERSE_MASK = ~(GEOMETRY_MASK << GEOMETRY_SHIFT); - private static final int MATERIAL_SHIFT = GEOMETRY_SHIFT + GeometryHelper.FLAG_BIT_COUNT; - private static final int MATERIAL_MASK = MathHelper.smallestEncompassingPowerOfTwo(RenderMaterialImpl.VALUE_COUNT) - 1; - private static final int MATERIAL_BIT_COUNT = Integer.bitCount(MATERIAL_MASK); - private static final int MATERIAL_INVERSE_MASK = ~(MATERIAL_MASK << MATERIAL_SHIFT); - - static { - Preconditions.checkArgument(MATERIAL_SHIFT + MATERIAL_BIT_COUNT <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE); - } - - static Direction cullFace(int bits) { - return ModelHelper.faceFromIndex((bits >> CULL_SHIFT) & DIRECTION_MASK); - } - - static int cullFace(int bits, Direction face) { - return (bits & CULL_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << CULL_SHIFT); - } - - static Direction lightFace(int bits) { - return ModelHelper.faceFromIndex((bits >> LIGHT_SHIFT) & DIRECTION_MASK); - } - - static int lightFace(int bits, Direction face) { - return (bits & LIGHT_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_SHIFT); - } - - /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */ - static int normalFlags(int bits) { - return (bits >> NORMALS_SHIFT) & NORMALS_MASK; - } - - static int normalFlags(int bits, int normalFlags) { - return (bits & NORMALS_INVERSE_MASK) | ((normalFlags & NORMALS_MASK) << NORMALS_SHIFT); - } - - static int geometryFlags(int bits) { - return (bits >> GEOMETRY_SHIFT) & GEOMETRY_MASK; - } - - static int geometryFlags(int bits, int geometryFlags) { - return (bits & GEOMETRY_INVERSE_MASK) | ((geometryFlags & GEOMETRY_MASK) << GEOMETRY_SHIFT); - } - - static RenderMaterialImpl.Value material(int bits) { - return RenderMaterialImpl.byIndex((bits >> MATERIAL_SHIFT) & MATERIAL_MASK); - } - - static int material(int bits, RenderMaterialImpl.Value material) { - return (bits & MATERIAL_INVERSE_MASK) | (material.index() << MATERIAL_SHIFT); - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshBuilderImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshBuilderImpl.java deleted file mode 100644 index 3ba34c0f4..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshBuilderImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh; - -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.MeshBuilder; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.client.render.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 MutableQuadView} instance. - * All the encoding and other work is handled in the quad base classes. - * The one interesting bit is in {@link Maker#emit()}. - */ -public class MeshBuilderImpl implements MeshBuilder { - int[] data = new int[256]; - private final Maker maker = new Maker(); - int index = 0; - int limit = data.length; - - 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 = bigger; - } - } - - @Override - public Mesh build() { - final int[] packed = new int[index]; - System.arraycopy(data, 0, packed, 0, index); - index = 0; - maker.begin(data, index); - return new MeshImpl(packed); - } - - @Override - public QuadEmitter getEmitter() { - ensureCapacity(EncodingFormat.TOTAL_STRIDE); - maker.begin(data, index); - return maker; - } - - /** - * 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 implements QuadEmitter { - @Override - public Maker emit() { - computeGeometry(); - index += EncodingFormat.TOTAL_STRIDE; - ensureCapacity(EncodingFormat.TOTAL_STRIDE); - baseIndex = index; - clear(); - return this; - } - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshImpl.java deleted file mode 100644 index fe7ec8561..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MeshImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh; - -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; - -import java.util.function.Consumer; - -/** - * 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)}. */ - ThreadLocal POOL = ThreadLocal.withInitial(QuadViewImpl::new); - - final int[] data; - - MeshImpl(int[] data) { - this.data = data; - } - - public int[] data() { - return data; - } - - @Override - public void forEach(Consumer consumer) { - forEach(consumer, POOL.get()); - } - - /** - * The renderer will call this with it's 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; - - while (index < limit) { - cursor.load(data, index); - consumer.accept(cursor); - index += EncodingFormat.TOTAL_STRIDE; - } - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MutableQuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MutableQuadViewImpl.java deleted file mode 100644 index 824147bb4..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/MutableQuadViewImpl.java +++ /dev/null @@ -1,151 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh; - -import com.google.common.base.Preconditions; -import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; -import net.modificationstation.stationapi.api.client.render.model.BakedQuad; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.ArsenicRenderer; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.RenderMaterialImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.NormalHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.TextureHelper; - -import static net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.EncodingFormat.*; - -/** - * Almost-concrete implementation of a mutable quad. The only missing part is {@link #emit()}, - * because that depends on where/how it is used. (Mesh encoding vs. render-time transformation). - */ -public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEmitter { - public final void begin(int[] data, int baseIndex) { - this.data = data; - this.baseIndex = baseIndex; - clear(); - } - - 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(ArsenicRenderer.MATERIAL_STANDARD); - } - - @Override - public final MutableQuadViewImpl material(RenderMaterial material) { - if (material == null) { - material = ArsenicRenderer.MATERIAL_STANDARD; - } - - data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (RenderMaterialImpl.Value) material); - return this; - } - - @Override - public final MutableQuadViewImpl cullFace(Direction face) { - data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(data[baseIndex + HEADER_BITS], face); - nominalFace(face); - return this; - } - - @Override - public final MutableQuadViewImpl nominalFace(Direction face) { - nominalFace = face; - return this; - } - - @Override - public final MutableQuadViewImpl colorIndex(int colourIndex) { - data[baseIndex + HEADER_COLOR_INDEX] = colourIndex; - return this; - } - - @Override - public final MutableQuadViewImpl tag(int tag) { - data[baseIndex + HEADER_TAG] = tag; - return this; - } - - @Override - public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, Direction cullFace) { - System.arraycopy(quad.getVertexData(), 0, data, baseIndex + HEADER_STRIDE, QUAD_STRIDE); - data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(0, cullFace); - nominalFace(quad.getFace()); - colorIndex(quad.getColorIndex()); - material(material); - tag(0); - shade(quad.hasShade()); - isGeometryInvalid = true; - return this; - } - - @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; - } - - 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, 0); - 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 = NormalHelper.packNormal(faceNormal(), 0); - - for (int v = 0; v < 4; v++) { - if ((normalFlags & (1 << v)) == 0) { - data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal; - } - } - - normalFlags(0b1111); - } - - @Override - public MutableQuadViewImpl spriteColor(int vertexIndex, int spriteIndex, int color) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color; - return this; - } - - @Override - public MutableQuadViewImpl sprite(int vertexIndex, int spriteIndex, float u, float v) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - 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(int spriteIndex, Sprite sprite, int bakeFlags) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - TextureHelper.bakeSprite(this, spriteIndex, sprite, bakeFlags); - return this; - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/QuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/QuadViewImpl.java deleted file mode 100644 index dba6c456e..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/mesh/QuadViewImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh; - -import com.google.common.base.Preconditions; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.client.render.mesh.QuadView; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.RenderMaterialImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.GeometryHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.NormalHelper; - -import static net.modificationstation.stationapi.impl.client.arsenic.renderer.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 { - protected Direction nominalFace; - /** True when geometry flags or light face may not match geometry. */ - protected boolean isGeometryInvalid = true; - protected final Vec3f faceNormal = new Vec3f(); - private boolean shade = 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; - - /** - * Use when subtype is "attached" to a pre-existing array. - * Sets data reference and index and decodes state from array. - */ - final void load(int[] data, int baseIndex) { - this.data = data; - this.baseIndex = baseIndex; - load(); - } - - /** - * Like {@link #load(int[], int)} but assumes array and index already set. - * Only does the decoding part. - */ - public final void load() { - isGeometryInvalid = false; - nominalFace = lightFace(); - - // face normal isn't encoded - NormalHelper.computeFaceNormal(faceNormal, this); - } - - /** Reference to underlying array. Use with caution. Meant for fast renderer access */ - public int[] data() { - return data; - } - - public int normalFlags() { - return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]); - } - - /** True if any vertex normal has been set. */ - public boolean hasVertexNormals() { - return normalFlags() != 0; - } - - /** gets flags used for lighting - lazily computed via {@link GeometryHelper#computeShapeFlags(QuadView)}. */ - public int geometryFlags() { - computeGeometry(); - return EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS]); - } - - protected void computeGeometry() { - if (isGeometryInvalid) { - isGeometryInvalid = false; - - NormalHelper.computeFaceNormal(faceNormal, this); - - // depends on face normal - data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], GeometryHelper.lightFace(this)); - - // depends on light face - data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], GeometryHelper.computeShapeFlags(this)); - } - } - - @Override - public final void toVanilla(int textureIndex, int[] target, int targetIndex, boolean isItem) { - System.arraycopy(data, baseIndex + VERTEX_X, target, targetIndex, QUAD_STRIDE); - } - - @Override - public final RenderMaterialImpl.Value 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 Direction lightFace() { - computeGeometry(); - return EncodingFormat.lightFace(data[baseIndex + HEADER_BITS]); - } - - @Override - public final Direction cullFace() { - return EncodingFormat.cullFace(data[baseIndex + HEADER_BITS]); - } - - @Override - public final Direction nominalFace() { - return nominalFace; - } - - @Override - public final Vec3f faceNormal() { - computeGeometry(); - return faceNormal; - } - - @Override - public void copyTo(MutableQuadView target) { - computeGeometry(); - - final MutableQuadViewImpl quad = (MutableQuadViewImpl) target; - // copy everything except the material - System.arraycopy(data, baseIndex + 1, quad.data, quad.baseIndex + 1, EncodingFormat.TOTAL_STRIDE - 1); - quad.faceNormal.set(faceNormal.getX(), faceNormal.getY(), faceNormal.getZ()); - quad.nominalFace = this.nominalFace; - quad.isGeometryInvalid = false; - } - - @Override - public Vec3f copyPos(int vertexIndex, Vec3f target) { - if (target == null) { - target = new Vec3f(); - } - - 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 float posByIndex(int vertexIndex, int coordinateIndex) { - return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]); - } - - @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 boolean hasNormal(int vertexIndex) { - return (normalFlags() & (1 << vertexIndex)) != 0; - } - - protected final int normalIndex(int vertexIndex) { - return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL; - } - - @Override - public Vec3f copyNormal(int vertexIndex, Vec3f target) { - if (hasNormal(vertexIndex)) { - if (target == null) { - target = new Vec3f(); - } - - final int normal = data[normalIndex(vertexIndex)]; - target.set(NormalHelper.getPackedNormalComponent(normal, 0), NormalHelper.getPackedNormalComponent(normal, 1), NormalHelper.getPackedNormalComponent(normal, 2)); - return target; - } else { - return null; - } - } - - @Override - public float normalX(int vertexIndex) { - return hasNormal(vertexIndex) ? NormalHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 0) : Float.NaN; - } - - @Override - public float normalY(int vertexIndex) { - return hasNormal(vertexIndex) ? NormalHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 1) : Float.NaN; - } - - @Override - public float normalZ(int vertexIndex) { - return hasNormal(vertexIndex) ? NormalHelper.getPackedNormalComponent(data[normalIndex(vertexIndex)], 2) : Float.NaN; - } - - @Override - public int spriteColor(int vertexIndex, int spriteIndex) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR]; - } - - @Override - public float spriteU(int vertexIndex, int spriteIndex) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]); - } - - @Override - public float spriteV(int vertexIndex, int spriteIndex) { - Preconditions.checkArgument(spriteIndex == 0, "Unsupported sprite index: %s", spriteIndex); - - return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]); - } - - public int vertexStart() { - return baseIndex + HEADER_STRIDE; - } - - public boolean hasShade() { - return shade && !material().disableDiffuse(0); - } - - public void shade(boolean shade) { - this.shade = shade; - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractMeshConsumer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractMeshConsumer.java deleted file mode 100644 index 0de3985ea..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractMeshConsumer.java +++ /dev/null @@ -1,113 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.render.Tessellator; -import net.modificationstation.stationapi.api.client.render.RenderContext; -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.ArsenicRenderer; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.RenderMaterialImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.aocalc.LightingCalculatorImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.EncodingFormat; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MeshImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MutableQuadViewImpl; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -/** - * Consumer for pre-baked meshes. Works by copying the mesh data to a - * "editor" quad held in the instance, where all transformations are applied before buffering. - */ -public abstract class AbstractMeshConsumer extends AbstractQuadRenderer implements Consumer { - protected AbstractMeshConsumer(BlockRenderInfo blockInfo, Supplier bufferFunc, LightingCalculatorImpl aoCalc, RenderContext.QuadTransform transform) { - super(blockInfo, bufferFunc, aoCalc, transform); - } - - /** - * Where we handle all pre-buffer coloring, lighting, transformation, etc. - * Reused for all mesh quads. Fixed baking array sized to hold largest possible mesh quad. - */ - private class Maker extends MutableQuadViewImpl implements QuadEmitter { - { - data = new int[EncodingFormat.TOTAL_STRIDE]; - material(ArsenicRenderer.MATERIAL_STANDARD); - } - - // only used via RenderContext.getEmitter() - @Override - public Maker emit() { - computeGeometry(); - renderQuad(this); - clear(); - return this; - } - } - - private final Maker editorQuad = new Maker(); - - @Override - public void accept(Mesh mesh) { - final MeshImpl m = (MeshImpl) mesh; - final int[] data = m.data(); - final int limit = data.length; - int index = 0; - - while (index < limit) { - System.arraycopy(data, index, editorQuad.data(), 0, EncodingFormat.TOTAL_STRIDE); - editorQuad.load(); - index += EncodingFormat.TOTAL_STRIDE; - renderQuad(editorQuad); - } - } - - public QuadEmitter getEmitter() { - editorQuad.clear(); - return editorQuad; - } - - private void renderQuad(MutableQuadViewImpl q) { - if (!transform.transform(editorQuad)) { - return; - } - - if (!blockInfo.shouldDrawQuad(q)) { - return; - } - - if (!blockInfo.shouldDrawFace(q.cullFace())) { - return; - } - - final RenderMaterialImpl.Value mat = q.material(); - - if (!mat.disableAo(0) && Minecraft.method_2148()) { - // needs to happen before offsets are applied - aoCalc.calculateForQuad(q); - } - - tesselateQuad(q, mat, 0); - } - - /** - * Determines color index and render layer, then routes to appropriate - * tesselate routine based on material properties. - */ - private void tesselateQuad(MutableQuadViewImpl quad, RenderMaterialImpl.Value mat, int textureIndex) { - final int colorIndex = mat.disableColorIndex(textureIndex) ? -1 : quad.colorIndex(); - - if (blockInfo.defaultAo && !mat.disableAo(textureIndex)) { - if (mat.emissive(textureIndex)) { - tessellateSmoothEmissive(quad, colorIndex); - } else { - tessellateSmooth(quad, colorIndex); - } - } else { - if (mat.emissive(textureIndex)) { - tessellateFlatEmissive(quad, colorIndex); - } else { - tessellateFlat(quad, colorIndex); - } - } - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractQuadRenderer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractQuadRenderer.java deleted file mode 100644 index 1adff152c..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractQuadRenderer.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.minecraft.client.render.Tessellator; -import net.modificationstation.stationapi.api.client.render.RenderContext; -import net.modificationstation.stationapi.api.util.math.Matrix3f; -import net.modificationstation.stationapi.api.util.math.Matrix4f; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.aocalc.LightingCalculatorImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.ColorHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MutableQuadViewImpl; - -import java.util.function.Supplier; - -public abstract class AbstractQuadRenderer { - - static final int FULL_BRIGHTNESS = 0xF000F0; - - protected final Supplier bufferFunc; - protected final BlockRenderInfo blockInfo; - protected final LightingCalculatorImpl aoCalc; - protected final RenderContext.QuadTransform transform; - protected final Vec3f normalVec = new Vec3f(); - - protected abstract Matrix4f matrix(); - - protected abstract Matrix3f normalMatrix(); - - protected abstract int overlay(); - - AbstractQuadRenderer(BlockRenderInfo blockInfo, Supplier bufferFunc, LightingCalculatorImpl aoCalc, RenderContext.QuadTransform transform) { - this.blockInfo = blockInfo; - this.bufferFunc = bufferFunc; - this.aoCalc = aoCalc; - this.transform = transform; - } - - /** handles block colour and red-blue swizzle, common to all renders. */ - private void colorizeQuad(MutableQuadViewImpl q, int blockColourIndex) { - if (blockColourIndex == -1) { - for (int i = 0; i < 4; i++) { - q.spriteColor(i, 0, ColorHelper.swapRedBlueIfNeeded(q.spriteColor(i, 0))); - } - } else { - final int blockColour = blockInfo.blockColour(blockColourIndex); - - for (int i = 0; i < 4; i++) { - q.spriteColor(i, 0, ColorHelper.swapRedBlueIfNeeded(ColorHelper.multiplyColour(blockColour, q.spriteColor(i, 0)))); - } - } - } - - private void bufferQuad(MutableQuadViewImpl q) { - bufferQuad(bufferFunc.get(), q, matrix(), overlay(), normalMatrix(), normalVec); - } - - // TODO: make this actually work lol - public static void bufferQuad(Tessellator buff, MutableQuadViewImpl quad, Matrix4f matrix, int overlay, Matrix3f normalMatrix, Vec3f normalVec) { -// final boolean useNormals = quad.hasVertexNormals(); -// -// if (useNormals) { -// quad.populateMissingNormals(); -// } else { -// final Vec3f faceNormal = quad.faceNormal(); -// normalVec.set(faceNormal.getX(), faceNormal.getY(), faceNormal.getZ()); -// normalVec.transform(normalMatrix); -// } -// -// for (int i = 0; i < 4; i++) { -// buff.vertex(matrix, quad.x(i), quad.y(i), quad.z(i)); -// final int colour = quad.spriteColour(i, 0); -// buff.color(colour & 0xFF, (colour >> 8) & 0xFF, (colour >> 16) & 0xFF, (colour >> 24) & 0xFF); -// buff.texture(quad.spriteU(i, 0), quad.spriteV(i, 0)); -// buff.overlay(overlay); -// buff.light(quad.lightmap(i)); -// -// if (useNormals) { -// normalVec.set(quad.normalX(i), quad.normalY(i), quad.normalZ(i)); -// normalVec.transform(normalMatrix); -// } -// -// buff.normal(normalVec.getX(), normalVec.getY(), normalVec.getZ()); -// buff.next(); -// } - } - - // routines below have a bit of copy-paste code reuse to avoid conditional execution inside a hot loop - - /** for non-emissive mesh quads and all fallback quads with smooth lighting. */ - protected void tessellateSmooth(MutableQuadViewImpl q, int blockColorIndex) { - colorizeQuad(q, blockColorIndex); - - for (int i = 0; i < 4; i++) { - q.spriteColor(i, 0, ColorHelper.multiplyRGB(q.spriteColor(i, 0), aoCalc.light[i])); -// q.spriteColor(i, 0, ColourHelper.multiplyRGB(q.spriteColour(i, 0), aoCalc.ao[i])); -// q.lightmap(i, ColourHelper.maxBrightness(q.lightmap(i), aoCalc.light[i])); - } - - bufferQuad(q); - } - - /** for emissive mesh quads with smooth lighting. */ - protected void tessellateSmoothEmissive(MutableQuadViewImpl q, int blockColorIndex) { - colorizeQuad(q, blockColorIndex); - -// for (int i = 0; i < 4; i++) { -// q.spriteColour(i, 0, ColourHelper.multiplyRGB(q.spriteColour(i, 0), aoCalc.ao[i])); -// q.lightmap(i, FULL_BRIGHTNESS); -// } - - bufferQuad(q); - } - - /** for non-emissive mesh quads and all fallback quads with flat lighting. */ - protected void tessellateFlat(MutableQuadViewImpl quad, int blockColorIndex) { - colorizeQuad(quad, blockColorIndex); - - // TODO: implement -// final int brightness = flatBrightness(quad, blockInfo.blockState, blockInfo.blockPos); - - for (int i = 0; i < 4; i++) { - quad.spriteColor(i, 0, ColorHelper.multiplyRGB(quad.spriteColor(i, 0), aoCalc.light[i])); -// quad.lightmap(i, ColourHelper.maxBrightness(quad.lightmap(i), brightness)); - } - - bufferQuad(quad); - } - - /** for emissive mesh quads with flat lighting. */ - protected void tessellateFlatEmissive(MutableQuadViewImpl quad, int blockColorIndex) { - colorizeQuad(quad, blockColorIndex); - shadeFlatQuad(quad); - -// for (int i = 0; i < 4; i++) { -// quad.lightmap(i, FULL_BRIGHTNESS); -// } - - bufferQuad(quad); - } - - private void shadeFlatQuad(MutableQuadViewImpl quad) { - float shade = aoCalc.shadeMultiplier(quad.lightFace()); - for (int i = 0; i < 4; i++) { - quad.spriteColor(i, 0, ColorHelper.multiplyRGB(quad.spriteColor(i, 0), shade)); - } - } -} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractRenderContext.java deleted file mode 100644 index d2f4c4d33..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractRenderContext.java +++ /dev/null @@ -1,63 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.modificationstation.stationapi.api.client.render.RenderContext; -import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; -import net.modificationstation.stationapi.api.util.math.Matrix3f; -import net.modificationstation.stationapi.api.util.math.Matrix4f; - -abstract class AbstractRenderContext implements RenderContext { - private final ObjectArrayList transformStack = new ObjectArrayList<>(); - private static final RenderContext.QuadTransform NO_TRANSFORM = (q) -> true; - protected Matrix4f matrix; - protected Matrix3f normalMatrix; - protected int overlay; - - private final QuadTransform stackTransform = (q) -> { - int i = transformStack.size() - 1; - - while (i >= 0) { - if (!transformStack.get(i--).transform(q)) { - return false; - } - } - - return true; - }; - - private QuadTransform activeTransform = NO_TRANSFORM; - - protected final boolean transform(MutableQuadView q) { - return activeTransform.transform(q); - } - - protected 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); - } - } -} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BakedModelRendererImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BakedModelRendererImpl.java index ab92bdccf..877bd93d7 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BakedModelRendererImpl.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BakedModelRendererImpl.java @@ -23,8 +23,8 @@ import net.modificationstation.stationapi.api.client.render.model.json.Transformation; import net.modificationstation.stationapi.api.client.texture.StationTextureManager; import net.modificationstation.stationapi.api.client.texture.atlas.Atlases; -import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.registry.ItemRegistry; +import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.util.Util; import net.modificationstation.stationapi.api.util.crash.CrashException; import net.modificationstation.stationapi.api.util.crash.CrashReport; @@ -60,8 +60,6 @@ public class BakedModelRendererImpl implements BakedModelRenderer { }); private final BlockColors blockColors = StationRenderAPI.getBlockColors(); private final ItemColors itemColors = StationRenderAPI.getItemColors(); - private final ThreadLocal BLOCK_CONTEXTS = ThreadLocal.withInitial(BlockRenderContext::new); - private final ThreadLocal ITEM_CONTEXTS = ThreadLocal.withInitial(() -> new ItemRenderContext(itemColors)); private boolean damage; @Override @@ -85,29 +83,25 @@ public boolean renderBlock(BlockState state, BlockPos pos, BlockView world, bool public boolean render(BlockView world, BakedModel model, BlockState state, BlockPos pos, boolean cull, Random random, long seed) { boolean rendered = false; model = Objects.requireNonNull(model.getOverrides().apply(model, state, world, pos, (int) seed)); - if (!model.isVanillaAdapter()) { - rendered = BLOCK_CONTEXTS.get().render(world, model, state, pos, random, seed); - } else { - Block block = state.getBlock(); - light.initialize( - block, - world, pos.x, pos.y, pos.z, - Minecraft.method_2148() && model.useAmbientOcclusion() - ); - ImmutableList qs; - BakedQuad q; - float[] qlight = light.light; - for (int quadSet = 0, size = DIRECTIONS.length; quadSet < size; quadSet++) { - Direction face = DIRECTIONS[quadSet]; - random.setSeed(seed); - qs = model.getQuads(state, face, random); - if (!qs.isEmpty() && (face == null || block.isSideVisible(world, pos.x + face.getOffsetX(), pos.y + face.getOffsetY(), pos.z + face.getOffsetZ(), quadSet))) { - rendered = true; - for (int j = 0, quadSize = qs.size(); j < quadSize; j++) { - q = qs.get(j); - light.calculateForQuad(q); - renderQuad(world, state, pos, q, qlight); - } + Block block = state.getBlock(); + light.initialize( + block, + world, pos.x, pos.y, pos.z, + Minecraft.method_2148() && model.useAmbientOcclusion() + ); + ImmutableList qs; + BakedQuad q; + float[] qlight = light.light; + for (int quadSet = 0, size = DIRECTIONS.length; quadSet < size; quadSet++) { + Direction face = DIRECTIONS[quadSet]; + random.setSeed(seed); + qs = model.getQuads(state, face, random); + if (!qs.isEmpty() && (face == null || block.isSideVisible(world, pos.x + face.getOffsetX(), pos.y + face.getOffsetY(), pos.z + face.getOffsetZ(), quadSet))) { + rendered = true; + for (int j = 0, quadSize = qs.size(); j < quadSize; j++) { + q = qs.get(j); + light.calculateForQuad(q); + renderQuad(world, state, pos, q, qlight); } } } @@ -206,29 +200,25 @@ private void renderBakedItemModelFlat(BakedModel model, ItemStack stack, float b @Override public void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, float brightness, BakedModel model) { if (stack == null || stack.itemId == 0) return; - if (model.isVanillaAdapter()) { - Transformation transformation = model.getTransformation().getTransformation(renderMode); - transformation.apply(); - boolean side = model.isSideLit(); - if (side && renderMode == ModelTransformation.Mode.GUI) { - float angle = transformation.rotation.getY() - 315; - if (angle != 0) { - class_583.method_1927(); - glPushMatrix(); - glRotatef(angle, 0, 1, 0); - class_583.method_1930(); - glPopMatrix(); - } + Transformation transformation = model.getTransformation().getTransformation(renderMode); + transformation.apply(); + boolean side = model.isSideLit(); + if (side && renderMode == ModelTransformation.Mode.GUI) { + float angle = transformation.rotation.getY() - 315; + if (angle != 0) { + class_583.method_1927(); + glPushMatrix(); + glRotatef(angle, 0, 1, 0); + class_583.method_1930(); + glPopMatrix(); } - glTranslatef(-0.5F, -0.5F, -0.5F); - if (model.isBuiltin()) return; - if (!side && renderMode == ModelTransformation.Mode.GROUND) - renderBakedItemModelFlat(model, stack, brightness); - else - renderBakedItemModel(model, stack, brightness); - } else { - ITEM_CONTEXTS.get().renderModel(stack, renderMode, model, this::renderBakedItemModel); } + glTranslatef(-0.5F, -0.5F, -0.5F); + if (model.isBuiltin()) return; + if (!side && renderMode == ModelTransformation.Mode.GROUND) + renderBakedItemModelFlat(model, stack, brightness); + else + renderBakedItemModel(model, stack, brightness); } private void renderBakedItemQuads(List quads, ItemStack stack, float brightness) { diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderContext.java deleted file mode 100644 index ba72f7b6e..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderContext.java +++ /dev/null @@ -1,97 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.render.Tessellator; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; -import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; -import net.modificationstation.stationapi.api.client.render.model.BakedModel; -import net.modificationstation.stationapi.api.util.math.Matrix3f; -import net.modificationstation.stationapi.api.util.math.Matrix4f; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.aocalc.LightingCalculatorImpl; - -import java.util.Random; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class BlockRenderContext extends AbstractRenderContext { - - private final BlockRenderInfo blockInfo = new BlockRenderInfo(); - private final LightingCalculatorImpl aoCalc = new LightingCalculatorImpl(3); - private final MeshConsumer meshConsumer = new MeshConsumer(blockInfo, this::outputBuffer, aoCalc, this::transform); - private Tessellator bufferBuilder; - private boolean didOutput; - private Random random; - private long seed; - private final Supplier randomSupplier = () -> { - random.setSeed(seed); - return random; - }; - - @Override - public Consumer meshConsumer() { - return meshConsumer; - } - - @Override - public Consumer fallbackConsumer() { - return null; - } - - @Override - public QuadEmitter getEmitter() { - return meshConsumer.getEmitter(); - } - - private Tessellator outputBuffer() { - didOutput = true; - return bufferBuilder; - } - - public boolean render(BlockView blockView, BakedModel model, BlockState state, BlockPos pos, Random random, long seed) { - this.bufferBuilder = Tessellator.INSTANCE; -// this.matrix = matrixStack.peek().getPositionMatrix(); -// this.normalMatrix = matrixStack.peek().getNormalMatrix(); - this.random = random; - this.seed = seed; - -// this.overlay = overlay; - this.didOutput = false; - aoCalc.initialize(state.getBlock(), blockView, pos.x, pos.y, pos.z, Minecraft.method_2148() && model.useAmbientOcclusion()); - blockInfo.setBlockView(blockView); - blockInfo.prepareForBlock(state, pos, model.useAmbientOcclusion()); - - model.emitBlockQuads(blockView, state, pos, randomSupplier, this); - - blockInfo.release(); - this.bufferBuilder = null; - this.random = null; - this.seed = seed; - - return didOutput; - } - - private class MeshConsumer extends AbstractMeshConsumer { - - MeshConsumer(BlockRenderInfo blockInfo, Supplier bufferFunc, LightingCalculatorImpl aoCalc, QuadTransform transform) { - super(blockInfo, bufferFunc, aoCalc, transform); - } - - @Override - protected Matrix4f matrix() { - return matrix; - } - - @Override - protected Matrix3f normalMatrix() { - return normalMatrix; - } - - @Override - protected int overlay() { - return overlay; - } - } -} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderInfo.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderInfo.java deleted file mode 100644 index 4db2cd56c..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderInfo.java +++ /dev/null @@ -1,89 +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.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.minecraft.client.Minecraft; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockView; -import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.client.StationRenderAPI; -import net.modificationstation.stationapi.api.client.color.block.BlockColors; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MutableQuadViewImpl; - -import java.util.Random; -import java.util.function.Supplier; - -/** - * Holds, manages and provides access to the block/world related state - * needed by fallback and mesh consumers. - * - *

Exception: per-block position offsets are tracked in {@link ChunkRenderInfo} - * so they can be applied together with chunk offsets. - */ -public class BlockRenderInfo { - private final BlockColors blockColorMap = StationRenderAPI.getBlockColors(); - public final Random random = new Random(); - public BlockView blockView; - public BlockPos blockPos; - public BlockState blockState; - public long seed; - boolean defaultAo; - - public final Supplier randomSupplier = () -> { - final Random result = random; - long seed = this.seed; - - if (seed == -1L) { - seed = blockState.getRenderingSeed(blockPos); - this.seed = seed; - } - - result.setSeed(seed); - return result; - }; - - public void setBlockView(BlockView blockView) { - this.blockView = blockView; - } - - public void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAO) { - this.blockPos = blockPos; - this.blockState = blockState; - // in the unlikely case seed actually matches this, we'll simply retrieve it more than one - seed = -1L; - defaultAo = modelAO && Minecraft.method_2148() && blockState.getLuminance() == 0; - } - - public void release() { - blockPos = null; - blockState = null; - } - - int blockColour(int colorIndex) { - return 0xFF000000 | blockColorMap.getColor(blockState, blockView, blockPos, colorIndex); - } - - boolean shouldDrawFace(Direction face) { - return true; - } - - boolean shouldDrawQuad(MutableQuadViewImpl quad) { - Direction cull = quad.cullFace(); - return cull == null || blockState.getBlock().isSideVisible(blockView, blockPos.x + cull.getOffsetX(), blockPos.y + cull.getOffsetY(), blockPos.z + cull.getOffsetZ(), cull.ordinal()); - } -} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ItemRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ItemRenderContext.java deleted file mode 100644 index 7814d864e..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ItemRenderContext.java +++ /dev/null @@ -1,211 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.minecraft.client.render.Tessellator; -import net.minecraft.item.ItemStack; -import net.modificationstation.stationapi.api.client.color.item.ItemColors; -import net.modificationstation.stationapi.api.client.render.material.BlendMode; -import net.modificationstation.stationapi.api.client.render.mesh.Mesh; -import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; -import net.modificationstation.stationapi.api.client.render.model.BakedModel; -import net.modificationstation.stationapi.api.client.render.model.BakedQuad; -import net.modificationstation.stationapi.api.client.render.model.ModelHelper; -import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; -import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Matrix4f; -import net.modificationstation.stationapi.api.util.math.MatrixStack; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.ArsenicRenderer; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.RenderMaterialImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.helper.ColorHelper; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.EncodingFormat; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MeshImpl; -import net.modificationstation.stationapi.impl.client.arsenic.renderer.mesh.MutableQuadViewImpl; - -import java.util.List; -import java.util.Random; -import java.util.function.Consumer; -import java.util.function.Supplier; - -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; - - /** used to accept a method reference from the ItemRenderer. */ - @FunctionalInterface - public interface VanillaQuadHandler { - void accept(BakedModel model, ItemStack stack, float brightness); - } - - private final ItemColors colorMap; - private final Random random = new Random(); - private final Consumer fallbackConsumer; - private final Vec3f normalVec = new Vec3f(); - - private MatrixStack matrixStack; - private Matrix4f matrix; -// private VertexConsumer vertexConsumerProvider; - private Tessellator modelVertexConsumer; - private BlendMode quadBlendMode; - private Tessellator quadVertexConsumer; - private ModelTransformation.Mode transformMode; - private float brightness; - private int lightmap; - private int overlay; - private ItemStack itemStack; - private VanillaQuadHandler vanillaHandler; - - private final Supplier randomSupplier = () -> { - random.setSeed(ITEM_RANDOM_SEED); - return random; - }; - - private final int[] quadData = new int[EncodingFormat.TOTAL_STRIDE]; - - public ItemRenderContext(ItemColors colorMap) { - this.colorMap = colorMap; - fallbackConsumer = this::fallbackConsumer; - } - - public void renderModel(ItemStack itemStack, ModelTransformation.Mode transformMode, BakedModel model, VanillaQuadHandler vanillaHandler) { - this.itemStack = itemStack; -// this.vertexConsumerProvider = vertexConsumerProvider; -// this.matrixStack = matrixStack; - this.transformMode = transformMode; - this.vanillaHandler = vanillaHandler; - quadBlendMode = BlendMode.DEFAULT; -// modelVertexConsumer = selectVertexConsumer(RenderLayers.getItemLayer(itemStack, transformMode != ModelTransformation.Mode.GROUND)); -// modelVertexConsumer = vertexConsumer; - - matrixStack.push(); - model.getTransformation().getTransformation(transformMode).apply(); - matrixStack.translate(-0.5D, -0.5D, -0.5D); - matrix = matrixStack.peek().getPositionMatrix(); - normalMatrix = matrixStack.peek().getNormalMatrix(); - - model.emitItemQuads(itemStack, randomSupplier, this); - - matrixStack.pop(); - - this.matrixStack = null; - this.itemStack = null; - this.vanillaHandler = null; - modelVertexConsumer = null; - } - - /** - * Use non-culling translucent material in GUI to match vanilla behavior. If the item - * is enchanted then also select a dual-output vertex consumer. For models with layered - * coplanar polygons this means we will render the glint more than once. Indigo doesn't - * support sprite layers, so this can't be helped in this implementation. - */ -// private VertexConsumer selectVertexConsumer(RenderLayer layerIn) { -// final RenderLayer layer = transformMode == ModelTransformation.Mode.GUI ? TexturedRenderLayers.getEntityTranslucentCull() : layerIn; -// return ItemRenderer.getArmorGlintConsumer(vertexConsumerProvider, layer, true, itemStack.hasGlint()); -// } - - private class Maker extends MutableQuadViewImpl implements QuadEmitter { - { - data = quadData; - clear(); - } - - @Override - public Maker emit() { - computeGeometry(); - renderQuad(); - clear(); - return this; - } - } - - private final Maker editorQuad = new Maker(); - - private final Consumer meshConsumer = (mesh) -> { - final MeshImpl m = (MeshImpl) mesh; - final int[] data = m.data(); - final int limit = data.length; - int index = 0; - - while (index < limit) { - System.arraycopy(data, index, editorQuad.data(), 0, EncodingFormat.TOTAL_STRIDE); - editorQuad.load(); - index += EncodingFormat.TOTAL_STRIDE; - renderQuad(); - } - }; - - private int indexColor() { - final int colorIndex = editorQuad.colorIndex(); - return colorIndex == -1 ? -1 : (colorMap.getColor(itemStack, colorIndex) | 0xFF000000); - } - - private void renderQuad() { - final MutableQuadViewImpl quad = editorQuad; - - if (!transform(editorQuad)) { - return; - } - - final RenderMaterialImpl.Value mat = quad.material(); - final int quadColor = mat.disableColorIndex(0) ? -1 : indexColor(); - final int lightmap = mat.emissive(0) ? AbstractQuadRenderer.FULL_BRIGHTNESS : this.lightmap; - - for (int i = 0; i < 4; i++) { - int c = quad.spriteColor(i, 0); - c = ColorHelper.multiplyColour(quadColor, c); - quad.spriteColor(i, 0, ColorHelper.swapRedBlueIfNeeded(c)); -// quad.lightmap(i, ColourHelper.maxBrightness(quad.lightmap(i), lightmap)); - } - - AbstractQuadRenderer.bufferQuad(quadVertexConsumer(mat.blendMode(0)), quad, matrix, overlay, normalMatrix, normalVec); - } - - private Tessellator quadVertexConsumer(BlendMode blendMode) { - return quadVertexConsumer = modelVertexConsumer; - } - - @Override - public Consumer meshConsumer() { - return meshConsumer; - } - - private void fallbackConsumer(BakedModel model) { - if (hasTransform()) { - // if there's a transform in effect, convert to mesh-based quads so that we can apply it - for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) { - random.setSeed(ITEM_RANDOM_SEED); - final Direction cullFace = ModelHelper.faceFromIndex(i); - renderFallbackWithTransform(model.getQuads(null, cullFace, random), cullFace); - } - } else { - for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) { - vanillaHandler.accept(model, itemStack, brightness); - } - } - } - - private void renderFallbackWithTransform(List quads, Direction cullFace) { - if (quads.isEmpty()) { - return; - } - - final Maker editorQuad = this.editorQuad; - - for (final BakedQuad q : quads) { - editorQuad.fromVanilla(q, ArsenicRenderer.MATERIAL_STANDARD, cullFace); - renderQuad(); - } - } - - @Override - public Consumer fallbackConsumer() { - return fallbackConsumer; - } - - @Override - public QuadEmitter getEmitter() { - editorQuad.clear(); - return editorQuad; - } -} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/VanillaModelsAdapter.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/VanillaModelsAdapter.java deleted file mode 100644 index 865142f24..000000000 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/VanillaModelsAdapter.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; - -import net.mine_diver.unsafeevents.listener.EventListener; -import net.modificationstation.stationapi.api.StationAPI; -import net.modificationstation.stationapi.api.client.event.render.model.LoadUnbakedModelEvent; -import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; -import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; - -@Entrypoint(eventBus = @EventBusPolicy(registerInstance = false)) -@EventListener(phase = StationAPI.INTERNAL_PHASE) -public class VanillaModelsAdapter { - - // EXPERIMENTAL BACKWARDS COMPATIBILITY WITH VANILLA RENDERER. - // BROKEN, CAN ONLY BAKE FULL-BLOCK MODELS, DOES NOT SUPPORT COLOUR PROVIDERS AND CAN NOT ADJUST RENDERER SIZES AND TEXTURES ON THE FLY (PORTAL, GRASS BLOCK) - // IMPLEMENTING THE LATTER MAY INDUCE LARGE PERFORMANCE DROPS - @EventListener - private static void registerModel(LoadUnbakedModelEvent event) { -// Identifier id = event.getIdentifier(); -// ModelIdentifier modelId = ModelIdentifier.of(id.toString()); -// if (modelId.id.modID == ModID.MINECRAFT) { -// Identifier itemId = modelId.id.id.startsWith("item/") ? Identifier.of(modelId.id.modID, modelId.id.id.substring(5)) : modelId.id; -// ItemRegistry.INSTANCE.get(itemId).ifPresent(itemBase -> event.model = new VanillaUnbakedModel(itemId)); -// } - } -} diff --git a/station-renderer-arsenic/src/main/resources/fabric.mod.json b/station-renderer-arsenic/src/main/resources/fabric.mod.json index eae182c21..9325699d9 100644 --- a/station-renderer-arsenic/src/main/resources/fabric.mod.json +++ b/station-renderer-arsenic/src/main/resources/fabric.mod.json @@ -20,8 +20,7 @@ "environment": "client", "entrypoints": { "stationapi:event_bus_client": [ - "net.modificationstation.stationapi.impl.client.arsenic.Arsenic", - "net.modificationstation.stationapi.impl.client.arsenic.renderer.render.VanillaModelsAdapter" + "net.modificationstation.stationapi.impl.client.arsenic.Arsenic" ] }, "mixins": [