From 8060a0b988fdd523ed5a4a4a5f114b8d7fee09b5 Mon Sep 17 00:00:00 2001 From: alpha Date: Sat, 5 Apr 2025 22:15:37 -0500 Subject: [PATCH 01/14] Initial Renderer api rework --- build.gradle.kts | 3 + gradle.properties | 3 +- settings.gradle.kts | 3 +- .../api/util/StringIdentifiable.java | 112 ++-- .../stationapi/api/util/Util.java | 21 +- .../stationapi/api/util/dynamic/Codecs.java | 79 ++- station-blockitems-v0/build.gradle.kts | 2 +- .../mixin/block/BlockItemMixin.java | 2 +- .../mixin/block/SecondaryBlockItemMixin.java | 2 +- .../api/item/ItemPlacementContext.java | 2 +- .../stationapi/api/item/ItemUsageContext.java | 2 +- .../stationapi/api/state/State.java | 2 +- .../impl/world/FlattenedWorldManager.java | 4 +- .../mixin/flattening/BlockItemMixin.java | 2 +- .../flattening/FallingBlockEntityMixin.java | 2 +- .../stationapi/api/bonemeal/BonemealAPI.java | 2 +- .../api/dispenser/ItemDispenseContext.java | 2 +- .../stationapi/api/util/BlockRotation.java | 1 + .../api/util/math/AxisTransformation.java | 9 +- .../stationapi/api/util/math/Direction.java | 82 ++- .../util/math/DirectionTransformation.java | 12 +- .../stationapi/api/util/math/GivensPair.java | 95 ++++ .../stationapi/api/util/math/Matrix3f.java | 505 ------------------ .../stationapi/api/util/math/Matrix4f.java | 489 ----------------- .../stationapi/api/util/math/MatrixStack.java | 158 ++++-- .../stationapi/api/util/math/MatrixUtil.java | 155 ++++++ .../stationapi/api/util/math/Quaternion.java | 168 ------ .../api/util/math/RotationAxis.java | 24 + .../stationapi/api/util/math/Vec3d.java | 7 +- .../stationapi/api/util/math/Vec3f.java | 188 ------- .../stationapi/api/util/math/Vector2f.java | 23 - .../stationapi/api/util/math/Vector4f.java | 126 ----- .../api/registry/RegistryLoader.java | 2 +- .../stationapi/api/tag/TagGroupLoader.java | 19 +- .../api/util/dynamic/EntryLoader.java | 2 +- .../api/client/render/Renderer.java | 18 - .../api/client/render/RendererAccess.java | 32 -- .../StationRendererBlockRenderManager.java | 10 - .../api/client/render/model/BakedQuad.java | 53 -- .../client/render/model/BakedQuadFactory.java | 270 ---------- .../render/model/json/Transformation.java | 96 ---- .../texture/atlas/AtlasSourceManager.java | 38 -- .../client/texture/atlas/AtlasSourceType.java | 6 - .../texture/atlas/DirectoryAtlasSource.java | 31 -- .../texture/atlas/FilterAtlasSource.java | 26 - .../texture/atlas/SingleAtlasSource.java | 37 -- .../api/util/math/AffineTransformation.java | 134 ----- .../client/render/RendererAccessImpl.java | 39 -- .../build.gradle.kts | 4 + .../api/client/StationRenderAPI.java | 0 .../client/block/StationRendererBlock.java | 0 .../color/block/BlockColorProvider.java | 0 .../api/client/color/block/BlockColors.java | 0 .../client/color/item/ItemColorProvider.java | 0 .../api/client/color/item/ItemColors.java | 0 .../api/client/color/world/BiomeColors.java | 0 .../color/block/BlockColorsRegisterEvent.java | 0 .../color/item/ItemColorsRegisterEvent.java | 0 ...ckModelPredicateProviderRegistryEvent.java | 0 ...emModelPredicateProviderRegistryEvent.java | 0 .../render/model/LoadUnbakedModelEvent.java | 0 .../model/PreLoadUnbakedModelEvent.java | 0 .../event/texture/TextureRegisterEvent.java | 0 .../api/client/item/StationRendererItem.java | 0 .../stationapi/api/client/model/Model.java | 0 .../block/BlockInventoryModelProvider.java | 3 +- .../block/BlockModelPredicateProvider.java | 0 .../block/BlockWithInventoryRenderer.java | 3 +- .../model/block/BlockWithWorldRenderer.java | 3 +- .../model/block/BlockWorldModelProvider.java | 6 +- .../client/model/block/RendererHolder.java | 5 +- .../item/ItemModelPredicateProvider.java | 0 .../client/model/item/ItemWithRenderer.java | 0 .../BlockModelPredicateProviderRegistry.java | 0 .../ItemModelPredicateProviderRegistry.java | 0 .../client/render/DelegatingTessellator.java | 96 ++++ .../api/client/render/Renderer.java | 38 ++ .../api/client/render/StationTessellator.java | 0 .../api/client/render/VertexConsumer.java | 31 ++ .../api/client/render/block/BlockModels.java | 0 .../render/block/BlockRendererHelper.java | 0 .../render/block/BlockRendererUtil.java | 0 .../StationRendererBlockRenderManager.java | 19 + .../api/client/render/item/ItemModels.java | 0 .../model/AndMultipartModelSelector.java | 0 .../api/client/render/model/BakedModel.java | 0 .../render/model/BakedModelManager.java | 0 .../render/model/BakedModelRenderer.java | 7 +- .../api/client/render/model/BakedQuad.java | 17 + .../client/render/model/BakedQuadFactory.java | 283 ++++++++++ .../api/client/render/model/Baker.java | 0 .../client/render/model/BasicBakedModel.java | 0 .../render/model/BuiltinBakedModel.java | 0 .../render/model/ForwardingBakedModel.java | 0 .../render/model/ItemModelGenerator.java | 8 +- .../render/model/ModelBakeRotation.java | 8 +- .../render/model/ModelBakeSettings.java | 0 .../client/render/model/ModelIdentifier.java | 0 .../api/client/render/model/ModelLoader.java | 0 .../client/render/model/ModelRotation.java | 4 +- .../render/model/MultipartBakedModel.java | 0 .../render/model/MultipartModelSelector.java | 0 .../model/OrMultipartModelSelector.java | 0 .../model/SimpleMultipartModelSelector.java | 0 .../render/model/SpriteAtlasManager.java | 0 .../api/client/render/model/UnbakedModel.java | 0 .../render/model/VanillaBakedModel.java | 0 .../render/model/WeightedBakedModel.java | 0 .../render/model/json/JsonUnbakedModel.java | 4 +- .../render/model/json/ModelElement.java | 46 +- .../render/model/json/ModelElementFace.java | 4 +- .../model/json/ModelElementTexture.java | 0 .../render/model/json/ModelOverride.java | 0 .../render/model/json/ModelOverrideList.java | 0 .../model/json/ModelTransformation.java | 0 .../render/model/json/ModelVariant.java | 0 .../render/model/json/ModelVariantMap.java | 0 .../model/json/MultipartModelComponent.java | 0 .../model/json/MultipartUnbakedModel.java | 0 .../render/model/json/Transformation.java | 111 ++++ .../model/json/WeightedUnbakedModel.java | 0 .../AnimationFrameResourceMetadata.java | 0 .../metadata/AnimationResourceMetadata.java | 0 .../AnimationResourceMetadataReader.java | 0 .../metadata/TextureResourceMetadata.java | 0 .../TextureResourceMetadataReader.java | 0 .../api/client/texture/AbstractTexture.java | 0 .../api/client/texture/Animator.java | 0 .../api/client/texture/DynamicTexture.java | 0 .../api/client/texture/MissingSprite.java | 0 .../api/client/texture/NativeImage.java | 0 .../texture/NativeImageBackedTexture.java | 0 .../api/client/texture/ResourceTexture.java | 0 .../stationapi/api/client/texture/Sprite.java | 0 .../client/texture/SpriteAtlasTexture.java | 0 .../api/client/texture/SpriteContents.java | 6 +- .../api/client/texture/SpriteDimensions.java | 0 .../api/client/texture/SpriteIdentifier.java | 0 .../api/client/texture/SpriteLoader.java | 0 .../api/client/texture/SpritesheetHelper.java | 0 .../client/texture/StationTextureManager.java | 0 .../api/client/texture/TextureHelper.java | 0 .../client/texture/TexturePackDependent.java | 0 .../api/client/texture/TextureStitcher.java | 0 .../TextureStitcherCannotFitException.java | 0 .../client/texture/TextureTickListener.java | 0 .../api/client/texture/TextureUtil.java | 0 .../api/client/texture/atlas/Atlas.java | 0 .../api/client/texture/atlas/AtlasLoader.java | 2 +- .../api/client/texture/atlas/AtlasSource.java | 3 +- .../texture/atlas/AtlasSourceManager.java | 33 ++ .../api/client/texture/atlas/Atlases.java | 0 .../texture/atlas/CustomAtlasProvider.java | 0 .../texture/atlas/DirectoryAtlasSource.java | 25 + .../client/texture/atlas/ExpandableAtlas.java | 0 .../texture/atlas/FilterAtlasSource.java | 21 + .../PalettedPermutationsAtlasSource.java | 62 +-- .../texture/atlas/SingleAtlasSource.java | 29 + .../api/client/texture/atlas/Sprite.java | 0 .../texture/atlas/UnstitchAtlasSource.java | 30 +- .../binder/StaticReferenceProvider.java | 0 .../texture/binder/StationTextureBinder.java | 0 .../api/client/world/ColorResolver.java | 0 .../api/util/collection/WeightedPicker.java | 0 .../api/util/math/AffineTransformation.java | 162 ++++++ .../api/util/math/AffineTransformations.java | 21 +- .../stationapi/api/util/math/CubeFace.java | 0 .../impl/client/render/RendererManager.java | 25 + .../client/render/StationTessellatorImpl.java | 53 +- .../render/StationTextureManagerImpl.java | 0 .../impl/client/texture/GuiItemsHelper.java | 0 .../client/texture/StationRenderImpl.java | 0 .../impl/client/texture/TerrainHelper.java | 0 .../mixin/render/BlockItemMixin.java | 0 .../stationapi/mixin/render/BlockMixin.java | 0 .../stationapi/mixin/render/ItemMixin.java | 0 .../client/BlockRenderManagerAccessor.java | 0 .../client/BlockRenderManagerMixin.java | 33 +- .../mixin/render/client/InGameHudMixin.java | 6 +- .../render/client/TessellatorAccessor.java | 0 .../mixin/render/client/TessellatorMixin.java | 23 +- .../render/client/TextureManagerAccessor.java | 0 .../render/client/TextureManagerMixin.java | 0 .../render/client/WaterColorAccessor.java | 0 .../minecraft/stationapi/atlases/game.json | 0 .../stationapi/models/block/block.json | 0 .../stationapi/models/block/cross.json | 0 .../stationapi/models/block/cube.json | 0 .../stationapi/models/block/cube_all.json | 0 .../models/block/cube_bottom_top.json | 0 .../stationapi/models/block/cube_column.json | 0 .../models/block/cube_column_horizontal.json | 0 .../models/block/cube_column_mirrored.json | 0 .../models/block/cube_directional.json | 0 .../models/block/cube_mirrored.json | 0 .../models/block/cube_mirrored_all.json | 0 .../stationapi/models/block/cube_top.json | 0 .../stationapi/models/block/legacy/block.json | 0 .../stationapi/models/block/legacy/cube.json | 0 .../models/block/legacy/cube_all.json | 0 .../models/block/legacy/cube_bottom_top.json | 0 .../models/block/legacy/cube_column.json | 0 .../block/legacy/cube_column_horizontal.json | 0 .../models/block/legacy/cube_directional.json | 0 .../models/block/legacy/cube_top.json | 0 .../models/block/legacy/orientable.json | 0 .../block/legacy/orientable_with_bottom.json | 0 .../stationapi/models/block/orientable.json | 0 .../models/block/orientable_with_bottom.json | 0 .../stationapi/models/block/tinted_cross.json | 0 .../stationapi/models/item/generated.json | 0 .../stationapi/models/item/handheld.json | 0 .../stationapi/models/item/handheld_rod.json | 0 .../assets/station-renderer-api-v0/icon.png | Bin .../src/main/resources/fabric.mod.json | 4 +- .../station-renderer-api-v0.mixins.json | 0 .../station-renderer-api-v1.accesswidener | 2 + station-renderer-arsenic/build.gradle.kts | 2 +- .../impl/client/arsenic/Arsenic.java | 4 +- .../aocalc/LightingCalculatorImpl.java | 30 +- .../renderer/render/ArsenicBlockRenderer.java | 12 +- .../renderer/render/ArsenicItemRenderer.java | 2 +- .../render/BakedModelRendererImpl.java | 34 +- .../renderer/render/RendererHolder.java | 4 +- .../client/PlayerEntityRendererMixin.java | 6 +- .../arsenic/client/WorldRendererMixin.java | 5 +- .../client/block/BlockRenderManagerMixin.java | 9 +- .../entity/PistonBlockEntityRenderer.java | 3 +- .../client/particle/ItemParticleMixin.java | 10 +- .../metadata/ResourceMetadataSerializer.java | 5 +- .../impl/resource/DefaultResourcePack.java | 6 +- .../impl/resource/DirectoryResourcePack.java | 6 +- .../resource/NamespaceResourceManager.java | 5 +- station-templates-v0/build.gradle.kts | 2 +- station-vanilla-fix-v0/build.gradle.kts | 2 +- .../datafixer/VanillaDataFixerImpl.java | 8 +- .../condition/SlopeSurfaceCondition.java | 8 +- 237 files changed, 1828 insertions(+), 2675 deletions(-) create mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/GivensPair.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix3f.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix4f.java create mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixUtil.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Quaternion.java create mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/RotationAxis.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3f.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector2f.java delete mode 100644 station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector4f.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RendererAccess.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceType.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java delete mode 100644 station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererAccessImpl.java rename {station-renderer-api-v0 => station-renderer-api-v1}/build.gradle.kts (84%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/StationRenderAPI.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/block/StationRendererBlock.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColorProvider.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColors.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColorProvider.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColors.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/color/world/BiomeColors.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/color/block/BlockColorsRegisterEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/color/item/ItemColorsRegisterEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/BlockModelPredicateProviderRegistryEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/ItemModelPredicateProviderRegistryEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/LoadUnbakedModelEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/PreLoadUnbakedModelEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/event/texture/TextureRegisterEvent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/item/StationRendererItem.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/Model.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java (77%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockModelPredicateProvider.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java (54%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java (54%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java (67%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java (71%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemModelPredicateProvider.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemWithRenderer.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/registry/BlockModelPredicateProviderRegistry.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/registry/ItemModelPredicateProviderRegistry.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/StationTessellator.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockModels.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererHelper.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererUtil.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/AndMultipartModelSelector.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelManager.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java (69%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/Baker.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java (94%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java (85%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeSettings.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelIdentifier.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelLoader.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java (59%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartModelSelector.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/OrMultipartModelSelector.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/SimpleMultipartModelSelector.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteAtlasManager.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/UnbakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java (98%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java (74%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java (95%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverride.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelTransformation.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariant.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariantMap.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartModelComponent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartUnbakedModel.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/WeightedUnbakedModel.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationFrameResourceMetadata.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadata.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadataReader.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadata.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadataReader.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/Animator.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/DynamicTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/MissingSprite.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImage.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/ResourceTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/Sprite.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java (97%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteDimensions.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteIdentifier.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteLoader.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/SpritesheetHelper.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/StationTextureManager.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureHelper.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TexturePackDependent.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcher.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcherCannotFitException.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureTickListener.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureUtil.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlas.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java (98%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java (93%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlases.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/CustomAtlasProvider.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/ExpandableAtlas.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java (64%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Sprite.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java (81%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StaticReferenceProvider.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StationTextureBinder.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/client/world/ColorResolver.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/util/collection/WeightedPicker.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java (76%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/api/util/math/CubeFace.java (100%) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererManager.java rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java (83%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTextureManagerImpl.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/impl/client/texture/GuiItemsHelper.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/impl/client/texture/StationRenderImpl.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/impl/client/texture/TerrainHelper.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/BlockItemMixin.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/BlockMixin.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/ItemMixin.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerAccessor.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java (53%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java (84%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorAccessor.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java (63%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerAccessor.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerMixin.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/java/net/modificationstation/stationapi/mixin/render/client/WaterColorAccessor.java (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/atlases/game.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/block.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cross.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_all.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_bottom_top.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_column.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_horizontal.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_mirrored.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_directional.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored_all.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/cube_top.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/block.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_all.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_bottom_top.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column_horizontal.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_directional.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_top.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable_with_bottom.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/orientable.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/orientable_with_bottom.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/block/tinted_cross.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/item/generated.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/item/handheld.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/minecraft/stationapi/models/item/handheld_rod.json (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/assets/station-renderer-api-v0/icon.png (100%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/fabric.mod.json (90%) rename {station-renderer-api-v0 => station-renderer-api-v1}/src/main/resources/station-renderer-api-v0.mixins.json (100%) create mode 100644 station-renderer-api-v1/src/main/resources/station-renderer-api-v1.accesswidener diff --git a/build.gradle.kts b/build.gradle.kts index 90eb97a59..e69c3fb21 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,7 @@ allprojects { maven(url = "https://maven.glass-launcher.net/babric") maven(url = "https://maven.glass-launcher.net/snapshots") maven(url = "https://maven.glass-launcher.net/releases") + maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") maven(url = "https://jitpack.io/") mavenCentral() exclusiveContent { @@ -74,6 +75,7 @@ allprojects { "transitiveImplementation"("com.github.ben-manes.caffeine:caffeine:${project.properties["caffeine_version"]}") "transitiveImplementation"("com.mojang:datafixerupper:${project.properties["dfu_version"]}") "transitiveImplementation"("maven.modrinth:spasm:${project.properties["spasm_version"]}") + "transitiveImplementation"("org.joml:joml:${project.properties["joml_version"]}") // convenience stuff // adds some useful annotations for data classes. does not add any dependencies @@ -257,6 +259,7 @@ dependencies { include("com.github.ben-manes.caffeine:caffeine:${project.properties["caffeine_version"]}") include("com.mojang:datafixerupper:${project.properties["dfu_version"]}") include("maven.modrinth:spasm:${project.properties["spasm_version"]}") + include("org.joml:joml:${project.properties["joml_version"]}") } // Makes java shut up diff --git a/gradle.properties b/gradle.properties index c96b861c6..faf362b12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,8 +18,9 @@ fabric.loom.multiProjectOptimisation=true unsafeevents_version = e31096e fastutil_version = 8.5.8 caffeine_version = 3.0.5 - dfu_version = 6.0.6 + dfu_version = 8.0.16 spasm_version = 0.2.2 + joml_version = 1.10.8 # Mod Properties mod_version = 2.0.0-alpha.4 diff --git a/settings.gradle.kts b/settings.gradle.kts index 737ddf9bb..d81b04b1d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,8 @@ include(":station-armor-api-v0") include(":station-localization-api-v0") include(":station-achievements-v0") include(":station-keybindings-v0") -include(":station-renderer-api-v0") +//include(":station-renderer-api-v0") +include(":station-renderer-api-v1") include(":station-audio-loader-v0") include(":station-lifecycle-events-v0") include(":station-vanilla-checker-v0") diff --git a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/StringIdentifiable.java b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/StringIdentifiable.java index 874c86721..88d18d129 100644 --- a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/StringIdentifiable.java +++ b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/StringIdentifiable.java @@ -1,45 +1,81 @@ package net.modificationstation.stationapi.api.util; -import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Keyable; -import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Object2ReferenceMaps; -import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import net.modificationstation.stationapi.api.util.dynamic.Codecs; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.ToIntFunction; import java.util.stream.Collectors; import java.util.stream.Stream; +/** + * An interface, usually implemented by enums, that allows the object to be serialized + * by codecs. An instance is identified using a string. + * + * @apiNote To make an enum serializable with codecs, implement this on the enum class, + * implement {@link #asString} to return a unique ID, and add a {@code static final} + * field that holds {@linkplain #createCodec the codec for the enum}. + */ public interface StringIdentifiable { int MAPIFY_THRESHOLD = 16; + /** + * {@return the unique string representation of the enum, used for serialization} + */ String asString(); + /** + * Creates a codec that serializes an enum implementing this interface either + * using its ordinals (when compressed) or using its {@link #asString()} method. + */ + static & StringIdentifiable> StringIdentifiable.EnumCodec createCodec(Supplier enumValues) { + return createCodec(enumValues, id -> id); + } + /** * Creates a codec that serializes an enum implementing this interface either * using its ordinals (when compressed) or using its {@link #asString()} method * and a given decode function. */ - static & StringIdentifiable> Codec createCodec(Supplier enumValues) { - E[] enums = enumValues.get(); - if (enums.length > MAPIFY_THRESHOLD) { - //noinspection Convert2MethodRef - Object2ReferenceMap map = Object2ReferenceMaps.unmodifiable(Arrays.stream(enums).collect(Collectors.toMap(StringIdentifiable::asString, Function.identity(), (o, o2) -> { throw new IllegalStateException(String.format("Duplicate key %s", o)); }, () -> new Object2ReferenceOpenHashMap<>()))); - return new Codec<>(enums, id -> id == null ? null : map.get(id)); + static & StringIdentifiable> StringIdentifiable.EnumCodec createCodec( + Supplier enumValues, Function valueNameTransformer + ) { + E[] enums = (E[])enumValues.get(); + Function function = createMapper(enums, valueNameTransformer); + return new StringIdentifiable.EnumCodec<>(enums, function); + } + + static Codec createBasicCodec(Supplier values) { + T[] identifiableValues = values.get(); + Function function = createMapper(identifiableValues, valueName -> valueName); + ToIntFunction toIntFunction = Util.lastIndexGetter(Arrays.asList(identifiableValues)); + return new StringIdentifiable.BasicCodec<>(identifiableValues, function, toIntFunction); + } + + static Function createMapper(T[] values, Function valueNameTransformer) { + if (values.length > 16) { + Map map = Arrays.stream(values) + .collect(Collectors.toMap(value -> valueNameTransformer.apply(value.asString()), value -> value)); + return name -> name == null ? null : map.get(name); + } else { + return name -> { + for (T stringIdentifiable : values) { + if (valueNameTransformer.apply(stringIdentifiable.asString()).equals(name)) { + return stringIdentifiable; + } + } + + return null; + }; } - return new Codec<>(enums, id -> { - for (E enum_ : enums) { - if (!enum_.asString().equals(id)) continue; - return enum_; - } - return null; - }); } static Keyable toKeyable(final StringIdentifiable[] values) { @@ -52,29 +88,45 @@ public Stream keys(DynamicOps ops) { }; } - class Codec> - implements com.mojang.serialization.Codec { - private final com.mojang.serialization.Codec base; - private final Function idToIdentifiable; + class BasicCodec implements Codec { + private final Codec codec; - public Codec(E[] values, Function idToIdentifiable) { - this.base = Codecs.orCompressed(Codecs.idChecked(identifiable -> ((StringIdentifiable) identifiable).asString(), idToIdentifiable), Codecs.rawIdChecked(Enum::ordinal, ordinal -> ordinal >= 0 && ordinal < values.length ? values[ordinal] : null, -1)); - this.idToIdentifiable = idToIdentifiable; + public BasicCodec(S[] values, Function idToIdentifiable, ToIntFunction identifiableToOrdinal) { + this.codec = Codecs.orCompressed( + Codec.stringResolver(StringIdentifiable::asString, idToIdentifiable), + Codecs.rawIdChecked(identifiableToOrdinal, ordinal -> ordinal >= 0 && ordinal < values.length ? values[ordinal] : null, -1) + ); } @Override - public DataResult> decode(DynamicOps ops, T input) { - return this.base.decode(ops, input); + public DataResult> decode(DynamicOps ops, T input) { + return this.codec.decode(ops, input); } - @Override - public DataResult encode(E enum_, DynamicOps dynamicOps, T object) { - return this.base.encode(enum_, dynamicOps, object); + public DataResult encode(S stringIdentifiable, DynamicOps dynamicOps, T object) { + return this.codec.encode(stringIdentifiable, dynamicOps, object); + } + } + + class EnumCodec & StringIdentifiable> extends StringIdentifiable.BasicCodec { + private final Function idToIdentifiable; + + public EnumCodec(E[] values, Function idToIdentifiable) { + super(values, idToIdentifiable, Enum::ordinal); + this.idToIdentifiable = idToIdentifiable; } @Nullable public E byId(@Nullable String id) { - return this.idToIdentifiable.apply(id); + return (E)this.idToIdentifiable.apply(id); + } + + public E byId(@Nullable String id, E fallback) { + return Objects.requireNonNullElse(this.byId(id), fallback); + } + + public E byId(@Nullable String id, Supplier fallbackSupplier) { + return Objects.requireNonNullElseGet(this.byId(id), fallbackSupplier); } } } diff --git a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/Util.java b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/Util.java index fd46df9be..9666267ea 100644 --- a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/Util.java +++ b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/Util.java @@ -8,10 +8,7 @@ import com.mojang.serialization.DataResult; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps; -import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.objects.*; import net.fabricmc.loader.api.FabricLoader; import net.modificationstation.stationapi.api.util.crash.CrashException; import org.apache.commons.io.IOUtils; @@ -294,6 +291,22 @@ public static void shuffle(ObjectArrayList list, Random random) { } } + public static ToIntFunction lastIndexGetter(List values) { + int i = values.size(); + if (i < 8) { + return values::indexOf; + } else { + Object2IntMap object2IntMap = new Object2IntOpenHashMap<>(i); + object2IntMap.defaultReturnValue(-1); + + for (int j = 0; j < i; j++) { + object2IntMap.put((T)values.get(j), j); + } + + return object2IntMap; + } + } + public static Consumer addPrefix(String prefix, Consumer consumer) { return string -> consumer.accept(prefix + string); } diff --git a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/dynamic/Codecs.java b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/dynamic/Codecs.java index 313a3d877..907abab5e 100644 --- a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/dynamic/Codecs.java +++ b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/dynamic/Codecs.java @@ -1,14 +1,19 @@ package net.modificationstation.stationapi.api.util.dynamic; import com.google.common.base.Suppliers; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.*; import com.mojang.serialization.codecs.RecordCodecBuilder; +import it.unimi.dsi.fastutil.floats.FloatArrayList; +import it.unimi.dsi.fastutil.floats.FloatList; import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.util.Util; import net.modificationstation.stationapi.api.util.Uuids; import org.apache.commons.lang3.mutable.MutableObject; +import org.joml.*; import java.time.Instant; import java.time.format.DateTimeFormatter; @@ -27,6 +32,50 @@ */ public class Codecs { public static final Codec UUID = Uuids.CODEC; + public static final Codec VECTOR_3F = Codec.FLOAT + .listOf() + .comapFlatMap( + list -> Util.toArray(list, 3).map(elements -> new Vector3f(elements.get(0), elements.get(1), elements.get(2))), + vec -> List.of(vec.x(), vec.y(), vec.z()) + ); + public static final Codec VECTOR_4F = Codec.FLOAT + .listOf() + .comapFlatMap( + list -> Util.toArray(list, 4).map(elements -> new Vector4f(elements.get(0), elements.get(1), elements.get(2), elements.get(3))), + vec -> List.of(vec.x(), vec.y(), vec.z(), vec.w()) + ); + public static final Codec QUATERNION_F = Codec.FLOAT + .listOf() + .comapFlatMap( + list -> Util.toArray(list, 4) + .map(elements -> new Quaternionf(elements.get(0), elements.get(1), elements.get(2), elements.get(3)).normalize()), + quaternion -> List.of(quaternion.x, quaternion.y, quaternion.z, quaternion.w) + ); + public static final Codec AXIS_ANGLE_4F = RecordCodecBuilder.create( + instance -> instance.group( + Codec.FLOAT.fieldOf("angle").forGetter(axisAngle4f -> axisAngle4f.angle), + VECTOR_3F.fieldOf("axis").forGetter(axisAngle4f -> new Vector3f(axisAngle4f.x, axisAngle4f.y, axisAngle4f.z)) + ) + .apply(instance, AxisAngle4f::new) + ); + public static final Codec ROTATION = Codec.withAlternative(QUATERNION_F, AXIS_ANGLE_4F.xmap(Quaternionf::new, AxisAngle4f::new)); + public static final Codec MATRIX_4F = Codec.FLOAT.listOf().comapFlatMap(list -> Util.toArray(list, 16).map(elements -> { + Matrix4f matrix4f = new Matrix4f(); + + for (int i = 0; i < elements.size(); i++) { + matrix4f.setRowColumn(i >> 2, i & 3, elements.get(i)); + } + + return matrix4f.determineProperties(); + }), matrix4f -> { + FloatList floatList = new FloatArrayList(16); + + for (int i = 0; i < 16; i++) { + floatList.add(matrix4f.getRowColumn(i >> 2, i & 3)); + } + + return floatList; + }); public static final Codec NONNEGATIVE_INT = Codecs.rangedInt(0, Integer.MAX_VALUE, v -> "Value must be non-negative: " + v); public static final Codec POSITIVE_INT = Codecs.rangedInt(1, Integer.MAX_VALUE, v -> "Value must be positive: " + v); public static final Codec POSITIVE_FLOAT = Codecs.rangedFloat(0.0f, Float.MAX_VALUE, v -> "Value must be positive: " + v); @@ -116,8 +165,14 @@ public static Codec rawIdChecked(ToIntFunction elementToRawId, IntFunc }); } - public static Codec idChecked(Function elementToId, Function idToElement) { - return Codec.STRING.flatXmap(id -> Optional.ofNullable(idToElement.apply(id)).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Unknown element name:" + id)), element -> Optional.ofNullable(elementToId.apply(element)).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Element with unknown name: " + element))); + public static Codec idChecked(Codec idCodec, Function idToElement, Function elementToId) { + return idCodec.flatXmap(id -> { + E object = (E)idToElement.apply(id); + return object == null ? DataResult.error(() -> "Unknown element id: " + id) : DataResult.success(object); + }, element -> { + I object = (I)elementToId.apply(element); + return object == null ? DataResult.error(() -> "Element with unknown id: " + element) : DataResult.success(object); + }); } public static Codec orCompressed(final Codec uncompressedCodec, final Codec compressedCodec) { @@ -394,6 +449,26 @@ public DataResult encode(A input, DynamicOps ops, T prefix) { } } + public static class IdMapper { + private final BiMap values = HashBiMap.create(); + + public Codec getCodec(Codec idCodec) { + BiMap biMap = this.values.inverse(); + return Codecs.idChecked(idCodec, this.values::get, biMap::get); + } + + public Codecs.IdMapper put(I id, V value) { + Objects.requireNonNull(value, () -> "Value for " + id + " is null"); + this.values.put(id, value); + return this; + } + + public V putIfAbsent(I id, V value) { + Objects.requireNonNull(value, () -> "Value for " + id + " is null"); + return this.values.putIfAbsent(id, value); + } + } + public record TagEntryId(Identifier id, boolean tag) { @Override public String toString() { diff --git a/station-blockitems-v0/build.gradle.kts b/station-blockitems-v0/build.gradle.kts index 9d84075bc..8f61ac290 100644 --- a/station-blockitems-v0/build.gradle.kts +++ b/station-blockitems-v0/build.gradle.kts @@ -8,7 +8,7 @@ addModuleDependencies(project, "station-registry-api-v0", "station-blocks-v0", "station-items-v0", - "station-renderer-api-v0", + "station-renderer-api-v1", "station-templates-v0", "station-flattening-v0" ) \ No newline at end of file diff --git a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/BlockItemMixin.java b/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/BlockItemMixin.java index 3f0ec5521..5975cae87 100644 --- a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/BlockItemMixin.java +++ b/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/BlockItemMixin.java @@ -31,7 +31,7 @@ private boolean stationapi_handlePlace( .world(world) .player(player) .x(x).y(y).z(z) - .side(Direction.byId(side)) + .side(Direction.byIndex(side)) .block(BlockRegistry.INSTANCE.get(id)) .meta(meta) .blockItem(blockItem) diff --git a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/SecondaryBlockItemMixin.java b/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/SecondaryBlockItemMixin.java index d6a05f30d..e6d0f2b22 100644 --- a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/SecondaryBlockItemMixin.java +++ b/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/SecondaryBlockItemMixin.java @@ -31,7 +31,7 @@ private boolean stationapi_handlePlace( .world(world) .player(player) .x(x).y(y).z(z) - .side(Direction.byId(side)) + .side(Direction.byIndex(side)) .block(BlockRegistry.INSTANCE.get(id)) .blockItem(blockItem) .placeFunction(() -> placeFunction.call(world, x, y, z, id)) diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemPlacementContext.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemPlacementContext.java index 10a1a097b..60c655bf3 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemPlacementContext.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemPlacementContext.java @@ -24,7 +24,7 @@ public ItemPlacementContext(ItemUsageContext context) { protected ItemPlacementContext(World world, @Nullable PlayerEntity playerEntity, ItemStack itemStack, HitResult blockHitResult) { super(world, playerEntity, itemStack, blockHitResult); - this.placementPos = new BlockPos(blockHitResult.blockX, blockHitResult.blockY, blockHitResult.blockZ).offset(Direction.byId(blockHitResult.side)); + this.placementPos = new BlockPos(blockHitResult.blockX, blockHitResult.blockY, blockHitResult.blockZ).offset(Direction.byIndex(blockHitResult.side)); this.canReplaceExisting = world.getBlockState(blockHitResult.blockX, blockHitResult.blockY, blockHitResult.blockZ).canReplace(this); } diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemUsageContext.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemUsageContext.java index 4950b0c94..9ce505237 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemUsageContext.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/item/ItemUsageContext.java @@ -38,7 +38,7 @@ public BlockPos getBlockPos() { } public Direction getSide() { - return Direction.byId(this.hit.side); + return Direction.byIndex(this.hit.side); } public Vec3d getHitPos() { diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/state/State.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/state/State.java index 616048db9..f9256d698 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/state/State.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/state/State.java @@ -146,7 +146,7 @@ public ImmutableMap, Comparable> getEntries() { protected static > Codec createCodec(Codec codec, Function ownerToStateFunction) { return codec.dispatch("Name", (state) -> state.owner, (object) -> { S state = ownerToStateFunction.apply(object); - return state.getEntries().isEmpty() ? Codec.unit(state) : state.codec.fieldOf("Properties").codec(); + return state.getEntries().isEmpty() ? MapCodec.unit(state) : state.codec.fieldOf("Properties").codec().lenientOptionalFieldOf("Properties").xmap(statex -> statex.orElse(state), Optional::of); }); } } diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/world/FlattenedWorldManager.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/world/FlattenedWorldManager.java index 3fbce25b4..6b82c26a8 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/world/FlattenedWorldManager.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/world/FlattenedWorldManager.java @@ -45,7 +45,7 @@ public static void saveChunk(FlattenedChunk chunk, World world, NbtCompound chun if (!ChunkSection.isEmpty(section)) { NbtCompound sectionTag = new NbtCompound(); sectionTag.putByte(HEIGHT_KEY, (byte)sectionY); - sectionTag.put("block_states", CODEC.encodeStart(NbtOps.INSTANCE, section.getBlockStateContainer()).getOrThrow(false, LOGGER::error)); + sectionTag.put("block_states", CODEC.encodeStart(NbtOps.INSTANCE, section.getBlockStateContainer()).getOrThrow()); sectionTag.put(METADATA_KEY, section.getMetadataArray().toTag()); sectionTag.put(SKY_LIGHT_KEY, section.getLightArray(LightType.SKY).toTag()); sectionTag.put(BLOCK_LIGHT_KEY, section.getLightArray(LightType.BLOCK).toTag()); @@ -87,7 +87,7 @@ public static Chunk loadChunk(World world, NbtCompound chunkTag) { int sectionY = sectionTag.getByte(HEIGHT_KEY); int index = world.sectionCoordToIndex(sectionY); if (index < 0 || index >= sections.length) continue; - PalettedContainer blockStates = sectionTag.contains("block_states") ? CODEC.parse(NbtOps.INSTANCE, sectionTag.getCompound("block_states")).promotePartial(errorMessage -> logRecoverableError(xPos, zPos, sectionY, errorMessage)).getOrThrow(false, LOGGER::error) : new PalettedContainer<>(Block.STATE_IDS, States.AIR.get(), PalettedContainer.PaletteProvider.BLOCK_STATE); + PalettedContainer blockStates = sectionTag.contains("block_states") ? CODEC.parse(NbtOps.INSTANCE, sectionTag.getCompound("block_states")).promotePartial(errorMessage -> logRecoverableError(xPos, zPos, sectionY, errorMessage)).getOrThrow() : new PalettedContainer<>(Block.STATE_IDS, States.AIR.get(), PalettedContainer.PaletteProvider.BLOCK_STATE); ChunkSection chunkSection = new ChunkSection(sectionY, blockStates); chunkSection.getMetadataArray().copyArray(sectionTag.getByteArray(METADATA_KEY)); chunkSection.getLightArray(LightType.SKY).copyArray(sectionTag.getByteArray(SKY_LIGHT_KEY)); diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/BlockItemMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/BlockItemMixin.java index 0b523f8b2..14c7e0e8a 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/BlockItemMixin.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/BlockItemMixin.java @@ -60,7 +60,7 @@ private boolean stationapi_canReplace( World argWorld, int blockID, int argX, int argY, int argZ, boolean checkCollision, int argSide, ItemStack itemStack, PlayerEntity player, World world, int x, int y, int z, int side ) { - Direction direction = Direction.byId(side); + Direction direction = Direction.byIndex(side); Box box = Block.BLOCKS[blockID].getCollisionShape(world, x, y, z); return (box == null || world.canSpawnEntity(box)) && StationAPI.EVENT_BUS.post( IsBlockReplaceableEvent.builder() diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/FallingBlockEntityMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/FallingBlockEntityMixin.java index a4f898788..1821204c1 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/FallingBlockEntityMixin.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/FallingBlockEntityMixin.java @@ -21,6 +21,6 @@ class FallingBlockEntityMixin { ) ) private boolean stationapi_redirectCanPlace(World world, int blockId, int x, int y, int z, boolean skipEntityCollisionCheck, int side) { - return StationAPI.EVENT_BUS.post(IsBlockReplaceableEvent.builder().context(new AutomaticItemPlacementContext(world, new BlockPos(x, y, z), Direction.DOWN, null, Direction.byId(side))).build()).context.canPlace(); + return StationAPI.EVENT_BUS.post(IsBlockReplaceableEvent.builder().context(new AutomaticItemPlacementContext(world, new BlockPos(x, y, z), Direction.DOWN, null, Direction.byIndex(side))).build()).context.canPlace(); } } diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/bonemeal/BonemealAPI.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/bonemeal/BonemealAPI.java index b0c0ecf0f..3f85e1698 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/bonemeal/BonemealAPI.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/bonemeal/BonemealAPI.java @@ -37,7 +37,7 @@ public static boolean generate(World world, int x, int y, int z, BlockState stat updateCache(state); if (CACHE.isEmpty()) return false; Random random = world.field_214; - Direction offset = Direction.byId(side); + Direction offset = Direction.byIndex(side); CACHE.get(random).generate( world, random, diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/dispenser/ItemDispenseContext.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/dispenser/ItemDispenseContext.java index 79866fb0f..783c71eaa 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/api/dispenser/ItemDispenseContext.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/api/dispenser/ItemDispenseContext.java @@ -31,7 +31,7 @@ public ItemDispenseContext(ItemStack itemStack, DispenserBlockEntity dispenser, this.dispenser = dispenser; this.itemStack = itemStack; this.slot = slot; - direction = Direction.byId(dispenser.world.getBlockMeta(dispenser.x, dispenser.y, dispenser.z)); + direction = Direction.byIndex(dispenser.world.getBlockMeta(dispenser.x, dispenser.y, dispenser.z)); } public static void genericShootEntity(Entity entity, double velX, double velY, double velZ, float pitch, float yaw) { diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/BlockRotation.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/BlockRotation.java index b690160b8..80c64658a 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/BlockRotation.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/BlockRotation.java @@ -1,5 +1,6 @@ package net.modificationstation.stationapi.api.util; +import com.mojang.serialization.Codec; import net.modificationstation.stationapi.api.util.math.Direction; import net.modificationstation.stationapi.api.util.math.DirectionTransformation; diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AxisTransformation.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AxisTransformation.java index 884491814..fe54d6664 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AxisTransformation.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AxisTransformation.java @@ -1,6 +1,7 @@ package net.modificationstation.stationapi.api.util.math; import net.modificationstation.stationapi.api.util.Util; +import org.joml.Matrix3f; import java.util.Arrays; @@ -34,10 +35,10 @@ public enum AxisTransformation { AxisTransformation(int xMapping, int yMapping, int zMapping) { this.mappings = new int[]{xMapping, yMapping, zMapping}; - this.matrix = new Matrix3f(); - this.matrix.set(0, this.map(0), 1.0F); - this.matrix.set(1, this.map(1), 1.0F); - this.matrix.set(2, this.map(2), 1.0F); + this.matrix = new Matrix3f().zero(); + this.matrix.set(this.map(0), 0, 1.0F); + this.matrix.set(this.map(1), 1, 1.0F); + this.matrix.set(this.map(2), 2, 1.0F); } public AxisTransformation prepend(AxisTransformation transformation) { diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Direction.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Direction.java index a88c0aab5..1b9ced495 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Direction.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Direction.java @@ -2,6 +2,7 @@ import com.google.common.collect.Iterators; import com.google.gson.annotations.SerializedName; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -12,8 +13,11 @@ import net.modificationstation.stationapi.api.util.Util; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.*; +import java.lang.Math; import java.util.*; +import java.util.Random; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -35,7 +39,7 @@ public enum Direction implements StringIdentifiable { @SerializedName("south") SOUTH(5, 4, 3, "south", AxisDirection.POSITIVE, X, new Vec3i(1, 0, 0)); - public static final Codec CODEC; + public static final EnumCodec CODEC; public static final com.mojang.serialization.Codec VERTICAL_CODEC; private final int id; private final int idOpposite; @@ -44,6 +48,7 @@ public enum Direction implements StringIdentifiable { private final Axis axis; private final AxisDirection direction; private final Vec3i vector; + private final Vector3f floatVector; private final int offsetX, offsetY, offsetZ; private static final Direction[] ALL; private static final Direction[] VALUES; @@ -58,14 +63,15 @@ public enum Direction implements StringIdentifiable { this.axis = axis; this.direction = direction; this.vector = vector; + this.floatVector = new Vector3f((float) vector.getX(), (float) vector.getY(), (float) vector.getZ()); offsetX = vector.getX(); offsetY = vector.getY(); offsetZ = vector.getZ(); } public static Direction[] getEntityFacingOrder(Entity entity) { - final float f = entity.pitch * ((float)Math.PI / 180); - final float g = -entity.yaw * ((float)Math.PI / 180); + final float f = entity.pitch * ((float) Math.PI / 180); + final float g = -entity.yaw * ((float) Math.PI / 180); final float h = net.minecraft.util.math.MathHelper.sin(f); final float i = net.minecraft.util.math.MathHelper.cos(f); final float j = net.minecraft.util.math.MathHelper.sin(g); @@ -91,11 +97,10 @@ private static Direction[] listClosest(Direction first, Direction second, Direct return new Direction[]{first, second, third, third.getOpposite(), second.getOpposite(), first.getOpposite()}; } - public static Direction transform(Matrix4f matrix, Direction direction) { - Vec3i vec3i = direction.getVector(); - Vector4f vector4f = new Vector4f(vec3i.getX(), vec3i.getY(), vec3i.getZ(), 0.0f); - vector4f.transform(matrix); - return Direction.getFacing(vector4f.getX(), vector4f.getY(), vector4f.getZ()); + public static Direction transform(Matrix4fc matrix, Direction direction) { + Vector3f vector4f = matrix.transformDirection(direction.floatVector, new Vector3f()); + + return Direction.getFacing(vector4f.x(), vector4f.y(), vector4f.z()); } public static Collection shuffle(Random random) { @@ -106,24 +111,14 @@ public static Stream stream() { return Stream.of(ALL); } - public Quaternion getRotationQuaternion() { - Quaternion quaternion = Vec3f.POSITIVE_X.getDegreesQuaternion(90.0f); + public Quaternionf getRotationQuaternion() { return switch (this) { - case DOWN -> Vec3f.POSITIVE_X.getDegreesQuaternion(180.0f); - case UP -> Quaternion.IDENTITY.copy(); - case EAST -> { - quaternion.hamiltonProduct(Vec3f.POSITIVE_Z.getDegreesQuaternion(180.0f)); - yield quaternion; - } - case WEST -> quaternion; - case NORTH -> { - quaternion.hamiltonProduct(Vec3f.POSITIVE_Z.getDegreesQuaternion(-90.0f)); - yield quaternion; - } - case SOUTH -> { - quaternion.hamiltonProduct(Vec3f.POSITIVE_Z.getDegreesQuaternion(90.0f)); - yield quaternion; - } + case DOWN -> new Quaternionf().rotationX((float) Math.PI); + case UP -> new Quaternionf(); + case EAST -> new Quaternionf().rotationXYZ(((float) Math.PI / 2F), 0.0F, (float) Math.PI); + case WEST -> new Quaternionf().rotationX(((float) Math.PI / 2F)); + case NORTH -> new Quaternionf().rotationXYZ(((float) Math.PI / 2F), 0.0F, ((float) Math.PI / 2F)); + case SOUTH -> new Quaternionf().rotationXYZ(((float) Math.PI / 2F), 0.0F, (-(float) Math.PI / 2F)); }; } @@ -239,8 +234,8 @@ public int getOffsetZ() { return offsetZ; } - public Vec3f getUnitVector() { - return new Vec3f(getOffsetX(), getOffsetY(), getOffsetZ()); + public Vector3f getUnitVector() { + return new Vector3f(getOffsetX(), getOffsetY(), getOffsetZ()); } public String getName() { @@ -252,11 +247,11 @@ public Axis getAxis() { } @Nullable - public static Direction byName(@Nullable String name) { + public static Direction byId(@Nullable String name) { return CODEC.byId(name); } - public static Direction byId(int id) { + public static Direction byIndex(int id) { return VALUES[Math.abs(id % VALUES.length)]; } @@ -295,14 +290,14 @@ public static Direction random(Random random) { } public static Direction getFacing(double x, double y, double z) { - return Direction.getFacing((float)x, (float)y, (float)z); + return Direction.getFacing((float) x, (float) y, (float) z); } public static Direction getFacing(float x, float y, float z) { Direction direction = NORTH; float f = Float.MIN_VALUE; for (Direction direction2 : ALL) { - float g = x * (float)direction2.vector.getX() + y * (float)direction2.vector.getY() + z * (float)direction2.vector.getZ(); + float g = x * (float) direction2.vector.getX() + y * (float) direction2.vector.getY() + z * (float) direction2.vector.getZ(); if (!(g > f)) continue; f = g; direction = direction2; @@ -335,6 +330,10 @@ public Vec3i getVector() { return vector; } + public Vector3fc getFloatVector() { + return this.floatVector; + } + /** * {@return whether the given yaw points to the direction} * @@ -343,10 +342,10 @@ public Vec3i getVector() { *

This always returns {@code false} for vertical directions. */ public boolean pointsTo(float yaw) { - float f = yaw * ((float)Math.PI / 180); + float f = yaw * ((float) Math.PI / 180); float g = -net.minecraft.util.math.MathHelper.sin(f); float h = net.minecraft.util.math.MathHelper.cos(f); - return (float)vector.getX() * g + (float)vector.getZ() * h > 0.0f; + return (float) vector.getX() * g + (float) vector.getZ() * h > 0.0f; } static { @@ -361,10 +360,8 @@ public boolean pointsTo(float yaw) { } public enum Axis implements StringIdentifiable, - Predicate - { - X("x"){ - + Predicate { + X("x") { @Override public int choose(int x, int y, int z) { return x; @@ -375,8 +372,7 @@ public double choose(double x, double y, double z) { return x; } }, - Y("y"){ - + Y("y") { @Override public int choose(int x, int y, int z) { return y; @@ -387,8 +383,7 @@ public double choose(double x, double y, double z) { return y; } }, - Z("z"){ - + Z("z") { @Override public int choose(int x, int y, int z) { return z; @@ -401,7 +396,7 @@ public double choose(double x, double y, double z) { }; public static final Axis[] VALUES; - public static final StringIdentifiable.Codec CODEC; + public static final StringIdentifiable.EnumCodec CODEC; private final String name; Axis(String name) { @@ -490,8 +485,7 @@ public AxisDirection getOpposite() { } public enum Type implements Iterable, - Predicate - { + Predicate { HORIZONTAL(new Direction[]{NORTH, EAST, SOUTH, WEST}, new Axis[]{Axis.X, Axis.Z}), VERTICAL(new Direction[]{UP, DOWN}, new Axis[]{Axis.Y}); diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/DirectionTransformation.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/DirectionTransformation.java index 42913ff89..f59eba9e9 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/DirectionTransformation.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/DirectionTransformation.java @@ -7,6 +7,8 @@ import net.modificationstation.stationapi.api.util.StringIdentifiable; import net.modificationstation.stationapi.api.util.Util; import org.jetbrains.annotations.Nullable; +import org.joml.Matrix3f; +import org.joml.Matrix3fc; import java.util.Arrays; import java.util.Map; @@ -62,7 +64,7 @@ public enum DirectionTransformation implements StringIdentifiable { ROT_90_REF_Z_NEG("rot_90_ref_z_neg", AxisTransformation.P213, false, true, true), ROT_90_REF_Z_POS("rot_90_ref_z_pos", AxisTransformation.P213, true, false, true); - private final Matrix3f matrix; + private final Matrix3fc matrix; private final String name; @Nullable private Map mappings; @@ -100,11 +102,9 @@ public enum DirectionTransformation implements StringIdentifiable { this.flipY = flipY; this.flipZ = flipZ; this.axisTransformation = axisTransformation; - this.matrix = new Matrix3f(); - this.matrix.a00 = flipX ? -1.0F : 1.0F; - this.matrix.a11 = flipY ? -1.0F : 1.0F; - this.matrix.a22 = flipZ ? -1.0F : 1.0F; - this.matrix.multiply(axisTransformation.getMatrix()); + Matrix3f matrix3f = (new Matrix3f()).scaling(flipX ? -1.0F : 1.0F, flipY ? -1.0F : 1.0F, flipZ ? -1.0F : 1.0F); + matrix3f.mul(axisTransformation.getMatrix()); + this.matrix = matrix3f; } private BooleanList getAxisFlips() { diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/GivensPair.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/GivensPair.java new file mode 100644 index 000000000..c2fe05088 --- /dev/null +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/GivensPair.java @@ -0,0 +1,95 @@ +package net.modificationstation.stationapi.api.util.math; + +import org.joml.Math; +import org.joml.Matrix3f; +import org.joml.Quaternionf; + +public record GivensPair(float sinHalf, float cosHalf) { + public static GivensPair normalize(float a, float b) { + float n = Math.invsqrt(a * a + b * b); + return new GivensPair(n * a, n * b); + } + + public static GivensPair fromAngle(float radians) { + float sin = Math.sin(radians / 2.0F); + float cos = Math.cosFromSin(sin, radians / 2.0F); + return new GivensPair(sin, cos); + } + + public GivensPair negateSin() { + return new GivensPair(-this.sinHalf, this.cosHalf); + } + + public Quaternionf setXRotation(Quaternionf quaternionf) { + return quaternionf.set(this.sinHalf, 0.0F, 0.0F, this.cosHalf); + } + + public Quaternionf setYRotation(Quaternionf quaternionf) { + return quaternionf.set(0.0F, this.sinHalf, 0.0F, this.cosHalf); + } + + public Quaternionf setZRotation(Quaternionf quaternionf) { + return quaternionf.set(0.0F, 0.0F, this.sinHalf, this.cosHalf); + } + + public float cosDouble() { + return this.cosHalf * this.cosHalf - this.sinHalf * this.sinHalf; + } + + public float sinDouble() { + return 2.0F * this.sinHalf * this.cosHalf; + } + + public Matrix3f setRotationX(Matrix3f matrix3f) { + matrix3f.m01 = 0.0F; + matrix3f.m02 = 0.0F; + matrix3f.m10 = 0.0F; + matrix3f.m20 = 0.0F; + float cos = this.cosDouble(); + float sin = this.sinDouble(); + matrix3f.m11 = cos; + matrix3f.m22 = cos; + matrix3f.m12 = sin; + matrix3f.m21 = -sin; + matrix3f.m00 = 1.0F; + return matrix3f; + } + + public Matrix3f setRotationY(Matrix3f matrix3f) { + matrix3f.m01 = 0.0F; + matrix3f.m10 = 0.0F; + matrix3f.m12 = 0.0F; + matrix3f.m21 = 0.0F; + float cos = this.cosDouble(); + float sin = this.sinDouble(); + matrix3f.m00 = cos; + matrix3f.m22 = cos; + matrix3f.m02 = -sin; + matrix3f.m20 = sin; + matrix3f.m11 = 1.0F; + return matrix3f; + } + + public Matrix3f setRotationZ(Matrix3f matrix3f) { + matrix3f.m02 = 0.0F; + matrix3f.m12 = 0.0F; + matrix3f.m20 = 0.0F; + matrix3f.m21 = 0.0F; + float cos = this.cosDouble(); + float sin = this.sinDouble(); + matrix3f.m00 = cos; + matrix3f.m11 = cos; + matrix3f.m01 = sin; + matrix3f.m10 = -sin; + matrix3f.m22 = 1.0F; + return matrix3f; + } + + public float sinHalf() { + return this.sinHalf; + } + + public float cosHalf() { + return this.cosHalf; + } +} \ No newline at end of file diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix3f.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix3f.java deleted file mode 100644 index 62703ca56..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix3f.java +++ /dev/null @@ -1,505 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -import com.mojang.datafixers.util.Pair; -import org.apache.commons.lang3.tuple.Triple; - -import java.nio.FloatBuffer; - -public final class Matrix3f { - private static final float THREE_PLUS_TWO_SQRT_TWO = 3.0F + 2.0F * (float)Math.sqrt(2.0D); - private static final float COS_PI_OVER_EIGHT = (float)Math.cos(0.39269908169872414D); - private static final float SIN_PI_OVER_EIGHT = (float)Math.sin(0.39269908169872414D); - float a00; - float a01; - float a02; - float a10; - float a11; - float a12; - float a20; - float a21; - float a22; - - public Matrix3f() {} - - public Matrix3f(Quaternion source) { - float f = source.getX(); - float g = source.getY(); - float h = source.getZ(); - float i = source.getW(); - float j = 2.0F * f * f; - float k = 2.0F * g * g; - float l = 2.0F * h * h; - this.a00 = 1.0F - k - l; - this.a11 = 1.0F - l - j; - this.a22 = 1.0F - j - k; - float m = f * g; - float n = g * h; - float o = h * f; - float p = f * i; - float q = g * i; - float r = h * i; - this.a10 = 2.0F * (m + r); - this.a01 = 2.0F * (m - r); - this.a20 = 2.0F * (o - q); - this.a02 = 2.0F * (o + q); - this.a21 = 2.0F * (n + p); - this.a12 = 2.0F * (n - p); - } - - public static Matrix3f scale(float x, float y, float z) { - Matrix3f matrix3f = new Matrix3f(); - matrix3f.a00 = x; - matrix3f.a11 = y; - matrix3f.a22 = z; - return matrix3f; - } - - public static Matrix3f scaleTmp(float x, float y, float z) { - tmpMatrix.loadIdentity(); - tmpMatrix.a00 = x; - tmpMatrix.a11 = y; - tmpMatrix.a22 = z; - return tmpMatrix; - } - - private static final Matrix3f tmpMatrix = new Matrix3f(); - - public Matrix3f(Matrix4f source) { - this.a00 = source.a00; - this.a01 = source.a01; - this.a02 = source.a02; - this.a10 = source.a10; - this.a11 = source.a11; - this.a12 = source.a12; - this.a20 = source.a20; - this.a21 = source.a21; - this.a22 = source.a22; - } - - public Matrix3f(Matrix3f source) { - this.a00 = source.a00; - this.a01 = source.a01; - this.a02 = source.a02; - this.a10 = source.a10; - this.a11 = source.a11; - this.a12 = source.a12; - this.a20 = source.a20; - this.a21 = source.a21; - this.a22 = source.a22; - } - - private static Pair getSinAndCosOfRotation(float upperLeft, float diagonalAverage, float lowerRight) { - float f = 2.0F * (upperLeft - lowerRight); - if (THREE_PLUS_TWO_SQRT_TWO * diagonalAverage * diagonalAverage < f * f) { - float h = MathHelper.fastInverseSqrt(diagonalAverage * diagonalAverage + f * f); - return Pair.of(h * diagonalAverage, h * f); - } else { - return Pair.of(SIN_PI_OVER_EIGHT, COS_PI_OVER_EIGHT); - } - } - - private static Pair method_22848(float f, float g) { - float h = (float)Math.hypot(f, g); - float i = h > 1.0E-6F ? g : 0.0F; - float j = Math.abs(f) + Math.max(h, 1.0E-6F); - float l; - if (f < 0.0F) { - l = i; - i = j; - j = l; - } - - l = MathHelper.fastInverseSqrt(j * j + i * i); - j *= l; - i *= l; - return Pair.of(i, j); - } - - private static Quaternion method_22857(Matrix3f matrix3f) { - Matrix3f matrix3f2 = new Matrix3f(); - Quaternion quaternion = Quaternion.IDENTITY.copy(); - Pair pair3; - Float float4; - Float float5; - Quaternion quaternion4; - float m; - float n; - float o; - if (matrix3f.a01 * matrix3f.a01 + matrix3f.a10 * matrix3f.a10 > 1.0E-6F) { - pair3 = getSinAndCosOfRotation(matrix3f.a00, 0.5F * (matrix3f.a01 + matrix3f.a10), matrix3f.a11); - float4 = pair3.getFirst(); - float5 = pair3.getSecond(); - quaternion4 = new Quaternion(0.0F, 0.0F, float4, float5); - m = float5 * float5 - float4 * float4; - n = -2.0F * float4 * float5; - o = float5 * float5 + float4 * float4; - quaternion.hamiltonProduct(quaternion4); - matrix3f2.loadIdentity(); - matrix3f2.a00 = m; - matrix3f2.a11 = m; - matrix3f2.a10 = -n; - matrix3f2.a01 = n; - matrix3f2.a22 = o; - matrix3f.multiply(matrix3f2); - matrix3f2.transpose(); - matrix3f2.multiply(matrix3f); - matrix3f.load(matrix3f2); - } - - if (matrix3f.a02 * matrix3f.a02 + matrix3f.a20 * matrix3f.a20 > 1.0E-6F) { - pair3 = getSinAndCosOfRotation(matrix3f.a00, 0.5F * (matrix3f.a02 + matrix3f.a20), matrix3f.a22); - float i = -(Float)pair3.getFirst(); - float5 = pair3.getSecond(); - quaternion4 = new Quaternion(0.0F, i, 0.0F, float5); - m = float5 * float5 - i * i; - n = -2.0F * i * float5; - o = float5 * float5 + i * i; - quaternion.hamiltonProduct(quaternion4); - matrix3f2.loadIdentity(); - matrix3f2.a00 = m; - matrix3f2.a22 = m; - matrix3f2.a20 = n; - matrix3f2.a02 = -n; - matrix3f2.a11 = o; - matrix3f.multiply(matrix3f2); - matrix3f2.transpose(); - matrix3f2.multiply(matrix3f); - matrix3f.load(matrix3f2); - } - - if (matrix3f.a12 * matrix3f.a12 + matrix3f.a21 * matrix3f.a21 > 1.0E-6F) { - pair3 = getSinAndCosOfRotation(matrix3f.a11, 0.5F * (matrix3f.a12 + matrix3f.a21), matrix3f.a22); - float4 = pair3.getFirst(); - float5 = pair3.getSecond(); - quaternion4 = new Quaternion(float4, 0.0F, 0.0F, float5); - m = float5 * float5 - float4 * float4; - n = -2.0F * float4 * float5; - o = float5 * float5 + float4 * float4; - quaternion.hamiltonProduct(quaternion4); - matrix3f2.loadIdentity(); - matrix3f2.a11 = m; - matrix3f2.a22 = m; - matrix3f2.a21 = -n; - matrix3f2.a12 = n; - matrix3f2.a00 = o; - matrix3f.multiply(matrix3f2); - matrix3f2.transpose(); - matrix3f2.multiply(matrix3f); - matrix3f.load(matrix3f2); - } - - return quaternion; - } - - public void transpose() { - float f = this.a01; - this.a01 = this.a10; - this.a10 = f; - f = this.a02; - this.a02 = this.a20; - this.a20 = f; - f = this.a12; - this.a12 = this.a21; - this.a21 = f; - } - - public Triple decomposeLinearTransformation() { - Quaternion quaternion = Quaternion.IDENTITY.copy(); - Quaternion quaternion2 = Quaternion.IDENTITY.copy(); - Matrix3f matrix3f = this.copy(); - matrix3f.transpose(); - matrix3f.multiply(this); - - for(int i = 0; i < 5; ++i) { - quaternion2.hamiltonProduct(method_22857(matrix3f)); - } - - quaternion2.normalize(); - Matrix3f matrix3f2 = new Matrix3f(this); - matrix3f2.multiply(new Matrix3f(quaternion2)); - float f = 1.0F; - Pair pair = method_22848(matrix3f2.a00, matrix3f2.a10); - Float float_ = pair.getFirst(); - Float float2 = pair.getSecond(); - float g = float2 * float2 - float_ * float_; - float h = -2.0F * float_ * float2; - float j = float2 * float2 + float_ * float_; - Quaternion quaternion3 = new Quaternion(0.0F, 0.0F, float_, float2); - quaternion.hamiltonProduct(quaternion3); - Matrix3f matrix3f3 = new Matrix3f(); - matrix3f3.loadIdentity(); - matrix3f3.a00 = g; - matrix3f3.a11 = g; - matrix3f3.a10 = h; - matrix3f3.a01 = -h; - matrix3f3.a22 = j; - f *= j; - matrix3f3.multiply(matrix3f2); - pair = method_22848(matrix3f3.a00, matrix3f3.a20); - float k = -(Float)pair.getFirst(); - Float float3 = pair.getSecond(); - float l = float3 * float3 - k * k; - float m = -2.0F * k * float3; - float n = float3 * float3 + k * k; - Quaternion quaternion4 = new Quaternion(0.0F, k, 0.0F, float3); - quaternion.hamiltonProduct(quaternion4); - Matrix3f matrix3f4 = new Matrix3f(); - matrix3f4.loadIdentity(); - matrix3f4.a00 = l; - matrix3f4.a22 = l; - matrix3f4.a20 = -m; - matrix3f4.a02 = m; - matrix3f4.a11 = n; - f *= n; - matrix3f4.multiply(matrix3f3); - pair = method_22848(matrix3f4.a11, matrix3f4.a21); - Float float4 = pair.getFirst(); - Float float5 = pair.getSecond(); - float o = float5 * float5 - float4 * float4; - float p = -2.0F * float4 * float5; - float q = float5 * float5 + float4 * float4; - Quaternion quaternion5 = new Quaternion(float4, 0.0F, 0.0F, float5); - quaternion.hamiltonProduct(quaternion5); - Matrix3f matrix3f5 = new Matrix3f(); - matrix3f5.loadIdentity(); - matrix3f5.a11 = o; - matrix3f5.a22 = o; - matrix3f5.a21 = p; - matrix3f5.a12 = -p; - matrix3f5.a00 = q; - f *= q; - matrix3f5.multiply(matrix3f4); - f = 1.0F / f; - quaternion.scale((float)Math.sqrt(f)); - Vec3f vector3f = new Vec3f(matrix3f5.a00 * f, matrix3f5.a11 * f, matrix3f5.a22 * f); - return Triple.of(quaternion, vector3f, quaternion2); - } - - public boolean equals(Object object) { - if (this == object) { - return true; - } else if (object != null && this.getClass() == object.getClass()) { - Matrix3f matrix3f = (Matrix3f)object; - return Float.compare(matrix3f.a00, this.a00) == 0 && Float.compare(matrix3f.a01, this.a01) == 0 && Float.compare(matrix3f.a02, this.a02) == 0 && Float.compare(matrix3f.a10, this.a10) == 0 && Float.compare(matrix3f.a11, this.a11) == 0 && Float.compare(matrix3f.a12, this.a12) == 0 && Float.compare(matrix3f.a20, this.a20) == 0 && Float.compare(matrix3f.a21, this.a21) == 0 && Float.compare(matrix3f.a22, this.a22) == 0; - } else { - return false; - } - } - - public int hashCode() { - int i = this.a00 != 0.0F ? Float.floatToIntBits(this.a00) : 0; - i = 31 * i + (this.a01 != 0.0F ? Float.floatToIntBits(this.a01) : 0); - i = 31 * i + (this.a02 != 0.0F ? Float.floatToIntBits(this.a02) : 0); - i = 31 * i + (this.a10 != 0.0F ? Float.floatToIntBits(this.a10) : 0); - i = 31 * i + (this.a11 != 0.0F ? Float.floatToIntBits(this.a11) : 0); - i = 31 * i + (this.a12 != 0.0F ? Float.floatToIntBits(this.a12) : 0); - i = 31 * i + (this.a20 != 0.0F ? Float.floatToIntBits(this.a20) : 0); - i = 31 * i + (this.a21 != 0.0F ? Float.floatToIntBits(this.a21) : 0); - i = 31 * i + (this.a22 != 0.0F ? Float.floatToIntBits(this.a22) : 0); - return i; - } - - private static int pack(int x, int y) { - return y * 3 + x; - } - - public void load(Matrix3f source) { - this.a00 = source.a00; - this.a01 = source.a01; - this.a02 = source.a02; - this.a10 = source.a10; - this.a11 = source.a11; - this.a12 = source.a12; - this.a20 = source.a20; - this.a21 = source.a21; - this.a22 = source.a22; - } - - /** - * Writes this matrix to the buffer in column-major order. - * - * @see #writeRowMajor(FloatBuffer) - * @see #write(FloatBuffer, boolean) - */ - public void writeColumnMajor(FloatBuffer buf) { - buf.put(Matrix3f.pack(0, 0), this.a00); - buf.put(Matrix3f.pack(0, 1), this.a01); - buf.put(Matrix3f.pack(0, 2), this.a02); - buf.put(Matrix3f.pack(1, 0), this.a10); - buf.put(Matrix3f.pack(1, 1), this.a11); - buf.put(Matrix3f.pack(1, 2), this.a12); - buf.put(Matrix3f.pack(2, 0), this.a20); - buf.put(Matrix3f.pack(2, 1), this.a21); - buf.put(Matrix3f.pack(2, 2), this.a22); - } - - /** - * Writes this matrix to the buffer in row-major order. - * - * @see #writeColumnMajor(FloatBuffer) - * @see #write(FloatBuffer, boolean) - */ - public void writeRowMajor(FloatBuffer buf) { - buf.put(Matrix3f.pack(0, 0), this.a00); - buf.put(Matrix3f.pack(1, 0), this.a01); - buf.put(Matrix3f.pack(2, 0), this.a02); - buf.put(Matrix3f.pack(0, 1), this.a10); - buf.put(Matrix3f.pack(1, 1), this.a11); - buf.put(Matrix3f.pack(2, 1), this.a12); - buf.put(Matrix3f.pack(0, 2), this.a20); - buf.put(Matrix3f.pack(1, 2), this.a21); - buf.put(Matrix3f.pack(2, 2), this.a22); - } - - /** - * Writes this matrix to the buffer. - * - * @see #writeRowMajor(FloatBuffer) - * @see #writeColumnMajor(FloatBuffer) - * - * @param rowMajor {@code true} to write in row-major order; {@code false} to write in - * column-major order - */ - public void write(FloatBuffer buf, boolean rowMajor) { - if (rowMajor) { - this.writeRowMajor(buf); - } else { - this.writeColumnMajor(buf); - } - } - - public String toString() { - return "Matrix3f:\n" + - this.a00 + - " " + - this.a01 + - " " + - this.a02 + - "\n" + - this.a10 + - " " + - this.a11 + - " " + - this.a12 + - "\n" + - this.a20 + - " " + - this.a21 + - " " + - this.a22 + - "\n"; - } - - public void loadIdentity() { - this.a00 = 1.0F; - this.a01 = 0.0F; - this.a02 = 0.0F; - this.a10 = 0.0F; - this.a11 = 1.0F; - this.a12 = 0.0F; - this.a20 = 0.0F; - this.a21 = 0.0F; - this.a22 = 1.0F; - } - - public float determinantAndAdjugate() { - float f = this.a11 * this.a22 - this.a12 * this.a21; - float g = -(this.a10 * this.a22 - this.a12 * this.a20); - float h = this.a10 * this.a21 - this.a11 * this.a20; - float i = -(this.a01 * this.a22 - this.a02 * this.a21); - float j = this.a00 * this.a22 - this.a02 * this.a20; - float k = -(this.a00 * this.a21 - this.a01 * this.a20); - float l = this.a01 * this.a12 - this.a02 * this.a11; - float m = -(this.a00 * this.a12 - this.a02 * this.a10); - float n = this.a00 * this.a11 - this.a01 * this.a10; - float o = this.a00 * f + this.a01 * g + this.a02 * h; - this.a00 = f; - this.a10 = g; - this.a20 = h; - this.a01 = i; - this.a11 = j; - this.a21 = k; - this.a02 = l; - this.a12 = m; - this.a22 = n; - return o; - } - - public boolean invert() { - float f = this.determinantAndAdjugate(); - if (Math.abs(f) > 1.0E-6F) { - this.multiply(f); - return true; - } else { - return false; - } - } - - public void set(int x, int y, float value) { - if (x == 0) { - if (y == 0) { - this.a00 = value; - } else if (y == 1) { - this.a01 = value; - } else { - this.a02 = value; - } - } else if (x == 1) { - if (y == 0) { - this.a10 = value; - } else if (y == 1) { - this.a11 = value; - } else { - this.a12 = value; - } - } else if (y == 0) { - this.a20 = value; - } else if (y == 1) { - this.a21 = value; - } else { - this.a22 = value; - } - - } - - public void multiply(Matrix3f other) { - float f = this.a00 * other.a00 + this.a01 * other.a10 + this.a02 * other.a20; - float g = this.a00 * other.a01 + this.a01 * other.a11 + this.a02 * other.a21; - float h = this.a00 * other.a02 + this.a01 * other.a12 + this.a02 * other.a22; - float i = this.a10 * other.a00 + this.a11 * other.a10 + this.a12 * other.a20; - float j = this.a10 * other.a01 + this.a11 * other.a11 + this.a12 * other.a21; - float k = this.a10 * other.a02 + this.a11 * other.a12 + this.a12 * other.a22; - float l = this.a20 * other.a00 + this.a21 * other.a10 + this.a22 * other.a20; - float m = this.a20 * other.a01 + this.a21 * other.a11 + this.a22 * other.a21; - float n = this.a20 * other.a02 + this.a21 * other.a12 + this.a22 * other.a22; - this.a00 = f; - this.a01 = g; - this.a02 = h; - this.a10 = i; - this.a11 = j; - this.a12 = k; - this.a20 = l; - this.a21 = m; - this.a22 = n; - } - - public void multiply(Quaternion quaternion) { - this.multiply(new Matrix3f(quaternion)); - } - - public void multiply(float scalar) { - this.a00 *= scalar; - this.a01 *= scalar; - this.a02 *= scalar; - this.a10 *= scalar; - this.a11 *= scalar; - this.a12 *= scalar; - this.a20 *= scalar; - this.a21 *= scalar; - this.a22 *= scalar; - } - - public Matrix3f copy() { - return new Matrix3f(this); - } -} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix4f.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix4f.java deleted file mode 100644 index 6de017f5f..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Matrix4f.java +++ /dev/null @@ -1,489 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -import java.nio.FloatBuffer; - -public final class Matrix4f { - float a00; - float a01; - float a02; - float a03; - float a10; - float a11; - float a12; - float a13; - float a20; - float a21; - float a22; - float a23; - float a30; - float a31; - float a32; - float a33; - - public Matrix4f() {} - - public Matrix4f(Matrix4f source) { - this.a00 = source.a00; - this.a01 = source.a01; - this.a02 = source.a02; - this.a03 = source.a03; - this.a10 = source.a10; - this.a11 = source.a11; - this.a12 = source.a12; - this.a13 = source.a13; - this.a20 = source.a20; - this.a21 = source.a21; - this.a22 = source.a22; - this.a23 = source.a23; - this.a30 = source.a30; - this.a31 = source.a31; - this.a32 = source.a32; - this.a33 = source.a33; - } - - public Matrix4f(Quaternion quaternion) { - float f = quaternion.getX(); - float g = quaternion.getY(); - float h = quaternion.getZ(); - float i = quaternion.getW(); - float j = 2.0F * f * f; - float k = 2.0F * g * g; - float l = 2.0F * h * h; - this.a00 = 1.0F - k - l; - this.a11 = 1.0F - l - j; - this.a22 = 1.0F - j - k; - this.a33 = 1.0F; - float m = f * g; - float n = g * h; - float o = h * f; - float p = f * i; - float q = g * i; - float r = h * i; - this.a10 = 2.0F * (m + r); - this.a01 = 2.0F * (m - r); - this.a20 = 2.0F * (o - q); - this.a02 = 2.0F * (o + q); - this.a21 = 2.0F * (n + p); - this.a12 = 2.0F * (n - p); - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o != null && this.getClass() == o.getClass()) { - Matrix4f matrix4f = (Matrix4f)o; - return Float.compare(matrix4f.a00, this.a00) == 0 && Float.compare(matrix4f.a01, this.a01) == 0 && Float.compare(matrix4f.a02, this.a02) == 0 && Float.compare(matrix4f.a03, this.a03) == 0 && Float.compare(matrix4f.a10, this.a10) == 0 && Float.compare(matrix4f.a11, this.a11) == 0 && Float.compare(matrix4f.a12, this.a12) == 0 && Float.compare(matrix4f.a13, this.a13) == 0 && Float.compare(matrix4f.a20, this.a20) == 0 && Float.compare(matrix4f.a21, this.a21) == 0 && Float.compare(matrix4f.a22, this.a22) == 0 && Float.compare(matrix4f.a23, this.a23) == 0 && Float.compare(matrix4f.a30, this.a30) == 0 && Float.compare(matrix4f.a31, this.a31) == 0 && Float.compare(matrix4f.a32, this.a32) == 0 && Float.compare(matrix4f.a33, this.a33) == 0; - } else { - return false; - } - } - - public int hashCode() { - int i = this.a00 != 0.0F ? Float.floatToIntBits(this.a00) : 0; - i = 31 * i + (this.a01 != 0.0F ? Float.floatToIntBits(this.a01) : 0); - i = 31 * i + (this.a02 != 0.0F ? Float.floatToIntBits(this.a02) : 0); - i = 31 * i + (this.a03 != 0.0F ? Float.floatToIntBits(this.a03) : 0); - i = 31 * i + (this.a10 != 0.0F ? Float.floatToIntBits(this.a10) : 0); - i = 31 * i + (this.a11 != 0.0F ? Float.floatToIntBits(this.a11) : 0); - i = 31 * i + (this.a12 != 0.0F ? Float.floatToIntBits(this.a12) : 0); - i = 31 * i + (this.a13 != 0.0F ? Float.floatToIntBits(this.a13) : 0); - i = 31 * i + (this.a20 != 0.0F ? Float.floatToIntBits(this.a20) : 0); - i = 31 * i + (this.a21 != 0.0F ? Float.floatToIntBits(this.a21) : 0); - i = 31 * i + (this.a22 != 0.0F ? Float.floatToIntBits(this.a22) : 0); - i = 31 * i + (this.a23 != 0.0F ? Float.floatToIntBits(this.a23) : 0); - i = 31 * i + (this.a30 != 0.0F ? Float.floatToIntBits(this.a30) : 0); - i = 31 * i + (this.a31 != 0.0F ? Float.floatToIntBits(this.a31) : 0); - i = 31 * i + (this.a32 != 0.0F ? Float.floatToIntBits(this.a32) : 0); - i = 31 * i + (this.a33 != 0.0F ? Float.floatToIntBits(this.a33) : 0); - return i; - } - - public void load(Matrix4f source) { - this.a00 = source.a00; - this.a01 = source.a01; - this.a02 = source.a02; - this.a03 = source.a03; - this.a10 = source.a10; - this.a11 = source.a11; - this.a12 = source.a12; - this.a13 = source.a13; - this.a20 = source.a20; - this.a21 = source.a21; - this.a22 = source.a22; - this.a23 = source.a23; - this.a30 = source.a30; - this.a31 = source.a31; - this.a32 = source.a32; - this.a33 = source.a33; - } - - /** - * Writes this matrix to the buffer in column-major order. - * - * @see #writeRowMajor(FloatBuffer) - * @see #write(FloatBuffer, boolean) - */ - public void writeColumnMajor(FloatBuffer buf) { - buf.put(Matrix4f.pack(0, 0), this.a00); - buf.put(Matrix4f.pack(0, 1), this.a01); - buf.put(Matrix4f.pack(0, 2), this.a02); - buf.put(Matrix4f.pack(0, 3), this.a03); - buf.put(Matrix4f.pack(1, 0), this.a10); - buf.put(Matrix4f.pack(1, 1), this.a11); - buf.put(Matrix4f.pack(1, 2), this.a12); - buf.put(Matrix4f.pack(1, 3), this.a13); - buf.put(Matrix4f.pack(2, 0), this.a20); - buf.put(Matrix4f.pack(2, 1), this.a21); - buf.put(Matrix4f.pack(2, 2), this.a22); - buf.put(Matrix4f.pack(2, 3), this.a23); - buf.put(Matrix4f.pack(3, 0), this.a30); - buf.put(Matrix4f.pack(3, 1), this.a31); - buf.put(Matrix4f.pack(3, 2), this.a32); - buf.put(Matrix4f.pack(3, 3), this.a33); - } - - /** - * Writes this matrix to the buffer in row-major order. - * - * @see #writeColumnMajor(FloatBuffer) - * @see #write(FloatBuffer, boolean) - */ - public void writeRowMajor(FloatBuffer buf) { - buf.put(Matrix4f.pack(0, 0), this.a00); - buf.put(Matrix4f.pack(1, 0), this.a01); - buf.put(Matrix4f.pack(2, 0), this.a02); - buf.put(Matrix4f.pack(3, 0), this.a03); - buf.put(Matrix4f.pack(0, 1), this.a10); - buf.put(Matrix4f.pack(1, 1), this.a11); - buf.put(Matrix4f.pack(2, 1), this.a12); - buf.put(Matrix4f.pack(3, 1), this.a13); - buf.put(Matrix4f.pack(0, 2), this.a20); - buf.put(Matrix4f.pack(1, 2), this.a21); - buf.put(Matrix4f.pack(2, 2), this.a22); - buf.put(Matrix4f.pack(3, 2), this.a23); - buf.put(Matrix4f.pack(0, 3), this.a30); - buf.put(Matrix4f.pack(1, 3), this.a31); - buf.put(Matrix4f.pack(2, 3), this.a32); - buf.put(Matrix4f.pack(3, 3), this.a33); - } - - /** - * Writes this matrix to the buffer. - * - * @see #writeRowMajor(FloatBuffer) - * @see #writeColumnMajor(FloatBuffer) - * - * @param rowMajor {@code true} to write in row-major order; {@code false} to write in - * column-major order - */ - public void write(FloatBuffer buf, boolean rowMajor) { - if (rowMajor) { - this.writeRowMajor(buf); - } else { - this.writeColumnMajor(buf); - } - } - - private static int pack(int x, int y) { - return y * 4 + x; - } - - public String toString() { - return "Matrix4f:\n" + - this.a00 + - " " + - this.a01 + - " " + - this.a02 + - " " + - this.a03 + - "\n" + - this.a10 + - " " + - this.a11 + - " " + - this.a12 + - " " + - this.a13 + - "\n" + - this.a20 + - " " + - this.a21 + - " " + - this.a22 + - " " + - this.a23 + - "\n" + - this.a30 + - " " + - this.a31 + - " " + - this.a32 + - " " + - this.a33 + - "\n"; - } - - public void writeToBuffer(FloatBuffer floatBuffer) { - floatBuffer.put(pack(0, 0), this.a00); - floatBuffer.put(pack(0, 1), this.a01); - floatBuffer.put(pack(0, 2), this.a02); - floatBuffer.put(pack(0, 3), this.a03); - floatBuffer.put(pack(1, 0), this.a10); - floatBuffer.put(pack(1, 1), this.a11); - floatBuffer.put(pack(1, 2), this.a12); - floatBuffer.put(pack(1, 3), this.a13); - floatBuffer.put(pack(2, 0), this.a20); - floatBuffer.put(pack(2, 1), this.a21); - floatBuffer.put(pack(2, 2), this.a22); - floatBuffer.put(pack(2, 3), this.a23); - floatBuffer.put(pack(3, 0), this.a30); - floatBuffer.put(pack(3, 1), this.a31); - floatBuffer.put(pack(3, 2), this.a32); - floatBuffer.put(pack(3, 3), this.a33); - } - - public void loadIdentity() { - this.a00 = 1.0F; - this.a01 = 0.0F; - this.a02 = 0.0F; - this.a03 = 0.0F; - this.a10 = 0.0F; - this.a11 = 1.0F; - this.a12 = 0.0F; - this.a13 = 0.0F; - this.a20 = 0.0F; - this.a21 = 0.0F; - this.a22 = 1.0F; - this.a23 = 0.0F; - this.a30 = 0.0F; - this.a31 = 0.0F; - this.a32 = 0.0F; - this.a33 = 1.0F; - } - - public float determinantAndAdjugate() { - float f = this.a00 * this.a11 - this.a01 * this.a10; - float g = this.a00 * this.a12 - this.a02 * this.a10; - float h = this.a00 * this.a13 - this.a03 * this.a10; - float i = this.a01 * this.a12 - this.a02 * this.a11; - float j = this.a01 * this.a13 - this.a03 * this.a11; - float k = this.a02 * this.a13 - this.a03 * this.a12; - float l = this.a20 * this.a31 - this.a21 * this.a30; - float m = this.a20 * this.a32 - this.a22 * this.a30; - float n = this.a20 * this.a33 - this.a23 * this.a30; - float o = this.a21 * this.a32 - this.a22 * this.a31; - float p = this.a21 * this.a33 - this.a23 * this.a31; - float q = this.a22 * this.a33 - this.a23 * this.a32; - float r = this.a11 * q - this.a12 * p + this.a13 * o; - float s = -this.a10 * q + this.a12 * n - this.a13 * m; - float t = this.a10 * p - this.a11 * n + this.a13 * l; - float u = -this.a10 * o + this.a11 * m - this.a12 * l; - float v = -this.a01 * q + this.a02 * p - this.a03 * o; - float w = this.a00 * q - this.a02 * n + this.a03 * m; - float x = -this.a00 * p + this.a01 * n - this.a03 * l; - float y = this.a00 * o - this.a01 * m + this.a02 * l; - float z = this.a31 * k - this.a32 * j + this.a33 * i; - float aa = -this.a30 * k + this.a32 * h - this.a33 * g; - float ab = this.a30 * j - this.a31 * h + this.a33 * f; - float ac = -this.a30 * i + this.a31 * g - this.a32 * f; - float ad = -this.a21 * k + this.a22 * j - this.a23 * i; - float ae = this.a20 * k - this.a22 * h + this.a23 * g; - float af = -this.a20 * j + this.a21 * h - this.a23 * f; - float ag = this.a20 * i - this.a21 * g + this.a22 * f; - this.a00 = r; - this.a10 = s; - this.a20 = t; - this.a30 = u; - this.a01 = v; - this.a11 = w; - this.a21 = x; - this.a31 = y; - this.a02 = z; - this.a12 = aa; - this.a22 = ab; - this.a32 = ac; - this.a03 = ad; - this.a13 = ae; - this.a23 = af; - this.a33 = ag; - return f * q - g * p + h * o + i * n - j * m + k * l; - } - - public void transpose() { - float f = this.a10; - this.a10 = this.a01; - this.a01 = f; - f = this.a20; - this.a20 = this.a02; - this.a02 = f; - f = this.a21; - this.a21 = this.a12; - this.a12 = f; - f = this.a30; - this.a30 = this.a03; - this.a03 = f; - f = this.a31; - this.a31 = this.a13; - this.a13 = f; - f = this.a32; - this.a32 = this.a23; - this.a23 = f; - } - - public boolean invert() { - float f = this.determinantAndAdjugate(); - if (Math.abs(f) > 1.0E-6F) { - this.multiply(f); - return true; - } else { - return false; - } - } - - public void multiply(Matrix4f matrix) { - float f = this.a00 * matrix.a00 + this.a01 * matrix.a10 + this.a02 * matrix.a20 + this.a03 * matrix.a30; - float g = this.a00 * matrix.a01 + this.a01 * matrix.a11 + this.a02 * matrix.a21 + this.a03 * matrix.a31; - float h = this.a00 * matrix.a02 + this.a01 * matrix.a12 + this.a02 * matrix.a22 + this.a03 * matrix.a32; - float i = this.a00 * matrix.a03 + this.a01 * matrix.a13 + this.a02 * matrix.a23 + this.a03 * matrix.a33; - float j = this.a10 * matrix.a00 + this.a11 * matrix.a10 + this.a12 * matrix.a20 + this.a13 * matrix.a30; - float k = this.a10 * matrix.a01 + this.a11 * matrix.a11 + this.a12 * matrix.a21 + this.a13 * matrix.a31; - float l = this.a10 * matrix.a02 + this.a11 * matrix.a12 + this.a12 * matrix.a22 + this.a13 * matrix.a32; - float m = this.a10 * matrix.a03 + this.a11 * matrix.a13 + this.a12 * matrix.a23 + this.a13 * matrix.a33; - float n = this.a20 * matrix.a00 + this.a21 * matrix.a10 + this.a22 * matrix.a20 + this.a23 * matrix.a30; - float o = this.a20 * matrix.a01 + this.a21 * matrix.a11 + this.a22 * matrix.a21 + this.a23 * matrix.a31; - float p = this.a20 * matrix.a02 + this.a21 * matrix.a12 + this.a22 * matrix.a22 + this.a23 * matrix.a32; - float q = this.a20 * matrix.a03 + this.a21 * matrix.a13 + this.a22 * matrix.a23 + this.a23 * matrix.a33; - float r = this.a30 * matrix.a00 + this.a31 * matrix.a10 + this.a32 * matrix.a20 + this.a33 * matrix.a30; - float s = this.a30 * matrix.a01 + this.a31 * matrix.a11 + this.a32 * matrix.a21 + this.a33 * matrix.a31; - float t = this.a30 * matrix.a02 + this.a31 * matrix.a12 + this.a32 * matrix.a22 + this.a33 * matrix.a32; - float u = this.a30 * matrix.a03 + this.a31 * matrix.a13 + this.a32 * matrix.a23 + this.a33 * matrix.a33; - this.a00 = f; - this.a01 = g; - this.a02 = h; - this.a03 = i; - this.a10 = j; - this.a11 = k; - this.a12 = l; - this.a13 = m; - this.a20 = n; - this.a21 = o; - this.a22 = p; - this.a23 = q; - this.a30 = r; - this.a31 = s; - this.a32 = t; - this.a33 = u; - } - - public void multiply(Quaternion quaternion) { - this.multiply(new Matrix4f(quaternion)); - } - - public void multiply(float scalar) { - this.a00 *= scalar; - this.a01 *= scalar; - this.a02 *= scalar; - this.a03 *= scalar; - this.a10 *= scalar; - this.a11 *= scalar; - this.a12 *= scalar; - this.a13 *= scalar; - this.a20 *= scalar; - this.a21 *= scalar; - this.a22 *= scalar; - this.a23 *= scalar; - this.a30 *= scalar; - this.a31 *= scalar; - this.a32 *= scalar; - this.a33 *= scalar; - } - - public static Matrix4f viewboxMatrix(double fov, float aspectRatio, float cameraDepth, float viewDistance) { - float f = (float)(1.0D / Math.tan(fov * 0.01745329238474369D / 2.0D)); - Matrix4f matrix4f = new Matrix4f(); - matrix4f.a00 = f / aspectRatio; - matrix4f.a11 = f; - matrix4f.a22 = (viewDistance + cameraDepth) / (cameraDepth - viewDistance); - matrix4f.a32 = -1.0F; - matrix4f.a23 = 2.0F * viewDistance * cameraDepth / (cameraDepth - viewDistance); - return matrix4f; - } - - public static Matrix4f projectionMatrix(float width, float height, float nearPlane, float farPlane) { - Matrix4f matrix4f = new Matrix4f(); - matrix4f.a00 = 2.0F / width; - matrix4f.a11 = 2.0F / height; - float f = farPlane - nearPlane; - matrix4f.a22 = -2.0F / f; - matrix4f.a33 = 1.0F; - matrix4f.a03 = -1.0F; - matrix4f.a13 = -1.0F; - matrix4f.a23 = -(farPlane + nearPlane) / f; - return matrix4f; - } - - public static Matrix4f projectionMatrix(float left, float right, float bottom, float top, float nearPlane, float farPlane) { - Matrix4f matrix4f = new Matrix4f(); - float f = right - left; - float g = bottom - top; - float h = farPlane - nearPlane; - matrix4f.a00 = 2.0f / f; - matrix4f.a11 = 2.0f / g; - matrix4f.a22 = -2.0f / h; - matrix4f.a03 = -(right + left) / f; - matrix4f.a13 = -(bottom + top) / g; - matrix4f.a23 = -(farPlane + nearPlane) / h; - matrix4f.a33 = 1.0f; - return matrix4f; - } - - public void addToLastColumn(Vec3f vector) { - this.a03 += vector.getX(); - this.a13 += vector.getY(); - this.a23 += vector.getZ(); - } - - public Matrix4f copy() { - return new Matrix4f(this); - } - - public static Matrix4f scale(float x, float y, float z) { - Matrix4f matrix4f = new Matrix4f(); - matrix4f.a00 = x; - matrix4f.a11 = y; - matrix4f.a22 = z; - matrix4f.a33 = 1.0F; - return matrix4f; - } - - public static Matrix4f scaleTmp(float x, float y, float z) { - tmpMatrix4f.loadIdentity(); - tmpMatrix4f.a00 = x; - tmpMatrix4f.a11 = y; - tmpMatrix4f.a22 = z; - return tmpMatrix4f; - } - - public static Matrix4f translate(float x, float y, float z) { - Matrix4f matrix4f = new Matrix4f(); - matrix4f.a00 = 1.0F; - matrix4f.a11 = 1.0F; - matrix4f.a22 = 1.0F; - matrix4f.a33 = 1.0F; - matrix4f.a03 = x; - matrix4f.a13 = y; - matrix4f.a23 = z; - return matrix4f; - } - - public static Matrix4f translateTmp(float x, float y, float z) { - tmpMatrix4f.loadIdentity(); - tmpMatrix4f.a03 = x; - tmpMatrix4f.a13 = y; - tmpMatrix4f.a23 = z; - return tmpMatrix4f; - } - - private static final Matrix4f tmpMatrix4f = new Matrix4f(); -} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixStack.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixStack.java index e91b4fa0e..93432a883 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixStack.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixStack.java @@ -1,84 +1,83 @@ package net.modificationstation.stationapi.api.util.math; -import net.modificationstation.stationapi.api.util.Util; +import net.minecraft.util.math.Vec3d; +import org.joml.*; +import java.lang.Math; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; public class MatrixStack { - private final List stack = Util.make(new ArrayList<>(), list -> list.add(new Entry(Util.make(new Matrix4f(), Matrix4f::loadIdentity), Util.make(new Matrix3f(), Matrix3f::loadIdentity)))); - private int n = 0; + private final List stack = new ArrayList<>(16); + private int stackDepth = 0; + + public MatrixStack() { + this.stack.add(new Entry()); + } public void translate(double x, double y, double z) { - MatrixStack.Entry entry = this.stack.get(n); - entry.positionMatrix.multiply(Matrix4f.translateTmp((float)x, (float)y, (float)z)); + this.translate((float)x, (float)y, (float)z); } - public void scale(float x, float y, float z) { - MatrixStack.Entry entry = this.stack.get(n); - entry.positionMatrix.multiply(Matrix4f.scaleTmp(x, y, z)); - if (x == y && y == z) { - if (x > 0.0F) { - return; - } + public void translate(float x, float y, float z) { + this.peek().translate(x, y, z); + } - entry.normalMatrix.multiply(-1.0F); - } + public void translate(Vec3d vec) { + this.translate(vec.x, vec.y, vec.z); + } + + public void scale(float x, float y, float z) { + this.peek().scale(x, y, z); + } - float f = 1.0F / x; - float g = 1.0F / y; - float h = 1.0F / z; - float i = MathHelper.fastInverseCbrt(f * g * h); - entry.normalMatrix.multiply(Matrix3f.scaleTmp(i * f, i * g, i * h)); + public void multiply(Quaternionfc quaternion) { + this.peek().rotate(quaternion); } - public void multiply(Quaternion quaternion) { - MatrixStack.Entry entry = this.stack.get(n); - entry.positionMatrix.multiply(quaternion); - entry.normalMatrix.multiply(quaternion); + public void multiply(Quaternionfc quaternion, float originX, float originY, float originZ) { + this.peek().rotateAround(quaternion, originX, originY, originZ); } public void push() { - MatrixStack.Entry entry = this.stack.get(n); - n++; - if (n >= stack.size()) { - stack.add(new Entry(Util.make(new Matrix4f(), Matrix4f::loadIdentity), Util.make(new Matrix3f(), Matrix3f::loadIdentity))); + Entry entry = this.peek(); + this.stackDepth++; + if (this.stackDepth >= this.stack.size()) { + this.stack.add(entry.copy()); + } else { + this.stack.get(this.stackDepth).copy(entry); } - Entry nextEntry = stack.get(n); - nextEntry.positionMatrix.load(entry.positionMatrix); - nextEntry.normalMatrix.load(entry.normalMatrix); } public void pop() { - n--; + if (this.stackDepth == 0) { + throw new NoSuchElementException(); + } else { + --this.stackDepth; + } } public MatrixStack.Entry peek() { - return this.stack.get(n); + return this.stack.get(stackDepth); } public boolean isEmpty() { - return this.stack.size() == 1; + return this.stackDepth == 0; } public void loadIdentity() { - Entry entry = this.stack.get(n); - entry.positionMatrix.loadIdentity(); - entry.normalMatrix.loadIdentity(); + this.peek().loadIdentity(); } public void multiplyPositionMatrix(Matrix4f matrix) { - this.stack.get(n).positionMatrix.multiply(matrix); + this.peek().multiplyPositionMatrix(matrix); } public static final class Entry { - private final Matrix4f positionMatrix; - private final Matrix3f normalMatrix; - - private Entry(Matrix4f matrix4f, Matrix3f matrix3f) { - this.positionMatrix = matrix4f; - this.normalMatrix = matrix3f; - } + private final Matrix4f positionMatrix = new Matrix4f(); + private final Matrix3f normalMatrix = new Matrix3f(); + private boolean canSkipNormalization = true; public Matrix4f getPositionMatrix() { return this.positionMatrix; @@ -87,5 +86,76 @@ public Matrix4f getPositionMatrix() { public Matrix3f getNormalMatrix() { return this.normalMatrix; } + + private void computeNormal() { + this.normalMatrix.set(this.positionMatrix).invert().transpose(); + this.canSkipNormalization = false; + } + + void copy(Entry entry) { + this.positionMatrix.set(entry.positionMatrix); + this.normalMatrix.set(entry.normalMatrix); + this.canSkipNormalization = entry.canSkipNormalization; + } + + public Vector3f transformNormal(Vector3fc vec, Vector3f dest) { + return this.transformNormal(vec.x(), vec.y(), vec.z(), dest); + } + + public Vector3f transformNormal(float x, float y, float z, Vector3f dest) { + Vector3f n = this.normalMatrix.transform(x, y, z, dest); + return this.canSkipNormalization ? n : n.normalize(); + } + + public Matrix4f translate(float x, float y, float z) { + return this.positionMatrix.translate(x, y, z); + } + + public void scale(float x, float y, float z) { + this.positionMatrix.scale(x, y, z); + if (Math.abs(x) == Math.abs(y) && Math.abs(y) == Math.abs(z)) { + if (x < 0.0F || y < 0.0F || z < 0.0F) { + this.normalMatrix.scale(Math.signum(x), Math.signum(y), Math.signum(z)); + } + + } else { + this.normalMatrix.scale(1.0F / x, 1.0F / y, 1.0F / z); + this.canSkipNormalization = false; + } + } + + public void rotate(Quaternionfc quaternion) { + this.positionMatrix.rotate(quaternion); + this.normalMatrix.rotate(quaternion); + } + + public void rotateAround(Quaternionfc quaternion, float originX, float originY, float originZ) { + this.positionMatrix.rotateAround(quaternion, originX, originY, originZ); + this.normalMatrix.rotate(quaternion); + } + + public void loadIdentity() { + this.positionMatrix.identity(); + this.normalMatrix.identity(); + this.canSkipNormalization = true; + } + + public void multiplyPositionMatrix(Matrix4fc matrix) { + this.positionMatrix.mul(matrix); + if (!MatrixUtil.isTranslation(matrix)) { + if (MatrixUtil.isOrthonormal(matrix)) { + this.normalMatrix.mul(new Matrix3f(matrix)); + } else { + this.computeNormal(); + } + } + + } + + public Entry copy() { + Entry entry = new Entry(); + entry.copy(this); + return entry; + } } } diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixUtil.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixUtil.java new file mode 100644 index 000000000..c68989d9f --- /dev/null +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MatrixUtil.java @@ -0,0 +1,155 @@ +package net.modificationstation.stationapi.api.util.math; + +import org.apache.commons.lang3.tuple.Triple; +import org.joml.*; +import org.joml.Math; + +public class MatrixUtil { + private static final float COT_PI_OVER_8 = 3.0F + 2.0F * Math.sqrt(2.0F); + private static final GivensPair SIN_COS_PI_OVER_8 = GivensPair.fromAngle(((float) Math.PI / 4F)); + + public static Matrix4f scale(Matrix4f matrix, float scalar) { + return matrix.set(matrix.m00() * scalar, matrix.m01() * scalar, matrix.m02() * scalar, matrix.m03() * scalar, matrix.m10() * scalar, matrix.m11() * scalar, matrix.m12() * scalar, matrix.m13() * scalar, matrix.m20() * scalar, matrix.m21() * scalar, matrix.m22() * scalar, matrix.m23() * scalar, matrix.m30() * scalar, matrix.m31() * scalar, matrix.m32() * scalar, matrix.m33() * scalar); + } + + private static GivensPair approximateGivensQuaternion(float a11, float a12, float a22) { + float f = 2.0F * (a11 - a22); + return COT_PI_OVER_8 * a12 * a12 < f * f ? GivensPair.normalize(a12, f) : SIN_COS_PI_OVER_8; + } + + private static GivensPair qrGivensQuaternion(float a1, float a2) { + float f = (float) java.lang.Math.hypot((double) a1, (double) a2); + float g = f > 1.0E-6F ? a2 : 0.0F; + float h = Math.abs(a1) + Math.max(f, 1.0E-6F); + if (a1 < 0.0F) { + float i = g; + g = h; + h = i; + } + + return GivensPair.normalize(g, h); + } + + private static void conjugate(Matrix3f X, Matrix3f A) { + X.mul(A); + A.transpose(); + A.mul(X); + X.set(A); + } + + private static void applyJacobiIteration(Matrix3f AtA, Matrix3f matrix3f, Quaternionf quaternionf, Quaternionf quaternionf2) { + if (AtA.m01 * AtA.m01 + AtA.m10 * AtA.m10 > 1.0E-6F) { + GivensPair givensPair = approximateGivensQuaternion(AtA.m00, 0.5F * (AtA.m01 + AtA.m10), AtA.m11); + Quaternionf quaternionf3 = givensPair.setZRotation(quaternionf); + quaternionf2.mul(quaternionf3); + givensPair.setRotationZ(matrix3f); + conjugate(AtA, matrix3f); + } + + if (AtA.m02 * AtA.m02 + AtA.m20 * AtA.m20 > 1.0E-6F) { + GivensPair givensPair = approximateGivensQuaternion(AtA.m00, 0.5F * (AtA.m02 + AtA.m20), AtA.m22).negateSin(); + Quaternionf quaternionf3 = givensPair.setYRotation(quaternionf); + quaternionf2.mul(quaternionf3); + givensPair.setRotationY(matrix3f); + conjugate(AtA, matrix3f); + } + + if (AtA.m12 * AtA.m12 + AtA.m21 * AtA.m21 > 1.0E-6F) { + GivensPair givensPair = approximateGivensQuaternion(AtA.m11, 0.5F * (AtA.m12 + AtA.m21), AtA.m22); + Quaternionf quaternionf3 = givensPair.setXRotation(quaternionf); + quaternionf2.mul(quaternionf3); + givensPair.setRotationX(matrix3f); + conjugate(AtA, matrix3f); + } + + } + + public static Quaternionf applyJacobiIterations(Matrix3f AtA, int numJacobiIterations) { + Quaternionf quaternionf = new Quaternionf(); + Matrix3f matrix3f = new Matrix3f(); + Quaternionf quaternionf2 = new Quaternionf(); + + for (int i = 0; i < numJacobiIterations; ++i) { + applyJacobiIteration(AtA, matrix3f, quaternionf2, quaternionf); + } + + quaternionf.normalize(); + return quaternionf; + } + + public static Triple svdDecompose(Matrix3f A) { + Matrix3f matrix3f = new Matrix3f(A); + matrix3f.transpose(); + matrix3f.mul(A); + Quaternionf quaternionf = applyJacobiIterations(matrix3f, 5); + float f = matrix3f.m00; + float g = matrix3f.m11; + boolean bl = (double) f < 1.0E-6; + boolean bl2 = (double) g < 1.0E-6; + Matrix3f matrix3f3 = A.rotate(quaternionf); + Quaternionf quaternionf2 = new Quaternionf(); + Quaternionf quaternionf3 = new Quaternionf(); + GivensPair givensPair; + if (bl) { + givensPair = qrGivensQuaternion(matrix3f3.m11, -matrix3f3.m10); + } else { + givensPair = qrGivensQuaternion(matrix3f3.m00, matrix3f3.m01); + } + + Quaternionf quaternionf4 = givensPair.setZRotation(quaternionf3); + Matrix3f matrix3f4 = givensPair.setRotationZ(matrix3f); + quaternionf2.mul(quaternionf4); + matrix3f4.transpose().mul(matrix3f3); + if (bl) { + givensPair = qrGivensQuaternion(matrix3f4.m22, -matrix3f4.m20); + } else { + givensPair = qrGivensQuaternion(matrix3f4.m00, matrix3f4.m02); + } + + givensPair = givensPair.negateSin(); + Quaternionf quaternionf5 = givensPair.setYRotation(quaternionf3); + Matrix3f matrix3f5 = givensPair.setRotationY(matrix3f3); + quaternionf2.mul(quaternionf5); + matrix3f5.transpose().mul(matrix3f4); + if (bl2) { + givensPair = qrGivensQuaternion(matrix3f5.m22, -matrix3f5.m21); + } else { + givensPair = qrGivensQuaternion(matrix3f5.m11, matrix3f5.m12); + } + + Quaternionf quaternionf6 = givensPair.setXRotation(quaternionf3); + Matrix3f matrix3f6 = givensPair.setRotationX(matrix3f4); + quaternionf2.mul(quaternionf6); + matrix3f6.transpose().mul(matrix3f5); + Vector3f vector3f = new Vector3f(matrix3f6.m00, matrix3f6.m11, matrix3f6.m22); + return Triple.of(quaternionf2, vector3f, quaternionf.conjugate()); + } + + private static boolean isPropertyBitSet(Matrix4fc matrix, int property) { + return (matrix.properties() & property) != 0; + } + + public static boolean hasProperty(Matrix4fc matrix, int property) { + if (isPropertyBitSet(matrix, property)) { + return true; + } else if (matrix instanceof Matrix4f) { + Matrix4f matrix4f = (Matrix4f) matrix; + matrix4f.determineProperties(); + return isPropertyBitSet(matrix, property); + } else { + return false; + } + } + + public static boolean isIdentity(Matrix4fc matrix) { + return hasProperty(matrix, 4); + } + + public static boolean isTranslation(Matrix4fc matrix) { + return hasProperty(matrix, 8); + } + + public static boolean isOrthonormal(Matrix4fc matrix) { + return hasProperty(matrix, 16); + } +} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Quaternion.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Quaternion.java deleted file mode 100644 index 37885cd53..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Quaternion.java +++ /dev/null @@ -1,168 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -public final class Quaternion { - public static final Quaternion IDENTITY = new Quaternion(0.0F, 0.0F, 0.0F, 1.0F); - private float x; - private float y; - private float z; - private float w; - - public Quaternion(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - public Quaternion(Vec3f axis, float rotationAngle, boolean degrees) { - if (degrees) { - rotationAngle *= 0.017453292F; - } - - float f = sin(rotationAngle / 2.0F); - this.x = axis.getX() * f; - this.y = axis.getY() * f; - this.z = axis.getZ() * f; - this.w = cos(rotationAngle / 2.0F); - } - - public Quaternion(float x, float y, float z, boolean degrees) { - if (degrees) { - x *= 0.017453292F; - y *= 0.017453292F; - z *= 0.017453292F; - } - - float f = sin(0.5F * x); - float g = cos(0.5F * x); - float h = sin(0.5F * y); - float i = cos(0.5F * y); - float j = sin(0.5F * z); - float k = cos(0.5F * z); - this.x = f * i * k + g * h * j; - this.y = g * h * k - f * i * j; - this.z = f * h * k + g * i * j; - this.w = g * i * k - f * h * j; - } - - public Quaternion(Quaternion other) { - this.x = other.x; - this.y = other.y; - this.z = other.z; - this.w = other.w; - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o != null && this.getClass() == o.getClass()) { - Quaternion quaternion = (Quaternion)o; - if (Float.compare(quaternion.x, this.x) != 0) { - return false; - } else if (Float.compare(quaternion.y, this.y) != 0) { - return false; - } else if (Float.compare(quaternion.z, this.z) != 0) { - return false; - } else { - return Float.compare(quaternion.w, this.w) == 0; - } - } else { - return false; - } - } - - public int hashCode() { - int i = Float.floatToIntBits(this.x); - i = 31 * i + Float.floatToIntBits(this.y); - i = 31 * i + Float.floatToIntBits(this.z); - i = 31 * i + Float.floatToIntBits(this.w); - return i; - } - - public String toString() { - return "Quaternion[" + this.getW() + " + " + - this.getX() + "i + " + - this.getY() + "j + " + - this.getZ() + "k]"; - } - - public float getX() { - return this.x; - } - - public float getY() { - return this.y; - } - - public float getZ() { - return this.z; - } - - public float getW() { - return this.w; - } - - public void hamiltonProduct(Quaternion other) { - float f = this.getX(); - float g = this.getY(); - float h = this.getZ(); - float i = this.getW(); - float j = other.getX(); - float k = other.getY(); - float l = other.getZ(); - float m = other.getW(); - this.x = i * j + f * m + g * l - h * k; - this.y = i * k - f * l + g * m + h * j; - this.z = i * l + f * k - g * j + h * m; - this.w = i * m - f * j - g * k - h * l; - } - - public void scale(float scale) { - this.x *= scale; - this.y *= scale; - this.z *= scale; - this.w *= scale; - } - - public void conjugate() { - this.x = -this.x; - this.y = -this.y; - this.z = -this.z; - } - - public void set(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - private static float cos(float value) { - return (float)Math.cos(value); - } - - private static float sin(float value) { - return (float)Math.sin(value); - } - - public void normalize() { - float f = this.getX() * this.getX() + this.getY() * this.getY() + this.getZ() * this.getZ() + this.getW() * this.getW(); - if (f > 1.0E-6F) { - float g = MathHelper.fastInverseSqrt(f); - this.x *= g; - this.y *= g; - this.z *= g; - this.w *= g; - } else { - this.x = 0.0F; - this.y = 0.0F; - this.z = 0.0F; - this.w = 0.0F; - } - - } - - public Quaternion copy() { - return new Quaternion(this); - } -} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/RotationAxis.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/RotationAxis.java new file mode 100644 index 000000000..c7489e318 --- /dev/null +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/RotationAxis.java @@ -0,0 +1,24 @@ +package net.modificationstation.stationapi.api.util.math; + +import org.joml.Quaternionf; +import org.joml.Vector3f; + +@FunctionalInterface +public interface RotationAxis { + RotationAxis NEGATIVE_X = rad -> new Quaternionf().rotationX(-rad); + RotationAxis POSITIVE_X = rad -> new Quaternionf().rotationX(rad); + RotationAxis NEGATIVE_Y = rad -> new Quaternionf().rotationY(-rad); + RotationAxis POSITIVE_Y = rad -> new Quaternionf().rotationY(rad); + RotationAxis NEGATIVE_Z = rad -> new Quaternionf().rotationZ(-rad); + RotationAxis POSITIVE_Z = rad -> new Quaternionf().rotationZ(rad); + + static RotationAxis of(Vector3f axis) { + return rad -> new Quaternionf().rotationAxis(rad, axis); + } + + Quaternionf rotation(float rad); + + default Quaternionf rotationDegrees(float deg) { + return this.rotation(deg * (float) (Math.PI / 180.0)); + } +} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3d.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3d.java index cfbc5dda8..dc434a61c 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3d.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3d.java @@ -1,5 +1,8 @@ package net.modificationstation.stationapi.api.util.math; +import org.joml.Vector3f; +import org.joml.Vector3fc; + import java.util.EnumSet; import static net.minecraft.util.math.MathHelper.*; @@ -99,8 +102,8 @@ public Vec3d(double x, double y, double z) { /** * Copies the given vector. */ - public Vec3d(Vec3f vec) { - this(vec.getX(), vec.getY(), vec.getZ()); + public Vec3d(Vector3fc vec) { + this(vec.x(), vec.y(), vec.z()); } /** diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3f.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3f.java deleted file mode 100644 index fc75d2ac6..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vec3f.java +++ /dev/null @@ -1,188 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -import it.unimi.dsi.fastutil.floats.Float2FloatFunction; - -public final class Vec3f { - public static Vec3f NEGATIVE_X = new Vec3f(-1.0F, 0.0F, 0.0F); - public static Vec3f POSITIVE_X = new Vec3f(1.0F, 0.0F, 0.0F); - public static Vec3f NEGATIVE_Y = new Vec3f(0.0F, -1.0F, 0.0F); - public static Vec3f POSITIVE_Y = new Vec3f(0.0F, 1.0F, 0.0F); - public static Vec3f NEGATIVE_Z = new Vec3f(0.0F, 0.0F, -1.0F); - public static Vec3f POSITIVE_Z = new Vec3f(0.0F, 0.0F, 1.0F); - public static Vec3f ZERO = new Vec3f(0.0F, 0.0F, 0.0F); - private float x; - private float y; - private float z; - - public Vec3f() { - } - - public Vec3f(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - public Vec3f(Vector4f vec) { - this(vec.getX(), vec.getY(), vec.getZ()); - } - - public Vec3f(net.minecraft.util.math.Vec3d other) { - this((float)other.x, (float)other.y, (float)other.z); - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o != null && this.getClass() == o.getClass()) { - Vec3f vector3f = (Vec3f)o; - if (Float.compare(vector3f.x, this.x) != 0) { - return false; - } else if (Float.compare(vector3f.y, this.y) != 0) { - return false; - } else { - return Float.compare(vector3f.z, this.z) == 0; - } - } else { - return false; - } - } - - public int hashCode() { - int i = Float.floatToIntBits(this.x); - i = 31 * i + Float.floatToIntBits(this.y); - i = 31 * i + Float.floatToIntBits(this.z); - return i; - } - - public float getX() { - return this.x; - } - - public float getY() { - return this.y; - } - - public float getZ() { - return this.z; - } - - public void scale(float scale) { - this.x *= scale; - this.y *= scale; - this.z *= scale; - } - - public void multiplyComponentwise(float x, float y, float z) { - this.x *= x; - this.y *= y; - this.z *= z; - } - - public void clamp(float min, float max) { - this.x = MathHelper.clamp(this.x, min, max); - this.y = MathHelper.clamp(this.y, min, max); - this.z = MathHelper.clamp(this.z, min, max); - } - - public void set(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - public void add(float x, float y, float z) { - this.x += x; - this.y += y; - this.z += z; - } - - public void add(Vec3f vector) { - this.x += vector.x; - this.y += vector.y; - this.z += vector.z; - } - - public void subtract(Vec3f other) { - this.x -= other.x; - this.y -= other.y; - this.z -= other.z; - } - - public float dot(Vec3f other) { - return this.x * other.x + this.y * other.y + this.z * other.z; - } - - public boolean normalize() { - float f = this.x * this.x + this.y * this.y + this.z * this.z; - if ((double)f < 1.0E-5D) { - return false; - } else { - float g = MathHelper.fastInverseSqrt(f); - this.x *= g; - this.y *= g; - this.z *= g; - return true; - } - } - - public void cross(Vec3f vector) { - float f = this.x; - float g = this.y; - float h = this.z; - float i = vector.getX(); - float j = vector.getY(); - float k = vector.getZ(); - this.x = g * k - h * j; - this.y = h * i - f * k; - this.z = f * j - g * i; - } - - public void transform(Matrix3f matrix3f) { - float f = this.x; - float g = this.y; - float h = this.z; - this.x = matrix3f.a00 * f + matrix3f.a01 * g + matrix3f.a02 * h; - this.y = matrix3f.a10 * f + matrix3f.a11 * g + matrix3f.a12 * h; - this.z = matrix3f.a20 * f + matrix3f.a21 * g + matrix3f.a22 * h; - } - - public void rotate(Quaternion rotation) { - Quaternion quaternion = new Quaternion(rotation); - quaternion.hamiltonProduct(new Quaternion(this.getX(), this.getY(), this.getZ(), 0.0F)); - Quaternion quaternion2 = new Quaternion(rotation); - quaternion2.conjugate(); - quaternion.hamiltonProduct(quaternion2); - this.set(quaternion.getX(), quaternion.getY(), quaternion.getZ()); - } - - public void lerp(Vec3f vector, float delta) { - float f = 1.0F - delta; - this.x = this.x * f + vector.x * delta; - this.y = this.y * f + vector.y * delta; - this.z = this.z * f + vector.z * delta; - } - - public Quaternion getRadialQuaternion(float angle) { - return new Quaternion(this, angle, false); - } - - public Quaternion getDegreesQuaternion(float angle) { - return new Quaternion(this, angle, true); - } - - public Vec3f copy() { - return new Vec3f(this.x, this.y, this.z); - } - - public void modify(Float2FloatFunction function) { - this.x = function.get(this.x); - this.y = function.get(this.y); - this.z = function.get(this.z); - } - - @Override - public String toString() { - return "[" + this.x + ", " + this.y + ", " + this.z + "]"; - } -} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector2f.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector2f.java deleted file mode 100644 index 0afe79ebd..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector2f.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -public class Vector2f { - public static final Vector2f ZERO = new Vector2f(0.0F, 0.0F); - public static final Vector2f SOUTH_EAST_UNIT = new Vector2f(1.0F, 1.0F); - public static final Vector2f EAST_UNIT = new Vector2f(1.0F, 0.0F); - public static final Vector2f WEST_UNIT = new Vector2f(-1.0F, 0.0F); - public static final Vector2f SOUTH_UNIT = new Vector2f(0.0F, 1.0F); - public static final Vector2f NORTH_UNIT = new Vector2f(0.0F, -1.0F); - public static final Vector2f MAX_SOUTH_EAST = new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE); - public static final Vector2f MIN_SOUTH_EAST = new Vector2f(Float.MIN_VALUE, Float.MIN_VALUE); - public final float x; - public final float y; - - public Vector2f(float x, float y) { - this.x = x; - this.y = y; - } - - public boolean equals(Vector2f other) { - return this.x == other.x && this.y == other.y; - } -} diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector4f.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector4f.java deleted file mode 100644 index e6a51b124..000000000 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/Vector4f.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -public class Vector4f { - private float x; - private float y; - private float z; - private float w; - - public Vector4f() {} - - public Vector4f(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - public Vector4f(Vec3f vector) { - this(vector.getX(), vector.getY(), vector.getZ(), 1.0F); - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o != null && this.getClass() == o.getClass()) { - Vector4f vector4f = (Vector4f)o; - if (Float.compare(vector4f.x, this.x) != 0) { - return false; - } else if (Float.compare(vector4f.y, this.y) != 0) { - return false; - } else if (Float.compare(vector4f.z, this.z) != 0) { - return false; - } else { - return Float.compare(vector4f.w, this.w) == 0; - } - } else { - return false; - } - } - - public int hashCode() { - int i = Float.floatToIntBits(this.x); - i = 31 * i + Float.floatToIntBits(this.y); - i = 31 * i + Float.floatToIntBits(this.z); - i = 31 * i + Float.floatToIntBits(this.w); - return i; - } - - public float getX() { - return this.x; - } - - public float getY() { - return this.y; - } - - public float getZ() { - return this.z; - } - - public float getW() { - return this.w; - } - - public void multiplyComponentwise(Vec3f vector) { - this.x *= vector.getX(); - this.y *= vector.getY(); - this.z *= vector.getZ(); - } - - public void set(float x, float y, float z, float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - - public float dotProduct(Vector4f other) { - return this.x * other.x + this.y * other.y + this.z * other.z + this.w * other.w; - } - - public boolean normalize() { - float f = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - if ((double)f < 1.0E-5D) { - return false; - } else { - float g = MathHelper.fastInverseSqrt(f); - this.x *= g; - this.y *= g; - this.z *= g; - this.w *= g; - return true; - } - } - - public void transform(Matrix4f matrix) { - float f = this.x; - float g = this.y; - float h = this.z; - float i = this.w; - this.x = matrix.a00 * f + matrix.a01 * g + matrix.a02 * h + matrix.a03 * i; - this.y = matrix.a10 * f + matrix.a11 * g + matrix.a12 * h + matrix.a13 * i; - this.z = matrix.a20 * f + matrix.a21 * g + matrix.a22 * h + matrix.a23 * i; - this.w = matrix.a30 * f + matrix.a31 * g + matrix.a32 * h + matrix.a33 * i; - } - - public void rotate(Quaternion rotation) { - Quaternion quaternion = new Quaternion(rotation); - quaternion.hamiltonProduct(new Quaternion(this.getX(), this.getY(), this.getZ(), 0.0F)); - Quaternion quaternion2 = new Quaternion(rotation); - quaternion2.conjugate(); - quaternion.hamiltonProduct(quaternion2); - this.set(quaternion.getX(), quaternion.getY(), quaternion.getZ(), this.getW()); - } - - public void normalizeProjectiveCoordinates() { - this.x /= this.w; - this.y /= this.w; - this.z /= this.w; - this.w = 1.0F; - } - - public String toString() { - return "[" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + "]"; - } -} diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/RegistryLoader.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/RegistryLoader.java index d27352546..efe720f82 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/RegistryLoader.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/RegistryLoader.java @@ -91,7 +91,7 @@ static void load(RegistryOps.RegistryInfoGetter registryInfoGetter, Resource try (BufferedReader reader = resource.getReader()) { JsonElement jsonElement = JsonParser.parseReader(reader); DataResult dataResult = decoder.parse(registryOps, jsonElement); - E object = dataResult.getOrThrow(false, error -> {}); + E object = dataResult.getOrThrow(); newRegistry.add(registryKey, object, resource.isAlwaysStable() ? Lifecycle.stable() : dataResult.lifecycle()); } catch (Exception exception) { exceptions.put(registryKey, new IllegalStateException(String.format(Locale.ROOT, "Failed to parse %s from pack %s", identifier, resource.getResourcePackName()), exception)); diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/tag/TagGroupLoader.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/tag/TagGroupLoader.java index a2db6d2f2..5c7b9d4aa 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/tag/TagGroupLoader.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/tag/TagGroupLoader.java @@ -52,16 +52,15 @@ public Map> loadTags(ResourceManager manager) { Reader reader = resource.getReader(); try { - JsonElement jsonElement = JsonParser.parseReader(reader); - List list = map.computeIfAbsent(identifier2, identifierx -> new ArrayList<>()); - DataResult var10000 = TagFile.CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, jsonElement)); - Logger var10002 = LOGGER; - Objects.requireNonNull(var10002); - TagFile tagFile = var10000.getOrThrow(false, var10002::error); - if (tagFile.replace()) list.clear(); - - String string2 = resource.getResourcePackName(); - tagFile.entries().forEach(tagEntry -> list.add(new TrackedEntry(tagEntry, string2))); + JsonElement json = JsonParser.parseReader(reader); + List list = map.computeIfAbsent(identifier2, id -> new ArrayList<>()); + TagFile tagFile = TagFile.CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, json)).getOrThrow(); + + if (tagFile.replace()) + list.clear(); + + String source = resource.getResourcePackName(); + tagFile.entries().forEach(tagEntry -> list.add(new TrackedEntry(tagEntry, source))); } catch (Throwable var16) { if (reader != null) try { reader.close(); diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/util/dynamic/EntryLoader.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/util/dynamic/EntryLoader.java index e086851ae..5c8243876 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/util/dynamic/EntryLoader.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/util/dynamic/EntryLoader.java @@ -130,7 +130,7 @@ final class Impl implements EntryLoader { public void add(DynamicRegistryManager registryManager, RegistryKey key, Encoder encoder, int rawId, E entry, Lifecycle lifecycle) { DataResult dataResult = encoder.encodeStart(RegistryOps.of(JsonOps.INSTANCE, registryManager), entry); - Optional> optional = dataResult.error(); + Optional> optional = dataResult.error(); if (optional.isPresent()) { LOGGER.error("Error adding element: {}", optional.get().message()); } else { 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 deleted file mode 100644 index 0b6259d94..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.modificationstation.stationapi.api.client.render; - -import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; - -/** - * Interface for rendering plug-ins that provide enhanced capabilities - * for model lighting, buffering and rendering. Such plug-ins implement the - * enhanced model rendering interfaces specified by the Fabric API. - */ -public interface Renderer { - /** - * Obtain a new {@link BakedModelRenderer} instance used to render - * baked models. - * - * - */ - BakedModelRenderer bakedModelRenderer(); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RendererAccess.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RendererAccess.java deleted file mode 100644 index 8758ec383..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/RendererAccess.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.modificationstation.stationapi.api.client.render; - -import net.modificationstation.stationapi.impl.client.render.RendererAccessImpl; - -/** - * Registration and access for rendering extensions. - */ -public interface RendererAccess { - - RendererAccess INSTANCE = RendererAccessImpl.INSTANCE; - - /** - * Rendering extension mods must implement {@link Renderer} and - * call this method during initialization. - * - *

Only one {@link Renderer} plug-in can be active in any game instance. - * If a second mod attempts to register this method will throw an UnsupportedOperationException. - */ - void registerRenderer(Renderer plugin); - - /** - * Access to the current {@link Renderer} for creating and retrieving model builders - * and materials. Will return null if no render plug in is active. - */ - // @Nullable - Renderer getRenderer(); - - /** - * Performant test for {@link #getRenderer()} != null. - */ - boolean hasRenderer(); -} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java deleted file mode 100644 index 1dab4f1b1..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.block; - -import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.util.Util; - -public interface StationRendererBlockRenderManager { - default void renderAllSides(BlockState state, int x, int y, int z) { - Util.assertImpl(); - } -} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java deleted file mode 100644 index 74818cef4..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.model; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.math.Direction; - -@Environment(EnvType.CLIENT) -public class BakedQuad { - protected final int[] vertexData; - protected final int colorIndex; - protected final Direction face; - protected final Sprite sprite; - private final boolean shade; - private final float emission; - - public BakedQuad(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade) { - this(vertexData, colorIndex, face, sprite, shade, 0); - } - - public BakedQuad(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade, float emission) { - this.vertexData = vertexData; - this.colorIndex = colorIndex; - this.face = face; - this.sprite = sprite; - this.shade = shade; - this.emission = emission; - } - - public int[] getVertexData() { - return this.vertexData; - } - - public boolean hasColor() { - return this.colorIndex != -1; - } - - public int getColorIndex() { - return this.colorIndex; - } - - public Direction getFace() { - return this.face; - } - - public boolean hasShade() { - return this.shade; - } - - public float getEmission() { - return emission; - } -} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java deleted file mode 100644 index 146337c3e..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java +++ /dev/null @@ -1,270 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.model; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.client.render.model.json.ModelElementFace; -import net.modificationstation.stationapi.api.client.render.model.json.ModelElementTexture; -import net.modificationstation.stationapi.api.client.texture.Sprite; -import net.modificationstation.stationapi.api.util.Identifier; -import net.modificationstation.stationapi.api.util.math.*; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -@Environment(EnvType.CLIENT) -public class BakedQuadFactory { - private static final float MIN_SCALE = 1.0F / (float)Math.cos(0.39269909262657166D) - 1.0F; - private static final float MAX_SCALE = 1.0F / (float)Math.cos(0.7853981852531433D) - 1.0F; - - public BakedQuad bake(Vec3f from, Vec3f to, ModelElementFace face, Sprite texture, Direction side, ModelBakeSettings settings, @Nullable ModelRotation rotation, boolean shade, Identifier modelId) { - ModelElementTexture modelElementTexture = face.textureData; - if (settings.isUvLocked()) { - modelElementTexture = uvLock(face.textureData, side, settings.getRotation(), modelId); - } - - float[] fs = new float[modelElementTexture.uvs.length]; - System.arraycopy(modelElementTexture.uvs, 0, fs, 0, fs.length); - float f = texture.getAnimationFrameDelta(); - float g = (modelElementTexture.uvs[0] + modelElementTexture.uvs[0] + modelElementTexture.uvs[2] + modelElementTexture.uvs[2]) / 4.0F; - float h = (modelElementTexture.uvs[1] + modelElementTexture.uvs[1] + modelElementTexture.uvs[3] + modelElementTexture.uvs[3]) / 4.0F; - modelElementTexture.uvs[0] = MathHelper.lerp(f, modelElementTexture.uvs[0], g); - modelElementTexture.uvs[2] = MathHelper.lerp(f, modelElementTexture.uvs[2], g); - modelElementTexture.uvs[1] = MathHelper.lerp(f, modelElementTexture.uvs[1], h); - modelElementTexture.uvs[3] = MathHelper.lerp(f, modelElementTexture.uvs[3], h); - int[] is = this.packVertexData(modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); - Direction direction = decodeDirection(is); - System.arraycopy(fs, 0, modelElementTexture.uvs, 0, fs.length); - if (rotation == null) { - this.encodeDirection(is, direction); - } - - return new BakedQuad(is, face.tintIndex, direction, texture, shade, face.emission); - } - - public static ModelElementTexture uvLock(ModelElementTexture texture, Direction orientation, AffineTransformation rotation, Identifier modelId) { - Matrix4f matrix4f = AffineTransformations.uvLock(rotation, orientation, () -> "Unable to resolve UVLock for model: " + modelId).getMatrix(); - float f = texture.getU(texture.getDirectionIndex(0)); - float g = texture.getV(texture.getDirectionIndex(0)); - Vector4f vector4f = new Vector4f(f / 16.0F, g / 16.0F, 0.0F, 1.0F); - vector4f.transform(matrix4f); - float h = 16.0F * vector4f.getX(); - float i = 16.0F * vector4f.getY(); - float j = texture.getU(texture.getDirectionIndex(2)); - float k = texture.getV(texture.getDirectionIndex(2)); - Vector4f vector4f2 = new Vector4f(j / 16.0F, k / 16.0F, 0.0F, 1.0F); - vector4f2.transform(matrix4f); - float l = 16.0F * vector4f2.getX(); - float m = 16.0F * vector4f2.getY(); - float p; - float q; - if (Math.signum(j - f) == Math.signum(l - h)) { - p = h; - q = l; - } else { - p = l; - q = h; - } - - float t; - float u; - if (Math.signum(k - g) == Math.signum(m - i)) { - t = i; - u = m; - } else { - t = m; - u = i; - } - - float v = (float)Math.toRadians(texture.rotation); - Vec3f vector3f = new Vec3f(net.minecraft.util.math.MathHelper.cos(v), net.minecraft.util.math.MathHelper.sin(v), 0.0F); - Matrix3f matrix3f = new Matrix3f(matrix4f); - vector3f.transform(matrix3f); - int w = Math.floorMod(-((int)Math.round(Math.toDegrees(Math.atan2(vector3f.getY(), vector3f.getX())) / 90.0D)) * 90, 360); - return new ModelElementTexture(new float[]{p, t, q, u}, w); - } - - private int[] packVertexData(ModelElementTexture texture, Sprite sprite, Direction direction, float[] positionMatrix, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { - int[] is = new int[32]; - - for(int i = 0; i < 4; ++i) { - this.packVertexData(is, i, direction, texture, positionMatrix, sprite, orientation, rotation, shaded); - } - - return is; - } - - private float[] getPositionMatrix(Vec3f from, Vec3f to) { - float[] fs = new float[Direction.values().length]; - fs[CubeFace.DirectionIds.EAST] = from.getZ() / 16.0F; - fs[CubeFace.DirectionIds.DOWN] = from.getY() / 16.0F; - fs[CubeFace.DirectionIds.NORTH] = from.getX() / 16.0F; - fs[CubeFace.DirectionIds.WEST] = to.getZ() / 16.0F; - fs[CubeFace.DirectionIds.UP] = to.getY() / 16.0F; - fs[CubeFace.DirectionIds.SOUTH] = to.getX() / 16.0F; - return fs; - } - - private void packVertexData(int[] vertices, int cornerIndex, Direction direction, ModelElementTexture texture, float[] positionMatrix, Sprite sprite, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { - CubeFace.Corner corner = CubeFace.getFace(direction).getCorner(cornerIndex); - Vec3f vector3f = new Vec3f(positionMatrix[corner.xSide], positionMatrix[corner.ySide], positionMatrix[corner.zSide]); - this.rotateVertex(vector3f, rotation); - this.transformVertex(vector3f, orientation); - this.packVertexData(vertices, cornerIndex, vector3f, sprite, texture); - } - - private void packVertexData(int[] vertices, int cornerIndex, Vec3f position, Sprite sprite, ModelElementTexture modelElementTexture) { - int i = cornerIndex * 8; - vertices[i] = Float.floatToRawIntBits(position.getX()); - vertices[i + 1] = Float.floatToRawIntBits(position.getY()); - vertices[i + 2] = Float.floatToRawIntBits(position.getZ()); -// vertices[i + 3] = -1; - vertices[i + 3] = Float.floatToRawIntBits(sprite.getFrameU(modelElementTexture.getU(cornerIndex))); - vertices[i + 3 + 1] = Float.floatToRawIntBits(sprite.getFrameV(modelElementTexture.getV(cornerIndex))); - } - - private void rotateVertex(Vec3f vector, @Nullable ModelRotation rotation) { - if (rotation != null) { - Vec3f vector3f7; - Vec3f vector3f8; - switch (rotation.axis()) { - case X -> { - vector3f7 = new Vec3f(1.0F, 0.0F, 0.0F); - vector3f8 = new Vec3f(0.0F, 1.0F, 1.0F); - } - case Y -> { - vector3f7 = new Vec3f(0.0F, 1.0F, 0.0F); - vector3f8 = new Vec3f(1.0F, 0.0F, 1.0F); - } - case Z -> { - vector3f7 = new Vec3f(0.0F, 0.0F, 1.0F); - vector3f8 = new Vec3f(1.0F, 1.0F, 0.0F); - } - default -> throw new IllegalArgumentException("There are only 3 axes"); - } - - Quaternion quaternion = new Quaternion(vector3f7, rotation.angle(), true); - if (rotation.rescale()) { - if (Math.abs(rotation.angle()) == 22.5F) { - vector3f8.scale(MIN_SCALE); - } else { - vector3f8.scale(MAX_SCALE); - } - - vector3f8.add(1.0F, 1.0F, 1.0F); - } else { - vector3f8.set(1.0F, 1.0F, 1.0F); - } - - this.transformVertex(vector, rotation.origin().copy(), new Matrix4f(quaternion), vector3f8); - } - } - - public void transformVertex(Vec3f vertex, AffineTransformation transformation) { - if (transformation != AffineTransformation.identity()) { - this.transformVertex(vertex, new Vec3f(0.5F, 0.5F, 0.5F), transformation.getMatrix(), new Vec3f(1.0F, 1.0F, 1.0F)); - } - } - - private void transformVertex(Vec3f vertex, Vec3f origin, Matrix4f transformationMatrix, Vec3f scale) { - Vector4f vector4f = new Vector4f(vertex.getX() - origin.getX(), vertex.getY() - origin.getY(), vertex.getZ() - origin.getZ(), 1.0F); - vector4f.transform(transformationMatrix); - vector4f.multiplyComponentwise(scale); - vertex.set(vector4f.getX() + origin.getX(), vector4f.getY() + origin.getY(), vector4f.getZ() + origin.getZ()); - } - - public static Direction decodeDirection(int[] rotationMatrix) { - Vec3f vector3f = new Vec3f(Float.intBitsToFloat(rotationMatrix[0]), Float.intBitsToFloat(rotationMatrix[1]), Float.intBitsToFloat(rotationMatrix[2])); - Vec3f vector3f2 = new Vec3f(Float.intBitsToFloat(rotationMatrix[8]), Float.intBitsToFloat(rotationMatrix[9]), Float.intBitsToFloat(rotationMatrix[10])); - Vec3f vector3f3 = new Vec3f(Float.intBitsToFloat(rotationMatrix[16]), Float.intBitsToFloat(rotationMatrix[17]), Float.intBitsToFloat(rotationMatrix[18])); - Vec3f vector3f4 = vector3f.copy(); - vector3f4.subtract(vector3f2); - Vec3f vector3f5 = vector3f3.copy(); - vector3f5.subtract(vector3f2); - Vec3f vector3f6 = vector3f5.copy(); - vector3f6.cross(vector3f4); - vector3f6.normalize(); - Direction direction = null; - float f = 0.0F; - Direction[] var9 = Direction.values(); - - for (Direction direction2 : var9) { - Vec3f vector3f7 = direction2.getUnitVector(); - float g = vector3f6.dot(vector3f7); - if (g >= 0.0F && g > f) { - f = g; - direction = direction2; - } - } - - return Objects.requireNonNullElse(direction, Direction.UP); - } - - private void encodeDirection(int[] rotationMatrix, Direction direction) { - int[] is = new int[rotationMatrix.length]; - System.arraycopy(rotationMatrix, 0, is, 0, rotationMatrix.length); - float[] fs = new float[Direction.values().length]; - fs[CubeFace.DirectionIds.NORTH] = 999.0F; - fs[CubeFace.DirectionIds.DOWN] = 999.0F; - fs[CubeFace.DirectionIds.EAST] = 999.0F; - fs[CubeFace.DirectionIds.SOUTH] = -999.0F; - fs[CubeFace.DirectionIds.UP] = -999.0F; - fs[CubeFace.DirectionIds.WEST] = -999.0F; - - int k; - float h; - for(int i = 0; i < 4; ++i) { - k = 8 * i; - float f = Float.intBitsToFloat(is[k]); - float g = Float.intBitsToFloat(is[k + 1]); - h = Float.intBitsToFloat(is[k + 2]); - if (f < fs[CubeFace.DirectionIds.NORTH]) { - fs[CubeFace.DirectionIds.NORTH] = f; - } - - if (g < fs[CubeFace.DirectionIds.DOWN]) { - fs[CubeFace.DirectionIds.DOWN] = g; - } - - if (h < fs[CubeFace.DirectionIds.EAST]) { - fs[CubeFace.DirectionIds.EAST] = h; - } - - if (f > fs[CubeFace.DirectionIds.SOUTH]) { - fs[CubeFace.DirectionIds.SOUTH] = f; - } - - if (g > fs[CubeFace.DirectionIds.UP]) { - fs[CubeFace.DirectionIds.UP] = g; - } - - if (h > fs[CubeFace.DirectionIds.WEST]) { - fs[CubeFace.DirectionIds.WEST] = h; - } - } - - CubeFace cubeFace = CubeFace.getFace(direction); - - for(k = 0; k < 4; ++k) { - int l = 8 * k; - CubeFace.Corner corner = cubeFace.getCorner(k); - h = fs[corner.xSide]; - float n = fs[corner.ySide]; - float o = fs[corner.zSide]; - rotationMatrix[l] = Float.floatToRawIntBits(h); - rotationMatrix[l + 1] = Float.floatToRawIntBits(n); - rotationMatrix[l + 2] = Float.floatToRawIntBits(o); - - for(int p = 0; p < 4; ++p) { - int q = 8 * p; - float r = Float.intBitsToFloat(is[q]); - float s = Float.intBitsToFloat(is[q + 1]); - float t = Float.intBitsToFloat(is[q + 2]); - if (MathHelper.approximatelyEquals(h, r) && MathHelper.approximatelyEquals(n, s) && MathHelper.approximatelyEquals(o, t)) { - rotationMatrix[l + 3] = is[q + 3]; - rotationMatrix[l + 3 + 1] = is[q + 3 + 1]; - } - } - } - - } -} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java deleted file mode 100644 index 438feeaf9..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java +++ /dev/null @@ -1,96 +0,0 @@ -package net.modificationstation.stationapi.api.client.render.model.json; - -import com.google.gson.*; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.util.JsonHelper; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import org.lwjgl.opengl.GL11; - -import java.lang.reflect.Type; - -@Environment(EnvType.CLIENT) -public class Transformation { - public static final Transformation IDENTITY = new Transformation(new Vec3f(), new Vec3f(), new Vec3f(1.0F, 1.0F, 1.0F)); - public final Vec3f rotation; - public final Vec3f translation; - public final Vec3f scale; - - public Transformation(Vec3f rotation, Vec3f translation, Vec3f scale) { - this.rotation = rotation.copy(); - this.translation = translation.copy(); - this.scale = scale.copy(); - } - - public void apply() { - if (this != IDENTITY) { - float f = this.rotation.getX(); - float g = this.rotation.getY(); - float h = this.rotation.getZ(); - - GL11.glTranslatef(this.translation.getX(), this.translation.getY(), this.translation.getZ()); - GL11.glRotatef(f, 1, 0, 0); - GL11.glRotatef(g, 0, 1, 0); - GL11.glRotatef(h, 0, 0, 1); - GL11.glScalef(this.scale.getX(), this.scale.getY(), this.scale.getZ()); - } - } - - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (this.getClass() != o.getClass()) { - return false; - } else { - Transformation transformation = (Transformation)o; - return this.rotation.equals(transformation.rotation) && this.scale.equals(transformation.scale) && this.translation.equals(transformation.translation); - } - } - - public int hashCode() { - int i = this.rotation.hashCode(); - i = 31 * i + this.translation.hashCode(); - i = 31 * i + this.scale.hashCode(); - return i; - } - - @Environment(EnvType.CLIENT) - public static class Deserializer implements JsonDeserializer { - private static final Vec3f DEFAULT_ROTATION = new Vec3f(0.0F, 0.0F, 0.0F); - private static final Vec3f DEFAULT_TRANSLATION = new Vec3f(0.0F, 0.0F, 0.0F); - private static final Vec3f DEFAULT_SCALE = new Vec3f(1.0F, 1.0F, 1.0F); - - protected Deserializer() { - } - - public Transformation deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - Vec3f vector3f = this.parseVector3f(jsonObject, "rotation", DEFAULT_ROTATION); - Vec3f vector3f2 = this.parseVector3f(jsonObject, "translation", DEFAULT_TRANSLATION); - vector3f2.scale(0.0625F); - vector3f2.clamp(-5.0F, 5.0F); - Vec3f vector3f3 = this.parseVector3f(jsonObject, "scale", DEFAULT_SCALE); - vector3f3.clamp(-4.0F, 4.0F); - return new Transformation(vector3f, vector3f2, vector3f3); - } - - private Vec3f parseVector3f(JsonObject json, String key, Vec3f fallback) { - if (!json.has(key)) { - return fallback; - } else { - JsonArray jsonArray = JsonHelper.getArray(json, key); - if (jsonArray.size() != 3) { - throw new JsonParseException("Expected 3 " + key + " values, found: " + jsonArray.size()); - } else { - float[] fs = new float[3]; - - for(int i = 0; i < fs.length; ++i) { - fs[i] = JsonHelper.asFloat(jsonArray.get(i), key + "[" + i + "]"); - } - - return new Vec3f(fs[0], fs[1], fs[2]); - } - } - } - } -} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java deleted file mode 100644 index 0558991b8..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.modificationstation.stationapi.api.client.texture.atlas; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import net.modificationstation.stationapi.api.util.Identifier; - -import java.util.List; - -public class AtlasSourceManager { - private static final BiMap SOURCE_TYPE_BY_ID = HashBiMap.create(); - public static final AtlasSourceType SINGLE = AtlasSourceManager.register("single", SingleAtlasSource.CODEC); - public static final AtlasSourceType DIRECTORY = AtlasSourceManager.register("directory", DirectoryAtlasSource.CODEC); - public static final AtlasSourceType FILTER = AtlasSourceManager.register("filter", FilterAtlasSource.CODEC); - public static final AtlasSourceType UNSTITCH = AtlasSourceManager.register("unstitch", UnstitchAtlasSource.CODEC); - public static final AtlasSourceType PALETTED_PERMUTATIONS = AtlasSourceManager.register("paletted_permutations", PalettedPermutationsAtlasSource.CODEC); - public static Codec CODEC = Identifier.CODEC.flatXmap(id -> { - AtlasSourceType atlasSourceType = SOURCE_TYPE_BY_ID.get(id); - return atlasSourceType != null ? DataResult.success(atlasSourceType) : DataResult.error(() -> "Unknown type " + id); - }, type -> { - Identifier identifier = SOURCE_TYPE_BY_ID.inverse().get(type); - return type != null ? DataResult.success(identifier) : DataResult.error(() -> "Unknown type " + identifier); - }); - public static Codec TYPE_CODEC = CODEC.dispatch(AtlasSource::getType, AtlasSourceType::codec); - public static Codec> LIST_CODEC = TYPE_CODEC.listOf().fieldOf("sources").codec(); - - private static AtlasSourceType register(String id, Codec codec) { - Identifier identifier = Identifier.of(id); - AtlasSourceType atlasSourceType = new AtlasSourceType(codec); - AtlasSourceType atlasSourceType2 = SOURCE_TYPE_BY_ID.putIfAbsent(identifier, atlasSourceType); - if (atlasSourceType2 != null) { - throw new IllegalStateException("Duplicate registration " + identifier); - } - return atlasSourceType; - } -} - diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceType.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceType.java deleted file mode 100644 index f98ab3c13..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceType.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.modificationstation.stationapi.api.client.texture.atlas; - -import com.mojang.serialization.Codec; - -public record AtlasSourceType(Codec codec) {} - diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java deleted file mode 100644 index 461c5d27a..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.modificationstation.stationapi.api.client.texture.atlas; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.modificationstation.stationapi.api.resource.ResourceFinder; -import net.modificationstation.stationapi.api.resource.ResourceManager; - -import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; - -public class DirectoryAtlasSource implements AtlasSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(Codec.STRING.fieldOf("source").forGetter(directoryAtlasSource -> directoryAtlasSource.source), Codec.STRING.fieldOf("prefix").forGetter(directoryAtlasSource -> directoryAtlasSource.prefix)).apply(instance, DirectoryAtlasSource::new)); - private final String source; - private final String prefix; - - public DirectoryAtlasSource(String source, String prefix) { - this.source = source; - this.prefix = prefix; - } - - @Override - public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { - ResourceFinder resourceFinder = new ResourceFinder(NAMESPACE + "/textures/" + this.source, ".png"); - resourceFinder.findResources(resourceManager).forEach((identifier, resource) -> regions.add(resourceFinder.toResourceId(identifier).withPrefixedPath(this.prefix), resource)); - } - - @Override - public AtlasSourceType getType() { - return AtlasSourceManager.DIRECTORY; - } -} - diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java deleted file mode 100644 index 71f9772b7..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.modificationstation.stationapi.api.client.texture.atlas; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.modificationstation.stationapi.api.resource.ResourceManager; -import net.modificationstation.stationapi.api.resource.metadata.BlockEntry; - -public class FilterAtlasSource implements AtlasSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(BlockEntry.CODEC.fieldOf("pattern").forGetter(filterAtlasSource -> filterAtlasSource.pattern)).apply(instance, FilterAtlasSource::new)); - private final BlockEntry pattern; - - public FilterAtlasSource(BlockEntry pattern) { - this.pattern = pattern; - } - - @Override - public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { - regions.removeIf(this.pattern.getIdentifierPredicate()); - } - - @Override - public AtlasSourceType getType() { - return AtlasSourceManager.FILTER; - } -} - diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java deleted file mode 100644 index 324929356..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.modificationstation.stationapi.api.client.texture.atlas; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.modificationstation.stationapi.api.util.Identifier; -import net.modificationstation.stationapi.api.resource.Resource; -import net.modificationstation.stationapi.api.resource.ResourceManager; - -import java.util.Optional; - -import static net.modificationstation.stationapi.impl.client.texture.StationRenderImpl.LOGGER; - -public class SingleAtlasSource implements AtlasSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(Identifier.CODEC.fieldOf("resource").forGetter(singleAtlasSource -> singleAtlasSource.resource), Identifier.CODEC.optionalFieldOf("sprite").forGetter(singleAtlasSource -> singleAtlasSource.sprite)).apply(instance, SingleAtlasSource::new)); - private final Identifier resource; - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - private final Optional sprite; - - public SingleAtlasSource(Identifier resource, @SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional sprite) { - this.resource = resource; - this.sprite = sprite; - } - - @Override - public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { - Identifier identifier = RESOURCE_FINDER.toResourcePath(this.resource); - Optional optional = resourceManager.getResource(identifier); - if (optional.isPresent()) regions.add(this.sprite.orElse(this.resource), optional.get()); - else LOGGER.warn("Missing sprite: {}", identifier); - } - - @Override - public AtlasSourceType getType() { - return AtlasSourceManager.SINGLE; - } -} - diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java deleted file mode 100644 index 872dffd13..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java +++ /dev/null @@ -1,134 +0,0 @@ -package net.modificationstation.stationapi.api.util.math; - -import com.mojang.datafixers.util.Pair; -import net.modificationstation.stationapi.api.util.Util; -import org.apache.commons.lang3.tuple.Triple; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -public final class AffineTransformation { - private final Matrix4f matrix; - private boolean initialized; - @Nullable - private Vec3f translation; - @Nullable - private Quaternion rotation2; - @Nullable - private Vec3f scale; - @Nullable - private Quaternion rotation1; - private static final AffineTransformation IDENTITY = Util.make(() -> { - Matrix4f matrix4f = new Matrix4f(); - matrix4f.loadIdentity(); - AffineTransformation affineTransformation = new AffineTransformation(matrix4f); - affineTransformation.getRotation2(); - return affineTransformation; - }); - - public AffineTransformation(@Nullable Matrix4f matrix) { - if (matrix == null) { - this.matrix = IDENTITY.matrix; - } else { - this.matrix = matrix; - } - - } - - public AffineTransformation(@Nullable Vec3f translation, @Nullable Quaternion rotation2, @Nullable Vec3f scale, @Nullable Quaternion rotation1) { - this.matrix = setup(translation, rotation2, scale, rotation1); - this.translation = translation != null ? translation : new Vec3f(); - this.rotation2 = rotation2 != null ? rotation2 : Quaternion.IDENTITY.copy(); - this.scale = scale != null ? scale : new Vec3f(1.0F, 1.0F, 1.0F); - this.rotation1 = rotation1 != null ? rotation1 : Quaternion.IDENTITY.copy(); - this.initialized = true; - } - - public static AffineTransformation identity() { - return IDENTITY; - } - - public AffineTransformation multiply(AffineTransformation other) { - Matrix4f matrix4f = this.getMatrix(); - matrix4f.multiply(other.getMatrix()); - return new AffineTransformation(matrix4f); - } - - @Nullable - public AffineTransformation invert() { - if (this == IDENTITY) { - return this; - } else { - Matrix4f matrix4f = this.getMatrix(); - return matrix4f.invert() ? new AffineTransformation(matrix4f) : null; - } - } - - private void init() { - if (!this.initialized) { - Pair pair = getLinearTransformationAndTranslationFromAffine(this.matrix); - Triple triple = pair.getFirst().decomposeLinearTransformation(); - this.translation = pair.getSecond(); - this.rotation2 = triple.getLeft(); - this.scale = triple.getMiddle(); - this.rotation1 = triple.getRight(); - this.initialized = true; - } - - } - - private static Matrix4f setup(@Nullable Vec3f translation, @Nullable Quaternion rotation2, @Nullable Vec3f scale, @Nullable Quaternion rotation1) { - Matrix4f matrix4f = new Matrix4f(); - matrix4f.loadIdentity(); - if (rotation2 != null) { - matrix4f.multiply(new Matrix4f(rotation2)); - } - - if (scale != null) { - matrix4f.multiply(Matrix4f.scale(scale.getX(), scale.getY(), scale.getZ())); - } - - if (rotation1 != null) { - matrix4f.multiply(new Matrix4f(rotation1)); - } - - if (translation != null) { - matrix4f.a03 = translation.getX(); - matrix4f.a13 = translation.getY(); - matrix4f.a23 = translation.getZ(); - } - - return matrix4f; - } - - public static Pair getLinearTransformationAndTranslationFromAffine(Matrix4f affineTransform) { - affineTransform.multiply(1.0F / affineTransform.a33); - Vec3f vector3f = new Vec3f(affineTransform.a03, affineTransform.a13, affineTransform.a23); - Matrix3f matrix3f = new Matrix3f(affineTransform); - return Pair.of(matrix3f, vector3f); - } - - public Matrix4f getMatrix() { - return this.matrix.copy(); - } - - public Quaternion getRotation2() { - this.init(); - return this.rotation2.copy(); - } - - public boolean equals(Object object) { - if (this == object) { - return true; - } else if (object != null && this.getClass() == object.getClass()) { - AffineTransformation affineTransformation = (AffineTransformation)object; - return Objects.equals(this.matrix, affineTransformation.matrix); - } else { - return false; - } - } - - public int hashCode() { - return Objects.hash(this.matrix); - } -} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererAccessImpl.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererAccessImpl.java deleted file mode 100644 index 152b87168..000000000 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererAccessImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.modificationstation.stationapi.impl.client.render; - -import net.modificationstation.stationapi.api.client.render.Renderer; -import net.modificationstation.stationapi.api.client.render.RendererAccess; - -public final class RendererAccessImpl implements RendererAccess { - - public static final RendererAccessImpl INSTANCE = new RendererAccessImpl(); - - // private constructor - private RendererAccessImpl() { } - - @Override - public void registerRenderer(Renderer renderer) { - if (renderer == null) { - throw new NullPointerException("Attempt to register a NULL rendering plug-in."); - } else if (activeRenderer != null) { - throw new UnsupportedOperationException("A second rendering plug-in attempted to register. Multiple rendering plug-ins are not supported."); - } else { - activeRenderer = renderer; - hasActiveRenderer = true; - } - } - - private Renderer activeRenderer = null; - - /** avoids null test every call to {@link #hasRenderer()}. */ - private boolean hasActiveRenderer = false; - - @Override - public Renderer getRenderer() { - return activeRenderer; - } - - @Override - public boolean hasRenderer() { - return hasActiveRenderer; - } -} \ No newline at end of file diff --git a/station-renderer-api-v0/build.gradle.kts b/station-renderer-api-v1/build.gradle.kts similarity index 84% rename from station-renderer-api-v0/build.gradle.kts rename to station-renderer-api-v1/build.gradle.kts index 632b75bd9..6b2c584f0 100644 --- a/station-renderer-api-v0/build.gradle.kts +++ b/station-renderer-api-v1/build.gradle.kts @@ -3,6 +3,10 @@ import net.modificationstation.stationapi.gradle.SubprojectHelpers.addModuleDepe base.archivesName.set("station-renderer-api-v0") version = getSubprojectVersion(project, "1.0.0") +loom { + accessWidenerPath = file("src/main/resources/station-renderer-api-v1.accesswidener") +} + addModuleDependencies(project, "station-api-base", "station-maths-v0", diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/StationRenderAPI.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/StationRenderAPI.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/StationRenderAPI.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/StationRenderAPI.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/block/StationRendererBlock.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/block/StationRendererBlock.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/block/StationRendererBlock.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/block/StationRendererBlock.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColorProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColorProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColorProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColorProvider.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColors.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColors.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColors.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/block/BlockColors.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColorProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColorProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColorProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColorProvider.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColors.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColors.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColors.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/item/ItemColors.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/world/BiomeColors.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/world/BiomeColors.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/color/world/BiomeColors.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/color/world/BiomeColors.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/color/block/BlockColorsRegisterEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/color/block/BlockColorsRegisterEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/color/block/BlockColorsRegisterEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/color/block/BlockColorsRegisterEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/color/item/ItemColorsRegisterEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/color/item/ItemColorsRegisterEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/color/item/ItemColorsRegisterEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/color/item/ItemColorsRegisterEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/BlockModelPredicateProviderRegistryEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/BlockModelPredicateProviderRegistryEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/BlockModelPredicateProviderRegistryEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/BlockModelPredicateProviderRegistryEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/ItemModelPredicateProviderRegistryEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/ItemModelPredicateProviderRegistryEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/ItemModelPredicateProviderRegistryEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/ItemModelPredicateProviderRegistryEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/LoadUnbakedModelEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/LoadUnbakedModelEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/LoadUnbakedModelEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/LoadUnbakedModelEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/PreLoadUnbakedModelEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/PreLoadUnbakedModelEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/PreLoadUnbakedModelEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/render/model/PreLoadUnbakedModelEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/texture/TextureRegisterEvent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/texture/TextureRegisterEvent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/event/texture/TextureRegisterEvent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/event/texture/TextureRegisterEvent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/item/StationRendererItem.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/item/StationRendererItem.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/item/StationRendererItem.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/item/StationRendererItem.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/Model.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/Model.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/Model.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/Model.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java similarity index 77% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java index f5ed09470..4695da747 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockInventoryModelProvider.java @@ -2,6 +2,7 @@ import net.minecraft.client.render.block.BlockRenderManager; import net.modificationstation.stationapi.api.client.model.Model; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; @Deprecated public interface BlockInventoryModelProvider extends BlockWithInventoryRenderer { @@ -14,7 +15,7 @@ public interface BlockInventoryModelProvider extends BlockWithInventoryRenderer @Override @Deprecated - default void renderInventory(BlockRenderManager blockRenderer, int meta) { + default void renderInventory(VertexConsumer consumer, BlockRenderManager blockRenderer, int meta) { // TODO: maybe implement this later for backwards compat with PRE2 // BAKED_MODEL_RENDERER.get().renderInventory(getInventoryModel(meta).getBaked()); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockModelPredicateProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockModelPredicateProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockModelPredicateProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockModelPredicateProvider.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java similarity index 54% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java index 11e83afef..86be1d1e8 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithInventoryRenderer.java @@ -1,10 +1,11 @@ package net.modificationstation.stationapi.api.client.model.block; import net.minecraft.client.render.block.BlockRenderManager; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; @Deprecated public interface BlockWithInventoryRenderer { @Deprecated - void renderInventory(BlockRenderManager tileRenderer, int meta); + void renderInventory(VertexConsumer consumer, BlockRenderManager tileRenderer, int meta); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java similarity index 54% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java index 70a2f8869..2089c5919 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWithWorldRenderer.java @@ -2,10 +2,11 @@ import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; @Deprecated public interface BlockWithWorldRenderer { @Deprecated - boolean renderWorld(BlockRenderManager tileRenderer, BlockView tileView, int x, int y, int z); + boolean renderWorld(VertexConsumer consumer, BlockRenderManager tileRenderer, BlockView tileView, int x, int y, int z); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java similarity index 67% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java index 9e0ab29ff..0699efbc1 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/BlockWorldModelProvider.java @@ -1,10 +1,12 @@ package net.modificationstation.stationapi.api.client.model.block; +import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockView; import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.client.model.Model; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.world.BlockStateView; import java.util.Random; @@ -22,9 +24,9 @@ public interface BlockWorldModelProvider extends BlockWithWorldRenderer { @Override @Deprecated - default boolean renderWorld(BlockRenderManager blockRenderer, BlockView blockView, int x, int y, int z) { + default boolean renderWorld(VertexConsumer consumer, BlockRenderManager blockRenderer, BlockView blockView, int x, int y, int z) { BlockState state = ((BlockStateView) blockView).getBlockState(x, y, z); BlockPos pos = new BlockPos(x, y, z); - return BAKED_MODEL_RENDERER.get().render(blockView, getCustomWorldModel(blockView, x, y, z).getBaked(), state, pos, true, new Random(), state.getRenderingSeed(pos)); + return BAKED_MODEL_RENDERER.get().render(consumer, blockView, getCustomWorldModel(blockView, x, y, z).getBaked(), state, pos, true, new Random(), state.getRenderingSeed(pos)); } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java similarity index 71% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java index 876b27f41..f463a5cae 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/block/RendererHolder.java @@ -3,14 +3,13 @@ import com.google.common.base.Suppliers; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; -import java.util.Objects; import java.util.function.Supplier; @NoArgsConstructor(access = AccessLevel.PRIVATE) final class RendererHolder { - static final Supplier BAKED_MODEL_RENDERER = Suppliers.memoize(() -> RendererAccess.INSTANCE.hasRenderer() ? Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer()).bakedModelRenderer() : null); + static final Supplier BAKED_MODEL_RENDERER = Suppliers.memoize(() -> Renderer.get().bakedModelRenderer()); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemModelPredicateProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemModelPredicateProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemModelPredicateProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemModelPredicateProvider.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemWithRenderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemWithRenderer.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemWithRenderer.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/model/item/ItemWithRenderer.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/registry/BlockModelPredicateProviderRegistry.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/registry/BlockModelPredicateProviderRegistry.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/registry/BlockModelPredicateProviderRegistry.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/registry/BlockModelPredicateProviderRegistry.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/registry/ItemModelPredicateProviderRegistry.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/registry/ItemModelPredicateProviderRegistry.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/registry/ItemModelPredicateProviderRegistry.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/registry/ItemModelPredicateProviderRegistry.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java new file mode 100644 index 000000000..f8c348d8e --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java @@ -0,0 +1,96 @@ +package net.modificationstation.stationapi.api.client.render; + +import net.minecraft.client.render.Tessellator; +import net.modificationstation.stationapi.api.client.render.model.BakedQuad; +import net.modificationstation.stationapi.api.util.math.MatrixStack; + +public class DelegatingTessellator extends Tessellator { + + private VertexConsumer delegate = Tessellator.INSTANCE; + + public DelegatingTessellator() { + super(0); + } + + public void setDelegate(VertexConsumer delegate) { + this.delegate = delegate; + } + + @Override + public void draw() { + if (this.delegate instanceof Tessellator t) + t.draw(); + } + + @Override + public void start(int mode) { + if (this.delegate instanceof Tessellator t) + t.start(mode); + } + + @Override + public void translate(double x, double y, double z) { + if (this.delegate instanceof Tessellator t) + t.translate(x, y, z); + } + + @Override + public void disableColor() { + if (this.delegate instanceof Tessellator t) + t.disableColor(); + } + + @Override + public void translate(float x, float y, float z) { + if (this.delegate instanceof Tessellator t) + t.translate(x, y, z); + } + + @Override + public void vertex(double x, double y, double z) { + this.delegate.vertex(x, y, z); + } + + @Override + public void vertex(float x, float y, float z) { + this.delegate.vertex(x, y, z); + } + + @Override + public void vertex(double x, double y, double z, double u, double v) { + this.delegate.texture(u, v); + this.delegate.vertex(x, y, z); + } + + @Override + public void texture(double u, double v) { + this.delegate.texture(u, v); + } + + @Override + public void normal(float x, float y, float z) { + this.delegate.normal(x, y, z); + } + + @Override + public void color(int r, int g, int b, int a) { + this.delegate.color(r, g, b, a); + } + + @Override + public void quad(BakedQuad quad, float x, float y, float z, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { + if (this.delegate instanceof StationTessellator t) + t.quad(quad, x, y, z, colour0, colour1, colour2, colour3, normalX, normalY, normalZ, spreadUV); + } + + @Override + public void ensureBufferCapacity(int criticalCapacity) { + if (this.delegate instanceof StationTessellator t) + t.ensureBufferCapacity(criticalCapacity); + } + + @Override + public VertexConsumer quad(MatrixStack.Entry entry, BakedQuad quad, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { + return this.delegate.quad(entry, quad, colour0, colour1, colour2, colour3, normalX, normalY, normalZ, spreadUV); + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java new file mode 100644 index 000000000..8f541639c --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java @@ -0,0 +1,38 @@ +package net.modificationstation.stationapi.api.client.render; + +import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; +import net.modificationstation.stationapi.impl.client.render.RendererManager; + +/** + * Interface for rendering plug-ins that provide enhanced capabilities + * for model lighting, buffering and rendering. Such plug-ins implement the + * enhanced model rendering interfaces specified by the Fabric API. + */ +public interface Renderer { + /** + * Access to the current {@link Renderer} for creating and retrieving mesh builders + * and materials. + */ + static Renderer get() { + return RendererManager.getRenderer(); + } + + /** + * Rendering extension mods must implement {@link Renderer} and + * call this method during initialization. + * + *

Only one {@link Renderer} plug-in can be active in any game instance. + * If a second mod attempts to register, this method will throw an UnsupportedOperationException. + */ + static void register(Renderer renderer) { + RendererManager.registerRenderer(renderer); + } + + /** + * Obtain a new {@link BakedModelRenderer} instance used to render + * baked models. + * + * + */ + BakedModelRenderer bakedModelRenderer(); +} \ No newline at end of file diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/StationTessellator.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StationTessellator.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/StationTessellator.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StationTessellator.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java new file mode 100644 index 000000000..648b01088 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java @@ -0,0 +1,31 @@ +package net.modificationstation.stationapi.api.client.render; + +import net.modificationstation.stationapi.api.client.render.model.BakedQuad; +import net.modificationstation.stationapi.api.util.math.MatrixStack; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +public interface VertexConsumer { + default void vertex(double x, double y, double z) { + vertex((float) x, (float) y, (float) z); + } + + void vertex(float x, float y, float z); + + void color(int red, int green, int blue, int alpha); + + void texture(double u, double v); + + void normal(float x, float y, float z); + + // TODO + default VertexConsumer quad(MatrixStack.Entry entry, BakedQuad quad, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { + int[] vertexData = quad.vertexData(); + + Vector3fc faceNormal = quad.face().getFloatVector(); + Matrix4f pos = entry.getPositionMatrix(); + Vector3f normal = entry.transformNormal(faceNormal, new Vector3f()); + return this; + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockModels.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockModels.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockModels.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockModels.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererHelper.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererHelper.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererHelper.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererUtil.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererUtil.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererUtil.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/BlockRendererUtil.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java new file mode 100644 index 000000000..91f124f30 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/block/StationRendererBlockRenderManager.java @@ -0,0 +1,19 @@ +package net.modificationstation.stationapi.api.client.render.block; + +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; +import net.modificationstation.stationapi.api.util.Util; + +public interface StationRendererBlockRenderManager { + default void renderAllSides(VertexConsumer consumer, BlockState state, int x, int y, int z) { + Util.assertImpl(); + } + + default void setVertexConsumer(VertexConsumer vertexConsumer) { + Util.assertImpl(); + } + + default VertexConsumer getVertexConsumer() { + return Util.assertImpl(); + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/AndMultipartModelSelector.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/AndMultipartModelSelector.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/AndMultipartModelSelector.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/AndMultipartModelSelector.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelManager.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelManager.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelManager.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java similarity index 69% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java index 1925804bf..2d119c58e 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModelRenderer.java @@ -6,6 +6,7 @@ import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.item.ItemModels; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; import org.jetbrains.annotations.Nullable; @@ -14,11 +15,11 @@ public interface BakedModelRenderer { - boolean renderBlock(BlockState state, BlockPos pos, BlockView world, boolean cull, Random random); + boolean renderBlock(VertexConsumer consumer, BlockState state, BlockPos pos, BlockView world, boolean cull, Random random); - boolean render(BlockView world, BakedModel model, BlockState state, BlockPos pos, boolean cull, Random random, long seed); + boolean render(VertexConsumer consumer, BlockView world, BakedModel model, BlockState state, BlockPos pos, boolean cull, Random random, long seed); - void renderDamage(BlockState state, BlockPos pos, BlockView world, float progress); + void renderDamage(VertexConsumer consumer, BlockState state, BlockPos pos, BlockView world, float progress); ItemModels getItemModels(); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java new file mode 100644 index 000000000..027a6d063 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java @@ -0,0 +1,17 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.texture.Sprite; +import net.modificationstation.stationapi.api.util.math.Direction; + +@Environment(EnvType.CLIENT) +public record BakedQuad(int[] vertexData, int tintIndex, Direction face, Sprite sprite, boolean shade, float lightEmission) { + public BakedQuad(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade) { + this(vertexData, colorIndex, face, sprite, shade, 0); + } + + public boolean hasTint() { + return this.tintIndex != -1; + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java new file mode 100644 index 000000000..0eacfbb38 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java @@ -0,0 +1,283 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.render.model.json.ModelElementFace; +import net.modificationstation.stationapi.api.client.render.model.json.ModelElementTexture; +import net.modificationstation.stationapi.api.client.texture.Sprite; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.util.math.*; +import org.jetbrains.annotations.Nullable; +import org.joml.*; + +import java.lang.Math; + +@Environment(EnvType.CLIENT) +public class BakedQuadFactory { + private static final float MIN_SCALE = 1.0F / (float)Math.cos(0.39269909262657166D) - 1.0F; + private static final float MAX_SCALE = 1.0F / (float)Math.cos(0.7853981852531433D) - 1.0F; + + public BakedQuad bake(Vector3f from, Vector3f to, ModelElementFace face, Sprite texture, Direction side, ModelBakeSettings settings, @Nullable ModelRotation rotation, boolean shade, Identifier modelId) { + ModelElementTexture modelElementTexture = face.textureData; + if (settings.isUvLocked()) { + modelElementTexture = uvLock(face.textureData, side, settings.getRotation(), modelId); + } + + float[] fs = new float[modelElementTexture.uvs.length]; + System.arraycopy(modelElementTexture.uvs, 0, fs, 0, fs.length); + float f = texture.getAnimationFrameDelta(); + float g = (modelElementTexture.uvs[0] + modelElementTexture.uvs[0] + modelElementTexture.uvs[2] + modelElementTexture.uvs[2]) / 4.0F; + float h = (modelElementTexture.uvs[1] + modelElementTexture.uvs[1] + modelElementTexture.uvs[3] + modelElementTexture.uvs[3]) / 4.0F; + modelElementTexture.uvs[0] = MathHelper.lerp(f, modelElementTexture.uvs[0], g); + modelElementTexture.uvs[2] = MathHelper.lerp(f, modelElementTexture.uvs[2], g); + modelElementTexture.uvs[1] = MathHelper.lerp(f, modelElementTexture.uvs[1], h); + modelElementTexture.uvs[3] = MathHelper.lerp(f, modelElementTexture.uvs[3], h); + int[] is = this.packVertexData(modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); + Direction direction = decodeDirection(is); + System.arraycopy(fs, 0, modelElementTexture.uvs, 0, fs.length); + if (rotation == null) { + this.encodeDirection(is, direction); + } + + return new BakedQuad(is, face.tintIndex, direction, texture, shade, face.emission); + } + + public static ModelElementTexture uvLock(ModelElementTexture texture, Direction orientation, AffineTransformation rotation, Identifier modelId) { + Matrix4f matrix4f = AffineTransformations.uvLock(rotation, orientation, () -> "Unable to resolve UVLock for model: " + modelId).copyMatrix(); + float f = texture.getU(texture.getDirectionIndex(0)); + float g = texture.getV(texture.getDirectionIndex(0)); + Vector4f vector4f = matrix4f.transform(new Vector4f(f / 16.0F, g / 16.0F, 0.0F, 1.0F)); + float h = 16.0F * vector4f.x(); + float i = 16.0F * vector4f.y(); + float j = texture.getU(texture.getDirectionIndex(2)); + float k = texture.getV(texture.getDirectionIndex(2)); + Vector4f vector4f2 = matrix4f.transform(new Vector4f(j / 16.0F, k / 16.0F, 0.0F, 1.0F)); + float l = 16.0F * vector4f2.x(); + float m = 16.0F * vector4f2.y(); + float p; + float q; + if (Math.signum(j - f) == Math.signum(l - h)) { + p = h; + q = l; + } else { + p = l; + q = h; + } + + float t; + float u; + if (Math.signum(k - g) == Math.signum(m - i)) { + t = i; + u = m; + } else { + t = m; + u = i; + } + + float v = (float)Math.toRadians(texture.rotation); + Matrix3f matrix3f = new Matrix3f(matrix4f); + Vector3f vector3f = matrix3f.transform(new Vector3f(net.minecraft.util.math.MathHelper.cos(v), net.minecraft.util.math.MathHelper.sin(v), 0.0F)); + int w = Math.floorMod(-((int)Math.round(Math.toDegrees(Math.atan2(vector3f.y(), vector3f.x())) / 90.0D)) * 90, 360); + return new ModelElementTexture(new float[]{p, t, q, u}, w); + } + + private int[] packVertexData(ModelElementTexture texture, Sprite sprite, Direction direction, float[] positionMatrix, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { + int[] is = new int[32]; + + for(int i = 0; i < 4; ++i) { + this.packVertexData(is, i, direction, texture, positionMatrix, sprite, orientation, rotation, shaded); + } + + return is; + } + + private float[] getPositionMatrix(Vector3f from, Vector3f to) { + float[] fs = new float[Direction.values().length]; + fs[CubeFace.DirectionIds.EAST] = from.z() / 16.0F; + fs[CubeFace.DirectionIds.DOWN] = from.y() / 16.0F; + fs[CubeFace.DirectionIds.NORTH] = from.x() / 16.0F; + fs[CubeFace.DirectionIds.WEST] = to.z() / 16.0F; + fs[CubeFace.DirectionIds.UP] = to.y() / 16.0F; + fs[CubeFace.DirectionIds.SOUTH] = to.x() / 16.0F; + return fs; + } + + private void packVertexData(int[] vertices, int cornerIndex, Direction direction, ModelElementTexture texture, float[] positionMatrix, Sprite sprite, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { + CubeFace.Corner corner = CubeFace.getFace(direction).getCorner(cornerIndex); + Vector3f vector3f = new Vector3f(positionMatrix[corner.xSide], positionMatrix[corner.ySide], positionMatrix[corner.zSide]); + this.rotateVertex(vector3f, rotation); + this.transformVertex(vector3f, orientation); + this.packVertexData(vertices, cornerIndex, vector3f, sprite, texture); + } + + private void packVertexData(int[] vertices, int cornerIndex, Vector3f position, Sprite sprite, ModelElementTexture modelElementTexture) { + int i = cornerIndex * 8; + vertices[i] = Float.floatToRawIntBits(position.x()); + vertices[i + 1] = Float.floatToRawIntBits(position.y()); + vertices[i + 2] = Float.floatToRawIntBits(position.z()); +// vertices[i + 3] = -1; + vertices[i + 3] = Float.floatToRawIntBits(sprite.getFrameU(modelElementTexture.getU(cornerIndex))); + vertices[i + 3 + 1] = Float.floatToRawIntBits(sprite.getFrameV(modelElementTexture.getV(cornerIndex))); + } + + private void rotateVertex(Vector3f vector, @Nullable ModelRotation rotation) { + if (rotation != null) { + Vector3f axis; + Vector3f scale; + switch (rotation.axis()) { + case X -> { + axis = new Vector3f(1.0F, 0.0F, 0.0F); + scale = new Vector3f(0.0F, 1.0F, 1.0F); + } + case Y -> { + axis = new Vector3f(0.0F, 1.0F, 0.0F); + scale = new Vector3f(1.0F, 0.0F, 1.0F); + } + case Z -> { + axis = new Vector3f(0.0F, 0.0F, 1.0F); + scale = new Vector3f(1.0F, 1.0F, 0.0F); + } + default -> throw new IllegalArgumentException("There are only 3 axes"); + } + + Quaternionf quaternion = (new Quaternionf()).rotationAxis(rotation.angle() * ((float)Math.PI / 180F), axis); + if (rotation.rescale()) { + if (Math.abs(rotation.angle()) == 22.5F) { + scale.mul(MIN_SCALE); + } else { + scale.mul(MAX_SCALE); + } + + scale.add(1.0F, 1.0F, 1.0F); + } else { + scale.set(1.0F, 1.0F, 1.0F); + } + + this.transformVertex(vector, new Vector3f(rotation.origin()), new Matrix4f().rotation(quaternion), scale); + } + } + + public void transformVertex(Vector3f vertex, AffineTransformation transformation) { + if (transformation != AffineTransformation.identity()) { + this.transformVertex(vertex, new Vector3f(0.5F, 0.5F, 0.5F), transformation.getMatrix(), new Vector3f(1.0F, 1.0F, 1.0F)); + } + } + + private void transformVertex(Vector3f vertex, Vector3fc origin, Matrix4fc transformationMatrix, Vector3fc scale) { + Vector4f vector4f = transformationMatrix.transform(new Vector4f(vertex.x() - origin.x(), vertex.y() - origin.y(), vertex.z() - origin.z(), 1.0F)); + vector4f.mul(new Vector4f(scale, 1)); + vertex.set(vector4f.x() + origin.x(), vector4f.y() + origin.y(), vector4f.z() + origin.z()); + } + + private static Direction decodeDirection(int[] rotationMatrix) { + Vector3f vector3f = bakeVectors(rotationMatrix, 0); + Vector3f vector3f2 = bakeVectors(rotationMatrix, 8); + Vector3f vector3f3 = bakeVectors(rotationMatrix, 16); + Vector3f vector3f4 = (new Vector3f(vector3f)).sub(vector3f2); + Vector3f vector3f5 = (new Vector3f(vector3f3)).sub(vector3f2); + Vector3f vector3f6 = (new Vector3f(vector3f5)).cross(vector3f4).normalize(); + if (!vector3f6.isFinite()) { + return Direction.UP; + } else { + Direction direction = null; + float f = 0.0F; + + for(Direction direction2 : Direction.values()) { + float g = vector3f6.dot(direction2.getFloatVector()); + if (g >= 0.0F && g > f) { + f = g; + direction = direction2; + } + } + + if (direction == null) { + return Direction.UP; + } else { + return direction; + } + } + } + + private static float bakeVectorX(int[] is, int i) { + return Float.intBitsToFloat(is[i]); + } + + private static float bakeVectorY(int[] is, int i) { + return Float.intBitsToFloat(is[i + 1]); + } + + private static float bakeVectorZ(int[] is, int i) { + return Float.intBitsToFloat(is[i + 2]); + } + + private static Vector3f bakeVectors(int[] is, int i) { + return new Vector3f(bakeVectorX(is, i), bakeVectorY(is, i), bakeVectorZ(is, i)); + } + + private static void encodeDirection(int[] rotationMatrix, Direction direction) { + int[] is = new int[rotationMatrix.length]; + System.arraycopy(rotationMatrix, 0, is, 0, rotationMatrix.length); + float[] fs = new float[Direction.values().length]; + fs[CubeFace.DirectionIds.WEST] = 999.0F; + fs[CubeFace.DirectionIds.DOWN] = 999.0F; + fs[CubeFace.DirectionIds.NORTH] = 999.0F; + fs[CubeFace.DirectionIds.EAST] = -999.0F; + fs[CubeFace.DirectionIds.UP] = -999.0F; + fs[CubeFace.DirectionIds.SOUTH] = -999.0F; + + for(int i = 0; i < 4; ++i) { + int j = 8 * i; + float f = bakeVectorX(is, j); + float g = bakeVectorY(is, j); + float h = bakeVectorZ(is, j); + if (f < fs[CubeFace.DirectionIds.WEST]) { + fs[CubeFace.DirectionIds.WEST] = f; + } + + if (g < fs[CubeFace.DirectionIds.DOWN]) { + fs[CubeFace.DirectionIds.DOWN] = g; + } + + if (h < fs[CubeFace.DirectionIds.NORTH]) { + fs[CubeFace.DirectionIds.NORTH] = h; + } + + if (f > fs[CubeFace.DirectionIds.EAST]) { + fs[CubeFace.DirectionIds.EAST] = f; + } + + if (g > fs[CubeFace.DirectionIds.UP]) { + fs[CubeFace.DirectionIds.UP] = g; + } + + if (h > fs[CubeFace.DirectionIds.SOUTH]) { + fs[CubeFace.DirectionIds.SOUTH] = h; + } + } + + CubeFace cubeFace = CubeFace.getFace(direction); + + for(int j = 0; j < 4; ++j) { + int k = 8 * j; + CubeFace.Corner corner = cubeFace.getCorner(j); + float h = fs[corner.xSide]; + float l = fs[corner.ySide]; + float m = fs[corner.zSide]; + rotationMatrix[k] = Float.floatToRawIntBits(h); + rotationMatrix[k + 1] = Float.floatToRawIntBits(l); + rotationMatrix[k + 2] = Float.floatToRawIntBits(m); + + for(int n = 0; n < 4; ++n) { + int o = 8 * n; + float p = bakeVectorX(is, o); + float q = bakeVectorY(is, o); + float r = bakeVectorZ(is, o); + if (MathHelper.approximatelyEquals(h, p) && MathHelper.approximatelyEquals(l, q) && MathHelper.approximatelyEquals(m, r)) { + rotationMatrix[k + 4] = is[o + 4]; + rotationMatrix[k + 4 + 1] = is[o + 4 + 1]; + } + } + } + + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/Baker.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/Baker.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/Baker.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/Baker.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java similarity index 94% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java index 4dd96054f..4764e6370 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModelGenerator.java @@ -12,7 +12,7 @@ import net.modificationstation.stationapi.api.client.texture.SpriteContents; import net.modificationstation.stationapi.api.client.texture.SpriteIdentifier; import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; +import org.joml.Vector3f; import java.util.*; import java.util.function.Function; @@ -55,7 +55,7 @@ private List addLayerElements(int layer, String key, Sprite sprite Map map = new EnumMap<>(Direction.class); map.put(Direction.WEST, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { 0.0F, 0.0F, 16.0F, 16.0F }, 0, animationFrameDelta))); map.put(Direction.EAST, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { 16.0F, 0.0F, 0.0F, 16.0F }, 0, animationFrameDelta))); - elements.add(new ModelElement(new Vec3f(0.0F, 0.0F, 7.5F), new Vec3f(16.0F, 16.0F, 8.5F), map, null, true)); + elements.add(new ModelElement(new Vector3f(0.0F, 0.0F, 7.5F), new Vector3f(16.0F, 16.0F, 8.5F), map, null, true)); int first1 = -1; int first2 = -1; @@ -132,13 +132,13 @@ private List addLayerElements(int layer, String key, Sprite sprite private static ModelElement createHorizontalOutlineElement(Direction direction, int layer, String key, int start, int end, int y, int height, float animationFrameDelta, float xFactor, float yFactor) { Map faces = new EnumMap<>(Direction.class); faces.put(direction, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { start / xFactor, y / yFactor, (end + 1) / xFactor, (y + 1) / yFactor }, 0, animationFrameDelta))); - return new ModelElement(new Vec3f(start / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vec3f((end + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true); + return new ModelElement(new Vector3f(start / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vector3f((end + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true); } private static ModelElement createVerticalOutlineElement(Direction direction, int layer, String key, int start, int end, int x, int height, float animationFrameDelta, float xFactor, float yFactor) { Map faces = new EnumMap<>(Direction.class); faces.put(direction, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { (x + 1) / xFactor, start / yFactor, x / xFactor, (end + 1) / yFactor }, 0, animationFrameDelta))); - return new ModelElement(new Vec3f(x / xFactor, (height - (end + 1)) / yFactor, 7.5F), new Vec3f((x + 1) / xFactor, (height - start) / yFactor, 8.5F), faces, null, true); + return new ModelElement(new Vector3f(x / xFactor, (height - (end + 1)) / yFactor, 7.5F), new Vector3f((x + 1) / xFactor, (height - start) / yFactor, 8.5F), faces, null, true); } private static ModelElementTexture createUnlerpedTexture(float[] uvs, @SuppressWarnings("SameParameterValue") int rotation, float delta) { diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java similarity index 85% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java index 244383601..c5deda8c5 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeRotation.java @@ -4,8 +4,7 @@ import net.fabricmc.api.Environment; import net.modificationstation.stationapi.api.util.math.AffineTransformation; import net.modificationstation.stationapi.api.util.math.DirectionTransformation; -import net.modificationstation.stationapi.api.util.math.Quaternion; -import net.modificationstation.stationapi.api.util.math.Vec3f; +import org.joml.Quaternionf; import java.util.Arrays; import java.util.Map; @@ -41,8 +40,7 @@ private static int getIndex(int x, int y) { ModelBakeRotation(int x, int y) { this.index = getIndex(x, y); - Quaternion quaternion = new Quaternion(new Vec3f(0.0F, 1.0F, 0.0F), (float) (-y), true); - quaternion.hamiltonProduct(new Quaternion(new Vec3f(1.0F, 0.0F, 0.0F), (float) (-x), true)); + Quaternionf quaternionf = new Quaternionf().rotateYXZ((float)(-y) * (float) (Math.PI / 180.0), (float)(-x) * (float) (Math.PI / 180.0), 0.0F); DirectionTransformation directionTransformation = DirectionTransformation.IDENTITY; int k; @@ -54,7 +52,7 @@ private static int getIndex(int x, int y) { directionTransformation = directionTransformation.prepend(DirectionTransformation.ROT_90_X_NEG); } - this.rotation = new AffineTransformation(null, quaternion, null, null); + this.rotation = new AffineTransformation(null, quaternionf, null, null); this.directionTransformation = directionTransformation; } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeSettings.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeSettings.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeSettings.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelBakeSettings.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelIdentifier.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelIdentifier.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelIdentifier.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelIdentifier.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelLoader.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelLoader.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelLoader.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelLoader.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java similarity index 59% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java index 44b844e8c..3866a9773 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelRotation.java @@ -3,7 +3,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; +import org.joml.Vector3f; @Environment(EnvType.CLIENT) -public record ModelRotation(Vec3f origin, Direction.Axis axis, float angle, boolean rescale) { } +public record ModelRotation(Vector3f origin, Direction.Axis axis, float angle, boolean rescale) { } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartModelSelector.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartModelSelector.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartModelSelector.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartModelSelector.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/OrMultipartModelSelector.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/OrMultipartModelSelector.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/OrMultipartModelSelector.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/OrMultipartModelSelector.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SimpleMultipartModelSelector.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SimpleMultipartModelSelector.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SimpleMultipartModelSelector.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SimpleMultipartModelSelector.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteAtlasManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteAtlasManager.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteAtlasManager.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteAtlasManager.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/UnbakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/UnbakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/UnbakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/UnbakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java similarity index 98% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java index ebe10b9d7..9a75f890a 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java @@ -149,7 +149,7 @@ public BakedModel bake(Baker baker, JsonUnbakedModel parent, Function resolveReference(Identifier id, if (JsonUnbakedModel.isTextureReference(name)) return Either.right(name.substring(1)); else { Identifier identifier = Identifier.tryParse(name); - if (identifier == null) throw new JsonParseException(name + " is not valid resource location"); + if (identifier == null) throw new JsonParseException(name + " is not valid resourceId location"); else return Either.left(SpriteIdentifier.of(id, identifier)); } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java similarity index 74% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java index 79a43a1ed..8d355e32c 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElement.java @@ -7,8 +7,8 @@ import net.modificationstation.stationapi.api.client.render.model.ModelRotation; import net.modificationstation.stationapi.api.util.JsonHelper; import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Vec3f; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; import java.lang.reflect.Type; import java.util.EnumMap; @@ -18,13 +18,13 @@ @Environment(EnvType.CLIENT) public class ModelElement { - public final Vec3f from; - public final Vec3f to; + public final Vector3f from; + public final Vector3f to; public final Map faces; public final ModelRotation rotation; public final boolean shade; - public ModelElement(Vec3f from, Vec3f to, Map faces, @Nullable ModelRotation rotation, boolean shade) { + public ModelElement(Vector3f from, Vector3f to, Map faces, @Nullable ModelRotation rotation, boolean shade) { this.from = from; this.to = to; this.faces = faces; @@ -42,12 +42,12 @@ private void initTextures() { private float[] getRotatedMatrix(Direction direction) { return switch (direction) { - case DOWN -> new float[] { from.getX(), 16 - to.getZ(), to.getX(), 16 - from.getZ() }; - case UP -> new float[] { from.getX(), from.getZ(), to.getX(), to.getZ() }; - case NORTH -> new float[] { 16 - to.getX(), 16 - to.getY(), 16 - from.getX(), 16 - from.getY() }; - case SOUTH -> new float[] { from.getX(), 16 - to.getY(), to.getX(), 16 - from.getY() }; - case WEST -> new float[] { from.getZ(), 16 - to.getY(), to.getZ(), 16 - from.getY() }; - case EAST -> new float[] { 16 - to.getZ(), 16 - to.getY(), 16 - from.getZ(), 16 - from.getY() }; + case DOWN -> new float[] { from.x(), 16 - to.z(), to.x(), 16 - from.z() }; + case UP -> new float[] { from.x(), from.z(), to.x(), to.z() }; + case NORTH -> new float[] { 16 - to.x(), 16 - to.y(), 16 - from.x(), 16 - from.y() }; + case SOUTH -> new float[] { from.x(), 16 - to.y(), to.x(), 16 - from.y() }; + case WEST -> new float[] { from.z(), 16 - to.y(), to.z(), 16 - from.y() }; + case EAST -> new float[] { 16 - to.z(), 16 - to.y(), 16 - from.z(), 16 - from.y() }; }; } @@ -58,8 +58,8 @@ protected Deserializer() { public ModelElement deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { JsonObject jsonObject = jsonElement.getAsJsonObject(); - Vec3f vec3f = this.deserializeFrom(jsonObject); - Vec3f vec3f1 = this.deserializeTo(jsonObject); + Vector3f vec3f = this.deserializeFrom(jsonObject); + Vector3f vec3f1 = this.deserializeTo(jsonObject); ModelRotation modelRotation = this.deserializeRotation(jsonObject); Map map = this.deserializeFacesValidating(jsonDeserializationContext, jsonObject); if (jsonObject.has("shade") && !JsonHelper.hasBoolean(jsonObject, "shade")) @@ -75,8 +75,8 @@ private ModelRotation deserializeRotation(JsonObject object) { ModelRotation modelRotation = null; if (object.has("rotation")) { JsonObject jsonObject = JsonHelper.getObject(object, "rotation"); - Vec3f vec3f = this.deserializeVec3f(jsonObject, "origin"); - vec3f.scale(0.0625F); + Vector3f vec3f = this.deserializeVec3f(jsonObject, "origin"); + vec3f.mul(0.0625F); Direction.Axis axis = this.deserializeAxis(jsonObject); float f = this.deserializeRotationAngle(jsonObject); boolean bl = JsonHelper.getBoolean(jsonObject, "rescale", false); @@ -119,26 +119,26 @@ private Map deserializeFaces(JsonDeserializationCon } private Direction getDirection(String name) { - Direction direction = Direction.byName(name).rotateClockwise(Direction.Axis.Y); + Direction direction = Direction.byId(name).rotateClockwise(Direction.Axis.Y); if (direction == null) throw new JsonParseException("Unknown facing: " + name); else return direction; } - private Vec3f deserializeTo(JsonObject object) { - Vec3f Vec3f = this.deserializeVec3f(object, "to"); - if (Vec3f.getX() >= -16.0F && Vec3f.getY() >= -16.0F && Vec3f.getZ() >= -16.0F && Vec3f.getX() <= 32.0F && Vec3f.getY() <= 32.0F && Vec3f.getZ() <= 32.0F) + private Vector3f deserializeTo(JsonObject object) { + Vector3f Vec3f = this.deserializeVec3f(object, "to"); + if (Vec3f.x() >= -16.0F && Vec3f.y() >= -16.0F && Vec3f.z() >= -16.0F && Vec3f.x() <= 32.0F && Vec3f.y() <= 32.0F && Vec3f.z() <= 32.0F) return Vec3f; else throw new JsonParseException("'to' specifier exceeds the allowed boundaries: " + Vec3f); } - private Vec3f deserializeFrom(JsonObject object) { - Vec3f Vec3f = this.deserializeVec3f(object, "from"); - if (Vec3f.getX() >= -16.0F && Vec3f.getY() >= -16.0F && Vec3f.getZ() >= -16.0F && Vec3f.getX() <= 32.0F && Vec3f.getY() <= 32.0F && Vec3f.getZ() <= 32.0F) + private Vector3f deserializeFrom(JsonObject object) { + Vector3f Vec3f = this.deserializeVec3f(object, "from"); + if (Vec3f.x() >= -16.0F && Vec3f.y() >= -16.0F && Vec3f.z() >= -16.0F && Vec3f.x() <= 32.0F && Vec3f.y() <= 32.0F && Vec3f.z() <= 32.0F) return Vec3f; else throw new JsonParseException("'from' specifier exceeds the allowed boundaries: " + Vec3f); } - private Vec3f deserializeVec3f(JsonObject object, String name) { + private Vector3f deserializeVec3f(JsonObject object, String name) { JsonArray jsonArray = JsonHelper.getArray(object, name); if (jsonArray.size() != 3) throw new JsonParseException("Expected 3 " + name + " values, found: " + jsonArray.size()); @@ -148,7 +148,7 @@ private Vec3f deserializeVec3f(JsonObject object, String name) { for(int i = 0; i < fs.length; ++i) fs[i] = JsonHelper.asFloat(jsonArray.get(i), name + "[" + i + "]"); // modern has x and z swapped - return new Vec3f(fs[0], fs[1], fs[2]); + return new Vector3f(fs[0], fs[1], fs[2]); } } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java similarity index 95% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java index 3ec7fa933..23bd41bca 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementFace.java @@ -42,7 +42,7 @@ public ModelElementFace deserialize(JsonElement jsonElement, Type type, JsonDese int i = this.deserializeTintIndex(jsonObject); String string = this.deserializeTexture(jsonObject); ModelElementTexture modelElementTexture = jsonDeserializationContext.deserialize(jsonObject, ModelElementTexture.class); - float emission = JsonHelper.getFloat(jsonObject, "emission", 0F); + float emission = JsonHelper.getFloat(jsonObject, "lightEmission", 0F); emission = MathHelper.clamp(emission, 0F, 1F); return new ModelElementFace(direction, i, string, modelElementTexture, emission); } @@ -58,7 +58,7 @@ private String deserializeTexture(JsonObject object) { @Nullable private Direction deserializeCullFace(JsonObject object) { String string = JsonHelper.getString(object, "cullface", ""); - return Direction.byName(string); + return Direction.byId(string); } } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelElementTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverride.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverride.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverride.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverride.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelTransformation.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelTransformation.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelTransformation.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelTransformation.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariant.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariant.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariant.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariant.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariantMap.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariantMap.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariantMap.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelVariantMap.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartModelComponent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartModelComponent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartModelComponent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartModelComponent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartUnbakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartUnbakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartUnbakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/MultipartUnbakedModel.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java new file mode 100644 index 000000000..53936357f --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/Transformation.java @@ -0,0 +1,111 @@ +package net.modificationstation.stationapi.api.client.render.model.json; + +import com.google.gson.*; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.util.JsonHelper; +import net.modificationstation.stationapi.api.util.math.MathHelper; +import net.modificationstation.stationapi.api.util.math.MatrixStack; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.lwjgl.opengl.GL11; + +import java.lang.reflect.Type; + +@Environment(EnvType.CLIENT) +public class Transformation { + public static final Transformation IDENTITY = new Transformation(new Vector3f(), new Vector3f(), new Vector3f(1.0F, 1.0F, 1.0F)); + public final Vector3f rotation; + public final Vector3f translation; + public final Vector3f scale; + + public Transformation(Vector3f rotation, Vector3f translation, Vector3f scale) { + this.rotation = new Vector3f(rotation); + this.translation = new Vector3f(translation); + this.scale = new Vector3f(scale); + } + + public void apply() { + if (this != IDENTITY) { + float f = this.rotation.x(); + float g = this.rotation.y(); + float h = this.rotation.z(); + + GL11.glTranslatef(this.translation.x(), this.translation.y(), this.translation.z()); + GL11.glRotatef(f, 1, 0, 0); + GL11.glRotatef(g, 0, 1, 0); + GL11.glRotatef(h, 0, 0, 1); + GL11.glScalef(this.scale.x(), this.scale.y(), this.scale.z()); + } + } + + public void apply(MatrixStack matrices) { + if (this != IDENTITY) { + float f = this.rotation.x(); + float g = this.rotation.y(); + float h = this.rotation.z(); + + matrices.translate(this.translation.x(), this.translation.y(), this.translation.z()); + matrices.multiply(new Quaternionf().rotationXYZ(f * (float) (Math.PI / 180.0), g * (float) (Math.PI / 180.0), h * (float) (Math.PI / 180.0))); + matrices.scale(this.scale.x(), this.scale.y(), this.scale.z()); + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (this.getClass() != o.getClass()) { + return false; + } else { + Transformation transformation = (Transformation)o; + return this.rotation.equals(transformation.rotation) && this.scale.equals(transformation.scale) && this.translation.equals(transformation.translation); + } + } + + public int hashCode() { + int i = this.rotation.hashCode(); + i = 31 * i + this.translation.hashCode(); + i = 31 * i + this.scale.hashCode(); + return i; + } + + @Environment(EnvType.CLIENT) + public static class Deserializer implements JsonDeserializer { + private static final Vector3f DEFAULT_ROTATION = new Vector3f(0.0F, 0.0F, 0.0F); + private static final Vector3f DEFAULT_TRANSLATION = new Vector3f(0.0F, 0.0F, 0.0F); + private static final Vector3f DEFAULT_SCALE = new Vector3f(1.0F, 1.0F, 1.0F); + + protected Deserializer() { + } + + public Transformation deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + Vector3f vector3f = this.parseVector3f(jsonObject, "rotation", DEFAULT_ROTATION); + Vector3f vector3f2 = this.parseVector3f(jsonObject, "translation", DEFAULT_TRANSLATION); + vector3f2.mul(0.0625F); + vector3f2.set(MathHelper.clamp(vector3f2.x, -5.0F, 5.0F), MathHelper.clamp(vector3f2.y, -5.0F, 5.0F), MathHelper.clamp(vector3f2.z, -5.0F, 5.0F)); + Vector3f vector3f3 = this.parseVector3f(jsonObject, "scale", DEFAULT_SCALE); + vector3f3.set(MathHelper.clamp(vector3f3.x, -4.0F, 4.0F), MathHelper.clamp(vector3f3.y, -4.0F, 4.0F), MathHelper.clamp(vector3f3.z, -4.0F, 4.0F)); + return new Transformation(vector3f, vector3f2, vector3f3); + } + + private Vector3f parseVector3f(JsonObject json, String key, Vector3f fallback) { + if (!json.has(key)) { + return fallback; + } else { + JsonArray jsonArray = JsonHelper.getArray(json, key); + if (jsonArray.size() != 3) { + throw new JsonParseException("Expected 3 " + key + " values, found: " + jsonArray.size()); + } else { + float[] fs = new float[3]; + + for(int i = 0; i < fs.length; ++i) { + fs[i] = JsonHelper.asFloat(jsonArray.get(i), key + "[" + i + "]"); + } + + return new Vector3f(fs[0], fs[1], fs[2]); + } + } + } + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/WeightedUnbakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/WeightedUnbakedModel.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/WeightedUnbakedModel.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/WeightedUnbakedModel.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationFrameResourceMetadata.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationFrameResourceMetadata.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationFrameResourceMetadata.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationFrameResourceMetadata.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadata.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadata.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadata.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadata.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadataReader.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadataReader.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadataReader.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/AnimationResourceMetadataReader.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadata.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadata.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadata.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadata.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadataReader.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadataReader.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadataReader.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/resource/metadata/TextureResourceMetadataReader.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/Animator.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/Animator.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/Animator.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/Animator.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/DynamicTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/DynamicTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/DynamicTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/DynamicTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/MissingSprite.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/MissingSprite.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/MissingSprite.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/MissingSprite.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImage.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImage.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImage.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImage.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/ResourceTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/ResourceTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/ResourceTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/ResourceTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/Sprite.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/Sprite.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/Sprite.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/Sprite.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteAtlasTexture.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java similarity index 97% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java index 08e021147..65c90e478 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java @@ -53,11 +53,11 @@ private Animation createAnimation(SpriteDimensions dimensions, int imageWidth, i AnimationFrame animationFrame = iterator.next(); boolean bl = true; if (animationFrame.time <= 0) { - LOGGER.warn("Invalid frame duration on sprite {} frame {}: {}", id, l, animationFrame.time); + LOGGER.warn("Invalid frame duration on spriteId {} frame {}: {}", id, l, animationFrame.time); bl = false; } if (animationFrame.index < 0 || animationFrame.index >= k) { - LOGGER.warn("Invalid frame index on sprite {} frame {}: {}", id, l, animationFrame.index); + LOGGER.warn("Invalid frame index on spriteId {} frame {}: {}", id, l, animationFrame.index); bl = false; } if (bl) intSet.add(animationFrame.index); @@ -66,7 +66,7 @@ private Animation createAnimation(SpriteDimensions dimensions, int imageWidth, i } int[] is = IntStream.range(0, k).filter(i -> !intSet.contains(i)).toArray(); if (is.length > 0) - LOGGER.warn("Unused frames in sprite {}: {}", id, Arrays.toString(is)); + LOGGER.warn("Unused frames in spriteId {}: {}", id, Arrays.toString(is)); } if (list.size() <= 1) return null; return new Animation(ImmutableList.copyOf(list), i2, metadata.shouldInterpolate()); diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteDimensions.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteDimensions.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteDimensions.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteDimensions.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteIdentifier.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteIdentifier.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteIdentifier.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteIdentifier.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteLoader.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteLoader.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteLoader.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteLoader.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpritesheetHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpritesheetHelper.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/SpritesheetHelper.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpritesheetHelper.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/StationTextureManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/StationTextureManager.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/StationTextureManager.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/StationTextureManager.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureHelper.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureHelper.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureHelper.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TexturePackDependent.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TexturePackDependent.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TexturePackDependent.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TexturePackDependent.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcher.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcher.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcher.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcher.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcherCannotFitException.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcherCannotFitException.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcherCannotFitException.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureStitcherCannotFitException.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureTickListener.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureTickListener.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureTickListener.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureTickListener.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureUtil.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureUtil.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureUtil.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/TextureUtil.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlas.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlas.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlas.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlas.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java similarity index 98% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java index 95829cc17..bc48b7193 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasLoader.java @@ -64,7 +64,7 @@ public static AtlasLoader of(ResourceManager resourceManager, Identifier id) { ArrayList list = new ArrayList<>(); for (Resource resource : resourceManager.getAllResources(identifier)) try (BufferedReader bufferedReader = resource.getReader()) { - list.addAll(AtlasSourceManager.LIST_CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, JsonParser.parseReader(bufferedReader))).getOrThrow(false, LOGGER::error)); + list.addAll(AtlasSourceManager.LIST_CODEC.parse(new Dynamic<>(JsonOps.INSTANCE, JsonParser.parseReader(bufferedReader))).getOrThrow()); } catch (Exception exception) { LOGGER.warn("Failed to parse atlas definition {} in pack {}", identifier, "Default", exception); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java similarity index 93% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java index fe35cf09c..c234a8dd0 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSource.java @@ -1,5 +1,6 @@ package net.modificationstation.stationapi.api.client.texture.atlas; +import com.mojang.serialization.MapCodec; import net.modificationstation.stationapi.api.client.texture.SpriteContents; import net.modificationstation.stationapi.api.client.texture.SpriteLoader; import net.modificationstation.stationapi.api.util.Identifier; @@ -17,7 +18,7 @@ public interface AtlasSource { void load(ResourceManager var1, SpriteRegions var2); - AtlasSourceType getType(); + MapCodec getCodec(); interface SpriteRegion extends Supplier { default void close() {} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java new file mode 100644 index 000000000..d4893c3c4 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/AtlasSourceManager.java @@ -0,0 +1,33 @@ +package net.modificationstation.stationapi.api.client.texture.atlas; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.util.dynamic.Codecs; + +import java.util.List; + +public class AtlasSourceManager { + private static final Codecs.IdMapper> ID_MAPPER = new Codecs.IdMapper<>(); + + public static final Codec TYPE_CODEC = ID_MAPPER.getCodec(Identifier.CODEC).dispatch(AtlasSource::getCodec, codec -> codec); + public static Codec> LIST_CODEC = TYPE_CODEC.listOf().fieldOf("sources").codec(); + + private static MapCodec register(String id, MapCodec codec) { + Identifier identifier = Identifier.of(id); + MapCodec last = ID_MAPPER.putIfAbsent(identifier, codec); + if (last != null) { + throw new IllegalStateException("Duplicate registration " + identifier); + } + return codec; + } + + static { + AtlasSourceManager.register("single", SingleAtlasSource.CODEC); + AtlasSourceManager.register("directory", DirectoryAtlasSource.CODEC); + AtlasSourceManager.register("filter", FilterAtlasSource.CODEC); + AtlasSourceManager.register("unstitch", UnstitchAtlasSource.CODEC); + AtlasSourceManager.register("paletted_permutations", PalettedPermutationsAtlasSource.CODEC); + } +} + diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlases.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlases.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlases.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Atlases.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/CustomAtlasProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/CustomAtlasProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/CustomAtlasProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/CustomAtlasProvider.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java new file mode 100644 index 000000000..f5e446c32 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/DirectoryAtlasSource.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.api.client.texture.atlas; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.modificationstation.stationapi.api.resource.ResourceFinder; +import net.modificationstation.stationapi.api.resource.ResourceManager; + +import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; + +public record DirectoryAtlasSource(String sourcePath, String idPrefix) implements AtlasSource { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(Codec.STRING.fieldOf("source").forGetter(DirectoryAtlasSource::sourcePath), Codec.STRING.fieldOf("prefix").forGetter(DirectoryAtlasSource::idPrefix)).apply(instance, DirectoryAtlasSource::new)); + + @Override + public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { + ResourceFinder resourceFinder = new ResourceFinder(NAMESPACE + "/textures/" + this.sourcePath, ".png"); + resourceFinder.findResources(resourceManager).forEach((identifier, resource) -> regions.add(resourceFinder.toResourceId(identifier).withPrefixedPath(this.idPrefix), resource)); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} + diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/ExpandableAtlas.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/ExpandableAtlas.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/ExpandableAtlas.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/ExpandableAtlas.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java new file mode 100644 index 000000000..30b5231b7 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/FilterAtlasSource.java @@ -0,0 +1,21 @@ +package net.modificationstation.stationapi.api.client.texture.atlas; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.modificationstation.stationapi.api.resource.ResourceManager; +import net.modificationstation.stationapi.api.resource.metadata.BlockEntry; + +public record FilterAtlasSource(BlockEntry pattern) implements AtlasSource { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(BlockEntry.CODEC.fieldOf("pattern").forGetter(FilterAtlasSource::pattern)).apply(instance, FilterAtlasSource::new)); + + @Override + public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { + regions.removeIf(this.pattern.getIdentifierPredicate()); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} + diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java similarity index 64% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java index 11f5b94fb..a4b24329d 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/PalettedPermutationsAtlasSource.java @@ -3,6 +3,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import net.modificationstation.stationapi.api.client.resource.metadata.AnimationResourceMetadata; @@ -25,23 +26,22 @@ import static net.modificationstation.stationapi.impl.client.texture.StationRenderImpl.LOGGER; -public class PalettedPermutationsAtlasSource implements AtlasSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(Codec.list(Identifier.CODEC).fieldOf("textures").forGetter(palettedPermutationsAtlasSource -> palettedPermutationsAtlasSource.textures), Identifier.CODEC.fieldOf("palette_key").forGetter(palettedPermutationsAtlasSource -> palettedPermutationsAtlasSource.paletteKey), Codec.unboundedMap(Codec.STRING, Identifier.CODEC).fieldOf("permutations").forGetter(palettedPermutationsAtlasSource -> palettedPermutationsAtlasSource.permutations)).apply(instance, PalettedPermutationsAtlasSource::new)); - private final List textures; - private final Map permutations; - private final Identifier paletteKey; - - private PalettedPermutationsAtlasSource(List textures, Identifier paletteKey, Map permutations) { - this.textures = textures; - this.permutations = permutations; - this.paletteKey = paletteKey; - } +public record PalettedPermutationsAtlasSource(List textures, Identifier paletteKey, Map permutations, String separator) implements AtlasSource { + public static final String DEFAULT_SEPARATOR = "_"; + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + Codec.list(Identifier.CODEC).fieldOf("textures").forGetter(PalettedPermutationsAtlasSource::textures), + Identifier.CODEC.fieldOf("palette_key").forGetter(PalettedPermutationsAtlasSource::paletteKey), + Codec.unboundedMap(Codec.STRING, Identifier.CODEC).fieldOf("permutations").forGetter(PalettedPermutationsAtlasSource::permutations), + Codec.STRING.optionalFieldOf("separator", DEFAULT_SEPARATOR).forGetter(PalettedPermutationsAtlasSource::separator) + ).apply(instance, PalettedPermutationsAtlasSource::new) + ); @Override public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { - Supplier supplier = Suppliers.memoize(() -> PalettedPermutationsAtlasSource.method_48486(resourceManager, this.paletteKey)); + Supplier supplier = Suppliers.memoize(() -> PalettedPermutationsAtlasSource.open(resourceManager, this.paletteKey)); Map> map = new HashMap<>(); - this.permutations.forEach((string, identifier) -> map.put(string, Suppliers.memoize(() -> PalettedPermutationsAtlasSource.method_48492(supplier.get(), PalettedPermutationsAtlasSource.method_48486(resourceManager, identifier))))); + this.permutations.forEach((string, identifier) -> map.put(string, Suppliers.memoize(() -> PalettedPermutationsAtlasSource.toMapper(supplier.get(), PalettedPermutationsAtlasSource.open(resourceManager, identifier))))); for (Identifier identifier2 : this.textures) { Identifier identifier22 = RESOURCE_FINDER.toResourcePath(identifier2); Optional optional = resourceManager.getResource(identifier22); @@ -51,37 +51,37 @@ public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regi } Sprite sprite = new Sprite(identifier22, optional.get(), map.size()); for (Map.Entry> entry : map.entrySet()) { - Identifier identifier3 = identifier2.withSuffixedPath("_" + entry.getKey()); + Identifier identifier3 = identifier2.withSuffixedPath(this.separator + entry.getKey()); regions.add(identifier3, new PalettedSpriteRegion(sprite, entry.getValue(), identifier3)); } } } - private static IntUnaryOperator method_48492(int[] is, int[] js) { - if (js.length != is.length) { - LOGGER.warn("Palette mapping has different sizes: {} and {}", is.length, js.length); + private static IntUnaryOperator toMapper(int[] from, int[] to) { + if (to.length != from.length) { + LOGGER.warn("Palette mapping has different sizes: {} and {}", from.length, to.length); throw new IllegalArgumentException(); } - Int2IntOpenHashMap int2IntMap = new Int2IntOpenHashMap(js.length); - for (int i2 = 0; i2 < is.length; ++i2) { - int j = is[i2]; - if (ColorHelper.Abgr.getAlpha(j) == 0) continue; - int2IntMap.put(ColorHelper.Abgr.getBgr(j), js[i2]); + Int2IntOpenHashMap int2IntMap = new Int2IntOpenHashMap(to.length); + for (int i = 0; i < from.length; ++i) { + int c = from[i]; + if (ColorHelper.Abgr.getAlpha(c) == 0) continue; + int2IntMap.put(ColorHelper.Abgr.getBgr(c), to[i]); } return i -> { - int j = ColorHelper.Abgr.getAlpha(i); - if (j == 0) return i; + int c = ColorHelper.Abgr.getAlpha(i); + if (c == 0) return i; int k = ColorHelper.Abgr.getBgr(i); int l = int2IntMap.getOrDefault(k, ColorHelper.Abgr.toOpaque(k)); int m = ColorHelper.Abgr.getAlpha(l); - return ColorHelper.Abgr.withAlpha(j * m / 255, l); + return ColorHelper.Abgr.withAlpha(c * m / 255, l); }; } - public static int[] method_48486(ResourceManager resourceManager, Identifier identifier) { - Optional optional = resourceManager.getResource(RESOURCE_FINDER.toResourcePath(identifier)); + public static int[] open(ResourceManager resourceManager, Identifier texture) { + Optional optional = resourceManager.getResource(RESOURCE_FINDER.toResourcePath(texture)); if (optional.isEmpty()) { - LOGGER.error("Failed to load palette image {}", identifier); + LOGGER.error("Failed to load palette image {}", texture); throw new IllegalArgumentException(); } try ( @@ -90,14 +90,14 @@ public static int[] method_48486(ResourceManager resourceManager, Identifier ide ) { return nativeImage.makePixelArray(); } catch (Exception exception) { - LOGGER.error("Couldn't load texture {}", identifier, exception); + LOGGER.error("Couldn't load texture {}", texture, exception); throw new IllegalArgumentException(); } } @Override - public AtlasSourceType getType() { - return AtlasSourceManager.PALETTED_PERMUTATIONS; + public MapCodec getCodec() { + return CODEC; } record PalettedSpriteRegion(Sprite baseImage, java.util.function.Supplier palette, Identifier permutationLocation) implements AtlasSource.SpriteRegion { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java new file mode 100644 index 000000000..06811271b --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java @@ -0,0 +1,29 @@ +package net.modificationstation.stationapi.api.client.texture.atlas; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.resource.Resource; +import net.modificationstation.stationapi.api.resource.ResourceManager; + +import java.util.Optional; + +import static net.modificationstation.stationapi.impl.client.texture.StationRenderImpl.LOGGER; + +public record SingleAtlasSource(Identifier resourceId, Optional spriteId) implements AtlasSource { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(Identifier.CODEC.fieldOf("resource").forGetter(singleAtlasSource -> singleAtlasSource.resourceId), Identifier.CODEC.optionalFieldOf("spriteId").forGetter(singleAtlasSource -> singleAtlasSource.spriteId)).apply(instance, SingleAtlasSource::new)); + + @Override + public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { + Identifier identifier = RESOURCE_FINDER.toResourcePath(this.resourceId); + Optional optional = resourceManager.getResource(identifier); + if (optional.isPresent()) regions.add(this.spriteId.orElse(this.resourceId), optional.get()); + else LOGGER.warn("Missing spriteId: {}", identifier); + } + + @Override + public MapCodec getCodec() { + return CODEC; + } +} + diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Sprite.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Sprite.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Sprite.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/Sprite.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java similarity index 81% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java index 988690e61..d7bf87e85 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/UnstitchAtlasSource.java @@ -1,6 +1,7 @@ package net.modificationstation.stationapi.api.client.texture.atlas; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.util.math.MathHelper; import net.modificationstation.stationapi.api.client.resource.metadata.AnimationResourceMetadata; @@ -18,24 +19,13 @@ import static net.modificationstation.stationapi.impl.client.texture.StationRenderImpl.LOGGER; -public class UnstitchAtlasSource implements AtlasSource { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Identifier.CODEC.fieldOf("resource").forGetter(unstitchAtlasSource -> unstitchAtlasSource.resource), - Codecs.nonEmptyList(Region.CODEC.listOf()).fieldOf("regions").forGetter(unstitchAtlasSource -> unstitchAtlasSource.regions), - Codec.DOUBLE.optionalFieldOf("divisor_x", 1.0).forGetter(unstitchAtlasSource -> unstitchAtlasSource.divisorX), - Codec.DOUBLE.optionalFieldOf("divisor_y", 1.0).forGetter(unstitchAtlasSource -> unstitchAtlasSource.divisorY) +public record UnstitchAtlasSource(Identifier resource, List regions, double divisorX, double divisorY) implements AtlasSource { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + Identifier.CODEC.fieldOf("resource").forGetter(UnstitchAtlasSource::resource), + Codecs.nonEmptyList(Region.CODEC.listOf()).fieldOf("regions").forGetter(UnstitchAtlasSource::regions), + Codec.DOUBLE.optionalFieldOf("divisor_x", 1.0).forGetter(UnstitchAtlasSource::divisorX), + Codec.DOUBLE.optionalFieldOf("divisor_y", 1.0).forGetter(UnstitchAtlasSource::divisorY) ).apply(instance, UnstitchAtlasSource::new)); - private final Identifier resource; - private final List regions; - private final double divisorX; - private final double divisorY; - - public UnstitchAtlasSource(Identifier resource, List regions, double divisorX, double divisorY) { - this.resource = resource; - this.regions = regions; - this.divisorX = divisorX; - this.divisorY = divisorY; - } @Override public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { @@ -49,8 +39,8 @@ public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regi } @Override - public AtlasSourceType getType() { - return AtlasSourceManager.UNSTITCH; + public MapCodec getCodec() { + return CODEC; } public record Region(Identifier sprite, double x, double y, double width, double height) { @@ -79,7 +69,7 @@ static class SpriteRegion implements AtlasSource.SpriteRegion { @Override public SpriteContents get() { try { - //noinspection resource + //noinspection resourceId NativeImage nativeImage = this.sprite.read(); double d = (double)nativeImage.getWidth() / this.divisorX; double e = (double)nativeImage.getHeight() / this.divisorY; diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StaticReferenceProvider.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StaticReferenceProvider.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StaticReferenceProvider.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StaticReferenceProvider.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StationTextureBinder.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StationTextureBinder.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StationTextureBinder.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/binder/StationTextureBinder.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/world/ColorResolver.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/world/ColorResolver.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/world/ColorResolver.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/world/ColorResolver.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/collection/WeightedPicker.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/collection/WeightedPicker.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/collection/WeightedPicker.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/collection/WeightedPicker.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java new file mode 100644 index 000000000..5613290b0 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformation.java @@ -0,0 +1,162 @@ +package net.modificationstation.stationapi.api.util.math; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.modificationstation.stationapi.api.util.Util; +import net.modificationstation.stationapi.api.util.dynamic.Codecs; +import org.apache.commons.lang3.tuple.Triple; +import org.jetbrains.annotations.Nullable; +import org.joml.*; + +import java.util.Objects; + +public final class AffineTransformation { + private final Matrix4fc matrix; + public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance.group(Codecs.VECTOR_3F.fieldOf("translation").forGetter((affineTransformation) -> affineTransformation.translation), Codecs.ROTATION.fieldOf("left_rotation").forGetter((affineTransformation) -> affineTransformation.leftRotation), Codecs.VECTOR_3F.fieldOf("scale").forGetter((affineTransformation) -> affineTransformation.scale), Codecs.ROTATION.fieldOf("right_rotation").forGetter((affineTransformation) -> affineTransformation.rightRotation)).apply(instance, AffineTransformation::new)); + public static final Codec ANY_CODEC = Codec.withAlternative(CODEC, Codecs.MATRIX_4F.xmap(AffineTransformation::new, AffineTransformation::copyMatrix)); + private boolean initialized; + @Nullable + private Vector3f translation; + @Nullable + private Quaternionf leftRotation; + @Nullable + private Vector3f scale; + @Nullable + private Quaternionf rightRotation; + private static final AffineTransformation IDENTITY = Util.make(() -> { + AffineTransformation affineTransformation = new AffineTransformation(new Matrix4f()); + affineTransformation.translation = new Vector3f(); + affineTransformation.leftRotation = new Quaternionf(); + affineTransformation.scale = new Vector3f(1.0F, 1.0F, 1.0F); + affineTransformation.rightRotation = new Quaternionf(); + affineTransformation.initialized = true; + return affineTransformation; + }); + + public AffineTransformation(@Nullable Matrix4fc matrix) { + if (matrix == null) { + this.matrix = IDENTITY.matrix; + } else { + this.matrix = matrix; + } + + } + + public AffineTransformation(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) { + this.matrix = setup(translation, leftRotation, scale, rightRotation); + this.translation = translation != null ? translation : new Vector3f(); + this.leftRotation = leftRotation != null ? leftRotation : new Quaternionf(); + this.scale = scale != null ? scale : new Vector3f(1.0F, 1.0F, 1.0F); + this.rightRotation = rightRotation != null ? rightRotation : new Quaternionf(); + this.initialized = true; + } + + public static AffineTransformation identity() { + return IDENTITY; + } + + public AffineTransformation multiply(AffineTransformation other) { + Matrix4f matrix4f = this.copyMatrix(); + matrix4f.mul(other.getMatrix()); + return new AffineTransformation(matrix4f); + } + + @Nullable + public AffineTransformation invert() { + if (this == IDENTITY) { + return this; + } else { + Matrix4f matrix4f = this.copyMatrix().invertAffine(); + return matrix4f.isFinite() ? new AffineTransformation(matrix4f) : null; + } + } + + private void init() { + if (!this.initialized) { + float scale = 1.0F / this.matrix.m33(); + Triple triple = MatrixUtil.svdDecompose(new Matrix3f(this.matrix).scale(scale)); + this.translation = this.matrix.getTranslation(new Vector3f()).mul(scale); + this.leftRotation = new Quaternionf(triple.getLeft()); + this.scale = new Vector3f(triple.getMiddle()); + this.rightRotation = new Quaternionf(triple.getRight()); + this.initialized = true; + } + + } + + private static Matrix4f setup(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) { + Matrix4f matrix4f = new Matrix4f(); + if (translation != null) { + matrix4f.translation(translation); + } + + if (leftRotation != null) { + matrix4f.rotate(leftRotation); + } + + if (scale != null) { + matrix4f.scale(scale); + } + + if (rightRotation != null) { + matrix4f.rotate(rightRotation); + } + + return matrix4f; + } + + public Matrix4fc getMatrix() { + return this.matrix; + } + + public Matrix4f copyMatrix() { + return new Matrix4f(this.matrix); + } + + public Vector3f getTranslation() { + this.init(); + return new Vector3f(this.translation); + } + + public Quaternionf getLeftRotation() { + this.init(); + return new Quaternionf(this.leftRotation); + } + + public Vector3f getScale() { + this.init(); + return new Vector3f(this.scale); + } + + public Quaternionf getRightRotation() { + this.init(); + return new Quaternionf(this.rightRotation); + } + + public boolean equals(Object object) { + if (this == object) { + return true; + } else if (object != null && this.getClass() == object.getClass()) { + AffineTransformation affineTransformation = (AffineTransformation)object; + return Objects.equals(this.matrix, affineTransformation.matrix); + } else { + return false; + } + } + + public int hashCode() { + return Objects.hash(this.matrix); + } + + public AffineTransformation interpolate(AffineTransformation target, float factor) { + Vector3f vector3f = this.getTranslation(); + Quaternionf quaternionf = this.getLeftRotation(); + Vector3f vector3f2 = this.getScale(); + Quaternionf quaternionf2 = this.getRightRotation(); + vector3f.lerp(target.getTranslation(), factor); + quaternionf.slerp(target.getLeftRotation(), factor); + vector3f2.lerp(target.getScale(), factor); + quaternionf2.slerp(target.getRightRotation(), factor); + return new AffineTransformation(vector3f, quaternionf, vector3f2, quaternionf2); + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java similarity index 76% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java index 8a479caaa..b37ff28c4 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/AffineTransformations.java @@ -6,6 +6,9 @@ import net.modificationstation.stationapi.api.util.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.util.EnumMap; import java.util.function.Supplier; @@ -15,11 +18,11 @@ public class AffineTransformations { private static final Logger LOGGER = LogManager.getLogger(); public static final EnumMap DIRECTION_ROTATIONS = Util.make(Maps.newEnumMap(Direction.class), (enumMap) -> { enumMap.put(Direction.WEST, AffineTransformation.identity()); - enumMap.put(Direction.SOUTH, new AffineTransformation(null, new Quaternion(new Vec3f(0.0F, 1.0F, 0.0F), 90.0F, true), null, null)); - enumMap.put(Direction.NORTH, new AffineTransformation(null, new Quaternion(new Vec3f(0.0F, 1.0F, 0.0F), -90.0F, true), null, null)); - enumMap.put(Direction.EAST, new AffineTransformation(null, new Quaternion(new Vec3f(0.0F, 1.0F, 0.0F), 180.0F, true), null, null)); - enumMap.put(Direction.UP, new AffineTransformation(null, new Quaternion(new Vec3f(1.0F, 0.0F, 0.0F), -90.0F, true), null, null)); - enumMap.put(Direction.DOWN, new AffineTransformation(null, new Quaternion(new Vec3f(1.0F, 0.0F, 0.0F), 90.0F, true), null, null)); + enumMap.put(Direction.SOUTH, new AffineTransformation(null, new Quaternionf().rotateY((float) (Math.PI / 2)), null, null)); + enumMap.put(Direction.NORTH, new AffineTransformation(null, new Quaternionf().rotateY((float) (-Math.PI / 2)), null, null)); + enumMap.put(Direction.EAST, new AffineTransformation(null, new Quaternionf().rotateY((float) Math.PI), null, null)); + enumMap.put(Direction.UP, new AffineTransformation(null, new Quaternionf().rotateX((float) (-Math.PI / 2)), null, null)); + enumMap.put(Direction.DOWN, new AffineTransformation(null, new Quaternionf().rotateX((float) (Math.PI / 2)), null, null)); }); public static final EnumMap INVERTED_DIRECTION_ROTATIONS = Util.make(Maps.newEnumMap(Direction.class), (enumMap) -> { Direction[] var1 = Direction.values(); @@ -31,9 +34,9 @@ public class AffineTransformations { }); public static AffineTransformation setupUvLock(AffineTransformation affineTransformation) { - Matrix4f matrix4f = Matrix4f.translate(0.5F, 0.5F, 0.5F); - matrix4f.multiply(affineTransformation.getMatrix()); - matrix4f.multiply(Matrix4f.translate(-0.5F, -0.5F, -0.5F)); + Matrix4f matrix4f = new Matrix4f().translation(0.5F, 0.5F, 0.5F); + matrix4f.mul(affineTransformation.getMatrix()); + matrix4f.translate(-0.5F, -0.5F, -0.5F); return new AffineTransformation(matrix4f); } @@ -42,7 +45,7 @@ public static AffineTransformation uvLock(AffineTransformation affineTransformat AffineTransformation affineTransformation2 = affineTransformation.invert(); if (affineTransformation2 == null) { LOGGER.warn(supplier.get()); - return new AffineTransformation(null, null, new Vec3f(0.0F, 0.0F, 0.0F), null); + return new AffineTransformation(null, null, new Vector3f(0.0F, 0.0F, 0.0F), null); } else { AffineTransformation affineTransformation3 = INVERTED_DIRECTION_ROTATIONS.get(direction).multiply(affineTransformation2).multiply(DIRECTION_ROTATIONS.get(direction2)); return setupUvLock(affineTransformation3); diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/CubeFace.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/CubeFace.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/util/math/CubeFace.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/util/math/CubeFace.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererManager.java new file mode 100644 index 000000000..775514355 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/RendererManager.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.impl.client.render; + +import net.modificationstation.stationapi.api.client.render.Renderer; + +public class RendererManager { + private static Renderer activeRenderer; + + public static void registerRenderer(Renderer renderer) { + if (renderer == null) { + throw new NullPointerException("Attempt to register a NULL rendering plug-in."); + } else if (activeRenderer != null) { + throw new UnsupportedOperationException("A second rendering plug-in attempted to register. Multiple rendering plug-ins are not supported."); + } else { + activeRenderer = renderer; + } + } + + public static Renderer getRenderer() { + if (activeRenderer == null) { + throw new UnsupportedOperationException("Attempted to retrieve active rendering plug-in before one was registered."); + } + + return activeRenderer; + } +} diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java similarity index 83% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java index b4b9c75ee..121d66def 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTessellatorImpl.java @@ -5,10 +5,10 @@ import net.modificationstation.stationapi.api.client.render.StationTessellator; import net.modificationstation.stationapi.api.client.render.model.BakedQuad; import net.modificationstation.stationapi.api.util.math.Direction; -import net.modificationstation.stationapi.api.util.math.Matrix4f; -import net.modificationstation.stationapi.api.util.math.Vec3f; -import net.modificationstation.stationapi.api.util.math.Vector4f; +import net.modificationstation.stationapi.api.util.math.RotationAxis; import net.modificationstation.stationapi.mixin.render.client.TessellatorAccessor; +import org.joml.Matrix4f; +import org.joml.Vector4f; import java.nio.ByteBuffer; import java.util.Arrays; @@ -33,7 +33,7 @@ public void quad(BakedQuad quad, float x, float y, float z, int colour0, int col byte by2 = (byte)(normalY * 127.0f); byte by3 = (byte)(normalZ * 127.0f); int normal = by | by2 << 8 | by3 << 16; - System.arraycopy(quad.getVertexData(), 0, fastVertexData, 0, 32); + System.arraycopy(quad.vertexData(), 0, fastVertexData, 0, 32); fastVertexData[0] = Float.floatToRawIntBits((float) (Float.intBitsToFloat(fastVertexData[0]) + x + access.getXOffset())); fastVertexData[1] = Float.floatToRawIntBits((float) (Float.intBitsToFloat(fastVertexData[1]) + y + access.getYOffset())); fastVertexData[2] = Float.floatToRawIntBits((float) (Float.intBitsToFloat(fastVertexData[2]) + z + access.getZOffset())); @@ -51,37 +51,38 @@ public void quad(BakedQuad quad, float x, float y, float z, int colour0, int col fastVertexData[26] = Float.floatToRawIntBits((float) (Float.intBitsToFloat(fastVertexData[26]) + z + access.getZOffset())); fastVertexData[30] = normal; if (spreadUV) { - Direction facing = quad.getFace(); - Matrix4f texture = Matrix4f.translateTmp((float) access.getXOffset(), (float) access.getYOffset(), (float) access.getZOffset()); + Direction facing = quad.face(); + Matrix4f texture = new Matrix4f(); + texture.m03((float) access.getXOffset()).m13((float) access.getYOffset()).m23((float) access.getZOffset()); texture.invert(); damageUV.set(Float.intBitsToFloat(fastVertexData[0]), Float.intBitsToFloat(fastVertexData[1]), Float.intBitsToFloat(fastVertexData[2]), 1.0F); - damageUV.transform(texture); - damageUV.rotate(Vec3f.POSITIVE_Y.getDegreesQuaternion(180.0F)); - damageUV.rotate(Vec3f.POSITIVE_X.getDegreesQuaternion(-90.0F)); + texture.transform(damageUV); + damageUV.rotate(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F)); + damageUV.rotate(RotationAxis.POSITIVE_X.rotationDegrees(-90.0F)); damageUV.rotate(facing.getRotationQuaternion()); - fastVertexData[3] = Float.floatToRawIntBits(-damageUV.getX()); - fastVertexData[4] = Float.floatToRawIntBits(-damageUV.getY()); + fastVertexData[3] = Float.floatToRawIntBits(-damageUV.x()); + fastVertexData[4] = Float.floatToRawIntBits(-damageUV.y()); damageUV.set(Float.intBitsToFloat(fastVertexData[8]), Float.intBitsToFloat(fastVertexData[9]), Float.intBitsToFloat(fastVertexData[10]), 1.0F); - damageUV.transform(texture); - damageUV.rotate(Vec3f.POSITIVE_Y.getDegreesQuaternion(180.0F)); - damageUV.rotate(Vec3f.POSITIVE_X.getDegreesQuaternion(-90.0F)); + texture.transform(damageUV); + damageUV.rotate(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F)); + damageUV.rotate(RotationAxis.POSITIVE_X.rotationDegrees(-90.0F)); damageUV.rotate(facing.getRotationQuaternion()); - fastVertexData[11] = Float.floatToRawIntBits(-damageUV.getX()); - fastVertexData[12] = Float.floatToRawIntBits(-damageUV.getY()); + fastVertexData[11] = Float.floatToRawIntBits(-damageUV.x()); + fastVertexData[12] = Float.floatToRawIntBits(-damageUV.y()); damageUV.set(Float.intBitsToFloat(fastVertexData[16]), Float.intBitsToFloat(fastVertexData[17]), Float.intBitsToFloat(fastVertexData[18]), 1.0F); - damageUV.transform(texture); - damageUV.rotate(Vec3f.POSITIVE_Y.getDegreesQuaternion(180.0F)); - damageUV.rotate(Vec3f.POSITIVE_X.getDegreesQuaternion(-90.0F)); + texture.transform(damageUV); + damageUV.rotate(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F)); + damageUV.rotate(RotationAxis.POSITIVE_X.rotationDegrees(-90.0F)); damageUV.rotate(facing.getRotationQuaternion()); - fastVertexData[19] = Float.floatToRawIntBits(-damageUV.getX()); - fastVertexData[20] = Float.floatToRawIntBits(-damageUV.getY()); + fastVertexData[19] = Float.floatToRawIntBits(-damageUV.x()); + fastVertexData[20] = Float.floatToRawIntBits(-damageUV.y()); damageUV.set(Float.intBitsToFloat(fastVertexData[24]), Float.intBitsToFloat(fastVertexData[25]), Float.intBitsToFloat(fastVertexData[26]), 1.0F); - damageUV.transform(texture); - damageUV.rotate(Vec3f.POSITIVE_Y.getDegreesQuaternion(180.0F)); - damageUV.rotate(Vec3f.POSITIVE_X.getDegreesQuaternion(-90.0F)); + texture.transform(damageUV); + damageUV.rotate(RotationAxis.POSITIVE_Y.rotationDegrees(180.0F)); + damageUV.rotate(RotationAxis.POSITIVE_X.rotationDegrees(-90.0F)); damageUV.rotate(facing.getRotationQuaternion()); - fastVertexData[27] = Float.floatToRawIntBits(-damageUV.getX()); - fastVertexData[28] = Float.floatToRawIntBits(-damageUV.getY()); + fastVertexData[27] = Float.floatToRawIntBits(-damageUV.x()); + fastVertexData[28] = Float.floatToRawIntBits(-damageUV.y()); } if (!access.getColorDisabled()) { fastVertexData[5] = colour0; diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTextureManagerImpl.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTextureManagerImpl.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTextureManagerImpl.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/render/StationTextureManagerImpl.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/GuiItemsHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/GuiItemsHelper.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/GuiItemsHelper.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/GuiItemsHelper.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/StationRenderImpl.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/StationRenderImpl.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/StationRenderImpl.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/StationRenderImpl.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/TerrainHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/TerrainHelper.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/impl/client/texture/TerrainHelper.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/impl/client/texture/TerrainHelper.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/BlockItemMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/BlockItemMixin.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/BlockItemMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/BlockItemMixin.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/BlockMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/BlockMixin.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/BlockMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/BlockMixin.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/ItemMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/ItemMixin.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/ItemMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/ItemMixin.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerAccessor.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerAccessor.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerAccessor.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerAccessor.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java similarity index 53% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java index 7f93d621d..ccf41643c 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java @@ -1,17 +1,22 @@ package net.modificationstation.stationapi.mixin.render.client; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import net.minecraft.block.Block; +import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.block.BlockRenderManager; 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.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.DelegatingTessellator; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.block.StationRendererBlockRenderManager; import net.modificationstation.stationapi.api.client.render.model.VanillaBakedModel; import net.modificationstation.stationapi.api.util.math.MutableBlockPos; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; import java.util.Random; @@ -21,6 +26,8 @@ abstract class BlockRenderManagerMixin implements StationRendererBlockRenderMana private final MutableBlockPos stationapi_pos = new MutableBlockPos(0, 0, 0); @Unique private final Random stationapi_random = new Random(); + @Unique + private final DelegatingTessellator delegator = new DelegatingTessellator(); @Shadow public abstract void renderWithoutCulling(Block arg, int i, int j, int k); @@ -29,10 +36,28 @@ abstract class BlockRenderManagerMixin implements StationRendererBlockRenderMana @SuppressWarnings("AddedMixinMembersNamePattern") @Override @Unique - public void renderAllSides(BlockState state, int x, int y, int z) { + public void renderAllSides(VertexConsumer consumer, BlockState state, int x, int y, int z) { + delegator.setDelegate(consumer); if (StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state) instanceof VanillaBakedModel) renderWithoutCulling(state.getBlock(), x, y, z); - else if (RendererAccess.INSTANCE.hasRenderer()) - RendererAccess.INSTANCE.getRenderer().bakedModelRenderer().renderBlock(state, stationapi_pos.set(x, y, z), blockView, false, stationapi_random); + else + Renderer.get().bakedModelRenderer().renderBlock(consumer, state, stationapi_pos.set(x, y, z), blockView, false, stationapi_random); + delegator.setDelegate(Tessellator.INSTANCE); + } + + @Override + @Unique + public void setVertexConsumer(VertexConsumer vertexConsumer) { + this.delegator.setDelegate(vertexConsumer); + } + + @Override + public VertexConsumer getVertexConsumer() { + return this.delegator; + } + + @ModifyExpressionValue(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/Tessellator;INSTANCE:Lnet/minecraft/client/render/Tessellator;")) + private Tessellator modifyTessellator(Tessellator value) { + return delegator; } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java similarity index 84% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java index 89d07cb74..3838dcc2e 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/InGameHudMixin.java @@ -4,15 +4,13 @@ import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.InGameHud; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -import java.util.Objects; - import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; @Mixin(InGameHud.class) @@ -28,6 +26,6 @@ class InGameHudMixin extends DrawContext { locals = LocalCapture.CAPTURE_FAILHARD ) private void stationapi_showCurrentRenderer(float flag, boolean i, int j, int par4, CallbackInfo ci, class_564 var5, int var6, int var7, TextRenderer textRenderer) { - drawTextWithShadow(textRenderer, "[" + NAMESPACE.getName() + "] Active renderer: " + (RendererAccess.INSTANCE.hasRenderer() ? Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer()).getClass().getSimpleName() : "none (vanilla)"), 2, 98, 14737632); + drawTextWithShadow(textRenderer, "[" + NAMESPACE.getName() + "] Active renderer: " + Renderer.get().getClass().getSimpleName(), 2, 98, 14737632); } } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorAccessor.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorAccessor.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorAccessor.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorAccessor.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java similarity index 63% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java index 5207b3438..b07809a16 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java @@ -2,13 +2,17 @@ import net.minecraft.client.render.Tessellator; import net.modificationstation.stationapi.api.client.render.StationTessellator; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.model.BakedQuad; import net.modificationstation.stationapi.impl.client.render.StationTessellatorImpl; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @Mixin(Tessellator.class) -class TessellatorMixin implements StationTessellator { +abstract +class TessellatorMixin implements StationTessellator, VertexConsumer { + @Unique private final StationTessellatorImpl stationapi$stationTessellatorImpl = new StationTessellatorImpl((Tessellator) (Object) this); @@ -23,4 +27,21 @@ public void quad(BakedQuad quad, float x, float y, float z, int colour0, int col public void ensureBufferCapacity(int criticalCapacity) { stationapi$stationTessellatorImpl.ensureBufferCapacity(criticalCapacity); } + + @Override @Shadow + public abstract void vertex(double x, double y, double z); + + @Override + public void vertex(float x, float y, float z) { + vertex((double) x, (double) y, (double) z); + } + + @Override @Shadow + public abstract void color(int red, int green, int blue, int alpha); + + @Override @Shadow + public abstract void texture(double u, double v); + + @Override @Shadow + public abstract void normal(float x, float y, float z); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerAccessor.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerAccessor.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerAccessor.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerAccessor.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerMixin.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerMixin.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TextureManagerMixin.java diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/WaterColorAccessor.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/WaterColorAccessor.java similarity index 100% rename from station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/mixin/render/client/WaterColorAccessor.java rename to station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/WaterColorAccessor.java diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/atlases/game.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/atlases/game.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/atlases/game.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/atlases/game.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/block.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/block.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/block.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/block.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cross.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cross.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cross.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cross.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_all.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_all.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_all.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_all.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_bottom_top.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_bottom_top.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_bottom_top.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_bottom_top.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_horizontal.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_horizontal.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_horizontal.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_horizontal.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_mirrored.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_mirrored.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_mirrored.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_column_mirrored.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_directional.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_directional.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_directional.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_directional.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored_all.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored_all.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored_all.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_mirrored_all.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_top.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_top.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/cube_top.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/cube_top.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/block.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/block.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/block.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/block.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_all.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_all.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_all.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_all.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_bottom_top.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_bottom_top.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_bottom_top.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_bottom_top.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column_horizontal.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column_horizontal.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column_horizontal.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_column_horizontal.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_directional.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_directional.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_directional.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_directional.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_top.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_top.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_top.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/cube_top.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable_with_bottom.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable_with_bottom.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable_with_bottom.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/legacy/orientable_with_bottom.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/orientable.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/orientable.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/orientable.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/orientable.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/orientable_with_bottom.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/orientable_with_bottom.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/orientable_with_bottom.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/orientable_with_bottom.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/tinted_cross.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/tinted_cross.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/block/tinted_cross.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/block/tinted_cross.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/generated.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/generated.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/generated.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/generated.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/handheld.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/handheld.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/handheld.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/handheld.json diff --git a/station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/handheld_rod.json b/station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/handheld_rod.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/minecraft/stationapi/models/item/handheld_rod.json rename to station-renderer-api-v1/src/main/resources/assets/minecraft/stationapi/models/item/handheld_rod.json diff --git a/station-renderer-api-v0/src/main/resources/assets/station-renderer-api-v0/icon.png b/station-renderer-api-v1/src/main/resources/assets/station-renderer-api-v0/icon.png similarity index 100% rename from station-renderer-api-v0/src/main/resources/assets/station-renderer-api-v0/icon.png rename to station-renderer-api-v1/src/main/resources/assets/station-renderer-api-v0/icon.png diff --git a/station-renderer-api-v0/src/main/resources/fabric.mod.json b/station-renderer-api-v1/src/main/resources/fabric.mod.json similarity index 90% rename from station-renderer-api-v0/src/main/resources/fabric.mod.json rename to station-renderer-api-v1/src/main/resources/fabric.mod.json index 0da340298..f9baab99d 100644 --- a/station-renderer-api-v0/src/main/resources/fabric.mod.json +++ b/station-renderer-api-v1/src/main/resources/fabric.mod.json @@ -18,6 +18,7 @@ "icon": "assets/station-renderer-api-v0/icon.png", "environment": "client", + "accessWidener" : "station-renderer-api-v1.accesswidener", "entrypoints": { "stationapi:event_bus_client": [ "net.modificationstation.stationapi.impl.client.texture.StationRenderImpl" @@ -39,7 +40,8 @@ "net/modificationstation/stationapi/api/client/block/StationRendererBlock" ], "net/minecraft/class_67": [ - "net/modificationstation/stationapi/api/client/render/StationTessellator" + "net/modificationstation/stationapi/api/client/render/StationTessellator", + "net/modificationstation/stationapi/api/client/render/VertexConsumer" ], "net/minecraft/class_124": [ "net/modificationstation/stationapi/api/client/item/StationRendererItem" diff --git a/station-renderer-api-v0/src/main/resources/station-renderer-api-v0.mixins.json b/station-renderer-api-v1/src/main/resources/station-renderer-api-v0.mixins.json similarity index 100% rename from station-renderer-api-v0/src/main/resources/station-renderer-api-v0.mixins.json rename to station-renderer-api-v1/src/main/resources/station-renderer-api-v0.mixins.json diff --git a/station-renderer-api-v1/src/main/resources/station-renderer-api-v1.accesswidener b/station-renderer-api-v1/src/main/resources/station-renderer-api-v1.accesswidener new file mode 100644 index 000000000..3cb5f4cba --- /dev/null +++ b/station-renderer-api-v1/src/main/resources/station-renderer-api-v1.accesswidener @@ -0,0 +1,2 @@ +accessWidener v2 named +accessible method net/minecraft/client/render/Tessellator (I)V \ No newline at end of file diff --git a/station-renderer-arsenic/build.gradle.kts b/station-renderer-arsenic/build.gradle.kts index 70ece2fa3..7447c2098 100644 --- a/station-renderer-arsenic/build.gradle.kts +++ b/station-renderer-arsenic/build.gradle.kts @@ -12,5 +12,5 @@ addModuleDependencies(project, "station-lifecycle-events-v0", "station-flattening-v0", "station-resource-loader-v0", - "station-renderer-api-v0" + "station-renderer-api-v1" ) \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/Arsenic.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/Arsenic.java index fd42ada67..d4c0f2662 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/Arsenic.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/Arsenic.java @@ -7,7 +7,7 @@ import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.client.event.resource.TexturePackLoadedEvent; import net.modificationstation.stationapi.api.client.event.texture.TextureRegisterEvent; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.texture.atlas.Atlases; import net.modificationstation.stationapi.api.client.texture.atlas.ExpandableAtlas; import net.modificationstation.stationapi.api.event.mod.InitEvent; @@ -45,7 +45,7 @@ private static void init(InitEvent event) { LOGGER.info("Compatibility mode enabled."); } - RendererAccess.INSTANCE.registerRenderer(ArsenicRenderer.INSTANCE); + Renderer.register(ArsenicRenderer.INSTANCE); StationAPI.EVENT_BUS.register(Listener.simple() .listener(Arsenic::registerTextures) .build()); 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 c79d428d2..a03304621 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 @@ -79,29 +79,29 @@ private int toIndex(int x, int y, int z) { } public void calculateForQuad(BakedQuad q) { - float emission = q.getEmission(); + float emission = q.lightEmission(); if (emission == 1) { System.arraycopy(FULL_BRIGHTNESS, 0, light, 0, light.length); return; } - Direction face = q.getFace(); + Direction face = q.face(); calculateForQuad( face, - x + Float.intBitsToFloat(q.getVertexData()[0]), - y + Float.intBitsToFloat(q.getVertexData()[1]), - z + Float.intBitsToFloat(q.getVertexData()[2]), - x + Float.intBitsToFloat(q.getVertexData()[8]), - y + Float.intBitsToFloat(q.getVertexData()[9]), - z + Float.intBitsToFloat(q.getVertexData()[10]), - x + Float.intBitsToFloat(q.getVertexData()[16]), - y + Float.intBitsToFloat(q.getVertexData()[17]), - z + Float.intBitsToFloat(q.getVertexData()[18]), - x + Float.intBitsToFloat(q.getVertexData()[24]), - y + Float.intBitsToFloat(q.getVertexData()[25]), - z + Float.intBitsToFloat(q.getVertexData()[26]), - q.hasShade() + x + Float.intBitsToFloat(q.vertexData()[0]), + y + Float.intBitsToFloat(q.vertexData()[1]), + z + Float.intBitsToFloat(q.vertexData()[2]), + x + Float.intBitsToFloat(q.vertexData()[8]), + y + Float.intBitsToFloat(q.vertexData()[9]), + z + Float.intBitsToFloat(q.vertexData()[10]), + x + Float.intBitsToFloat(q.vertexData()[16]), + y + Float.intBitsToFloat(q.vertexData()[17]), + z + Float.intBitsToFloat(q.vertexData()[18]), + x + Float.intBitsToFloat(q.vertexData()[24]), + y + Float.intBitsToFloat(q.vertexData()[25]), + z + Float.intBitsToFloat(q.vertexData()[26]), + q.shade() ); if (emission == 0) return; diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicBlockRenderer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicBlockRenderer.java index 438f1f3c5..86572f729 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicBlockRenderer.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicBlockRenderer.java @@ -1,11 +1,13 @@ package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; import net.minecraft.block.Block; +import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.block.BlockRenderManager; import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.client.StationRenderAPI; import net.modificationstation.stationapi.api.client.model.block.BlockWithInventoryRenderer; import net.modificationstation.stationapi.api.client.model.block.BlockWithWorldRenderer; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.model.BakedModel; import net.modificationstation.stationapi.api.client.texture.Sprite; import net.modificationstation.stationapi.api.client.texture.atlas.Atlases; @@ -98,20 +100,20 @@ public ArsenicBlockRenderer(BlockRenderManager blockRenderer) { blockRendererAccessor = (BlockRenderManagerAccessor) blockRenderer; } - public void renderWorld(Block block, int x, int y, int z, CallbackInfoReturnable cir) { + public void renderWorld(VertexConsumer consumer, Block block, int x, int y, int z, CallbackInfoReturnable cir) { BlockState state = ((BlockStateView) blockRendererAccessor.getBlockView()).getBlockState(x, y, z); BakedModel model = StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state); if (!model.isBuiltin()) { - cir.setReturnValue(RendererHolder.RENDERER.renderBlock(state, blockPos.set(x, y, z), blockRendererAccessor.getBlockView(), !blockRendererAccessor.getSkipFaceCulling(), random)); + cir.setReturnValue(RendererHolder.RENDERER.renderBlock(consumer, state, blockPos.set(x, y, z), blockRendererAccessor.getBlockView(), !blockRendererAccessor.getSkipFaceCulling(), random)); } else //noinspection deprecation if (block instanceof BlockWithWorldRenderer renderer) { block.updateBoundingBox(blockRendererAccessor.getBlockView(), x, y, z); //noinspection deprecation - cir.setReturnValue(renderer.renderWorld(blockRenderer, blockRendererAccessor.getBlockView(), x, y, z)); + cir.setReturnValue(renderer.renderWorld(consumer, blockRenderer, blockRendererAccessor.getBlockView(), x, y, z)); } } - public void renderInventory(Block block, int meta, float brightness, CallbackInfo ci) { + public void renderInventory(VertexConsumer consumer, Block block, int meta, float brightness, CallbackInfo ci) { if (block instanceof BlockWithInventoryRenderer renderer) { if (blockRenderer.inventoryColorEnabled) { int var5 = block.getColor(meta); @@ -120,7 +122,7 @@ public void renderInventory(Block block, int meta, float brightness, CallbackInf float var8 = (float)(var5 & 255) / 255.0F; GL11.glColor4f(var6 * brightness, var7 * brightness, var8 * brightness, 1.0F); } - renderer.renderInventory(blockRenderer, meta); + renderer.renderInventory(consumer, blockRenderer, meta); ci.cancel(); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicItemRenderer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicItemRenderer.java index 1b88a438d..a873efceb 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicItemRenderer.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ArsenicItemRenderer.java @@ -133,7 +133,7 @@ private void renderVanilla(ItemEntity item, float x, float y, float z, float del private void renderModel(ItemEntity item, float x, float y, float z, float delta, ItemStack var10, float var11, float var12, byte renderedAmount, SpriteAtlasTexture atlas, BakedModel model) { glPushMatrix(); atlas.bindTexture(); - glTranslatef(x, y + var11 + 0.25F * model.getTransformation().getTransformation(ModelTransformation.Mode.GROUND).scale.getY(), z); + glTranslatef(x, y + var11 + 0.25F * model.getTransformation().getTransformation(ModelTransformation.Mode.GROUND).scale.y(), z); val sideLit = model.isSideLit(); Tessellator tessellator = Tessellator.INSTANCE; 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 877bd93d7..851daea10 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 @@ -17,6 +17,7 @@ import net.modificationstation.stationapi.api.client.StationRenderAPI; import net.modificationstation.stationapi.api.client.color.block.BlockColors; import net.modificationstation.stationapi.api.client.color.item.ItemColors; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.item.ItemModels; import net.modificationstation.stationapi.api.client.render.model.*; import net.modificationstation.stationapi.api.client.render.model.json.ModelTransformation; @@ -32,6 +33,7 @@ import net.modificationstation.stationapi.api.util.exception.CrashReportSectionBlockState; import net.modificationstation.stationapi.api.util.math.Direction; import net.modificationstation.stationapi.api.util.math.MathHelper; +import net.modificationstation.stationapi.api.util.math.MatrixStack; import net.modificationstation.stationapi.impl.client.arsenic.renderer.aocalc.LightingCalculatorImpl; import org.jetbrains.annotations.Nullable; @@ -63,13 +65,13 @@ public class BakedModelRendererImpl implements BakedModelRenderer { private boolean damage; @Override - public boolean renderBlock(BlockState state, BlockPos pos, BlockView world, boolean cull, Random random) { + public boolean renderBlock(VertexConsumer consumer, BlockState state, BlockPos pos, BlockView world, boolean cull, Random random) { try { // BlockRenderType blockRenderType = state.getRenderType(); // if (blockRenderType != BlockRenderType.MODEL) { // return false; // } - return render(world, StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state), state, pos, cull, random, state.getRenderingSeed(pos)); + return render(consumer, world, StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state), state, pos, cull, random, state.getRenderingSeed(pos)); } catch (Throwable throwable) { CrashReport crashReport = CrashReport.create(throwable, "Tesselating block in world"); @@ -80,7 +82,7 @@ public boolean renderBlock(BlockState state, BlockPos pos, BlockView world, bool } @Override - public boolean render(BlockView world, BakedModel model, BlockState state, BlockPos pos, boolean cull, Random random, long seed) { + public boolean render(VertexConsumer consumer, 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)); Block block = state.getBlock(); @@ -101,7 +103,7 @@ public boolean render(BlockView world, BakedModel model, BlockState state, Block for (int j = 0, quadSize = qs.size(); j < quadSize; j++) { q = qs.get(j); light.calculateForQuad(q); - renderQuad(world, state, pos, q, qlight); + renderQuad(null, consumer, world, state, pos, q, qlight); } } } @@ -132,7 +134,7 @@ private int colorChannelF2I(float colorChannel) { } @Override - public void renderDamage(BlockState state, BlockPos pos, BlockView world, float progress) { + public void renderDamage(VertexConsumer consumer, BlockState state, BlockPos pos, BlockView world, float progress) { // if (state.getRenderType() != BlockRenderType.MODEL) { // return; // } @@ -141,13 +143,13 @@ public void renderDamage(BlockState state, BlockPos pos, BlockView world, float damage = true; //noinspection deprecation StationTextureManager.get(((Minecraft) FabricLoader.getInstance().getGameInstance()).textureManager).getTexture(ModelLoader.BLOCK_DESTRUCTION_STAGE_TEXTURES.get((int) (progress * 10))).bindTexture(); - render(world, bakedModel, state, pos, true, this.random, l); + render(consumer, world, bakedModel, state, pos, true, this.random, l); damage = false; } - private void renderQuad(BlockView world, BlockState state, BlockPos pos, BakedQuad quad, float[] brightness) { - if (quad.hasColor()) { - int i = blockColors.getColor(state, world, pos, quad.getColorIndex()); + private void renderQuad(MatrixStack.Entry entry, VertexConsumer consumer, BlockView world, BlockState state, BlockPos pos, BakedQuad quad, float[] brightness) { + if (quad.hasTint()) { + int i = blockColors.getColor(state, world, pos, quad.tintIndex()); float r = redI2F(i), g = greenI2F(i), @@ -189,9 +191,9 @@ private void renderBakedItemModelFlat(BakedModel model, ItemStack stack, float b random.setSeed(42L); boolean bl = stack != null && stack.itemId != 0 && stack.count > 0; for (BakedQuad bakedQuad : model.getQuads(null, null, random)) { - if (bakedQuad.getFace() != Direction.WEST) continue; - int i = bl && bakedQuad.hasColor() ? this.itemColors.getColor(stack, bakedQuad.getColorIndex()) : -1; - float light = MathHelper.lerp(bakedQuad.getEmission(), brightness, 1F); + if (bakedQuad.face() != Direction.WEST) continue; + int i = bl && bakedQuad.hasTint() ? this.itemColors.getColor(stack, bakedQuad.tintIndex()) : -1; + float light = MathHelper.lerp(bakedQuad.lightEmission(), brightness, 1F); i = colorF2I(redI2F(i) * light, greenI2F(i) * light, blueI2F(i) * light); tessellator.quad(bakedQuad, 0, 0, 0, i, i, i, i, 0, 1, 0, false); } @@ -204,7 +206,7 @@ public void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, flo transformation.apply(); boolean side = model.isSideLit(); if (side && renderMode == ModelTransformation.Mode.GUI) { - float angle = transformation.rotation.getY() - 315; + float angle = transformation.rotation.y() - 315; if (angle != 0) { class_583.method_1927(); glPushMatrix(); @@ -224,10 +226,10 @@ public void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, flo private void renderBakedItemQuads(List quads, ItemStack stack, float brightness) { boolean bl = stack != null && stack.itemId != 0 && stack.count > 0; for (BakedQuad bakedQuad : quads) { - int i = bl && bakedQuad.hasColor() ? this.itemColors.getColor(stack, bakedQuad.getColorIndex()) : -1; - float light = MathHelper.lerp(bakedQuad.getEmission(), brightness, 1F); + int i = bl && bakedQuad.hasTint() ? this.itemColors.getColor(stack, bakedQuad.tintIndex()) : -1; + float light = MathHelper.lerp(bakedQuad.lightEmission(), brightness, 1F); i = colorF2I(redI2F(i) * light, greenI2F(i) * light, blueI2F(i) * light); - Direction face = bakedQuad.getFace(); + Direction face = bakedQuad.face(); tessellator.quad(bakedQuad, 0, 0, 0, i, i, i, i, face.getOffsetX(), face.getOffsetY(), face.getOffsetZ(), false); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/RendererHolder.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/RendererHolder.java index bffc4f7e3..1bbdc0d79 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/RendererHolder.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/RendererHolder.java @@ -1,6 +1,6 @@ package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; import java.util.Objects; @@ -8,5 +8,5 @@ final class RendererHolder { private RendererHolder() { throw new RuntimeException("No"); } - final static BakedModelRenderer RENDERER = Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer()).bakedModelRenderer(); + final static BakedModelRenderer RENDERER = Objects.requireNonNull(Renderer.get()).bakedModelRenderer(); } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/PlayerEntityRendererMixin.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/PlayerEntityRendererMixin.java index d5669f788..c0d4554f5 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/PlayerEntityRendererMixin.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/PlayerEntityRendererMixin.java @@ -3,7 +3,7 @@ import net.minecraft.client.render.entity.PlayerEntityRenderer; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.render.model.VanillaBakedModel; import org.lwjgl.opengl.GL11; import org.spongepowered.asm.mixin.Mixin; @@ -24,7 +24,7 @@ class PlayerEntityRendererMixin { locals = LocalCapture.CAPTURE_FAILHARD ) private void stationapi_pushIfJson(PlayerEntity f, float par2, CallbackInfo ci, ItemStack var3, ItemStack var4) { - if (RendererAccess.INSTANCE.hasRenderer() && !(RendererAccess.INSTANCE.getRenderer().bakedModelRenderer().getItemModels().getModel(var4) instanceof VanillaBakedModel)) + if (!(Renderer.get().bakedModelRenderer().getItemModels().getModel(var4) instanceof VanillaBakedModel)) GL11.glPushMatrix(); } @@ -38,7 +38,7 @@ private void stationapi_pushIfJson(PlayerEntity f, float par2, CallbackInfo ci, locals = LocalCapture.CAPTURE_FAILHARD ) private void stationapi_popIfJson(PlayerEntity f, float par2, CallbackInfo ci, ItemStack var3, ItemStack var4) { - if (RendererAccess.INSTANCE.hasRenderer() && !(RendererAccess.INSTANCE.getRenderer().bakedModelRenderer().getItemModels().getModel(var4) instanceof VanillaBakedModel)) + if (!(Renderer.get().bakedModelRenderer().getItemModels().getModel(var4) instanceof VanillaBakedModel)) GL11.glPopMatrix(); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/WorldRendererMixin.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/WorldRendererMixin.java index b4aba7c7f..650da1adc 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/WorldRendererMixin.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/WorldRendererMixin.java @@ -1,6 +1,7 @@ package net.modificationstation.stationapi.mixin.arsenic.client; import net.minecraft.block.Block; +import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.entity.player.PlayerEntity; @@ -10,7 +11,7 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.client.StationRenderAPI; -import net.modificationstation.stationapi.api.client.render.RendererAccess; +import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.render.model.VanillaBakedModel; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -36,6 +37,6 @@ private void stationapi_renderDamage(BlockRenderManager instance, Block block, i if (StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state) instanceof VanillaBakedModel) instance.renderWithTexture(block, j, k, l, texture); else - Objects.requireNonNull(RendererAccess.INSTANCE.getRenderer()).bakedModelRenderer().renderDamage(state, new BlockPos(j, k, l), world, field_1803); + Objects.requireNonNull(Renderer.get()).bakedModelRenderer().renderDamage(Tessellator.INSTANCE, state, new BlockPos(j, k, l), world, field_1803); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/BlockRenderManagerMixin.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/BlockRenderManagerMixin.java index da6ff1c7d..8ac98df28 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/BlockRenderManagerMixin.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/BlockRenderManagerMixin.java @@ -5,6 +5,7 @@ import net.minecraft.block.Block; import net.minecraft.client.render.block.BlockRenderManager; import net.modificationstation.stationapi.api.client.StationRenderAPI; +import net.modificationstation.stationapi.api.client.render.block.StationRendererBlockRenderManager; import net.modificationstation.stationapi.api.client.texture.Sprite; import net.modificationstation.stationapi.api.client.texture.atlas.Atlases; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.ArsenicBlockRenderer; @@ -18,7 +19,7 @@ import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.ArsenicBlockRenderer.*; @Mixin(BlockRenderManager.class) -class BlockRenderManagerMixin { +class BlockRenderManagerMixin implements StationRendererBlockRenderManager { @Inject( method = { "renderBottomFace", @@ -503,7 +504,7 @@ private int stationapi_block_modTextureWidth3( cancellable = true ) private void stationapi_onRenderInWorld(Block block, int blockX, int blockY, int blockZ, CallbackInfoReturnable cir) { - arsenic_plugin.renderWorld(block, blockX, blockY, blockZ, cir); + arsenic_plugin.renderWorld(getVertexConsumer(), block, blockX, blockY, blockZ, cir); } @Inject( @@ -514,7 +515,7 @@ private void stationapi_onRenderInWorld(Block block, int blockX, int blockY, int ), cancellable = true ) - private void stationapi_onRenderInInventory(Block arg, int meta, float brightness, CallbackInfo ci) { - arsenic_plugin.renderInventory(arg, meta, brightness, ci); + private void stationapi_onRenderInInventory(Block block, int meta, float brightness, CallbackInfo ci) { + arsenic_plugin.renderInventory(getVertexConsumer(), block, meta, brightness, ci); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/entity/PistonBlockEntityRenderer.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/entity/PistonBlockEntityRenderer.java index 29965e626..3099a7eed 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/entity/PistonBlockEntityRenderer.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/block/entity/PistonBlockEntityRenderer.java @@ -3,6 +3,7 @@ import net.minecraft.block.Block; import net.minecraft.class_282; import net.minecraft.class_283; +import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.block.BlockRenderManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -21,6 +22,6 @@ private void stationapi_renderBlockState( BlockRenderManager manager, Block block, int x, int y, int z, class_283 pistonBlockEntity, double renderX, double renderY, double renderZ, float partialTicks ) { - manager.renderAllSides(pistonBlockEntity.getPushedBlockState(), x, y, z); + manager.renderAllSides(Tessellator.INSTANCE, pistonBlockEntity.getPushedBlockState(), x, y, z); } } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java index 8912075f4..f36d9572e 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java @@ -26,7 +26,7 @@ private ItemParticleMixin(World world, double x, double y, double z, double velo ) private void stationapi_initializeSprite( Tessellator f, float g, float h, float i, float j, float k, float par7, CallbackInfo ci, - @Share("sprite") LocalRef spriteRef + @Share("spriteId") LocalRef spriteRef ) { spriteRef.set(Atlases.getGuiItems().getTexture(field_2635).getSprite()); } @@ -38,7 +38,7 @@ private void stationapi_initializeSprite( ) private float stationapi_modStartU( float value, - @Share("sprite") LocalRef spriteRef + @Share("spriteId") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return sprite.getMinU() + (sprite.getMaxU() - sprite.getMinU()) * field_2636 / 4; @@ -53,7 +53,7 @@ private float stationapi_modStartU( ) private float stationapi_modEndU( float constant, - @Share("sprite") LocalRef spriteRef + @Share("spriteId") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return (sprite.getMaxU() - sprite.getMinU()) / 3.996F; @@ -66,7 +66,7 @@ private float stationapi_modEndU( ) private float stationapi_modStartV( float value, - @Share("sprite") LocalRef spriteRef + @Share("spriteId") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return sprite.getMinV() + (sprite.getMaxV() - sprite.getMinV()) * field_2637 / 4; @@ -81,7 +81,7 @@ private float stationapi_modStartV( ) private float stationapi_modEndV( float constant, - @Share("sprite") LocalRef spriteRef + @Share("spriteId") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return (sprite.getMaxV() - sprite.getMinV()) / 3.996F; diff --git a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/api/resource/metadata/ResourceMetadataSerializer.java b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/api/resource/metadata/ResourceMetadataSerializer.java index daab0252d..2dcf40eda 100644 --- a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/api/resource/metadata/ResourceMetadataSerializer.java +++ b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/api/resource/metadata/ResourceMetadataSerializer.java @@ -1,6 +1,7 @@ package net.modificationstation.stationapi.api.resource.metadata; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; @@ -18,12 +19,12 @@ public String getKey() { @Override public T fromJson(JsonObject json) { - return codec.parse(JsonOps.INSTANCE, json).getOrThrow(false, error -> {}); + return codec.parse(JsonOps.INSTANCE, json).getOrThrow(JsonParseException::new); } @Override public JsonObject toJson(T metadata) { - return codec.encodeStart(JsonOps.INSTANCE, metadata).getOrThrow(false, error -> {}).getAsJsonObject(); + return codec.encodeStart(JsonOps.INSTANCE, metadata).getOrThrow(JsonParseException::new).getAsJsonObject(); } }; } diff --git a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DefaultResourcePack.java b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DefaultResourcePack.java index 8f16be553..5d2d648d9 100644 --- a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DefaultResourcePack.java +++ b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DefaultResourcePack.java @@ -51,7 +51,7 @@ public class DefaultResourcePack implements ResourcePack { @Override public @Nullable InputSupplier open(ResourceType type, Identifier id) { - return PathUtil.split(id.path).get().map(segments -> { + return PathUtil.split(id.path).mapOrElse(segments -> { String string = id.namespace.toString(); if (NAMESPACE_PATHS.containsKey(type)) for (Path path : NAMESPACE_PATHS.get(type)) { Path path2 = PathUtil.getPath(path.resolve(string), segments); @@ -68,7 +68,7 @@ public class DefaultResourcePack implements ResourcePack { @Override public void findResources(ResourceType type, Namespace namespace, String prefix, ResultConsumer consumer) { val atRoot = prefix.startsWith("/"); - PathUtil.split(atRoot ? prefix.substring(1) : prefix).get().ifLeft(segments -> { + PathUtil.split(atRoot ? prefix.substring(1) : prefix).ifSuccess(segments -> { final List paths; if (namespace == Namespace.MINECRAFT && atRoot) { paths = ROOT_PATHS; @@ -88,7 +88,7 @@ else if (i > 1) { map.forEach(consumer); } } - }).ifRight(result -> LOGGER.error("Invalid path {}: {}", prefix, result.message())); + }).ifError(result -> LOGGER.error("Invalid path {}: {}", prefix, result.message())); } private static void collectIdentifiers(ResultConsumer consumer, Namespace namespace, Path root, List prefixSegments, boolean atRoot) { diff --git a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DirectoryResourcePack.java b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DirectoryResourcePack.java index f63e28126..c90fb7571 100644 --- a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DirectoryResourcePack.java +++ b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/DirectoryResourcePack.java @@ -56,7 +56,7 @@ public InputSupplier open(ResourceType type, Identifier id) { } public static InputSupplier open(Identifier id, Path path) { - return PathUtil.split(id.path).get().map(segments -> { + return PathUtil.split(id.path).mapOrElse(segments -> { Path path2 = PathUtil.getPath(path, segments); return DirectoryResourcePack.open(path2); }, result -> { @@ -75,10 +75,10 @@ private static InputSupplier open(Path path) { @Override public void findResources(ResourceType type, Namespace namespace, String prefix, ResourcePack.ResultConsumer consumer) { - PathUtil.split(prefix).get().ifLeft(prefixSegments -> { + PathUtil.split(prefix).ifSuccess(prefixSegments -> { Path path = this.root.resolve(type.getDirectory()).resolve(namespace.toString()); DirectoryResourcePack.findResources(namespace, path, prefixSegments, consumer); - }).ifRight(result -> LOGGER.error("Invalid path {}: {}", prefix, result.message())); + }).ifError(result -> LOGGER.error("Invalid path {}: {}", prefix, result.message())); } public static void findResources(Namespace namespace, Path path, List prefixSegments, ResourcePack.ResultConsumer consumer) { diff --git a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/NamespaceResourceManager.java b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/NamespaceResourceManager.java index 3549efda7..ed38c1130 100644 --- a/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/NamespaceResourceManager.java +++ b/station-resource-loader-v0/src/main/java/net/modificationstation/stationapi/impl/resource/NamespaceResourceManager.java @@ -52,7 +52,10 @@ public Set getAllNamespaces() { private Function> createOpener(Identifier id) { if (id.namespace == Namespace.MINECRAFT && id.path.startsWith("/")) { - final String[] segments = PathUtil.split(id.path.substring(1)).getOrThrow(false, LOGGER::error).toArray(String[]::new); + final String[] segments = PathUtil.split(id.path.substring(1)).getOrThrow(s -> { + LOGGER.error(s); + return new RuntimeException(s); + }).toArray(String[]::new); return pack -> pack.openRoot(segments.clone()); } else return pack -> pack.open(type, id); } diff --git a/station-templates-v0/build.gradle.kts b/station-templates-v0/build.gradle.kts index e8906f829..287baedb3 100644 --- a/station-templates-v0/build.gradle.kts +++ b/station-templates-v0/build.gradle.kts @@ -10,7 +10,7 @@ addModuleDependencies(project, "station-registry-api-v0", "station-blocks-v0", "station-items-v0", - "station-renderer-api-v0", + "station-renderer-api-v1", "station-tools-api-v1", "station-flattening-v0" ) \ No newline at end of file diff --git a/station-vanilla-fix-v0/build.gradle.kts b/station-vanilla-fix-v0/build.gradle.kts index 524049ee2..eab55d3f9 100644 --- a/station-vanilla-fix-v0/build.gradle.kts +++ b/station-vanilla-fix-v0/build.gradle.kts @@ -20,5 +20,5 @@ addModuleDependencies(project, "station-nbt-v0", "station-localization-api-v0", "station-gui-api-v0", - "station-renderer-api-v0" + "station-renderer-api-v1" ) \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/datafixer/VanillaDataFixerImpl.java b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/datafixer/VanillaDataFixerImpl.java index 647482e83..d0dcb871e 100644 --- a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/datafixer/VanillaDataFixerImpl.java +++ b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/datafixer/VanillaDataFixerImpl.java @@ -48,7 +48,9 @@ public final class VanillaDataFixerImpl { builder.addFixer(new StationFlatteningToMcRegionChunkDamage(schema69420, "StationFlatteningToMcRegionChunkDamage")); Schema schema19132 = builder.addSchema(VANILLA_VERSION, McRegionItemStackDamagerSchema::new); builder.addFixer(new StationFlatteningToMcRegionItemStackDamage(schema19132, "StationFlatteningToMcRegionItemStackDamage")); - return builder.buildOptimized(Set.of(TypeReferences.LEVEL), Util.getBootstrapExecutor()); + DataFixerBuilder.Result result = builder.build(); + result.optimize(Set.of(TypeReferences.LEVEL), Util.getBootstrapExecutor()).join(); + return result.fixer(); }); @EventListener @@ -60,7 +62,9 @@ private static void registerFixer(DataFixerRegisterEvent event) { builder.addFixer(new McRegionToStationFlatteningItemStackFix(schema69420, "McRegionToStationFlatteningItemStackFix")); Schema schema69421 = builder.addSchema(69421, StationFlatteningChunkSchema::new); builder.addFixer(new McRegionToStationFlatteningChunkFix(schema69421, "McRegionToStationFlatteningChunkFix")); - return builder.buildOptimized(Set.of(TypeReferences.LEVEL), executor); + DataFixerBuilder.Result result = builder.build(); + result.optimize(Set.of(TypeReferences.LEVEL), executor).join(); + return result.fixer(); }, CURRENT_VERSION); } } diff --git a/station-worldgen-api-v0/src/main/java/net/modificationstation/stationapi/api/worldgen/surface/condition/SlopeSurfaceCondition.java b/station-worldgen-api-v0/src/main/java/net/modificationstation/stationapi/api/worldgen/surface/condition/SlopeSurfaceCondition.java index fe6128775..5ae564d5f 100644 --- a/station-worldgen-api-v0/src/main/java/net/modificationstation/stationapi/api/worldgen/surface/condition/SlopeSurfaceCondition.java +++ b/station-worldgen-api-v0/src/main/java/net/modificationstation/stationapi/api/worldgen/surface/condition/SlopeSurfaceCondition.java @@ -2,11 +2,11 @@ import net.minecraft.world.World; import net.modificationstation.stationapi.api.block.BlockState; -import net.modificationstation.stationapi.api.util.math.Vec3f; +import org.joml.Vector3f; public class SlopeSurfaceCondition implements SurfaceCondition { - private final Vec3f a = new Vec3f(); - private final Vec3f b = new Vec3f(); + private final Vector3f a = new Vector3f(); + private final Vector3f b = new Vector3f(); private final boolean greater; private final float angle; @@ -26,7 +26,7 @@ public boolean canApply(World world, int x, int y, int z, BlockState state) { a.cross(b); a.normalize(); - b.set(a.getX(), 0, a.getZ()); + b.set(a.x(), 0, a.z()); b.normalize(); float dot = a.dot(b); From 3ab8c9bb5ac19d677894f9ccda512aee4f17f8e3 Mon Sep 17 00:00:00 2001 From: alpha Date: Sat, 5 Apr 2025 22:43:52 -0500 Subject: [PATCH 02/14] Fix accidental variable renames --- .../stationapi/api/client/texture/SpriteContents.java | 6 +++--- .../api/client/texture/atlas/SingleAtlasSource.java | 4 ++-- .../arsenic/client/particle/ItemParticleMixin.java | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java index 65c90e478..08e021147 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/SpriteContents.java @@ -53,11 +53,11 @@ private Animation createAnimation(SpriteDimensions dimensions, int imageWidth, i AnimationFrame animationFrame = iterator.next(); boolean bl = true; if (animationFrame.time <= 0) { - LOGGER.warn("Invalid frame duration on spriteId {} frame {}: {}", id, l, animationFrame.time); + LOGGER.warn("Invalid frame duration on sprite {} frame {}: {}", id, l, animationFrame.time); bl = false; } if (animationFrame.index < 0 || animationFrame.index >= k) { - LOGGER.warn("Invalid frame index on spriteId {} frame {}: {}", id, l, animationFrame.index); + LOGGER.warn("Invalid frame index on sprite {} frame {}: {}", id, l, animationFrame.index); bl = false; } if (bl) intSet.add(animationFrame.index); @@ -66,7 +66,7 @@ private Animation createAnimation(SpriteDimensions dimensions, int imageWidth, i } int[] is = IntStream.range(0, k).filter(i -> !intSet.contains(i)).toArray(); if (is.length > 0) - LOGGER.warn("Unused frames in spriteId {}: {}", id, Arrays.toString(is)); + LOGGER.warn("Unused frames in sprite {}: {}", id, Arrays.toString(is)); } if (list.size() <= 1) return null; return new Animation(ImmutableList.copyOf(list), i2, metadata.shouldInterpolate()); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java index 06811271b..de9ceebef 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/atlas/SingleAtlasSource.java @@ -11,14 +11,14 @@ import static net.modificationstation.stationapi.impl.client.texture.StationRenderImpl.LOGGER; public record SingleAtlasSource(Identifier resourceId, Optional spriteId) implements AtlasSource { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(Identifier.CODEC.fieldOf("resource").forGetter(singleAtlasSource -> singleAtlasSource.resourceId), Identifier.CODEC.optionalFieldOf("spriteId").forGetter(singleAtlasSource -> singleAtlasSource.spriteId)).apply(instance, SingleAtlasSource::new)); + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(Identifier.CODEC.fieldOf("resource").forGetter(singleAtlasSource -> singleAtlasSource.resourceId), Identifier.CODEC.optionalFieldOf("sprite").forGetter(singleAtlasSource -> singleAtlasSource.spriteId)).apply(instance, SingleAtlasSource::new)); @Override public void load(ResourceManager resourceManager, AtlasSource.SpriteRegions regions) { Identifier identifier = RESOURCE_FINDER.toResourcePath(this.resourceId); Optional optional = resourceManager.getResource(identifier); if (optional.isPresent()) regions.add(this.spriteId.orElse(this.resourceId), optional.get()); - else LOGGER.warn("Missing spriteId: {}", identifier); + else LOGGER.warn("Missing sprite: {}", identifier); } @Override diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java index f36d9572e..8912075f4 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/mixin/arsenic/client/particle/ItemParticleMixin.java @@ -26,7 +26,7 @@ private ItemParticleMixin(World world, double x, double y, double z, double velo ) private void stationapi_initializeSprite( Tessellator f, float g, float h, float i, float j, float k, float par7, CallbackInfo ci, - @Share("spriteId") LocalRef spriteRef + @Share("sprite") LocalRef spriteRef ) { spriteRef.set(Atlases.getGuiItems().getTexture(field_2635).getSprite()); } @@ -38,7 +38,7 @@ private void stationapi_initializeSprite( ) private float stationapi_modStartU( float value, - @Share("spriteId") LocalRef spriteRef + @Share("sprite") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return sprite.getMinU() + (sprite.getMaxU() - sprite.getMinU()) * field_2636 / 4; @@ -53,7 +53,7 @@ private float stationapi_modStartU( ) private float stationapi_modEndU( float constant, - @Share("spriteId") LocalRef spriteRef + @Share("sprite") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return (sprite.getMaxU() - sprite.getMinU()) / 3.996F; @@ -66,7 +66,7 @@ private float stationapi_modEndU( ) private float stationapi_modStartV( float value, - @Share("spriteId") LocalRef spriteRef + @Share("sprite") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return sprite.getMinV() + (sprite.getMaxV() - sprite.getMinV()) * field_2637 / 4; @@ -81,7 +81,7 @@ private float stationapi_modStartV( ) private float stationapi_modEndV( float constant, - @Share("spriteId") LocalRef spriteRef + @Share("sprite") LocalRef spriteRef ) { Sprite sprite = spriteRef.get(); return (sprite.getMaxV() - sprite.getMinV()) / 3.996F; From cc18517e7c0d0ef98b7e356ef8bc655117bb915f Mon Sep 17 00:00:00 2001 From: alpha Date: Sun, 6 Apr 2025 18:00:47 -0500 Subject: [PATCH 03/14] Add VertexFormats unused for right now Refactor VertexConsumer --- .../client/render/DelegatingTessellator.java | 41 +++- .../api/client/render/VertexConsumer.java | 73 ++++++- .../api/client/render/VertexFormat.java | 193 ++++++++++++++++++ .../client/render/VertexFormatElement.java | 174 ++++++++++++++++ .../api/client/render/VertexFormats.java | 10 + .../mixin/render/client/TessellatorMixin.java | 37 +++- 6 files changed, 506 insertions(+), 22 deletions(-) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormat.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java index f8c348d8e..6f51527b5 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/DelegatingTessellator.java @@ -48,33 +48,58 @@ public void translate(float x, float y, float z) { @Override public void vertex(double x, double y, double z) { - this.delegate.vertex(x, y, z); + this.delegate.setVertex((float) x, (float) y, (float) z); } @Override - public void vertex(float x, float y, float z) { - this.delegate.vertex(x, y, z); + public VertexConsumer setVertex(float x, float y, float z) { + return this.delegate.setVertex(x, y, z); } @Override public void vertex(double x, double y, double z, double u, double v) { - this.delegate.texture(u, v); - this.delegate.vertex(x, y, z); + this.delegate.setTexture((float) u, (float) v); + this.delegate.setVertex((float) x, (float) y, (float) z); } @Override public void texture(double u, double v) { - this.delegate.texture(u, v); + this.delegate.setTexture((float) u, (float) v); + } + + @Override + public VertexConsumer setTexture(float u, float v) { + return this.delegate.setTexture(u, v); } @Override public void normal(float x, float y, float z) { - this.delegate.normal(x, y, z); + this.delegate.setNormal(x, y, z); + } + + @Override + public VertexConsumer setNormal(float x, float y, float z) { + return this.delegate.setNormal(x, y, z); } @Override public void color(int r, int g, int b, int a) { - this.delegate.color(r, g, b, a); + this.delegate.setColor(r, g, b, a); + } + + @Override + public VertexConsumer setColor(int red, int green, int blue, int alpha) { + return this.delegate.setColor(red, green, blue, alpha); + } + + @Override + public VertexConsumer setLight(int u, int v) { + return this.delegate.setLight(u, v); + } + + @Override + public VertexConsumer setOverlay(int u, int v) { + return this.delegate.setOverlay(u, v); } @Override diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java index 648b01088..db8f0437a 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java @@ -1,23 +1,78 @@ package net.modificationstation.stationapi.api.client.render; import net.modificationstation.stationapi.api.client.render.model.BakedQuad; +import net.modificationstation.stationapi.api.util.Util; import net.modificationstation.stationapi.api.util.math.MatrixStack; import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector3fc; +/** + * An interface that consumes vertices in a certain {@linkplain + * VertexFormat vertex format}. + * + *

The vertex elements must be specified in the same order as defined in + * the format the vertices being consumed are in. + */ public interface VertexConsumer { - default void vertex(double x, double y, double z) { - vertex((float) x, (float) y, (float) z); - } + /** + * Specifies the {@linkplain VertexFormatElement#POSITION + * position element} of the current vertex. + * + *

This is typically the first element in a vertex, hence the name. + * + * @throws IllegalStateException if this consumer is not currently + * accepting a position element. + * + * @return this consumer, for chaining + */ + VertexConsumer setVertex(float x, float y, float z); + + /** + * Specifies the {@linkplain VertexFormatElement#COLOR + * color element} of the current vertex. + * + * @throws IllegalStateException if this consumer is not currently + * accepting a color element. + * + * @return this consumer, for chaining + */ + VertexConsumer setColor(int red, int green, int blue, int alpha); - void vertex(float x, float y, float z); + /** + * Specifies the {@linkplain VertexFormatElement#UV0 + * texture element} of the current vertex. + * + * @throws IllegalStateException if this consumer is not currently + * accepting a texture element. + * + * @return this consumer, for chaining + */ + VertexConsumer setTexture(float u, float v); - void color(int red, int green, int blue, int alpha); + /** + * Specifies the {@linkplain VertexFormatElement#UV1 + * overlay element} of the current vertex. + * + * @throws IllegalStateException if this consumer is not currently + * accepting an overlay element. + * + * @return this consumer, for chaining + */ + VertexConsumer setOverlay(int u, int v); - void texture(double u, double v); + /** + * Specifies the {@linkplain VertexFormatElement#UV2 + * light element} of the current vertex. + * + * @throws IllegalStateException if this consumer is not currently + * accepting a light element. + * + * @return this consumer, for chaining + */ + VertexConsumer setLight(int u, int v); - void normal(float x, float y, float z); + VertexConsumer setNormal(float x, float y, float z); // TODO default VertexConsumer quad(MatrixStack.Entry entry, BakedQuad quad, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { @@ -28,4 +83,8 @@ default VertexConsumer quad(MatrixStack.Entry entry, BakedQuad quad, int colour0 Vector3f normal = entry.transformNormal(faceNormal, new Vector3f()); return this; } + + default void quad(BakedQuad quad, float x, float y, float z, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { + Util.assertImpl(); + } } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormat.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormat.java new file mode 100644 index 000000000..d10d92ffa --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormat.java @@ -0,0 +1,193 @@ +package net.modificationstation.stationapi.api.client.render; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; + +import java.util.Arrays; +import java.util.List; + +public class VertexFormat { + public static final int UNKNOWN_ELEMENT = -1; + private final List elements; + private final List names; + private final int vertexSize; + private final int elementsMask; + private final int[] offsetsByElement = new int[32]; + + VertexFormat(List elements, List names, IntList offsets, int vertexSize) { + this.elements = elements; + this.names = names; + this.vertexSize = vertexSize; + this.elementsMask = elements.stream().mapToInt(VertexFormatElement::mask).reduce(0, (a, b) -> a | b); + + for (int i = 0; i < this.offsetsByElement.length; i++) { + VertexFormatElement element = VertexFormatElement.byId(i); + int index = element != null ? elements.indexOf(element) : UNKNOWN_ELEMENT; + this.offsetsByElement[i] = index != UNKNOWN_ELEMENT ? offsets.getInt(index) : UNKNOWN_ELEMENT; + } + } + + public static VertexFormat.Builder builder() { + return new VertexFormat.Builder(); + } + + public String toString() { + return "VertexFormat" + this.names; + } + + public int getVertexSize() { + return this.vertexSize; + } + + public List getElements() { + return this.elements; + } + + public List getElementAttributeNames() { + return this.names; + } + + public int[] getOffsetsByElement() { + return this.offsetsByElement; + } + + public int getOffset(VertexFormatElement element) { + return this.offsetsByElement[element.id()]; + } + + public boolean contains(VertexFormatElement element) { + return (this.elementsMask & element.mask()) != 0; + } + + public int getElementsMask() { + return this.elementsMask; + } + + public String getElementName(VertexFormatElement element) { + int index = this.elements.indexOf(element); + if (index == UNKNOWN_ELEMENT) { + throw new IllegalArgumentException(element + " is not contained in format"); + } else { + return this.names.get(index); + } + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else { + if (o instanceof VertexFormat vertexFormat + && this.elementsMask == vertexFormat.elementsMask + && this.vertexSize == vertexFormat.vertexSize + && this.names.equals(vertexFormat.names) + && Arrays.equals(this.offsetsByElement, vertexFormat.offsetsByElement)) { + return true; + } + + return false; + } + } + + @Override + public int hashCode() { + return this.elementsMask * 31 + Arrays.hashCode(this.offsetsByElement); + } + + public void startDrawing(long pointer) { + int stride = getVertexSize(); + + for (VertexFormatElement element : getElements()) { + element.startDrawing(pointer + (long) this.offsetsByElement[element.id()], stride); + } + } + + public void endDrawing() { + for (VertexFormatElement element : this.getElements()) { + element.endDrawing(); + } + } + + public static class Builder { + private final ImmutableMap.Builder elements = ImmutableMap.builder(); + private final IntList offsets = new IntArrayList(); + private int offset; + + Builder() { + } + + public VertexFormat.Builder add(String name, VertexFormatElement element) { + this.elements.put(name, element); + this.offsets.add(this.offset); + this.offset = this.offset + element.byteSize(); + return this; + } + + public VertexFormat.Builder padding(int padding) { + this.offset += padding; + return this; + } + + public VertexFormat build() { + ImmutableMap immutableMap = this.elements.buildOrThrow(); + ImmutableList elements = immutableMap.values().asList(); + ImmutableList names = immutableMap.keySet().asList(); + return new VertexFormat(elements, names, this.offsets, this.offset); + } + } + + public enum DrawMode { + LINES(2, 2, false), + LINE_STRIP(2, 1, true), + DEBUG_LINES(2, 2, false), + DEBUG_LINE_STRIP(2, 1, true), + TRIANGLES(3, 3, false), + TRIANGLE_STRIP(3, 1, true), + TRIANGLE_FAN(3, 1, true), + QUADS(4, 4, false); + + /** + * The number of vertices needed to form a first shape. + */ + public final int firstVertexCount; + /** + * The number of vertices needed to form an additional shape. In other words, it's + * firstVertexCount - s where s is the number of vertices shared with the previous shape. + */ + public final int additionalVertexCount; + /** + * Whether there are shared vertices in consecutive shapes. + */ + public final boolean shareVertices; + + DrawMode(final int firstVertexCount, final int additionalVertexCount, final boolean shareVertices) { + this.firstVertexCount = firstVertexCount; + this.additionalVertexCount = additionalVertexCount; + this.shareVertices = shareVertices; + } + + public int getIndexCount(int vertexCount) { + return switch (this) { + case LINES, QUADS -> vertexCount / 4 * 6; + case LINE_STRIP, DEBUG_LINES, DEBUG_LINE_STRIP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN -> vertexCount; + default -> 0; + }; + } + } + + public enum IndexType { + SHORT(2), + INT(4); + + public final int size; + + IndexType(final int size) { + this.size = size; + } + + public static VertexFormat.IndexType smallestFor(int i) { + return (i & -65536) != 0 ? INT : SHORT; + } + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java new file mode 100644 index 000000000..122d0f88e --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java @@ -0,0 +1,174 @@ +package net.modificationstation.stationapi.api.client.render; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntConsumer; +import java.util.stream.Stream; + +public record VertexFormatElement(int id, int index, Type type, Usage usage, int count) { + public static final int MAX_COUNT = 32; + private static final VertexFormatElement[] BY_ID = new VertexFormatElement[MAX_COUNT]; + private static final List ELEMENTS = new ArrayList<>(MAX_COUNT); + + public static final VertexFormatElement POSITION = register(0, 0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, 3); + public static final VertexFormatElement COLOR = register(1, 0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, 4); + public static final VertexFormatElement UV0 = register(2, 0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.UV, 2); + public static final VertexFormatElement UV1 = register(3, 1, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.UV, 2); + public static final VertexFormatElement UV2 = register(4, 2, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.UV, 2); + public static final VertexFormatElement NORMAL = register(5, 0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.NORMAL, 3); + + public VertexFormatElement(int id, int index, Type type, Usage usage, int count) { + if (id < 0 || id >= BY_ID.length) { + throw new IllegalArgumentException("Element ID must be in range [0; " + BY_ID.length + ")"); + } else if (!this.supportsUsage(index, usage)) { + throw new IllegalStateException("Multiple vertex elements of the same type other than UVs are not supported"); + } else { + this.id = id; + this.index = index; + this.type = type; + this.usage = usage; + this.count = count; + } + } + + public static VertexFormatElement register(int id, int index, Type type, Usage usage, int count) { + VertexFormatElement vertexFormatElement = new VertexFormatElement(id, index, type, usage, count); + if (BY_ID[id] != null) { + throw new IllegalArgumentException("Duplicate element registration for: " + id); + } else { + BY_ID[id] = vertexFormatElement; + ELEMENTS.add(vertexFormatElement); + return vertexFormatElement; + } + } + + private boolean supportsUsage(int uvIndex, VertexFormatElement.Usage usage) { + return uvIndex == 0 || usage == VertexFormatElement.Usage.UV; + } + + public String toString() { + return this.count + "," + this.usage + "," + this.type + " (" + this.id + ")"; + } + + public int mask() { + return 1 << this.id; + } + + public int byteSize() { + return this.type.size() * this.count; + } + + @Nullable + public static VertexFormatElement byId(int id) { + return BY_ID[id]; + } + + public static Stream elementsFromMask(int mask) { + return ELEMENTS.stream().filter(element -> element != null && (mask & element.mask()) != 0); + } + + public void startDrawing(long pointer, int stride) { + this.usage.startDrawing(this.count, this.type.getGlId(), stride, pointer, this.index); + } + + public void endDrawing() { + this.usage.endDrawing(this.index); + } + + enum Type { + FLOAT(4, "Float", GL11.GL_FLOAT), + UBYTE(1, "Unsigned Byte", GL11.GL_UNSIGNED_BYTE), + BYTE(1, "Byte", GL11.GL_BYTE), + USHORT(2, "Unsigned Short", GL11.GL_UNSIGNED_SHORT), + SHORT(2, "Short", GL11.GL_SHORT), + UINT(4, "Unsigned Int", GL11.GL_UNSIGNED_INT), + INT(4, "Int", GL11.GL_INT); + + private final int size; + private final String name; + private final int glId; + + Type(int size, String name, int glId) { + this.size = size; + this.name = name; + this.glId = glId; + } + + public int size() { + return this.size; + } + + public String toString() { + return this.name; + } + + public int getGlId() { + return this.glId; + } + } + + @Environment(EnvType.CLIENT) + enum Usage { + POSITION("Position", (size, glId, stride, pointer, elementIndex) -> { + GL11.glVertexPointer(size, glId, stride, pointer); + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + }, i -> GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY)), + NORMAL("Normal", (size, glId, stride, pointer, elementIndex) -> { + GL11.glNormalPointer(glId, stride, pointer); + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); + }, i -> GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY)), + COLOR("Vertex Color", (size, glId, stride, pointer, elementIndex) -> { + GL11.glColorPointer(size, glId, stride, pointer); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + }, i -> { + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); +// GlStateManager.clearCurrentColor(); + }), + UV("UV", (size, glId, stride, pointer, elementIndex) -> { + GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + elementIndex); + GL11.glTexCoordPointer(size, glId, stride, pointer); + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + }, i -> { + GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + i); + GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + }), + PADDING("Padding", (size, glId, stride, pointer, elementIndex) -> { + }, i -> { + }); + + private final String name; + private final Usage.Starter starter; + private final IntConsumer finisher; + + Usage(String name, Usage.Starter starter, IntConsumer intConsumer) { + this.name = name; + this.starter = starter; + this.finisher = intConsumer; + } + + private void startDrawing(int count, int glId, int stride, long pointer, int elementIndex) { + this.starter.setupBufferState(count, glId, stride, pointer, elementIndex); + } + + public void endDrawing(int elementIndex) { + this.finisher.accept(elementIndex); + } + + public String getName() { + return this.name; + } + + @Environment(EnvType.CLIENT) + interface Starter { + void setupBufferState(int size, int glId, int stride, long pointer, int elementIndex); + } + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java new file mode 100644 index 000000000..023a5b065 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java @@ -0,0 +1,10 @@ +package net.modificationstation.stationapi.api.client.render; + +public class VertexFormats { + public static final VertexFormat BLOCK = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("Color", VertexFormatElement.COLOR) + .add("UV0", VertexFormatElement.UV0) + .add("Normal", VertexFormatElement.NORMAL) + .build(); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java index b07809a16..555320829 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java @@ -28,20 +28,43 @@ public void ensureBufferCapacity(int criticalCapacity) { stationapi$stationTessellatorImpl.ensureBufferCapacity(criticalCapacity); } - @Override @Shadow - public abstract void vertex(double x, double y, double z); + @Override + public VertexConsumer setVertex(float x, float y, float z) { + vertex(x, y, z); + return this; + } + + @Override + public VertexConsumer setColor(int red, int green, int blue, int alpha) { + color(red, green, blue, alpha); + return this; + } + + @Override + public VertexConsumer setTexture(float u, float v) { + texture(u, v); + return this; + } @Override - public void vertex(float x, float y, float z) { - vertex((double) x, (double) y, (double) z); + public VertexConsumer setLight(int u, int v) { + return this; } - @Override @Shadow + @Override + public VertexConsumer setOverlay(int u, int v) { + return this; + } + + @Shadow + public abstract void vertex(double x, double y, double z); + + @Shadow public abstract void color(int red, int green, int blue, int alpha); - @Override @Shadow + @Shadow public abstract void texture(double u, double v); - @Override @Shadow + @Shadow public abstract void normal(float x, float y, float z); } From fd097d042e720621b2d3c51335471d9fed6b617d Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 7 Apr 2025 14:04:10 -0500 Subject: [PATCH 04/14] Add StateManager --- .../api/client/render/Renderer.java | 2 + .../api/client/render/StateManager.java | 39 ++++ .../mixin/render/client/TessellatorMixin.java | 6 + .../arsenic/renderer/ArsenicRenderer.java | 8 + .../render/BakedModelRendererImpl.java | 38 ++-- .../renderer/render/StateManagerImpl.java | 189 ++++++++++++++++++ 6 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StateManager.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java index 8f541639c..958a26987 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java @@ -35,4 +35,6 @@ static void register(Renderer renderer) { * */ BakedModelRenderer bakedModelRenderer(); + + StateManager stateManager(); } \ No newline at end of file diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StateManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StateManager.java new file mode 100644 index 000000000..6ccd9da97 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/StateManager.java @@ -0,0 +1,39 @@ +package net.modificationstation.stationapi.api.client.render; + +public interface StateManager { + void pushMatrix(); + + void popMatrix(); + + void rotate(float angle, float x, float y, float z); + + void translate(float x, float y, float z); + + void scale(float x, float y, float z); + + void blendFunc(int srcFactor, int dstFactor); + + void blendFuncSeparate(int srcRGBFactor, int dstRGBFactor, int srcAlphaFactor, int dstAlphaFactor); + + void depthFunc(int depthFunc); + + void depthMask(boolean depthMask); + + void enableBlend(); + + void disableBlend(); + + void enableDepthTest(); + + void disableDepthTest(); + + void enableCull(); + + void disableCull(); + + void disableLighting(); + + void enableLighting(); + + void colorMask(boolean red, boolean green, boolean blue, boolean alpha); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java index 555320829..0d27eb845 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/TessellatorMixin.java @@ -46,6 +46,12 @@ public VertexConsumer setTexture(float u, float v) { return this; } + @Override + public VertexConsumer setNormal(float x, float y, float z) { + normal(x, y, z); + return this; + } + @Override public VertexConsumer setLight(int u, int v) { return this; 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 a047304dd..83fdbd08c 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,8 +4,10 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.client.render.StateManager; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.BakedModelRendererImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.StateManagerImpl; import java.util.function.Supplier; @@ -19,5 +21,11 @@ public BakedModelRenderer bakedModelRenderer() { return bakedModelRenderer.get(); } + @Override + public StateManager stateManager() { + return stateManager.get(); + } + private final Supplier bakedModelRenderer = Suppliers.memoize(BakedModelRendererImpl::new); + private final Supplier stateManager = Suppliers.memoize(StateManagerImpl::new); } 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 851daea10..5c72c68da 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 @@ -17,6 +17,8 @@ import net.modificationstation.stationapi.api.client.StationRenderAPI; import net.modificationstation.stationapi.api.client.color.block.BlockColors; import net.modificationstation.stationapi.api.client.color.item.ItemColors; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.client.render.StateManager; import net.modificationstation.stationapi.api.client.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.item.ItemModels; import net.modificationstation.stationapi.api.client.render.model.*; @@ -43,8 +45,6 @@ import java.util.Objects; import java.util.Random; -import static org.lwjgl.opengl.GL11.*; - public class BakedModelRendererImpl implements BakedModelRenderer { private static final Direction[] DIRECTIONS = Util.make(() -> { @@ -202,6 +202,7 @@ 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; + StateManager states = Renderer.get().stateManager(); Transformation transformation = model.getTransformation().getTransformation(renderMode); transformation.apply(); boolean side = model.isSideLit(); @@ -209,13 +210,13 @@ public void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, flo float angle = transformation.rotation.y() - 315; if (angle != 0) { class_583.method_1927(); - glPushMatrix(); - glRotatef(angle, 0, 1, 0); + states.pushMatrix(); + states.rotate(angle, 0, 1, 0); class_583.method_1930(); - glPopMatrix(); + states.popMatrix(); } } - glTranslatef(-0.5F, -0.5F, -0.5F); + states.translate(-0.5F, -0.5F, -0.5F); if (model.isBuiltin()) return; if (!side && renderMode == ModelTransformation.Mode.GROUND) renderBakedItemModelFlat(model, stack, brightness); @@ -251,26 +252,27 @@ public void renderItem(@Nullable LivingEntity entity, ItemStack item, ModelTrans protected void renderGuiItemModel(ItemStack stack, int x, int y, BakedModel model) { StationRenderAPI.getBakedModelManager().getAtlas(Atlases.GAME_ATLAS_TEXTURE).setFilter(false, false); - glPushMatrix(); - glTranslated(x, y, 14.5 /* approximate. should probably be replaced later with a value properly calculated against vanilla's transformations */); - glTranslatef(8, 8, 0); - glScalef(1, -1, 1); - glScalef(16, 16, 16); + StateManager states = Renderer.get().stateManager(); + states.pushMatrix(); + states.translate(x, y, 14.5F /* approximate. should probably be replaced later with a value properly calculated against vanilla's transformations */); + states.translate(8, 8, 0); + states.scale(1, -1, 1); + states.scale(16, 16, 16); boolean flat = !model.isSideLit(); - if (flat) glDisable(GL_LIGHTING); + if (flat) states.disableLighting(); tessellator.startQuads(); this.renderItem(stack, ModelTransformation.Mode.GUI, 1, model); tessellator.draw(); - if (flat) glEnable(GL_LIGHTING); - glPopMatrix(); + if (flat) states.enableLighting(); + states.popMatrix(); if (!flat) { class_583.method_1927(); - glPushMatrix(); - glRotatef(120.0f, 1.0f, 0.0f, 0.0f); + states.pushMatrix(); + states.rotate(120.0f, 1.0f, 0.0f, 0.0f); class_583.method_1930(); - glPopMatrix(); + states.popMatrix(); } - glEnable(GL_CULL_FACE); + states.disableCull(); } /** diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java new file mode 100644 index 000000000..8167f904a --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java @@ -0,0 +1,189 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.render.StateManager; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +public class StateManagerImpl implements StateManager { + private static final BlendFuncState BLEND = new BlendFuncState(); + private static final DepthTestState DEPTH = new DepthTestState(); + private static final CullFaceState CULL = new CullFaceState(); + private static final LightState LIGHT = new LightState(); + private static final ColorMask COLOR_MASK = new ColorMask(); + + @Override + public void pushMatrix() { + GL11.glPushMatrix(); + } + + @Override + public void popMatrix() { + GL11.glPopMatrix(); + } + + @Override + public void rotate(float angle, float x, float y, float z) { + GL11.glRotatef(angle, x, y, z); + } + + @Override + public void translate(float x, float y, float z) { + GL11.glTranslatef(x, y, z); + } + + @Override + public void scale(float x, float y, float z) { + GL11.glScalef(x, y, z); + } + + @Override + public void blendFunc(int srcFactor, int dstFactor) { + if (srcFactor != BLEND.srcFactorRGB || dstFactor != BLEND.dstFactorRGB) { + BLEND.srcFactorRGB = srcFactor; + BLEND.dstFactorRGB = dstFactor; + GL11.glBlendFunc(srcFactor, dstFactor); + } + } + + @Override + public void blendFuncSeparate(int srcFactorRGB, int dstFactorRGB, int srcFactorAlpha, int dstFactorAlpha) { + if (srcFactorRGB != BLEND.srcFactorRGB + || dstFactorRGB != BLEND.dstFactorRGB + || srcFactorAlpha != BLEND.srcFactorAlpha + || dstFactorAlpha != BLEND.dstFactorAlpha) { + BLEND.srcFactorRGB = srcFactorRGB; + BLEND.dstFactorRGB = dstFactorRGB; + BLEND.srcFactorAlpha = srcFactorAlpha; + BLEND.dstFactorAlpha = dstFactorAlpha; + GL14.glBlendFuncSeparate(srcFactorRGB, dstFactorRGB, srcFactorAlpha, dstFactorAlpha); + } + } + + @Override + public void depthFunc(int func) { + if (func != DEPTH.func) { + DEPTH.func = func; + GL11.glDepthFunc(func); + } + } + + @Override + public void depthMask(boolean mask) { + if (mask != DEPTH.mask) { + DEPTH.mask = mask; + GL11.glDepthMask(mask); + } + } + + @Override + public void enableBlend() { + BLEND.capState.enable(); + } + + @Override + public void disableBlend() { + BLEND.capState.disable(); + } + + @Override + public void enableDepthTest() { + DEPTH.capState.enable(); + } + + @Override + public void disableDepthTest() { + DEPTH.capState.disable(); + } + + @Override + public void enableCull() { + CULL.capState.enable(); + } + + @Override + public void disableCull() { + CULL.capState.disable(); + } + + @Override + public void enableLighting() { + LIGHT.capState.enable(); + } + + @Override + public void disableLighting() { + LIGHT.capState.disable(); + } + + @Override + public void colorMask(boolean red, boolean green, boolean blue, boolean alpha) { + if (red != COLOR_MASK.red || green != COLOR_MASK.green || blue != COLOR_MASK.blue || alpha != COLOR_MASK.alpha) { + COLOR_MASK.red = red; + COLOR_MASK.green = green; + COLOR_MASK.blue = blue; + COLOR_MASK.alpha = alpha; + GL11.glColorMask(red, green, blue, alpha); + } + } + + static class ColorMask { + public boolean red = true; + public boolean green = true; + public boolean blue = true; + public boolean alpha = true; + } + + static class CapabilityTracker { + private final int cap; + private boolean state; + + public CapabilityTracker(int cap) { + this.cap = cap; + } + + public void disable() { + this.setState(false); + } + + public void enable() { + this.setState(true); + } + + public void setState(boolean state) { + if (state != this.state) { + this.state = state; + if (state) { + GL11.glEnable(this.cap); + } else { + GL11.glDisable(this.cap); + } + } + } + } + + static class BlendFuncState { + public final CapabilityTracker capState = new CapabilityTracker(GL11.GL_BLEND); + public int srcFactorRGB = 1; + public int dstFactorRGB = 0; + public int srcFactorAlpha = 1; + public int dstFactorAlpha = 0; + } + + static class CullFaceState { + public final CapabilityTracker capState = new CapabilityTracker(GL11.GL_CULL_FACE); + public int mode = GL11.GL_BACK; + } + + static class DepthTestState { + public final CapabilityTracker capState = new CapabilityTracker(GL11.GL_DEPTH_TEST); + public boolean mask = true; + public int func = GL11.GL_LESS; + } + + static class LightState { + public final CapabilityTracker capState = new CapabilityTracker(GL11.GL_LIGHTING); + public boolean enabled = true; + } +} From 87e538164be63bf610172fa8de64d845bab8373d Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 7 Apr 2025 16:25:52 -0500 Subject: [PATCH 05/14] Actual renderer api --- .../api/client/render/Renderer.java | 44 +++ .../render/material/MaterialFinder.java | 80 +++++ .../client/render/material/MaterialView.java | 25 ++ .../render/material/RenderMaterial.java | 58 ++++ .../api/client/render/material/ShadeMode.java | 20 ++ .../api/client/render/mesh/Mesh.java | 16 + .../api/client/render/mesh/MeshView.java | 38 +++ .../api/client/render/mesh/MutableMesh.java | 47 +++ .../client/render/mesh/MutableQuadView.java | 251 +++++++++++++++ .../api/client/render/mesh/QuadEmitter.java | 210 +++++++++++++ .../api/client/render/mesh/QuadTransform.java | 10 + .../api/client/render/mesh/QuadView.java | 204 +++++++++++++ .../api/client/render/model/BakedQuad.java | 5 + .../api/client/render/model/ModelHelper.java | 80 +++++ .../api/client/render/model/SpriteFinder.java | 53 ++++ .../arsenic/renderer/ArsenicRenderer.java | 49 ++- .../arsenic/renderer/SpriteFinderImpl.java | 149 +++++++++ .../renderer/render/StateManagerImpl.java | 2 - .../renderer/render/helper/ColorHelper.java | 74 +++++ .../render/helper/GeometryHelper.java | 223 ++++++++++++++ .../renderer/render/helper/NormalHelper.java | 131 ++++++++ .../renderer/render/helper/TextureHelper.java | 94 ++++++ .../render/material/MaterialFinderImpl.java | 83 +++++ .../render/material/MaterialViewImpl.java | 85 ++++++ .../render/material/RenderMaterialImpl.java | 41 +++ .../renderer/render/mesh/EncodingFormat.java | 133 ++++++++ .../renderer/render/mesh/MeshImpl.java | 10 + .../renderer/render/mesh/MeshViewImpl.java | 80 +++++ .../renderer/render/mesh/MutableMeshImpl.java | 77 +++++ .../render/mesh/MutableQuadViewImpl.java | 285 ++++++++++++++++++ .../renderer/render/mesh/QuadViewImpl.java | 255 ++++++++++++++++ 31 files changed, 2909 insertions(+), 3 deletions(-) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/ShadeMode.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshView.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableMesh.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadTransform.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/SpriteFinderImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/ColorHelper.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/GeometryHelper.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/NormalHelper.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/TextureHelper.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialFinderImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialViewImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/RenderMaterialImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshViewImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableMeshImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java index 958a26987..3a51ebec4 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java @@ -1,7 +1,14 @@ 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.MutableMesh; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; +import net.modificationstation.stationapi.api.client.render.model.SpriteFinder; +import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; +import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.impl.client.render.RendererManager; +import org.jetbrains.annotations.Nullable; /** * Interface for rendering plug-ins that provide enhanced capabilities @@ -28,6 +35,43 @@ static void register(Renderer renderer) { RendererManager.registerRenderer(renderer); } + /** + * Obtain a new {@link MutableMesh} instance to build optimized meshes and create baked models + * with enhanced features. + * + *

Renderer does not retain a reference to returned instances, so they should be re-used + * when possible to avoid memory allocation overhead. + */ + MutableMesh mutableMesh(); + + /** + * Obtain a new {@link MaterialFinder} instance to retrieve standard {@link RenderMaterial} + * instances. + * + *

Renderer does not retain a reference to returned instances, so 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); + + SpriteFinder getSpriteFinder(SpriteAtlasTexture atlas); + /** * Obtain a new {@link BakedModelRenderer} instance used to render * baked models. diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java new file mode 100644 index 000000000..5376bc894 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java @@ -0,0 +1,80 @@ +package net.modificationstation.stationapi.api.client.render.material; + +import net.minecraft.client.Minecraft; +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.util.TriState; + +public interface MaterialFinder extends MaterialView { + /** + * When true, sprite texture and color will be rendered at full brightness. + * Lightmap values provided via {@link QuadEmitter#lightmap(int)} will be ignored. + * + *

This is the preferred method for emissive lighting effects. Some renderers + * with advanced lighting pipelines 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 #disableDiffuse(boolean)} and {@link #ambientOcclusion(TriState)}. + * + *

The default value is {@code false}. + */ + MaterialFinder emissive(boolean isEmissive); + + /** + * Controls whether vertex colors should be modified for diffuse shading. This property + * is inverted, so a value of {@code false} means that diffuse shading will be applied. + * + *

The default value is {@code false}. + * + *

This property is guaranteed to be respected in block contexts. Some renderers may also respect it in item + * contexts, but this is not guaranteed. + */ + MaterialFinder disableDiffuse(boolean disable); + + /** + * Controls whether vertex colors should be modified for ambient occlusion. + * + *

If set to {@link TriState#UNSET}, ambient occlusion will be used if the block state has + * {@linkplain BlockState#getLuminance() a luminance} of 0. Set to {@link TriState#TRUE} or {@link TriState#FALSE} + * to override this behavior. {@link TriState#TRUE} will not have an effect if + * {@linkplain Minecraft#method_2148()} () ambient occlusion is disabled globally}. + * + *

The default value is {@link TriState#UNSET}. + * + *

This property is respected only in block contexts. It will not have an effect in other contexts. + */ + MaterialFinder ambientOcclusion(TriState mode); + + /** + * A hint to the renderer about how the quad is intended to be shaded, for example through ambient occlusion and + * diffuse shading. The renderer is free to ignore this hint. + * + *

The default value is {@link ShadeMode#ENHANCED}. + * + *

This property is respected only in block contexts. It will not have an effect in other contexts. + * + * @see ShadeMode + */ + MaterialFinder shadeMode(ShadeMode mode); + + /** + * Copies all properties from the given {@link MaterialView} to this material finder. + */ + MaterialFinder copyFrom(MaterialView material); + + /** + * Resets this instance to default values. Values will match those in effect when an instance is newly obtained via + * {@link Renderer#materialFinder()}. + */ + MaterialFinder clear(); + + /** + * Returns the standard material encoding all 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(); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java new file mode 100644 index 000000000..56ea1ca0b --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.api.client.render.material; + +import net.modificationstation.stationapi.api.util.TriState; + +public interface MaterialView { + /** + * @see MaterialFinder#emissive(boolean) + */ + boolean emissive(); + + /** + * @see MaterialFinder#disableDiffuse(boolean) + */ + boolean disableDiffuse(); + + /** + * @see MaterialFinder#ambientOcclusion(TriState) + */ + TriState ambientOcclusion(); + + /** + * @see MaterialFinder#shadeMode(ShadeMode) + */ + ShadeMode shadeMode(); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java new file mode 100644 index 000000000..58026c835 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/RenderMaterial.java @@ -0,0 +1,58 @@ +package net.modificationstation.stationapi.api.client.render.material; + +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.util.Identifier; + +/** + * 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 MutableMesh} 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 extends MaterialView { + /** + * 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 RenderLayers#getBlockLayer(BlockState)} 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 STANDARD_ID = StationAPI.NAMESPACE.id("standard"); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/ShadeMode.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/ShadeMode.java new file mode 100644 index 000000000..6f0ab8bf2 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/ShadeMode.java @@ -0,0 +1,20 @@ +package net.modificationstation.stationapi.api.client.render.material; + +/** + * A hint to the renderer about how the quad is intended to be shaded, for example through ambient occlusion and + * diffuse shading. The renderer is free to ignore this hint. + */ +public enum ShadeMode { + /** + * Conveys the intent that shading should be generally consistent, lack edge cases, and produce visually pleasing + * results, even for quads that are not used by vanilla or are not possible to create through resource packs in + * vanilla. + */ + ENHANCED, + + /** + * Conveys the intent that shading should mimic vanilla results, potentially to preserve certain visuals produced + * by resource packs that modify models. + */ + VANILLA; +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java new file mode 100644 index 000000000..2ce2da044 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/Mesh.java @@ -0,0 +1,16 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +/** + * An immutable bundle of {@linkplain QuadView quads} encoded by the renderer, typically via + * {@link MutableMesh#immutableCopy()}. + * + *

All declared methods in this interface and inherited methods from {@link MeshView} are thread-safe and may be used + * concurrently. + * + *

Only the renderer should implement or extend this interface. + * + * @see MeshView + * @see MutableMesh + */ +public interface Mesh extends MeshView { +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshView.java new file mode 100644 index 000000000..e7ade6381 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MeshView.java @@ -0,0 +1,38 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; + +/** + * A bundle of {@linkplain QuadView quads} encoded by the renderer. It may be {@linkplain MutableMesh mutable} or + * {@linkplain Mesh immutable}. + * + *

Meshes are similar in purpose to {@code List} instances passed around in vanilla pipelines, but allow + * the renderer to optimize their format for performance and memory allocation. + * + *

All declared methods in this interface are not thread-safe and must not be used concurrently. Subclasses + * may override this contract. + * + *

Only the renderer should implement or extend this interface. + */ +public interface MeshView { + /** + * Returns the number of quads encoded in this mesh. + */ + @Range(from = 0, to = Integer.MAX_VALUE) + int size(); + + /** + * Access all quads encoded in this mesh. The quad instance sent to the consumer should never be retained outside + * the current call to the consumer. + * + *

Nesting calls to this method on the same mesh is allowed. + */ + void forEach(Consumer action); + + /** + * Outputs all quads in this mesh to the given quad emitter. + */ + void outputTo(QuadEmitter emitter); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableMesh.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableMesh.java new file mode 100644 index 000000000..4644d3cb4 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableMesh.java @@ -0,0 +1,47 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +import java.util.function.Consumer; + +/** + * A bundle of {@linkplain MutableQuadView mutable quads} encoded by the renderer that can have more quads added to it. + * Typically used to build optimized, thread-safe, immutable {@link Mesh}es via {@link #emitter()}, + * {@link #immutableCopy()}, and {@link #clear()}. Encoded quads can also be inspected, modified, and output directly to + * allow for advanced use cases where creating an immutable {@link Mesh} is not desirable. + * + *

All declared methods in this interface are not thread-safe and must not be used concurrently. + * + *

Only the renderer should implement or extend this interface. + * + * @see MeshView + * @see Mesh + */ +public interface MutableMesh extends MeshView { + /** + * Returns the {@link QuadEmitter} used to append quads to this mesh. Calling this method a second time invalidates + * any prior result. Do not retain references outside the context of this mesh. + */ + QuadEmitter emitter(); + + /** + * Access all the quads encoded in this mesh and modify them as necessary. The quad instance sent to the consumer + * should never be retained outside the current call to the consumer. + * + *

Nesting calls to this method on the same mesh is not allowed. + */ + void forEachMutable(Consumer action); + + /** + * Returns a new, optimized, thread-safe, immutable {@link Mesh} containing all quads currently encoded in + * {@code this} mesh. This operation does not change the state of {@code this} mesh; if you need to build another + * immutable mesh from scratch, call {@link #clear()} first. + * + *

If quad data has been added to the {@link #emitter()} but has not yet been emitted, calling this method will + * not affect it. + */ + Mesh immutableCopy(); + + /** + * Resets this mesh to an empty state with zero quads, effectively clearing all existing quads. + */ + void clear(); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java new file mode 100644 index 000000000..27b32bd3c --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java @@ -0,0 +1,251 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +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.model.BakedQuad; +import net.modificationstation.stationapi.api.client.texture.Sprite; +import net.modificationstation.stationapi.api.util.math.Direction; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector2fc; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +public interface MutableQuadView extends QuadView { + /** + * Causes texture to appear with no rotation. + * Pass in bakeFlags parameter to {@link #spriteBake(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(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(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(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(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 from what + * can be obtained via rotation and both can be applied. + * Pass in bakeFlags parameter to {@link #spriteBake(Sprite, int)}. + */ + int BAKE_FLIP_U = 8; + + /** + * Same as {@link #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(Sprite, int)}. + */ + int BAKE_NORMALIZED = 32; + + /** + * 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, Vector3f pos) { + return pos(vertexIndex, pos.x, pos.y, pos.z); + } + + /** + * Same as {@link #pos(int, float, float, float)} but accepts vector type. + */ + default MutableQuadView pos(int vertexIndex, Vector3fc pos) { + return pos(vertexIndex, pos.x(), pos.y(), pos.z()); + } + + /** + * Set vertex color in ARGB format (0xAARRGGBB). + */ + MutableQuadView color(int vertexIndex, int color); + + /** + * Convenience: set vertex color for all vertices at once. + */ + default MutableQuadView color(int c0, int c1, int c2, int c3) { + color(0, c0); + color(1, c1); + color(2, c2); + color(3, c3); + return this; + } + + /** + * Set texture coordinates. + */ + MutableQuadView uv(int vertexIndex, float u, float v); + + /** + * Set texture coordinates. + * + *

Only use this function if you already have a {@link Vector2f}. + * Otherwise, see {@link MutableQuadView#uv(int, float, float)}. + */ + default MutableQuadView uv(int vertexIndex, Vector2f uv) { + return uv(vertexIndex, uv.x, uv.y); + } + + /** + * Set texture coordinates. + * + *

Only use this function if you already have a {@link Vector2fc}. + * Otherwise, see {@link MutableQuadView#uv(int, float, float)}. + */ + default MutableQuadView uv(int vertexIndex, Vector2fc uv) { + return uv(vertexIndex, 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. + */ + MutableQuadView spriteBake(Sprite sprite, int bakeFlags); + + /** + * Accept vanilla lightmap values. Input values will override lightmap values + * computed from world state if input values are higher. Exposed for completeness + * but some rendering implementations with non-standard lighting model may not honor it. + * + *

For emissive rendering, it is better to use {@link MaterialFinder#emissive(boolean)}. + */ + MutableQuadView lightmap(int vertexIndex, int lightmap); + + /** + * Convenience: set lightmap for all vertices at once. + * + *

For emissive rendering, it is better to use {@link MaterialFinder#emissive(boolean)}. + * See {@link #lightmap(int, int)}. + */ + default MutableQuadView lightmap(int b0, int b1, int b2, int b3) { + lightmap(0, b0); + lightmap(1, b1); + lightmap(2, b2); + lightmap(3, b3); + return this; + } + + /** + * 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, Vector3f normal) { + return normal(vertexIndex, normal.x, normal.y, normal.z); + } + + /** + * Same as {@link #normal(int, float, float, float)} but accepts vector type. + */ + default MutableQuadView normal(int vertexIndex, Vector3fc normal) { + return normal(vertexIndex, normal.x(), normal.y(), normal.z()); + } + + /** + * 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 from the value reported by {@link BakedQuad#face()}. That value + * is computed based on face geometry and must be non-null in vanilla quads. + * That computed value is returned by {@link #lightFace()}. + */ + 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()}. + */ + MutableQuadView nominalFace(@Nullable Direction face); + + /** + * 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); + + /** + * Value functions identically to {@link BakedQuad#tintIndex()} and is + * used by renderer in same way. Default value is -1. + */ + MutableQuadView tintIndex(int tintIndex); + + /** + * 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); + + /** + * Copies all quad properties from the given {@link QuadView} to this quad. + * + *

Calling this method does not emit the quad. + */ + MutableQuadView copyFrom(QuadView quad); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java new file mode 100644 index 000000000..2205867d9 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java @@ -0,0 +1,210 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +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 org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector2fc; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +/** + * Specialized {@link MutableQuadView} that supports transformers and + * sends quads to some destination, such as a mesh builder or rendering. + * + *

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

Only the renderer should implement or extend this interface. + */ +public interface QuadEmitter extends MutableQuadView { + @Override + QuadEmitter pos(int vertexIndex, float x, float y, float z); + + @Override + default QuadEmitter pos(int vertexIndex, Vector3f pos) { + MutableQuadView.super.pos(vertexIndex, pos); + return this; + } + + @Override + default QuadEmitter pos(int vertexIndex, Vector3fc pos) { + MutableQuadView.super.pos(vertexIndex, pos); + return this; + } + + @Override + QuadEmitter color(int vertexIndex, int color); + + @Override + default QuadEmitter color(int c0, int c1, int c2, int c3) { + MutableQuadView.super.color(c0, c1, c2, c3); + return this; + } + + @Override + QuadEmitter uv(int vertexIndex, float u, float v); + + @Override + default QuadEmitter uv(int vertexIndex, Vector2f uv) { + MutableQuadView.super.uv(vertexIndex, uv); + return this; + } + + @Override + default QuadEmitter uv(int vertexIndex, Vector2fc uv) { + MutableQuadView.super.uv(vertexIndex, uv); + return this; + } + + @Override + QuadEmitter spriteBake(Sprite sprite, int bakeFlags); + + default QuadEmitter uvUnitSquare() { + uv(0, 0, 0); + uv(1, 0, 1); + uv(2, 1, 1); + uv(3, 1, 0); + return this; + } + + @Override + QuadEmitter lightmap(int vertexIndex, int lightmap); + + @Override + default QuadEmitter lightmap(int b0, int b1, int b2, int b3) { + MutableQuadView.super.lightmap(b0, b1, b2, b3); + return this; + } + + @Override + QuadEmitter normal(int vertexIndex, float x, float y, float z); + + @Override + default QuadEmitter normal(int vertexIndex, Vector3f normal) { + MutableQuadView.super.normal(vertexIndex, normal); + return this; + } + + @Override + default QuadEmitter normal(int vertexIndex, Vector3fc normal) { + MutableQuadView.super.normal(vertexIndex, normal); + return this; + } + + @Override + QuadEmitter cullFace(@Nullable Direction face); + + @Override + QuadEmitter nominalFace(@Nullable Direction face); + + @Override + QuadEmitter material(RenderMaterial material); + + @Override + QuadEmitter tintIndex(int tintIndex); + + @Override + QuadEmitter tag(int tag); + + QuadEmitter copyFrom(QuadView quad); + +// @Override +// QuadEmitter fromVanilla(int[] quadData, int startIndex); +// +// @Override +// QuadEmitter fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace); + + /** + * 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 EAST: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + + case WEST: + pos(0, depth, top, left); + pos(1, depth, bottom, left); + pos(2, depth, bottom, right); + pos(3, depth, top, right); + break; + + case SOUTH: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + + case NORTH: + 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; + } + + return this; + } + + /** + * Pushed transforms will be applied immediately after every call to {@link #emit()} and before the quad data is + * delivered to its destination. If any transform returns {@code false}, the emitted quad will be discarded and will + * not be delivered to its destination. + * + *

You MUST call {@link #popTransform()} once you are done using this emitter in the current scope. + * + *

More than one transformer can be pushed. Transformers are applied in reverse order. (Last pushed is applied + * first.) + * + *

Using {@code this} emitter from inside the pushed quad transform is not supported. + */ + void pushTransform(QuadTransform transform); + + /** + * Removes the transformer added by the last call to {@link #pushTransform(QuadTransform)}. MUST be called once you + * are done using this emitter in the current scope. + */ + void popTransform(); + + /** + * 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(); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadTransform.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadTransform.java new file mode 100644 index 000000000..2618a4fb6 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadTransform.java @@ -0,0 +1,10 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +@FunctionalInterface +public 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); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java new file mode 100644 index 000000000..6d9c2c6c8 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java @@ -0,0 +1,204 @@ +package net.modificationstation.stationapi.api.client.render.mesh; + +import net.modificationstation.stationapi.api.client.render.VertexFormats; +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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +/** + * Interface for reading quad data encoded in {@link Mesh}es. + * 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 = VertexFormats.BLOCK.getVertexSize() / 4; + + /** Count of integers in a conventional (un-modded) block or item quad. */ + int VANILLA_QUAD_STRIDE = VANILLA_VERTEX_STRIDE * 4; + + /** + * Retrieve geometric position, x coordinate. + */ + float x(int vertexIndex); + + /** + * Retrieve geometric position, y coordinate. + */ + float y(int vertexIndex); + + /** + * Retrieve geometric position, z coordinate. + */ + float z(int vertexIndex); + + /** + * Convenience: access x, y, z by index 0-2. + */ + float posByIndex(int vertexIndex, int coordinateIndex); + + /** + * Pass a non-null target to avoid allocation - will be returned with values. + * Otherwise returns a new instance. + */ + Vector3f copyPos(int vertexIndex, @Nullable Vector3f target); + + /** + * Retrieve vertex color in ARGB format (0xAARRGGBB). + */ + int color(int vertexIndex); + + /** + * Retrieve horizontal texture coordinates. + */ + float u(int vertexIndex); + + /** + * Retrieve vertical texture coordinates. + */ + float v(int vertexIndex); + + /** + * Pass a non-null target to avoid allocation - will be returned with values. + * Otherwise returns a new instance. + */ + Vector2f copyUv(int vertexIndex, @Nullable Vector2f target); + + /** + * Minimum block brightness. Zero if not set. + */ + int lightmap(int vertexIndex); + + /** + * If false, no vertex normal was provided. + * Lighting should use face normal in that case. + */ + boolean hasNormal(int vertexIndex); + + /** + * 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); + + /** + * 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 + Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target); + + /** + * 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(); + + /** + * Equivalent to {@link BakedQuad#face()}. 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(); + + /** + * See {@link MutableQuadView#nominalFace(Direction)}. + */ + @Nullable + 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. + * + *

Not typically needed by models. Exposed to enable standard lighting + * utility functions for use by renderers. + */ + Vector3fc faceNormal(); + + /** + * Retrieves the material serialized with the quad. + */ + RenderMaterial material(); + + /** + * Retrieves the quad tint index serialized with the quad. + */ + int tintIndex(); + + /** + * 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(); + + /** + * Reads baked vertex data and outputs standard {@link BakedQuad#vertexData() baked quad vertex data} + * in the given array and location. + * + * @param target Target array for the baked quad data. + * + * @param targetIndex Starting position in target array - array must have + * at least {@link #VANILLA_QUAD_STRIDE} elements available at this index. + */ + void toVanilla(int[] target, int targetIndex); + + /** + * Generates a new BakedQuad instance with texture + * coordinates and colors from the given sprite. + * + * @param sprite {@link QuadView} does not serialize sprites + * so the sprite must be provided by the caller. + * + * @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. + */ + @Deprecated + default BakedQuad toBakedQuad(Sprite sprite) { + int[] vertexData = new int[VANILLA_QUAD_STRIDE]; + toVanilla(vertexData, 0); + + // Mimic material properties to the largest possible extent + boolean outputShade = !material().disableDiffuse(); + // The output light emission is equal to the minimum of all four sky light values and all four block light values. + int outputLightEmission = 15; + + for (int i = 0; i < 4; i++) { + int lightmap = lightmap(i); + + if (lightmap == 0) { + outputLightEmission = 0; + break; + } + + int blockLight = lightmap >>> 4 & 15; + int skyLight = lightmap >>> 20 & 15; + outputLightEmission = Math.min(outputLightEmission, lightmap); + } + + return new BakedQuad(vertexData, tintIndex(), lightFace(), sprite, outputShade, outputLightEmission); + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java index 027a6d063..5ce6fb755 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuad.java @@ -2,10 +2,15 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.render.mesh.QuadView; import net.modificationstation.stationapi.api.client.texture.Sprite; import net.modificationstation.stationapi.api.util.math.Direction; +/** + * @deprecated functionality of this class will be replaced by {@link QuadView} + */ @Environment(EnvType.CLIENT) +@Deprecated(forRemoval = true) public record BakedQuad(int[] vertexData, int tintIndex, Direction face, Sprite sprite, boolean shade, float lightEmission) { public BakedQuad(int[] vertexData, int colorIndex, Direction face, Sprite sprite, boolean shade) { this(vertexData, colorIndex, face, sprite, shade, 0); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java new file mode 100644 index 000000000..f8182a16d --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java @@ -0,0 +1,80 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import java.util.Arrays; +import java.util.List; + +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.texture.atlas.Atlases; +import net.modificationstation.stationapi.api.util.math.Direction; +import org.jetbrains.annotations.Nullable; + +/** + * Collection of utilities for model implementations. + */ +public final class ModelHelper { + /** @see #faceFromIndex(int) */ + private static final Direction[] FACES = Arrays.copyOf(Direction.values(), 7); + + /** Result from {@link #toFaceIndex(Direction)} for null values. */ + public static final int NULL_FACE_ID = 6; + + private ModelHelper() { } + + /** + * 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(@Nullable 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]; + } + + /** + * 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 -> { + Direction cullFace = q.cullFace(); + builders[cullFace == null ? NULL_FACE_ID : cullFace.getId()].add(q.toBakedQuad(finder.find(q))); + }); + } + + @SuppressWarnings("unchecked") + List[] result = new List[7]; + + for (int i = 0; i < 7; i++) { + result[i] = builders[i].build(); + } + + return result; + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java new file mode 100644 index 000000000..3d1651797 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/SpriteFinder.java @@ -0,0 +1,53 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import net.modificationstation.stationapi.api.client.render.Renderer; +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 org.jetbrains.annotations.ApiStatus; + +/** + * 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(Sprite)}. + */ +@ApiStatus.NonExtendable +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 Renderer.get().getSpriteFinder(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); + + /** + * Alternative to {@link #find(QuadView)} 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(Sprite, int)}. + * + *

Coordinates must be in the sprite interior for reliable results. Generally will + * be easier to use {@link #find(QuadView)} 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); +} 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 83fdbd08c..0652f1aed 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 @@ -5,17 +5,64 @@ import lombok.NoArgsConstructor; import net.modificationstation.stationapi.api.client.render.Renderer; import net.modificationstation.stationapi.api.client.render.StateManager; +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.MutableMesh; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; +import net.modificationstation.stationapi.api.client.render.model.SpriteFinder; +import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; +import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.BakedModelRendererImpl; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.StateManagerImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.MaterialFinderImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableMeshImpl; +import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; import java.util.function.Supplier; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class ArsenicRenderer implements Renderer { - public static final ArsenicRenderer INSTANCE = new ArsenicRenderer(); + public static final RenderMaterial STANDARD_MATERIAL = INSTANCE.materialFinder().find(); + + static { + INSTANCE.registerMaterial(RenderMaterial.STANDARD_ID, STANDARD_MATERIAL); + } + + private final Map materialMap = new HashMap<>(); + + @Override + public MutableMesh mutableMesh() { + return new MutableMeshImpl(); + } + + @Override + public MaterialFinder materialFinder() { + return new MaterialFinderImpl(); + } + + @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 SpriteFinder getSpriteFinder(SpriteAtlasTexture atlas) { + return SpriteFinderImpl.get(atlas); + } + @Override public BakedModelRenderer bakedModelRenderer() { return bakedModelRenderer.get(); diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/SpriteFinderImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/SpriteFinderImpl.java new file mode 100644 index 000000000..e5ed7d47f --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/SpriteFinderImpl.java @@ -0,0 +1,149 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer; + +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 static final Logger LOGGER = LoggerFactory.getLogger(SpriteFinderImpl.class); + + private final Node root; + private final SpriteAtlasTexture spriteAtlasTexture; + private int badSpriteCount = 0; + + 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) { + float u = 0; + float v = 0; + + for (int i = 0; i < 4; i++) { + u += quad.u(i); + v += quad.v(i); + } + + 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) { + if (sprite.getMinU() < 0 - EPS || sprite.getMaxU() > 1 + EPS || sprite.getMinV() < 0 - EPS || sprite.getMaxV() > 1 + EPS) { + // Sprite has broken bounds. This SHOULD NOT happen, but in the past some mods have broken this. + // Prefer failing with a log warning rather than risking a stack overflow. + if (badSpriteCount++ < 5) { + String errorMessage = "SpriteFinderImpl: Skipping sprite {} with broken bounds [{}, {}]x[{}, {}]. Sprite bounds should be between 0 and 1."; + LOGGER.error(errorMessage, sprite.getContents().getId(), sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV()); + } + + return; + } + + 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 ((SpriteFinderAccess) atlas).fabric_spriteFinder(); + } + + public interface SpriteFinderAccess { + SpriteFinderImpl fabric_spriteFinder(); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java index 8167f904a..22ccdd754 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/StateManagerImpl.java @@ -1,7 +1,5 @@ package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; import net.modificationstation.stationapi.api.client.render.StateManager; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/ColorHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/ColorHelper.java new file mode 100644 index 000000000..99fd50211 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/ColorHelper.java @@ -0,0 +1,74 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper; + +import java.nio.ByteOrder; + +/** + * Static routines of general utility for renderer implementations. + * Renderers are not required to use these helpers, but they were + * designed to be usable without the default renderer. + */ +public final class ColorHelper { + private ColorHelper() { } + + private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + + /** + * Component-wise max. + */ + public static int maxLight(int l0, int l1) { + if (l0 == 0) return l1; + if (l1 == 0) return l0; + + return Math.max(l0 & 0xFFFF, l1 & 0xFFFF) | Math.max(l0 & 0xFFFF0000, l1 & 0xFFFF0000); + } + + /* + Renderer color format: ARGB (0xAARRGGBB) + Vanilla color format (little endian): ABGR (0xAABBGGRR) + Vanilla color format (big endian): RGBA (0xRRGGBBAA) + + Why does the vanilla color format change based on endianness? + See VertexConsumer#quad. Quad data is loaded as integers into + a native byte order buffer. Color is read directly from bytes + 12, 13, 14 of each vertex. A different byte order will yield + different results. + + The renderer always uses ARGB because the API color methods + always consume and return ARGB. Vanilla block and item colors + also use ARGB. + */ + + /** + * Converts from ARGB color to ABGR color if little endian or RGBA color if big endian. + */ + public static int toVanillaColor(int color) { + if (color == -1) { + return -1; + } + + if (BIG_ENDIAN) { + // ARGB to RGBA + return ((color & 0x00FFFFFF) << 8) | ((color & 0xFF000000) >>> 24); + } else { + // ARGB to ABGR + return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16); + } + } + + /** + * Converts to ARGB color from ABGR color if little endian or RGBA color if big endian. + */ + public static int fromVanillaColor(int color) { + if (color == -1) { + return -1; + } + + if (BIG_ENDIAN) { + // RGBA to ARGB + return ((color & 0xFFFFFF00) >>> 8) | ((color & 0x000000FF) << 24); + } else { + // ABGR to ARGB + return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16); + } + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/GeometryHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/GeometryHelper.java new file mode 100644 index 000000000..d00989422 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/GeometryHelper.java @@ -0,0 +1,223 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.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.Direction.Axis; +import net.modificationstation.stationapi.api.util.math.Direction.AxisDirection; +import org.joml.Vector3fc; + +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 final 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) its light face. */ + public static final int AXIS_ALIGNED_FLAG = CUBIC_FLAG << 1; + + /** set when a quad is coplanar with its light face. Implies {@link #AXIS_ALIGNED_FLAG} */ + public static final int LIGHT_FACE_FLAG = AXIS_ALIGNED_FLAG << 1; + + /** how many bits quad header encoding should reserve for encoding geometry flags. */ + public static final int FLAG_BIT_COUNT = 3; + + private static final float EPS_MIN = 0.0001f; + private static final float EPS_MAX = 1.0f - EPS_MIN; + + /** + * Analyzes the quad and returns a value with some combination + * of {@link #AXIS_ALIGNED_FLAG}, {@link #LIGHT_FACE_FLAG} and {@link #CUBIC_FLAG}. + * Intended use is to optimize lighting when the geometry is regular. + * Expects convex quads with all points co-planar. + */ + public static int computeShapeFlags(QuadView quad) { + Direction lightFace = quad.lightFace(); + int bits = 0; + + if (isQuadParallelToFace(lightFace, quad)) { + bits |= AXIS_ALIGNED_FLAG; + + if (isParallelQuadOnFace(lightFace, quad)) { + bits |= LIGHT_FACE_FLAG; + } + } + + if (isQuadCubic(lightFace, quad)) { + bits |= CUBIC_FLAG; + } + + return bits; + } + + /** + * Returns true if quad is parallel to the given face. + * Does not validate quad winding order. + * Expects convex quads with all points co-planar. + */ + public static boolean isQuadParallelToFace(Direction face, QuadView quad) { + int i = face.getAxis().ordinal(); + final float val = quad.posByIndex(0, i); + return 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) { + final float x = quad.posByIndex(0, lightFace.getAxis().ordinal()); + return lightFace.getDirection() == AxisDirection.POSITIVE ? x >= EPS_MAX : x <= EPS_MIN; + } + + /** + * Returns true if quad is truly a quad (not a triangle) and fills a full block cross-section. + * If known to be true, allows use of a simpler/faster AO lighting algorithm. + * + *

Does not check if quad is actually coplanar with the light face, nor does it check that all + * quad vertices are coplanar with each other. + * + *

Expects convex quads with all points co-planar. + */ + public static boolean isQuadCubic(Direction lightFace, QuadView quad) { + int a, b; + + switch (lightFace) { + case EAST: + case WEST: + a = 1; + b = 2; + break; + case UP: + case DOWN: + a = 0; + b = 2; + break; + case SOUTH: + case NORTH: + a = 1; + b = 0; + break; + default: + // handle WTF case + return false; + } + + return confirmSquareCorners(a, b, quad); + } + + /** + * Used by {@link #isQuadCubic(Direction, QuadView)}. + * True if quad touches all four corners of unit square. + * + *

For compatibility with resource packs that contain models with quads exceeding + * block boundaries, considers corners outside the block to be at the corners. + */ + private static boolean confirmSquareCorners(int aCoordinate, int bCoordinate, QuadView quad) { + int flags = 0; + + for (int i = 0; i < 4; i++) { + final float a = quad.posByIndex(i, aCoordinate); + final float b = quad.posByIndex(i, bCoordinate); + + if (a <= EPS_MIN) { + if (b <= EPS_MIN) { + flags |= 1; + } else if (b >= EPS_MAX) { + flags |= 2; + } else { + return false; + } + } else if (a >= EPS_MAX) { + if (b <= EPS_MIN) { + flags |= 4; + } else if (b >= EPS_MAX) { + flags |= 8; + } else { + return false; + } + } else { + return false; + } + } + + return flags == 15; + } + + /** + * Identifies the face to which the quad is most closely aligned. + * This mimics the value that {@link BakedQuad#face()} 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 Vector3fc normal = quad.faceNormal(); + switch (GeometryHelper.longestAxis(normal)) { + case X: + return normal.x() > 0 ? Direction.EAST : Direction.WEST; + + case Y: + return normal.y() > 0 ? Direction.UP : Direction.DOWN; + + case Z: + return normal.z() > 0 ? Direction.SOUTH : Direction.NORTH; + + default: + // handle WTF case + return Direction.UP; + } + } + + /** + * Simple 4-way compare, doesn't handle NaN values. + */ + public static float min(float a, float b, float c, float d) { + final float x = a < b ? a : b; + final float y = c < d ? c : d; + return x < y ? x : y; + } + + /** + * Simple 4-way compare, doesn't handle NaN values. + */ + public static float max(float a, float b, float c, float d) { + final float x = a > b ? a : b; + final float y = c > d ? c : d; + return x > y ? x : y; + } + + /** + * @see #longestAxis(float, float, float) + */ + public static Axis longestAxis(Vector3fc vec) { + return longestAxis(vec.x(), vec.y(), vec.z()); + } + + /** + * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector. + */ + public static Axis longestAxis(float normalX, float normalY, float normalZ) { + Axis result = Axis.Y; + float longest = Math.abs(normalY); + float a = Math.abs(normalX); + + if (a > longest) { + result = Axis.X; + longest = a; + } + + return Math.abs(normalZ) > longest + ? Axis.Z : result; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/NormalHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/NormalHelper.java new file mode 100644 index 000000000..25904dd73 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/NormalHelper.java @@ -0,0 +1,131 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.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.Vec3i; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; + +/** + * Static routines of general utility for renderer implementations. + * Renderers are not required to use these helpers, but they were + * designed to be usable without the default renderer. + */ +public final class NormalHelper { + private NormalHelper() { } + + private static final float PACK = 127.0f; + private static final float UNPACK = 1.0f / PACK; + + /** + * Stores a normal plus an extra value as a quartet of signed bytes. + * This is the same normal format that vanilla rendering expects. + * The extra value is for use by shaders. + */ + public static int packNormal(float x, float y, float z, float w) { + x = 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 * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16) | (((int) (w * PACK) & 0xFF) << 24); + } + + /** + * Version of {@link #packNormal(float, float, float, float)} that accepts a vector type. + */ + public static int packNormal(Vector3f normal, float w) { + return packNormal(normal.x(), normal.y(), normal.z(), w); + } + + /** + * Like {@link #packNormal(float, float, float, float)}, but without a {@code w} value. + */ + public static int packNormal(float x, float y, float z) { + x = MathHelper.clamp(x, -1, 1); + y = MathHelper.clamp(y, -1, 1); + z = MathHelper.clamp(z, -1, 1); + + return ((int) (x * PACK) & 0xFF) | (((int) (y * PACK) & 0xFF) << 8) | (((int) (z * PACK) & 0xFF) << 16); + } + + /** + * Like {@link #packNormal(Vector3f, float)}, but without a {@code w} value. + */ + public static int packNormal(Vector3f normal) { + return packNormal(normal.x(), normal.y(), normal.z()); + } + + public static float unpackNormalX(int packedNormal) { + return ((byte) (packedNormal & 0xFF)) * UNPACK; + } + + public static float unpackNormalY(int packedNormal) { + return ((byte) ((packedNormal >>> 8) & 0xFF)) * UNPACK; + } + + public static float unpackNormalZ(int packedNormal) { + return ((byte) ((packedNormal >>> 16) & 0xFF)) * UNPACK; + } + + public static float unpackNormalW(int packedNormal) { + return ((byte) ((packedNormal >>> 24) & 0xFF)) * UNPACK; + } + + public static void unpackNormal(int packedNormal, Vector3f target) { + target.set(unpackNormalX(packedNormal), unpackNormalY(packedNormal), unpackNormalZ(packedNormal)); + } + + /** + * Computes the face normal of the given quad and saves it in the provided non-null vector. + * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that + * face and, if so, use the standard normal for that face direction. + * + *

Will work with triangles also. Assumes counter-clockwise winding order, which is the norm. + * Expects convex quads with all points co-planar. + */ + public static void computeFaceNormal(@NotNull Vector3f saveTo, QuadView q) { + final Direction nominalFace = q.nominalFace(); + + if (nominalFace != null && GeometryHelper.isQuadParallelToFace(nominalFace, q)) { + Vec3i vec = nominalFace.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); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/TextureHelper.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/TextureHelper.java new file mode 100644 index 000000000..518ebe09c --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/helper/TextureHelper.java @@ -0,0 +1,94 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.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, Sprite, int)}. Also used by the API + * itself to implement automatic block-breaking models for enhanced models. + */ +public final 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, Sprite sprite, int bakeFlags) { + if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) { + // Assigns normalized UV coordinates based on vertex positions + applyModifier(quad, UVLOCKERS[quad.nominalFace().getId()]); + } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { // flag is NOT set, UVs are assumed to not be normalized yet as is the default, normalize through dividing by 16 + // Scales from 0-16 to 0-1 + applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER)); + } + + final int rotation = bakeFlags & 3; + + if (rotation != 0) { + // Rotates texture around the center of sprite. + // Assumes normalized coordinates. + applyModifier(quad, ROTATIONS[rotation]); + } + + if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) { + // Inverts U coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i))); + } + + if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) { + // Inverts V coordinates. Assumes normalized (0-1) values. + applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i))); + } + + interpolate(quad, sprite); + } + + /** + * Faster than sprite method. Sprite computes span and normalizes inputs each call, + * so we'd have to denormalize before we called, only to have the sprite renormalize immediately. + */ + private static void interpolate(MutableQuadView q, 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.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan); + } + } + + @FunctionalInterface + private interface VertexModifier { + void apply(MutableQuadView quad, int vertexIndex); + } + + private static void applyModifier(MutableQuadView quad, VertexModifier modifier) { + for (int i = 0; i < 4; i++) { + modifier.apply(quad, i); + } + } + + private static final VertexModifier[] ROTATIONS = new VertexModifier[] { + null, + (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), //90 + (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), //180 + (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270 + }; + + private static final VertexModifier[] UVLOCKERS = new VertexModifier[6]; + + static { + UVLOCKERS[Direction.EAST.getId()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i)); + UVLOCKERS[Direction.WEST.getId()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i)); + UVLOCKERS[Direction.NORTH.getId()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i)); + UVLOCKERS[Direction.SOUTH.getId()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i)); + UVLOCKERS[Direction.DOWN.getId()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i)); + UVLOCKERS[Direction.UP.getId()] = (q, i) -> q.uv(i, q.x(i), q.z(i)); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialFinderImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialFinderImpl.java new file mode 100644 index 000000000..f8cdc5017 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialFinderImpl.java @@ -0,0 +1,83 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material; + +import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; +import net.modificationstation.stationapi.api.client.render.material.MaterialView; +import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; +import net.modificationstation.stationapi.api.client.render.material.ShadeMode; +import net.modificationstation.stationapi.api.util.TriState; + +import java.util.Objects; + +public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFinder { + private static final int DEFAULT_BITS; + + static { + // Start with all zeroes + MaterialFinderImpl finder = new MaterialFinderImpl(0); + // Apply non-zero defaults + finder.ambientOcclusion(TriState.UNSET); + DEFAULT_BITS = finder.bits; + + if (!areBitsValid(DEFAULT_BITS)) { + throw new AssertionError("Default MaterialFinder bits are not valid!"); + } + } + + protected MaterialFinderImpl(int bits) { + super(bits); + } + + public MaterialFinderImpl() { + this(DEFAULT_BITS); + } + + @Override + public MaterialFinder emissive(boolean isEmissive) { + bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG); + return this; + } + + @Override + public MaterialFinder disableDiffuse(boolean disable) { + bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG); + return this; + } + + @Override + public MaterialFinder ambientOcclusion(TriState mode) { + Objects.requireNonNull(mode, "ambient occlusion TriState may not be null"); + + bits = (bits & ~AO_MASK) | (mode.ordinal() << AO_BIT_OFFSET); + return this; + } + + @Override + public MaterialFinder shadeMode(ShadeMode mode) { + Objects.requireNonNull(mode, "ShadeMode may not be null"); + + bits = (bits & ~SHADE_MODE_MASK) | (mode.ordinal() << SHADE_MODE_BIT_OFFSET); + return this; + } + + @Override + public MaterialFinder copyFrom(MaterialView material) { + bits = ((MaterialViewImpl) material).bits; + return this; + } + + @Override + public MaterialFinder clear() { + bits = DEFAULT_BITS; + return this; + } + + @Override + public RenderMaterial find() { + return RenderMaterialImpl.byIndex(bits); + } + + @Override + public String toString() { + return "MaterialFinderImpl{" + contentsToString() + "}"; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialViewImpl.java new file mode 100644 index 000000000..7683b9322 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/MaterialViewImpl.java @@ -0,0 +1,85 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material; + +import net.modificationstation.stationapi.api.client.render.material.MaterialView; +import net.modificationstation.stationapi.api.client.render.material.ShadeMode; +import net.modificationstation.stationapi.api.util.TriState; +import net.modificationstation.stationapi.api.util.math.MathHelper; + +import java.util.Locale; + +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.bitMask; + +/** + * Default implementation of the standard render materials. + * The underlying representation is simply an int with bit-wise + * packing of the various material properties. This offers + * easy/fast interning via int/object hashmap. + */ +public class MaterialViewImpl implements MaterialView { + private static final TriState[] TRI_STATES = TriState.values(); + private static final int TRI_STATE_COUNT = TRI_STATES.length; + private static final ShadeMode[] SHADE_MODES = ShadeMode.values(); + private static final int SHADE_MODE_COUNT = SHADE_MODES.length; + + protected static final int EMISSIVE_BIT_LENGTH = 1; + protected static final int DIFFUSE_BIT_LENGTH = 1; + protected static final int AO_BIT_LENGTH = MathHelper.ceilLog2(TRI_STATE_COUNT); + protected static final int SHADE_MODE_BIT_LENGTH = MathHelper.ceilLog2(SHADE_MODE_COUNT); + + protected static final int EMISSIVE_BIT_OFFSET = 0; + protected static final int DIFFUSE_BIT_OFFSET = EMISSIVE_BIT_OFFSET + EMISSIVE_BIT_LENGTH; + protected static final int AO_BIT_OFFSET = DIFFUSE_BIT_OFFSET + DIFFUSE_BIT_LENGTH; + protected static final int SHADE_MODE_BIT_OFFSET = AO_BIT_OFFSET + AO_BIT_LENGTH; + public static final int TOTAL_BIT_LENGTH = SHADE_MODE_BIT_OFFSET + SHADE_MODE_BIT_LENGTH; + + protected static final int EMISSIVE_FLAG = bitMask(EMISSIVE_BIT_LENGTH, EMISSIVE_BIT_OFFSET); + protected static final int DIFFUSE_FLAG = bitMask(DIFFUSE_BIT_LENGTH, DIFFUSE_BIT_OFFSET); + protected static final int AO_MASK = bitMask(AO_BIT_LENGTH, AO_BIT_OFFSET); + protected static final int SHADE_MODE_MASK = bitMask(SHADE_MODE_BIT_LENGTH, SHADE_MODE_BIT_OFFSET); + + protected static boolean areBitsValid(int bits) { + int ao = (bits & AO_MASK) >>> AO_BIT_OFFSET; + int shadeMode = (bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET; + + return ao < TRI_STATE_COUNT + && shadeMode < SHADE_MODE_COUNT; + } + + protected int bits; + + protected MaterialViewImpl(int bits) { + this.bits = bits; + } + + @Override + public boolean emissive() { + return (bits & EMISSIVE_FLAG) != 0; + } + + @Override + public boolean disableDiffuse() { + return (bits & DIFFUSE_FLAG) != 0; + } + + @Override + public TriState ambientOcclusion() { + return TRI_STATES[(bits & AO_MASK) >>> AO_BIT_OFFSET]; + } + + @Override + public ShadeMode shadeMode() { + return SHADE_MODES[(bits & SHADE_MODE_MASK) >>> SHADE_MODE_BIT_OFFSET]; + } + + /** + * Returns a string representation of the material properties. + * To be used in {@link #toString} overrides so they show in the debugger. + */ + String contentsToString() { + return String.format("emissive=%b, disable diffuse=%b, ao=%s, shade=%s", + emissive(), + disableDiffuse(), + ambientOcclusion().toString().toLowerCase(Locale.ROOT), + shadeMode().toString().toLowerCase(Locale.ROOT)); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/RenderMaterialImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/RenderMaterialImpl.java new file mode 100644 index 000000000..3dd49c5e9 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/material/RenderMaterialImpl.java @@ -0,0 +1,41 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material; + +import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; + +public class RenderMaterialImpl extends MaterialViewImpl implements RenderMaterial { + public static final int VALUE_COUNT = 1 << TOTAL_BIT_LENGTH; + private static final RenderMaterialImpl[] BY_INDEX = new RenderMaterialImpl[VALUE_COUNT]; + + static { + for (int i = 0; i < VALUE_COUNT; i++) { + if (areBitsValid(i)) { + BY_INDEX[i] = new RenderMaterialImpl(i); + } + } + } + + private RenderMaterialImpl(int bits) { + super(bits); + } + + public int index() { + return bits; + } + + @Override + public String toString() { + return "RenderMaterialImpl{" + contentsToString() + "}"; + } + + public static RenderMaterialImpl byIndex(int index) { + return BY_INDEX[index]; + } + + public static RenderMaterialImpl setDisableDiffuse(RenderMaterialImpl material, boolean disable) { + if (material.disableDiffuse() != disable) { + return byIndex(disable ? (material.bits | DIFFUSE_FLAG) : (material.bits & ~DIFFUSE_FLAG)); + } + + return material; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java new file mode 100644 index 000000000..51cf26e97 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java @@ -0,0 +1,133 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import com.google.common.base.Preconditions; +import net.modificationstation.stationapi.api.client.render.VertexFormat; +import net.modificationstation.stationapi.api.client.render.VertexFormats; +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.render.helper.GeometryHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.MaterialViewImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.RenderMaterialImpl; +import org.jetbrains.annotations.Nullable; + +/** + * Holds all the array offsets and bit-wise encoders/decoders for + * packing/unpacking quad data in an array of integers. + * All of this is implementation-specific - that's why it isn't a "helper" class. + */ +public final class EncodingFormat { + private EncodingFormat() { } + + static final int HEADER_BITS = 0; + static final int HEADER_FACE_NORMAL = 1; + static final int HEADER_TINT_INDEX = 2; + static final int HEADER_TAG = 3; + public static final int HEADER_STRIDE = 4; + + static final int VERTEX_X; + static final int VERTEX_Y; + static final int VERTEX_Z; + static final int VERTEX_COLOR; + static final int VERTEX_U; + static final int VERTEX_V; + static final int VERTEX_LIGHTMAP; + static final int VERTEX_NORMAL; + public static final int VERTEX_STRIDE; + + public static final int QUAD_STRIDE; + public static final int QUAD_STRIDE_BYTES; + public static final int TOTAL_STRIDE; + + static { + final VertexFormat format = VertexFormats.BLOCK; + VERTEX_X = HEADER_STRIDE + 0; + VERTEX_Y = HEADER_STRIDE + 1; + VERTEX_Z = HEADER_STRIDE + 2; + VERTEX_COLOR = HEADER_STRIDE + 3; + VERTEX_U = HEADER_STRIDE + 4; + VERTEX_V = VERTEX_U + 1; + VERTEX_LIGHTMAP = HEADER_STRIDE + 6; + VERTEX_NORMAL = HEADER_STRIDE + 7; + VERTEX_STRIDE = format.getVertexSize() / 4; + QUAD_STRIDE = VERTEX_STRIDE * 4; + QUAD_STRIDE_BYTES = QUAD_STRIDE * 4; + TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE; + + Preconditions.checkState(VERTEX_STRIDE == QuadView.VANILLA_VERTEX_STRIDE, "Arsenic vertex stride (%s) mismatched with rendering API (%s)", VERTEX_STRIDE, QuadView.VANILLA_VERTEX_STRIDE); + Preconditions.checkState(QUAD_STRIDE == QuadView.VANILLA_QUAD_STRIDE, "Arsenic quad stride (%s) mismatched with rendering API (%s)", QUAD_STRIDE, QuadView.VANILLA_QUAD_STRIDE); + } + + private static final int DIRECTION_COUNT = Direction.values().length; + private static final int NULLABLE_DIRECTION_COUNT = DIRECTION_COUNT + 1; + + private static final int CULL_BIT_LENGTH = MathHelper.ceilLog2(NULLABLE_DIRECTION_COUNT); + private static final int LIGHT_BIT_LENGTH = MathHelper.ceilLog2(DIRECTION_COUNT); + private static final int NORMALS_BIT_LENGTH = 4; + private static final int GEOMETRY_BIT_LENGTH = GeometryHelper.FLAG_BIT_COUNT; + private static final int MATERIAL_BIT_LENGTH = MaterialViewImpl.TOTAL_BIT_LENGTH; + + private static final int CULL_BIT_OFFSET = 0; + private static final int LIGHT_BIT_OFFSET = CULL_BIT_OFFSET + CULL_BIT_LENGTH; + private static final int NORMALS_BIT_OFFSET = LIGHT_BIT_OFFSET + LIGHT_BIT_LENGTH; + private static final int GEOMETRY_BIT_OFFSET = NORMALS_BIT_OFFSET + NORMALS_BIT_LENGTH; + private static final int MATERIAL_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH; + private static final int TOTAL_BIT_LENGTH = MATERIAL_BIT_OFFSET + MATERIAL_BIT_LENGTH; + + private static final int CULL_MASK = bitMask(CULL_BIT_LENGTH, CULL_BIT_OFFSET); + private static final int LIGHT_MASK = bitMask(LIGHT_BIT_LENGTH, LIGHT_BIT_OFFSET); + private static final int NORMALS_MASK = bitMask(NORMALS_BIT_LENGTH, NORMALS_BIT_OFFSET); + private static final int GEOMETRY_MASK = bitMask(GEOMETRY_BIT_LENGTH, GEOMETRY_BIT_OFFSET); + private static final int MATERIAL_MASK = bitMask(MATERIAL_BIT_LENGTH, MATERIAL_BIT_OFFSET); + + static { + Preconditions.checkArgument(TOTAL_BIT_LENGTH <= 32, "Arsenic header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE); + } + + public static int bitMask(int bitLength, int bitOffset) { + return ((1 << bitLength) - 1) << bitOffset; + } + + @Nullable + static Direction cullFace(int bits) { + return ModelHelper.faceFromIndex((bits & CULL_MASK) >>> CULL_BIT_OFFSET); + } + + static int cullFace(int bits, @Nullable Direction face) { + return (bits & ~CULL_MASK) | (ModelHelper.toFaceIndex(face) << CULL_BIT_OFFSET); + } + + static Direction lightFace(int bits) { + return ModelHelper.faceFromIndex((bits & LIGHT_MASK) >>> LIGHT_BIT_OFFSET); + } + + static int lightFace(int bits, Direction face) { + return (bits & ~LIGHT_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_BIT_OFFSET); + } + + /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */ + static int normalFlags(int bits) { + return (bits & NORMALS_MASK) >>> NORMALS_BIT_OFFSET; + } + + static int normalFlags(int bits, int normalFlags) { + return (bits & ~NORMALS_MASK) | ((normalFlags << NORMALS_BIT_OFFSET) & NORMALS_MASK); + } + + static int geometryFlags(int bits) { + return (bits & GEOMETRY_MASK) >>> GEOMETRY_BIT_OFFSET; + } + + static int geometryFlags(int bits, int geometryFlags) { + return (bits & ~GEOMETRY_MASK) | ((geometryFlags << GEOMETRY_BIT_OFFSET) & GEOMETRY_MASK); + } + + static RenderMaterialImpl material(int bits) { + return RenderMaterialImpl.byIndex((bits & MATERIAL_MASK) >>> MATERIAL_BIT_OFFSET); + } + + static int material(int bits, RenderMaterialImpl material) { + return (bits & ~MATERIAL_MASK) | (material.index() << MATERIAL_BIT_OFFSET); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshImpl.java new file mode 100644 index 000000000..d078cfd97 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshImpl.java @@ -0,0 +1,10 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import net.modificationstation.stationapi.api.client.render.mesh.Mesh; + +public class MeshImpl extends MeshViewImpl implements Mesh { + public MeshImpl(int[] data) { + this.data = data; + limit = data.length; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshViewImpl.java new file mode 100644 index 000000000..bdeeb8754 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MeshViewImpl.java @@ -0,0 +1,80 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.modificationstation.stationapi.api.client.render.mesh.MeshView; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; +import net.modificationstation.stationapi.api.client.render.mesh.QuadView; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; + +public class MeshViewImpl implements MeshView { + /** Used to satisfy external calls to {@link #forEach(Consumer)}. */ + private static final ThreadLocal> CURSOR_POOLS = ThreadLocal.withInitial(ObjectArrayList::new); + + int[] data; + int limit; + + MeshViewImpl() { + } + + @Override + @Range(from = 0, to = Integer.MAX_VALUE) + public int size() { + return limit / EncodingFormat.TOTAL_STRIDE; + } + + @Override + public void forEach(Consumer action) { + ObjectArrayList pool = CURSOR_POOLS.get(); + QuadViewImpl cursor; + + if (pool.isEmpty()) { + cursor = new QuadViewImpl(); + } else { + cursor = pool.pop(); + } + + forEach(action, cursor); + + pool.push(cursor); + } + + /** + * The renderer can call this with its own cursor to avoid the performance hit of a + * thread-local lookup or to use a mutable cursor. + */ + void forEach(Consumer action, C cursor) { + final int limit = this.limit; + int index = 0; + cursor.data = data; + + while (index < limit) { + cursor.baseIndex = index; + cursor.load(); + action.accept(cursor); + index += EncodingFormat.TOTAL_STRIDE; + } + + cursor.data = null; + } + + // TODO: This could be optimized by checking if the emitter is that of a MutableMeshImpl and if + // it has no transforms, in which case the entire data array can be copied in bulk. + @Override + public void outputTo(QuadEmitter emitter) { + MutableQuadViewImpl e = (MutableQuadViewImpl) emitter; + final int[] data = this.data; + final int limit = this.limit; + int index = 0; + + while (index < limit) { + System.arraycopy(data, index, e.data, e.baseIndex, EncodingFormat.TOTAL_STRIDE); + e.load(); + e.transformAndEmit(); + index += EncodingFormat.TOTAL_STRIDE; + } + + e.clear(); + } +} \ No newline at end of file diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableMeshImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableMeshImpl.java new file mode 100644 index 000000000..7fc5aa293 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableMeshImpl.java @@ -0,0 +1,77 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import net.modificationstation.stationapi.api.client.render.mesh.Mesh; +import net.modificationstation.stationapi.api.client.render.mesh.MutableMesh; +import net.modificationstation.stationapi.api.client.render.mesh.MutableQuadView; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; + +import java.util.function.Consumer; + +/** + * Our implementation of {@link MutableMesh}, mainly used for optimized mesh creation. + * 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 #emitter}. + */ +public class MutableMeshImpl extends MeshViewImpl implements MutableMesh { + private final MutableQuadViewImpl emitter = new MutableQuadViewImpl() { + @Override + protected void emitDirectly() { + // Necessary because the validity of geometry is not encoded; reading mesh data always + // uses QuadViewImpl#load(), which assumes valid geometry. Built immutable meshes + // should also have valid geometry for better performance. + computeGeometry(); + limit += EncodingFormat.TOTAL_STRIDE; + ensureCapacity(EncodingFormat.TOTAL_STRIDE); + baseIndex = limit; + } + }; + + public MutableMeshImpl() { + data = new int[8 * EncodingFormat.TOTAL_STRIDE]; + limit = 0; + + ensureCapacity(EncodingFormat.TOTAL_STRIDE); + emitter.data = data; + emitter.baseIndex = limit; + emitter.clear(); + } + + private void ensureCapacity(int stride) { + if (stride > data.length - limit) { + final int[] bigger = new int[data.length * 2]; + System.arraycopy(data, 0, bigger, 0, limit); + data = bigger; + emitter.data = data; + } + } + + @Override + public QuadEmitter emitter() { + emitter.clear(); + return emitter; + } + + @Override + public void forEachMutable(Consumer action) { + // emitDirectly will not be called by forEach, so just reuse the main emitter. + forEach(action, emitter); + emitter.data = data; + emitter.baseIndex = limit; + } + + @Override + public Mesh immutableCopy() { + final int[] packed = new int[limit]; + System.arraycopy(data, 0, packed, 0, limit); + return new MeshImpl(packed); + } + + @Override + public void clear() { + limit = 0; + emitter.baseIndex = limit; + emitter.clear(); + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java new file mode 100644 index 000000000..5713e2053 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java @@ -0,0 +1,285 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_BITS; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TAG; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TINT_INDEX; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_COLOR; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_LIGHTMAP; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_NORMAL; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_STRIDE; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_U; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_X; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +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.mesh.QuadTransform; +import net.modificationstation.stationapi.api.client.render.mesh.QuadView; +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.render.helper.NormalHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.TextureHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.RenderMaterialImpl; +import org.jetbrains.annotations.Nullable; + +/** + * Almost-concrete implementation of a mutable quad. The only missing part is {@link #emitDirectly()}, + * because that depends on where/how it is used. (Mesh encoding vs. render-time transformation). + * + *

In many cases an instance of this class is used as an "editor quad". The editor quad's + * {@link #emitDirectly()} method calls some other internal method that transforms the quad + * data and then buffers it. Transformations should be the same as they would be in a vanilla + * render - the editor is serving mainly as a way to access vertex data without magical + * numbers. It also allows for a consistent interface for those transformations. + */ +public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEmitter { + private static final QuadTransform NO_TRANSFORM = q -> true; + + private static final int[] DEFAULT_QUAD_DATA = new int[EncodingFormat.TOTAL_STRIDE]; + + static { + MutableQuadViewImpl quad = new MutableQuadViewImpl() { + @Override + protected void emitDirectly() { + // This quad won't be emitted. It's only used to configure the default quad data. + } + }; + + // Start with all zeroes + quad.data = DEFAULT_QUAD_DATA; + // Apply non-zero defaults + quad.color(-1, -1, -1, -1); + quad.cullFace(null); + quad.material(ArsenicRenderer.STANDARD_MATERIAL); + quad.tintIndex(-1); + } + + private QuadTransform activeTransform = NO_TRANSFORM; + private final ObjectArrayList transformStack = new ObjectArrayList<>(); + private final QuadTransform stackTransform = q -> { + int i = transformStack.size() - 1; + + while (i >= 0) { + if (!transformStack.get(i--).transform(q)) { + return false; + } + } + + return true; + }; + + public final void clear() { + System.arraycopy(DEFAULT_QUAD_DATA, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE); + isGeometryInvalid = true; + nominalFace = null; + } + + @Override + public final MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) { + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + data[index] = Float.floatToRawIntBits(x); + data[index + 1] = Float.floatToRawIntBits(y); + data[index + 2] = Float.floatToRawIntBits(z); + isGeometryInvalid = true; + return this; + } + + @Override + public final MutableQuadViewImpl color(int vertexIndex, int color) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color; + return this; + } + + @Override + public final MutableQuadViewImpl uv(int vertexIndex, float u, float v) { + final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U; + data[i] = Float.floatToRawIntBits(u); + data[i + 1] = Float.floatToRawIntBits(v); + return this; + } + + @Override + public final MutableQuadViewImpl spriteBake(Sprite sprite, int bakeFlags) { + TextureHelper.bakeSprite(this, sprite, bakeFlags); + return this; + } + + @Override + public final MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) { + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap; + return this; + } + + protected final void normalFlags(int flags) { + data[baseIndex + HEADER_BITS] = EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS], flags); + } + + @Override + public final MutableQuadViewImpl normal(int vertexIndex, float x, float y, float z) { + normalFlags(normalFlags() | (1 << vertexIndex)); + data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = NormalHelper.packNormal(x, y, z); + return this; + } + + /** + * Internal helper method. Copies face normals to vertex normals lacking one. + */ + public final void populateMissingNormals() { + final int normalFlags = this.normalFlags(); + + if (normalFlags == 0b1111) return; + + final int packedFaceNormal = packedFaceNormal(); + + for (int v = 0; v < 4; v++) { + if ((normalFlags & (1 << v)) == 0) { + data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal; + } + } + + normalFlags(0b1111); + } + + @Override + public final MutableQuadViewImpl cullFace(@Nullable Direction face) { + data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(data[baseIndex + HEADER_BITS], face); + nominalFace(face); + return this; + } + + @Override + public final MutableQuadViewImpl nominalFace(@Nullable Direction face) { + nominalFace = face; + return this; + } + + @Override + public final MutableQuadViewImpl material(RenderMaterial material) { + data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (RenderMaterialImpl) material); + return this; + } + + @Override + public final MutableQuadViewImpl tintIndex(int tintIndex) { + data[baseIndex + HEADER_TINT_INDEX] = tintIndex; + return this; + } + + @Override + public final MutableQuadViewImpl tag(int tag) { + data[baseIndex + HEADER_TAG] = tag; + return this; + } + + @Override + public final MutableQuadViewImpl copyFrom(QuadView quad) { + final QuadViewImpl q = (QuadViewImpl) quad; + System.arraycopy(q.data, q.baseIndex, data, baseIndex, EncodingFormat.TOTAL_STRIDE); + nominalFace = q.nominalFace; + isGeometryInvalid = q.isGeometryInvalid; + + if (!isGeometryInvalid) { + faceNormal.set(q.faceNormal); + } + + return this; + } + +// @Override +// public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) { +// System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, VANILLA_QUAD_STRIDE); +// isGeometryInvalid = true; +// +// int normalFlags = 0; +// int colorIndex = baseIndex + VERTEX_COLOR; +// int normalIndex = baseIndex + VERTEX_NORMAL; +// +// for (int i = 0; i < 4; i++) { +// data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]); +// +// // Set normal flag if normal is not zero, ignoring W component +// if ((data[normalIndex] & 0xFFFFFF) != 0) { +// normalFlags |= 1 << i; +// } +// +// colorIndex += VERTEX_STRIDE; +// normalIndex += VERTEX_STRIDE; +// } +// +// normalFlags(normalFlags); +// return this; +// } +// +// @Override +// public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) { +// fromVanilla(quad.vertexData(), 0); +// cullFace(cullFace); +// nominalFace(quad.face()); +// tintIndex(quad.tintIndex()); +// +// if (!quad.shade()) { +// material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true); +// } +// +// int lightEmission = quad.lightEmission(); +// +// if (lightEmission > 0) { +// for (int i = 0; i < 4; i++) { +//// lightmap(i, LightmapTextureManager.applyEmission(lightmap(i), lightEmission)); +// } +// } +// +// material(material); +// tag(0); +// return this; +// } + + @Override + public void pushTransform(QuadTransform transform) { + if (transform == null) { + throw new NullPointerException("QuadTransform cannot be null!"); + } + + 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); + } + } + + /** + * Emit the quad without applying transforms and without clearing the underlying data. + * Geometry is not guaranteed to be valid when called, but can be computed by calling {@link #computeGeometry()}. + */ + protected abstract void emitDirectly(); + + /** + * Apply transforms and then if transforms return true, emit the quad without clearing the underlying data. + */ + public final void transformAndEmit() { + if (activeTransform.transform(this)) { + emitDirectly(); + } + } + + @Override + public final MutableQuadViewImpl emit() { + transformAndEmit(); + clear(); + return this; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java new file mode 100644 index 000000000..f0ec099c6 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java @@ -0,0 +1,255 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; + +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_BITS; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_FACE_NORMAL; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_STRIDE; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TAG; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TINT_INDEX; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.QUAD_STRIDE; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_COLOR; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_LIGHTMAP; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_NORMAL; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_STRIDE; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_U; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_V; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_X; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_Y; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_Z; + +import net.modificationstation.stationapi.api.client.render.mesh.QuadView; +import net.modificationstation.stationapi.api.util.math.Direction; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.ColorHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.GeometryHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.NormalHelper; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.RenderMaterialImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +/** + * Base class for all quads / quad makers. Handles the ugly bits + * of maintaining and encoding the quad state. + */ +public class QuadViewImpl implements QuadView { + @Nullable + protected Direction nominalFace; + /** True when face normal, light face, or geometry flags may not match geometry. */ + protected boolean isGeometryInvalid = true; + protected final Vector3f faceNormal = new Vector3f(); + + /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */ + protected int[] data; + + /** Beginning of the quad. Also the header index. */ + protected int baseIndex = 0; + + /** + * Decodes necessary state from the backing data array. + * The encoded data must contain valid computed geometry. + */ + public final void load() { + isGeometryInvalid = false; + nominalFace = lightFace(); + NormalHelper.unpackNormal(packedFaceNormal(), faceNormal); + } + + protected final void computeGeometry() { + if (isGeometryInvalid) { + isGeometryInvalid = false; + + NormalHelper.computeFaceNormal(faceNormal, this); + data[baseIndex + HEADER_FACE_NORMAL] = NormalHelper.packNormal(faceNormal); + + // 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)); + } + } + + /** gets flags used for lighting - lazily computed via {@link GeometryHelper#computeShapeFlags(QuadView)}. */ + public final int geometryFlags() { + computeGeometry(); + return EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS]); + } + + public final boolean hasShade() { + return !material().disableDiffuse(); + } + + @Override + public final float x(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]); + } + + @Override + public final float y(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]); + } + + @Override + public final float z(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]); + } + + @Override + public final float posByIndex(int vertexIndex, int coordinateIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]); + } + + @Override + public final Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) { + if (target == null) { + target = new Vector3f(); + } + + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; + target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), Float.intBitsToFloat(data[index + 2])); + return target; + } + + @Override + public final int color(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR]; + } + + @Override + public final float u(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]); + } + + @Override + public final float v(int vertexIndex) { + return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]); + } + + @Override + public final Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { + if (target == null) { + target = new Vector2f(); + } + + final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U; + target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1])); + return target; + } + + @Override + public final int lightmap(int vertexIndex) { + return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP]; + } + + public final int normalFlags() { + return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]); + } + + @Override + public final boolean hasNormal(int vertexIndex) { + return (normalFlags() & (1 << vertexIndex)) != 0; + } + + /** True if any vertex normal has been set. */ + public final boolean hasVertexNormals() { + return normalFlags() != 0; + } + + /** True if all vertex normals have been set. */ + public final boolean hasAllVertexNormals() { + return (normalFlags() & 0b1111) == 0b1111; + } + + protected final int normalIndex(int vertexIndex) { + return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL; + } + + @Override + public final float normalX(int vertexIndex) { + return hasNormal(vertexIndex) ? NormalHelper.unpackNormalX(data[normalIndex(vertexIndex)]) : Float.NaN; + } + + @Override + public final float normalY(int vertexIndex) { + return hasNormal(vertexIndex) ? NormalHelper.unpackNormalY(data[normalIndex(vertexIndex)]) : Float.NaN; + } + + @Override + public final float normalZ(int vertexIndex) { + return hasNormal(vertexIndex) ? NormalHelper.unpackNormalZ(data[normalIndex(vertexIndex)]) : Float.NaN; + } + + @Override + @Nullable + public final Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) { + if (hasNormal(vertexIndex)) { + if (target == null) { + target = new Vector3f(); + } + + final int normal = data[normalIndex(vertexIndex)]; + NormalHelper.unpackNormal(normal, target); + return target; + } else { + return null; + } + } + + @Override + @Nullable + public final Direction cullFace() { + return EncodingFormat.cullFace(data[baseIndex + HEADER_BITS]); + } + + @Override + @NotNull + public final Direction lightFace() { + computeGeometry(); + return EncodingFormat.lightFace(data[baseIndex + HEADER_BITS]); + } + + @Override + @Nullable + public final Direction nominalFace() { + return nominalFace; + } + + public final int packedFaceNormal() { + computeGeometry(); + return data[baseIndex + HEADER_FACE_NORMAL]; + } + + @Override + public final Vector3fc faceNormal() { + computeGeometry(); + return faceNormal; + } + + @Override + public final RenderMaterialImpl material() { + return EncodingFormat.material(data[baseIndex + HEADER_BITS]); + } + + @Override + public final int tintIndex() { + return data[baseIndex + HEADER_TINT_INDEX]; + } + + @Override + public final int tag() { + return data[baseIndex + HEADER_TAG]; + } + + @Override + public final void toVanilla(int[] target, int targetIndex) { + System.arraycopy(data, baseIndex + HEADER_STRIDE, target, targetIndex, QUAD_STRIDE); + + int colorIndex = targetIndex + VERTEX_COLOR - HEADER_STRIDE; + + for (int i = 0; i < 4; i++) { + target[colorIndex] = ColorHelper.toVanillaColor(target[colorIndex]); + colorIndex += VANILLA_VERTEX_STRIDE; + } + } +} From 4213981419d934585dd8b1da26359be0533ab260 Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 7 Apr 2025 21:50:13 -0500 Subject: [PATCH 06/14] Renderer implementation --- .../stationapi/api/util/TriState.java | 11 ++ .../api/block/AbstractBlockState.java | 20 ++- .../api/block/StationFlatteningBlock.java | 4 + .../stationapi/api/util/math/ColorHelper.java | 9 + .../api/util/math/MutableBlockPos.java | 4 + .../impl/recipe/JsonRecipeParserInit.java | 4 +- .../api/client/render/Renderer.java | 27 +++ .../api/client/render/VertexConsumer.java | 30 ++++ .../render/material/MaterialFinder.java | 1 - .../client/render/material/MaterialView.java | 4 + .../client/render/mesh/MutableQuadView.java | 33 ++-- .../api/client/render/mesh/QuadEmitter.java | 13 +- .../api/client/render/mesh/QuadView.java | 44 +---- .../api/client/render/model/BakedModel.java | 32 ++-- .../client/render/model/BakedQuadFactory.java | 30 +++- .../client/render/model/BasicBakedModel.java | 51 ++---- .../render/model/BuiltinBakedModel.java | 22 ++- .../render/model/ForwardingBakedModel.java | 15 +- .../api/client/render/model/InputContext.java | 19 ++ .../api/client/render/model/ItemModel.java | 4 + .../api/client/render/model/ModelHelper.java | 40 ----- .../render/model/MultipartBakedModel.java | 49 +++-- .../render/model/VanillaBakedModel.java | 14 +- .../render/model/WeightedBakedModel.java | 21 ++- .../client/render/model/fluid/FluidModel.java | 17 ++ .../render/model/json/JsonUnbakedModel.java | 50 +++--- .../render/model/json/ModelOverrideList.java | 41 ++--- .../client/BlockRenderManagerMixin.java | 5 +- .../arsenic/renderer/ArsenicRenderer.java | 23 +++ .../renderer/TerrainLikeRenderContext.java | 61 +++++++ .../render/AbstractRenderContext.java | 63 +++++++ .../render/AbstractTerrainRenderContext.java | 170 ++++++++++++++++++ .../render/BakedModelRendererImpl.java | 61 +++---- .../renderer/render/BlockRenderInfo.java | 100 +++++++++++ .../renderer/render/ItemRenderContext.java | 12 ++ .../render/SimpleBlockRenderContext.java | 114 ++++++++++++ .../renderer/render/TerrainRenderContext.java | 89 +++++++++ .../renderer/render/aocalc/AoCalculator.java | 4 + .../renderer/render/aocalc/AoFaceData.java | 86 +++++++++ .../renderer/render/mesh/EncodingFormat.java | 4 +- .../render/mesh/MutableQuadViewImpl.java | 81 +++------ .../renderer/render/mesh/QuadViewImpl.java | 6 - 42 files changed, 1103 insertions(+), 385 deletions(-) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/InputContext.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModel.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/fluid/FluidModel.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/TerrainLikeRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderInfo.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ItemRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/SimpleBlockRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoCalculator.java create mode 100644 station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoFaceData.java diff --git a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/TriState.java b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/TriState.java index d65ef283d..fa13424b7 100644 --- a/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/TriState.java +++ b/station-api-base/src/main/java/net/modificationstation/stationapi/api/util/TriState.java @@ -27,6 +27,17 @@ public Boolean getBoolObj() { return value; } + /** + * Gets the value of this tri-state. + * If the value is {@link TriState#UNSET} then use the supplied value. + * + * @param value the value to fall back to + * @return the value of the tri-state or the supplied value if {@link TriState#UNSET}. + */ + public boolean orElse(boolean value) { + return this == UNSET ? value : this.getBool(); + } + @API public boolean getBool() { Boolean b = getBoolObj(); diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/block/AbstractBlockState.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/block/AbstractBlockState.java index 8046c71ea..c3bb33ea3 100644 --- a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/block/AbstractBlockState.java +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/block/AbstractBlockState.java @@ -9,6 +9,7 @@ import net.minecraft.class_259; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.modificationstation.stationapi.api.item.ItemPlacementContext; @@ -18,6 +19,7 @@ import net.modificationstation.stationapi.api.tag.TagKey; import net.modificationstation.stationapi.api.util.math.MathHelper; import net.modificationstation.stationapi.impl.block.StationFlatteningBlockInternal; +import org.jetbrains.annotations.Nullable; import java.util.function.Predicate; import java.util.stream.Stream; @@ -29,6 +31,8 @@ public abstract class AbstractBlockState extends State { private final boolean toolRequired; private final boolean opaque; private int luminance = -1; + @Nullable + private final Offsetter offsetter; protected AbstractBlockState(Block block, ImmutableMap, Comparable> propertyMap, MapCodec mapCodec) { super(block, propertyMap, mapCodec); @@ -37,6 +41,7 @@ protected AbstractBlockState(Block block, ImmutableMap, Comparable provider) { default void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState) { Util.assertImpl(); } + + default AbstractBlockState.Offsetter getOffsetter() { + return null; + } } diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/ColorHelper.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/ColorHelper.java index 15784db12..e71aebf74 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/ColorHelper.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/ColorHelper.java @@ -59,6 +59,15 @@ public static int getArgb(int alpha, int red, int green, int blue) { public static int mixColor(int first, int second) { return Argb.getArgb(Argb.getAlpha(first) * Argb.getAlpha(second) / 255, Argb.getRed(first) * Argb.getRed(second) / 255, Argb.getGreen(first) * Argb.getGreen(second) / 255, Argb.getBlue(first) * Argb.getBlue(second) / 255); } + + public static int scaleRgb(int argb, float redScale, float greenScale, float blueScale) { + return getArgb( + getAlpha(argb), + MathHelper.clamp((int)(getRed(argb) * redScale), 0, 255), + MathHelper.clamp((int)(getGreen(argb) * greenScale), 0, 255), + MathHelper.clamp((int)(getBlue(argb) * blueScale), 0, 255) + ); + } } } diff --git a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MutableBlockPos.java b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MutableBlockPos.java index 16b683749..831b3a4cd 100644 --- a/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MutableBlockPos.java +++ b/station-maths-v0/src/main/java/net/modificationstation/stationapi/api/util/math/MutableBlockPos.java @@ -75,6 +75,10 @@ public MutableBlockPos set(AxisCycleDirection axis, int x, int y, int z) { return set(axis.choose(x, y, z, Direction.Axis.X), axis.choose(x, y, z, Direction.Axis.Y), axis.choose(x, y, z, Direction.Axis.Z)); } + public MutableBlockPos set(BlockPos pos, Direction direction) { + return set(pos.getX() + direction.getOffsetX(), pos.getY() + direction.getOffsetY(), pos.getZ() + direction.getOffsetZ()); + } + public MutableBlockPos set(Vec3i pos, Direction direction) { return set(pos.getX() + direction.getOffsetX(), pos.getY() + direction.getOffsetY(), pos.getZ() + direction.getOffsetZ()); } diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java index d3d3dd91d..739b22411 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java @@ -45,8 +45,8 @@ private static void registerJsonRecipeParsers(JsonRecipeParserRegistryEvent even private static void parseAndRegisterRecipe(RecipeRegisterEvent event) { Consumer jsonRecipeParser = JsonRecipeParserRegistry.INSTANCE.get(event.recipeId); Set jsonRecipes = JsonRecipesRegistry.INSTANCE.get(event.recipeId); - if (jsonRecipeParser != null && jsonRecipes != null) - jsonRecipes.forEach(jsonRecipeParser); +// if (jsonRecipeParser != null && jsonRecipes != null) +// jsonRecipes.forEach(jsonRecipeParser); } private static void parseCraftingShaped(URL recipe) { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java index 3a51ebec4..63fe4c159 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/Renderer.java @@ -1,15 +1,24 @@ package net.modificationstation.stationapi.api.client.render; +import net.minecraft.client.render.block.BlockRenderManager; +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.material.MaterialFinder; import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; import net.modificationstation.stationapi.api.client.render.mesh.MutableMesh; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; import net.modificationstation.stationapi.api.client.render.model.SpriteFinder; import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.util.math.MatrixStack; import net.modificationstation.stationapi.impl.client.render.RendererManager; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.function.IntFunction; + /** * Interface for rendering plug-ins that provide enhanced capabilities * for model lighting, buffering and rendering. Such plug-ins implement the @@ -81,4 +90,22 @@ static void register(Renderer renderer) { BakedModelRenderer bakedModelRenderer(); StateManager stateManager(); + + /** + * @see FabricBlockModelRenderer#render(BlockRenderView, BlockStateModel, BlockState, BlockPos, MatrixStack, VertexConsumerProvider, boolean, long) + */ + @ApiStatus.OverrideOnly + void render(BakedModelRenderer modelRenderer, BlockView blockView, BakedModel model, BlockState state, BlockPos pos, MatrixStack matrices, IntFunction vertexConsumers, boolean cull, long seed); + + /** + * @see FabricBlockModelRenderer#render(MatrixStack, VertexConsumerProvider, BlockStateModel, float, float, float, int, int, BlockRenderView, BlockPos, BlockState) + */ + @ApiStatus.OverrideOnly + void render(MatrixStack matrices, IntFunction vertexConsumers, BakedModel model, float red, float green, float blue, int light, int overlay, BlockView blockView, BlockPos pos, BlockState state); + + /** + * @see FabricBlockRenderManager#renderBlockAsEntity(BlockState, MatrixStack, VertexConsumerProvider, int, int, BlockRenderView, BlockPos) + */ + @ApiStatus.OverrideOnly + void renderBlockAsEntity(BakedModelRenderer renderManager, BlockState state, MatrixStack matrices, IntFunction vertexConsumers, int light, int overlay, BlockView blockView, BlockPos pos); } \ No newline at end of file diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java index db8f0437a..ba7891c40 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java @@ -2,6 +2,7 @@ import net.modificationstation.stationapi.api.client.render.model.BakedQuad; import net.modificationstation.stationapi.api.util.Util; +import net.modificationstation.stationapi.api.util.math.ColorHelper; import net.modificationstation.stationapi.api.util.math.MatrixStack; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -74,6 +75,35 @@ public interface VertexConsumer { VertexConsumer setNormal(float x, float y, float z); + default void vertex(float x, float y, float z, int color, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) { + setVertex(x, y, z); + setColor(color); + setTexture(u, v); +// setOverlay(overlay); +// setLight(light); + setNormal(normalX, normalY, normalZ); + } + + default void vertex(float x, float y, float z, int color, float u, float v, float normalX, float normalY, float normalZ) { + setVertex(x, y, z); + setColor(color); + setTexture(u, v); + setNormal(normalX, normalY, normalZ); + } + + default VertexConsumer setColor(float red, float green, float blue, float alpha) { + return this.setColor((int)(red * 255.0F), (int)(green * 255.0F), (int)(blue * 255.0F), (int)(alpha * 255.0F)); + } + + default VertexConsumer setColor(int argb) { + return this.setColor(ColorHelper.Abgr.getRed(argb), ColorHelper.Abgr.getGreen(argb), ColorHelper.Abgr.getBlue(argb), ColorHelper.Abgr.getAlpha(argb)); + } + + default VertexConsumer setColorRgb(int rgb) { + return this.setColor(ColorHelper.Abgr.withAlpha(rgb, -1)); + } + + // TODO default VertexConsumer quad(MatrixStack.Entry entry, BakedQuad quad, int colour0, int colour1, int colour2, int colour3, float normalX, float normalY, float normalZ, boolean spreadUV) { int[] vertexData = quad.vertexData(); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java index 5376bc894..cb7c34b0b 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialFinder.java @@ -8,7 +8,6 @@ public interface MaterialFinder extends MaterialView { /** * When true, sprite texture and color will be rendered at full brightness. - * Lightmap values provided via {@link QuadEmitter#lightmap(int)} will be ignored. * *

This is the preferred method for emissive lighting effects. Some renderers * with advanced lighting pipelines may not use block lightmaps and this method will diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java index 56ea1ca0b..1f0f34852 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/material/MaterialView.java @@ -22,4 +22,8 @@ public interface MaterialView { * @see MaterialFinder#shadeMode(ShadeMode) */ ShadeMode shadeMode(); + + default int renderLayer() { + return 1; + } } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java index 27b32bd3c..465065b5a 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/MutableQuadView.java @@ -143,29 +143,6 @@ default MutableQuadView uv(int vertexIndex, Vector2fc uv) { */ MutableQuadView spriteBake(Sprite sprite, int bakeFlags); - /** - * Accept vanilla lightmap values. Input values will override lightmap values - * computed from world state if input values are higher. Exposed for completeness - * but some rendering implementations with non-standard lighting model may not honor it. - * - *

For emissive rendering, it is better to use {@link MaterialFinder#emissive(boolean)}. - */ - MutableQuadView lightmap(int vertexIndex, int lightmap); - - /** - * Convenience: set lightmap for all vertices at once. - * - *

For emissive rendering, it is better to use {@link MaterialFinder#emissive(boolean)}. - * See {@link #lightmap(int, int)}. - */ - default MutableQuadView lightmap(int b0, int b1, int b2, int b3) { - lightmap(0, b0); - lightmap(1, b1); - lightmap(2, b2); - lightmap(3, b3); - return this; - } - /** * Adds a vertex normal. Models that have per-vertex * normals should include them to get correct lighting when it matters. @@ -248,4 +225,14 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { *

Calling this method does not emit the quad. */ MutableQuadView copyFrom(QuadView quad); + + /** + * Enables bulk vertex data transfer using the standard Minecraft vertex formats. + * Only the {@link BakedQuad#vertexData() quad vertex data} is copied. + * This method should be performant whenever caller's vertex representation makes it feasible. + * + * + *

Calling this method does not emit the quad. + */ + MutableQuadView fromVanilla(int[] quadData, int startIndex); } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java index 2205867d9..94ecd5c97 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadEmitter.java @@ -69,15 +69,6 @@ default QuadEmitter uvUnitSquare() { return this; } - @Override - QuadEmitter lightmap(int vertexIndex, int lightmap); - - @Override - default QuadEmitter lightmap(int b0, int b1, int b2, int b3) { - MutableQuadView.super.lightmap(b0, b1, b2, b3); - return this; - } - @Override QuadEmitter normal(int vertexIndex, float x, float y, float z); @@ -110,8 +101,8 @@ default QuadEmitter normal(int vertexIndex, Vector3fc normal) { QuadEmitter copyFrom(QuadView quad); -// @Override -// QuadEmitter fromVanilla(int[] quadData, int startIndex); + @Override + QuadEmitter fromVanilla(int[] quadData, int startIndex); // // @Override // QuadEmitter fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java index 6d9c2c6c8..dc6447a10 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java @@ -20,7 +20,7 @@ */ public interface QuadView { /** Count of integers in a conventional (un-modded) block or item vertex. */ - int VANILLA_VERTEX_STRIDE = VertexFormats.BLOCK.getVertexSize() / 4; + int VANILLA_VERTEX_STRIDE = 8;//VertexFormats.BLOCK.getVertexSize() / 4; /** Count of integers in a conventional (un-modded) block or item quad. */ int VANILLA_QUAD_STRIDE = VANILLA_VERTEX_STRIDE * 4; @@ -72,11 +72,6 @@ public interface QuadView { */ Vector2f copyUv(int vertexIndex, @Nullable Vector2f target); - /** - * Minimum block brightness. Zero if not set. - */ - int lightmap(int vertexIndex); - /** * If false, no vertex normal was provided. * Lighting should use face normal in that case. @@ -164,41 +159,4 @@ public interface QuadView { * at least {@link #VANILLA_QUAD_STRIDE} elements available at this index. */ void toVanilla(int[] target, int targetIndex); - - /** - * Generates a new BakedQuad instance with texture - * coordinates and colors from the given sprite. - * - * @param sprite {@link QuadView} does not serialize sprites - * so the sprite must be provided by the caller. - * - * @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. - */ - @Deprecated - default BakedQuad toBakedQuad(Sprite sprite) { - int[] vertexData = new int[VANILLA_QUAD_STRIDE]; - toVanilla(vertexData, 0); - - // Mimic material properties to the largest possible extent - boolean outputShade = !material().disableDiffuse(); - // The output light emission is equal to the minimum of all four sky light values and all four block light values. - int outputLightEmission = 15; - - for (int i = 0; i < 4; i++) { - int lightmap = lightmap(i); - - if (lightmap == 0) { - outputLightEmission = 0; - break; - } - - int blockLight = lightmap >>> 4 & 15; - int skyLight = lightmap >>> 20 & 15; - outputLightEmission = Math.min(outputLightEmission, lightmap); - } - - return new BakedQuad(vertexData, tintIndex(), lightFace(), sprite, outputShade, outputLightEmission); - } } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java index 175a1647c..d5b434a65 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java @@ -1,26 +1,18 @@ 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.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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 org.jetbrains.annotations.Nullable; - -import java.util.Random; public interface BakedModel { - /** - * Returns an immutable list of model's quads, depending on the level, block position, cullface group and position-fixed random. - * - * @param state the {@link BlockState} that's being rendered. - * @param face the cullface group that's being currently rendered. Null if a non-cullface group is being rendered. - * @param random random generator that's fixed on block's position to give consistent values. Uses seed 42 if the model is rendered inside inventory. - * @return an immutable list of model's quads, depending on the level, block position, cullface group and position-fixed random. - */ - ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random); + void emitBlockQuads(BlockInputContext input, QuadEmitter output); + + void emitItemQuads(ItemInputContext input, QuadEmitter output); boolean useAmbientOcclusion(); @@ -35,4 +27,16 @@ public interface BakedModel { ModelTransformation getTransformation(); ModelOverrideList getOverrides(); + + interface BlockInputContext extends InputContext { + boolean isFluidModel(); + + BlockState blockState(); + + BlockPos pos(); + } + + interface ItemInputContext extends InputContext { + ItemStack itemStack(); + } } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java index 0eacfbb38..d3933baac 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java @@ -2,6 +2,10 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; +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.json.ModelElementFace; import net.modificationstation.stationapi.api.client.render.model.json.ModelElementTexture; import net.modificationstation.stationapi.api.client.texture.Sprite; @@ -17,7 +21,7 @@ public class BakedQuadFactory { private static final float MIN_SCALE = 1.0F / (float)Math.cos(0.39269909262657166D) - 1.0F; private static final float MAX_SCALE = 1.0F / (float)Math.cos(0.7853981852531433D) - 1.0F; - public BakedQuad bake(Vector3f from, Vector3f to, ModelElementFace face, Sprite texture, Direction side, ModelBakeSettings settings, @Nullable ModelRotation rotation, boolean shade, Identifier modelId) { + public void emitQuad(QuadEmitter emitter, Vector3f from, Vector3f to, ModelElementFace face, Sprite texture, Direction side, ModelBakeSettings settings, @Nullable ModelRotation rotation, boolean shade, Identifier modelId) { ModelElementTexture modelElementTexture = face.textureData; if (settings.isUvLocked()) { modelElementTexture = uvLock(face.textureData, side, settings.getRotation(), modelId); @@ -32,14 +36,30 @@ public BakedQuad bake(Vector3f from, Vector3f to, ModelElementFace face, Sprite modelElementTexture.uvs[2] = MathHelper.lerp(f, modelElementTexture.uvs[2], g); modelElementTexture.uvs[1] = MathHelper.lerp(f, modelElementTexture.uvs[1], h); modelElementTexture.uvs[3] = MathHelper.lerp(f, modelElementTexture.uvs[3], h); - int[] is = this.packVertexData(modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); - Direction direction = decodeDirection(is); + int[] quadData = this.packVertexData(modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); + emitter.fromVanilla(quadData, 0); + Direction direction = decodeDirection(quadData); System.arraycopy(fs, 0, modelElementTexture.uvs, 0, fs.length); if (rotation == null) { - this.encodeDirection(is, direction); + emitter.nominalFace(direction); } - return new BakedQuad(is, face.tintIndex, direction, texture, shade, face.emission); + emitter.tintIndex(face.tintIndex); + + MaterialFinder finder = Renderer.get().materialFinder(); + + if (!shade) { + finder.disableDiffuse(true); + } + + if (face.cullFace != null) + emitter.cullFace(Direction.transform(settings.getRotation().copyMatrix(), face.cullFace)); + + emitter.spriteBake(texture, MutableQuadView.BAKE_ROTATE_NONE); + emitter.material(finder.find()); + emitter.tag(0); + + emitter.emit(); } public static ModelElementTexture uvLock(ModelElementTexture texture, Direction orientation, AffineTransformation rotation, Identifier modelId) { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java index ecf558d38..b9947f784 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BasicBakedModel.java @@ -1,29 +1,22 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.Renderer; +import net.modificationstation.stationapi.api.client.render.mesh.Mesh; +import net.modificationstation.stationapi.api.client.render.mesh.MutableMesh; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; import net.modificationstation.stationapi.api.client.render.model.json.JsonUnbakedModel; 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 org.jetbrains.annotations.Nullable; - -import java.util.EnumMap; -import java.util.Map; -import java.util.Random; @Environment(EnvType.CLIENT) @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class BasicBakedModel implements BakedModel { - protected final ImmutableList quads; - protected final ImmutableMap> faceQuads; + protected final Mesh mesh; protected final boolean usesAo; protected final boolean hasDepth; protected final boolean isSideLit; @@ -32,8 +25,13 @@ public class BasicBakedModel implements BakedModel { protected final ModelOverrideList itemPropertyOverrides; @Override - public ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return face == null ? this.quads : this.faceQuads.get(face); + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) { + this.mesh.outputTo(output); + } + + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) { + this.mesh.outputTo(output); } @Override @@ -73,8 +71,7 @@ public ModelOverrideList getOverrides() { @Environment(EnvType.CLIENT) public static class Builder { - private final ImmutableList.Builder quads; - private final Map> faceQuads; + private final MutableMesh mesh; private final ModelOverrideList itemPropertyOverrides; private final boolean usesAo; private Sprite particleTexture; @@ -87,14 +84,7 @@ public Builder(JsonUnbakedModel unbakedModel, ModelOverrideList itemPropertyOver } public Builder(boolean usesAo, boolean isSideLit, boolean hasDepth, ModelTransformation modelTransformation, ModelOverrideList modelOverrideList) { - this.quads = ImmutableList.builder(); - this.faceQuads = new EnumMap<>(Direction.class); - Direction[] var6 = Direction.values(); - - for (Direction direction : var6) { - this.faceQuads.put(direction, ImmutableList.builder()); - } - + this.mesh = Renderer.get().mutableMesh(); this.itemPropertyOverrides = modelOverrideList; this.usesAo = usesAo; this.isSideLit = isSideLit; @@ -102,14 +92,8 @@ public Builder(boolean usesAo, boolean isSideLit, boolean hasDepth, ModelTransfo this.transformation = modelTransformation; } - public BasicBakedModel.Builder addQuad(Direction side, BakedQuad quad) { - this.faceQuads.get(side).add(quad); - return this; - } - - public BasicBakedModel.Builder addQuad(BakedQuad quad) { - this.quads.add(quad); - return this; + public QuadEmitter quadEmitter() { + return this.mesh.emitter(); } public BasicBakedModel.Builder setParticle(Sprite sprite) { @@ -122,8 +106,7 @@ public BakedModel build() { throw new RuntimeException("Missing particle!"); } else { return new BasicBakedModel( - quads.build(), - faceQuads.entrySet().stream().collect(Maps.toImmutableEnumMap(Map.Entry::getKey, e -> e.getValue().build())), + mesh.immutableCopy(), usesAo, hasDepth, isSideLit, diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java index cc1b515ec..5f651f1e3 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BuiltinBakedModel.java @@ -1,16 +1,11 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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 org.jetbrains.annotations.Nullable; - -import java.util.Random; @Environment(EnvType.CLIENT) public class BuiltinBakedModel implements BakedModel { @@ -26,34 +21,43 @@ public BuiltinBakedModel(ModelTransformation transformation, ModelOverrideList i this.sideLit = sideLit; } - public ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return ImmutableList.of(); - } + @Override + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) {} + + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) {} + @Override public boolean useAmbientOcclusion() { return false; } + @Override public boolean hasDepth() { return true; } + @Override public boolean isSideLit() { return this.sideLit; } + @Override public boolean isBuiltin() { return true; } + @Override public Sprite getSprite() { return this.sprite; } + @Override public ModelTransformation getTransformation() { return this.transformation; } + @Override public ModelOverrideList getOverrides() { return this.itemPropertyOverrides; } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java index 8c90d6fcd..4a1149bba 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ForwardingBakedModel.java @@ -1,13 +1,9 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; -import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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; /** * Base class for specialized model implementations that need to wrap other baked models. @@ -19,8 +15,13 @@ public abstract class ForwardingBakedModel implements BakedModel { protected BakedModel wrapped; @Override - public ImmutableList getQuads(BlockState blockState, Direction face, Random rand) { - return wrapped.getQuads(blockState, face, rand); + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) { + this.wrapped.emitBlockQuads(input, output); + } + + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) { + this.wrapped.emitItemQuads(input, output); } @Override diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/InputContext.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/InputContext.java new file mode 100644 index 000000000..9dcddf36e --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/InputContext.java @@ -0,0 +1,19 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.util.math.MatrixStack; + +import java.util.Random; + +public interface InputContext { + + BlockView blockView(); + + MatrixStack matrixStack(); + + Random random(); + + +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModel.java new file mode 100644 index 000000000..b4327b203 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ItemModel.java @@ -0,0 +1,4 @@ +package net.modificationstation.stationapi.api.client.render.model; + +public interface ItemModel { +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java index f8182a16d..c421abebb 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/ModelHelper.java @@ -1,12 +1,7 @@ package net.modificationstation.stationapi.api.client.render.model; import java.util.Arrays; -import java.util.List; -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.texture.atlas.Atlases; import net.modificationstation.stationapi.api.util.math.Direction; import org.jetbrains.annotations.Nullable; @@ -42,39 +37,4 @@ public static int toFaceIndex(@Nullable Direction face) { public static Direction faceFromIndex(int faceIndex) { return FACES[faceIndex]; } - - /** - * 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 -> { - Direction cullFace = q.cullFace(); - builders[cullFace == null ? NULL_FACE_ID : cullFace.getId()].add(q.toBakedQuad(finder.find(q))); - }); - } - - @SuppressWarnings("unchecked") - List[] result = new List[7]; - - for (int i = 0; i < 7; i++) { - result[i] = builders[i].build(); - } - - return result; - } } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java index 60cbbb154..2a57a13ba 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/MultipartBakedModel.java @@ -1,18 +1,16 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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.Util; -import net.modificationstation.stationapi.api.util.math.Direction; import org.apache.commons.lang3.tuple.Pair; -import org.jetbrains.annotations.Nullable; import java.util.BitSet; import java.util.List; @@ -43,37 +41,36 @@ public MultipartBakedModel(List, BakedModel>> compone } @Override - public ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - if (state == null) { - return ImmutableList.of(); - } else { - BitSet bitSet = this.stateCache.get(state); - if (bitSet == null) { - bitSet = new BitSet(); - - for(int i = 0; i < this.components.size(); ++i) { - Pair, BakedModel> pair = this.components.get(i); - if (pair.getLeft().test(state)) { - bitSet.set(i); - } + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) { + BlockState state = input.blockState(); + BitSet bitSet = this.stateCache.get(state); + if (bitSet == null) { + bitSet = new BitSet(); + + for(int i = 0; i < this.components.size(); ++i) { + Pair, BakedModel> pair = this.components.get(i); + if (pair.getLeft().test(state)) { + bitSet.set(i); } - - this.stateCache.put(state, bitSet); } - ImmutableList.Builder list = ImmutableList.builder(); - long l = random.nextLong(); + this.stateCache.put(state, bitSet); + } - for(int j = 0; j < bitSet.length(); ++j) { - if (bitSet.get(j)) { - list.addAll((this.components.get(j)).getRight().getQuads(state, face, new Random(l))); - } - } + Random random = input.random(); + long seed = random.nextLong(); + random.setSeed(seed); - return list.build(); + for(int i = 0; i < bitSet.length(); ++i) { + if (bitSet.get(i)) { + this.components.get(i).getRight().emitBlockQuads(input, output); + } } } + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) {} + public boolean useAmbientOcclusion() { return this.ambientOcclusion; } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java index 51bedf0bb..af19b0c92 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/VanillaBakedModel.java @@ -1,22 +1,18 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; -import net.modificationstation.stationapi.api.block.BlockState; import net.modificationstation.stationapi.api.client.StationRenderAPI; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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 org.jetbrains.annotations.Nullable; - -import java.util.Random; public final class VanillaBakedModel implements BakedModel { @Override - public ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return ImmutableList.of(); - } + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) {} + + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) {} @Override public boolean useAmbientOcclusion() { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java index a9059606f..566d3b24e 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/WeightedBakedModel.java @@ -1,20 +1,16 @@ package net.modificationstation.stationapi.api.client.render.model; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; 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.collection.WeightedPicker; -import net.modificationstation.stationapi.api.util.math.Direction; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Objects; -import java.util.Random; @Environment(EnvType.CLIENT) public class WeightedBakedModel implements BakedModel { @@ -29,8 +25,19 @@ public WeightedBakedModel(List models) { } @Override - public ImmutableList getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return Objects.requireNonNull(WeightedPicker.getAt(this.models, Math.abs((int) random.nextLong()) % this.totalWeight)).model.getQuads(state, face, random); + public void emitBlockQuads(BlockInputContext input, QuadEmitter output) { + WeightedBakedModel.Entry selected = WeightedPicker.getAt(this.models, Math.abs((int) input.random().nextLong()) % this.totalWeight); + if (selected != null) { + selected.model.emitBlockQuads(input, output); + } + } + + @Override + public void emitItemQuads(ItemInputContext input, QuadEmitter output) { + WeightedBakedModel.Entry selected = WeightedPicker.getAt(this.models, Math.abs((int) input.random().nextLong()) % this.totalWeight); + if (selected != null) { + selected.model.emitItemQuads(input, output); + } } public boolean useAmbientOcclusion() { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/fluid/FluidModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/fluid/FluidModel.java new file mode 100644 index 000000000..a9d20153f --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/fluid/FluidModel.java @@ -0,0 +1,17 @@ +package net.modificationstation.stationapi.api.client.render.model.fluid; + +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.InputContext; + +/** + * Identical in operation to {@link BakedModel} but for fluids. + * + *

A compliant renderer will call this - in addition to the block quad emitter - for + * block state with a non-empty fluid state. Block state is passed instead of fluid state + * to keep the method signature compact and provide access to the block state if needed. + */ +@FunctionalInterface +public interface FluidModel { + void emitQuads(InputContext context, QuadEmitter output); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java index 9a75f890a..bf449b12e 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/JsonUnbakedModel.java @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.objects.ReferenceSet; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; import net.modificationstation.stationapi.api.client.render.model.*; import net.modificationstation.stationapi.api.client.texture.MissingSprite; import net.modificationstation.stationapi.api.client.texture.Sprite; @@ -136,28 +137,27 @@ public BakedModel bake(Baker baker, Function textureGe } public BakedModel bake(Baker baker, JsonUnbakedModel parent, Function textureGetter, ModelBakeSettings settings, Identifier id, boolean hasDepth) { - Sprite sprite = textureGetter.apply(this.resolveSprite("particle")); + Sprite particle = textureGetter.apply(this.resolveSprite("particle")); if (this.getRootModel() == ModelLoader.BLOCK_ENTITY_MARKER) - return new BuiltinBakedModel(this.getTransformations(), this.compileOverrides(baker, parent), sprite, this.getGuiLight().isSide()); + return new BuiltinBakedModel(this.getTransformations(), this.compileOverrides(baker, parent), particle, this.getGuiLight().isSide()); else if (getRootModel() == ModelLoader.VANILLA_MARKER) return new VanillaBakedModel(); else { - BasicBakedModel.Builder builder = new BasicBakedModel.Builder(this, this.compileOverrides(baker, parent), hasDepth).setParticle(sprite); + // Create a mesh for us to emit quads to + BasicBakedModel.Builder builder = new BasicBakedModel.Builder(this, this.compileOverrides(baker, parent), hasDepth).setParticle(particle); + QuadEmitter emitter = builder.quadEmitter(); for (ModelElement modelElement : this.getElements()) for (Direction direction : modelElement.faces.keySet()) { ModelElementFace modelElementFace = modelElement.faces.get(direction); - Sprite sprite2 = textureGetter.apply(this.resolveSprite(modelElementFace.textureId)); - if (modelElementFace.cullFace == null) - builder.addQuad(createQuad(modelElement, modelElementFace, sprite2, direction, settings, id)); - else - builder.addQuad(Direction.transform(settings.getRotation().copyMatrix(), modelElementFace.cullFace), createQuad(modelElement, modelElementFace, sprite2, direction, settings, id)); + Sprite sprite = textureGetter.apply(this.resolveSprite(modelElementFace.textureId)); + emitQuad(emitter, modelElement, modelElementFace, sprite, direction, settings, id); } return builder.build(); } } - private static BakedQuad createQuad(ModelElement element, ModelElementFace elementFace, Sprite sprite, Direction side, ModelBakeSettings settings, Identifier id) { - return QUAD_FACTORY.bake(element.from, element.to, elementFace, sprite, side, settings, element.rotation, element.shade, id); + private static void emitQuad(QuadEmitter emitter, ModelElement element, ModelElementFace elementFace, Sprite sprite, Direction side, ModelBakeSettings settings, Identifier id) { + QUAD_FACTORY.emitQuad(emitter, element.from, element.to, elementFace, sprite, side, settings, element.rotation, element.shade, id); } public boolean textureExists(String name) { @@ -255,25 +255,25 @@ public boolean isSide() { @Environment(EnvType.CLIENT) public static class Deserializer implements JsonDeserializer { - public JsonUnbakedModel deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - List list = this.deserializeElements(jsonDeserializationContext, jsonObject); - String string = this.deserializeParent(jsonObject); - Map> map = this.deserializeTextures(jsonObject); - boolean bl = this.deserializeAmbientOcclusion(jsonObject); - ModelTransformation modelTransformation = ModelTransformation.NONE; - if (jsonObject.has("display")) { - JsonObject jsonObject2 = JsonHelper.getObject(jsonObject, "display"); - modelTransformation = jsonDeserializationContext.deserialize(jsonObject2, ModelTransformation.class); + public JsonUnbakedModel deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { + JsonObject modelObj = json.getAsJsonObject(); + List modelElements = this.deserializeElements(context, modelObj); + String parent = this.deserializeParent(modelObj); + Map> textureMap = this.deserializeTextures(modelObj); + boolean ambientOcclusion = this.deserializeAmbientOcclusion(modelObj); + ModelTransformation transformation = ModelTransformation.NONE; + if (modelObj.has("display")) { + JsonObject displayObj = JsonHelper.getObject(modelObj, "display"); + transformation = context.deserialize(displayObj, ModelTransformation.class); } - List list2 = this.deserializeOverrides(jsonDeserializationContext, jsonObject); + List modelOverrides = this.deserializeOverrides(context, modelObj); JsonUnbakedModel.GuiLight guiLight = null; - if (jsonObject.has("gui_light")) - guiLight = GuiLight.deserialize(JsonHelper.getString(jsonObject, "gui_light")); + if (modelObj.has("gui_light")) + guiLight = GuiLight.deserialize(JsonHelper.getString(modelObj, "gui_light")); - Identifier identifier = string.isEmpty() ? null : Identifier.of(string); - return new JsonUnbakedModel(identifier, list, map, bl, guiLight, modelTransformation, list2); + Identifier parentId = parent.isEmpty() ? null : Identifier.of(parent); + return new JsonUnbakedModel(parentId, modelElements, textureMap, ambientOcclusion, guiLight, transformation, modelOverrides); } protected List deserializeOverrides(JsonDeserializationContext context, JsonObject object) { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java index 504b01275..18a1eaf56 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/json/ModelOverrideList.java @@ -15,10 +15,7 @@ import net.modificationstation.stationapi.api.client.model.item.ItemModelPredicateProvider; import net.modificationstation.stationapi.api.client.registry.BlockModelPredicateProviderRegistry; import net.modificationstation.stationapi.api.client.registry.ItemModelPredicateProviderRegistry; -import net.modificationstation.stationapi.api.client.render.model.BakedModel; -import net.modificationstation.stationapi.api.client.render.model.Baker; -import net.modificationstation.stationapi.api.client.render.model.ModelBakeRotation; -import net.modificationstation.stationapi.api.client.render.model.UnbakedModel; +import net.modificationstation.stationapi.api.client.render.model.*; import net.modificationstation.stationapi.api.util.Identifier; import org.jetbrains.annotations.Nullable; @@ -40,17 +37,17 @@ private ModelOverrideList() { public ModelOverrideList(Baker baker, JsonUnbakedModel parent, Function unbakedModelGetter, List overrides) { this.conditionTypes = overrides.stream().flatMap(ModelOverride::streamConditions).map(ModelOverride.Condition::getType).distinct().toArray(Identifier[]::new); - Object2IntOpenHashMap object2IntMap = new Object2IntOpenHashMap<>(); + Object2IntOpenHashMap overrideTypes = new Object2IntOpenHashMap<>(); for (int i = 0; i < this.conditionTypes.length; ++i) { - object2IntMap.put(this.conditionTypes[i], i); + overrideTypes.put(this.conditionTypes[i], i); } ArrayList list = Lists.newArrayList(); for (int j = overrides.size() - 1; j >= 0; --j) { ModelOverride modelOverride = overrides.get(j); BakedModel bakedModel = this.bakeOverridingModel(baker, parent, unbakedModelGetter, modelOverride); InlinedCondition[] inlinedConditions = modelOverride.streamConditions().map(condition -> { - int i = object2IntMap.getInt(condition.getType()); - return new InlinedCondition(i, condition.getThreshold()); + int index = overrideTypes.getInt(condition.getType()); + return new InlinedCondition(index, condition.getThreshold()); }).toArray(InlinedCondition[]::new); list.add(new BakedOverride(inlinedConditions, bakedModel)); } @@ -70,15 +67,15 @@ private BakedModel bakeOverridingModel(Baker baker, JsonUnbakedModel parent, Fun public BakedModel apply(BakedModel model, BlockState state, @Nullable BlockView world, @Nullable BlockPos pos, int seed) { if (this.overrides.length != 0) { Block block = state.getBlock(); - int i = this.conditionTypes.length; - float[] fs = new float[i]; - for (int j = 0; j < i; ++j) { - Identifier identifier = this.conditionTypes[j]; - BlockModelPredicateProvider modelPredicateProvider = BlockModelPredicateProviderRegistry.INSTANCE.get(block, identifier); - fs[j] = modelPredicateProvider != null ? modelPredicateProvider.call(state, world, pos, seed) : Float.NEGATIVE_INFINITY; + int conditionsLength = this.conditionTypes.length; + float[] values = new float[conditionsLength]; + for (int i = 0; i < conditionsLength; ++i) { + Identifier id = this.conditionTypes[i]; + BlockModelPredicateProvider provider = BlockModelPredicateProviderRegistry.INSTANCE.get(block, id); + values[i] = provider != null ? provider.call(state, world, pos, seed) : Float.NEGATIVE_INFINITY; } for (BakedOverride bakedOverride : this.overrides) { - if (!bakedOverride.test(fs)) continue; + if (!bakedOverride.test(values)) continue; BakedModel bakedModel = bakedOverride.model; if (bakedModel == null) { return model; @@ -93,15 +90,15 @@ public BakedModel apply(BakedModel model, BlockState state, @Nullable BlockView public BakedModel apply(BakedModel model, ItemStack stack, @Nullable BlockView world, @Nullable LivingEntity entity, int seed) { if (this.overrides.length != 0) { Item item = stack.getItem(); - int i = this.conditionTypes.length; - float[] fs = new float[i]; - for (int j = 0; j < i; ++j) { - Identifier identifier = this.conditionTypes[j]; - ItemModelPredicateProvider modelPredicateProvider = ItemModelPredicateProviderRegistry.INSTANCE.get(item, identifier); - fs[j] = modelPredicateProvider != null ? modelPredicateProvider.call(stack, world, entity, seed) : Float.NEGATIVE_INFINITY; + int conditionsLength = this.conditionTypes.length; + float[] values = new float[conditionsLength]; + for (int i = 0; i < conditionsLength; ++i) { + Identifier id = this.conditionTypes[i]; + ItemModelPredicateProvider provider = ItemModelPredicateProviderRegistry.INSTANCE.get(item, id); + values[i] = provider != null ? provider.call(stack, world, entity, seed) : Float.NEGATIVE_INFINITY; } for (BakedOverride bakedOverride : this.overrides) { - if (!bakedOverride.test(fs)) continue; + if (!bakedOverride.test(values)) continue; BakedModel bakedModel = bakedOverride.model; if (bakedModel == null) { return model; diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java index ccf41643c..c11a39423 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/mixin/render/client/BlockRenderManagerMixin.java @@ -38,10 +38,11 @@ abstract class BlockRenderManagerMixin implements StationRendererBlockRenderMana @Unique public void renderAllSides(VertexConsumer consumer, BlockState state, int x, int y, int z) { delegator.setDelegate(consumer); - if (StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state) instanceof VanillaBakedModel) + if (StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state) instanceof VanillaBakedModel) { renderWithoutCulling(state.getBlock(), x, y, z); - else + } else { Renderer.get().bakedModelRenderer().renderBlock(consumer, state, stationapi_pos.set(x, y, z), blockView, false, stationapi_random); + } delegator.setDelegate(Tessellator.INSTANCE); } 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 0652f1aed..d890fcf3b 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 @@ -3,16 +3,23 @@ import com.google.common.base.Suppliers; import lombok.AccessLevel; import lombok.NoArgsConstructor; +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.Renderer; import net.modificationstation.stationapi.api.client.render.StateManager; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; 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.MutableMesh; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; import net.modificationstation.stationapi.api.client.render.model.BakedModelRenderer; import net.modificationstation.stationapi.api.client.render.model.SpriteFinder; import net.modificationstation.stationapi.api.client.texture.SpriteAtlasTexture; import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.util.math.MatrixStack; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.BakedModelRendererImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.SimpleBlockRenderContext; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.StateManagerImpl; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.MaterialFinderImpl; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableMeshImpl; @@ -20,6 +27,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.IntFunction; import java.util.function.Supplier; @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -73,6 +81,21 @@ public StateManager stateManager() { return stateManager.get(); } + @Override + public void render(BakedModelRenderer modelRenderer, BlockView blockView, BakedModel model, BlockState state, BlockPos pos, MatrixStack matrices, IntFunction vertexConsumers, boolean cull, long seed) { + TerrainLikeRenderContext.POOL.get().bufferModel(blockView, model, state, pos, matrices, vertexConsumers, cull, seed); + } + + @Override + public void render(MatrixStack matrices, IntFunction vertexConsumers, BakedModel model, float red, float green, float blue, int light, int overlay, BlockView blockView, BlockPos pos, BlockState state) { + SimpleBlockRenderContext.POOL.get().bufferModel(matrices, vertexConsumers, model, red, green, blue, light, blockView, pos, state); + } + + @Override + public void renderBlockAsEntity(BakedModelRenderer renderManager, BlockState state, MatrixStack matrices, IntFunction vertexConsumers, int light, int overlay, BlockView blockView, BlockPos pos) { + + } + private final Supplier bakedModelRenderer = Suppliers.memoize(BakedModelRendererImpl::new); private final Supplier stateManager = Suppliers.memoize(StateManagerImpl::new); } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/TerrainLikeRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/TerrainLikeRenderContext.java new file mode 100644 index 000000000..7b481f2ae --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/TerrainLikeRenderContext.java @@ -0,0 +1,61 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer; + +import net.minecraft.client.render.Tessellator; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; +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.api.util.math.MatrixStack; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.AbstractTerrainRenderContext; + +import java.util.Random; +import java.util.function.IntFunction; + +public class TerrainLikeRenderContext extends AbstractTerrainRenderContext { + public static final ThreadLocal POOL = ThreadLocal.withInitial(TerrainLikeRenderContext::new); + + private final Random random = new Random(); + + private IntFunction vertexConsumers = value -> Tessellator.INSTANCE; + + @Override + protected VertexConsumer getVertexConsumer(int layer) { + return this.vertexConsumers.apply(layer); + } + + public void bufferModel(BlockView blockView, BakedModel model, BlockState state, BlockPos pos, MatrixStack matrixStack, IntFunction vertexConsumers, boolean cull, long seed) { + try { + Vec3d offset = state.getModelOffset(pos); + matrixStack.translate(offset.x, offset.y, offset.z); + matrices = matrixStack.peek(); + + this.vertexConsumers = vertexConsumers; + + blockInfo.prepareForWorld(blockView, cull); + random.setSeed(seed); + + prepare(pos, state); + inputContext.prepare(false, state, pos, blockView, matrixStack, random); + model.emitBlockQuads(inputContext, getEmitter()); + inputContext.release(); + } catch (Throwable throwable) { + CrashReport crashReport = CrashReport.create(throwable, "Tessellating block model - Indigo Renderer"); + CrashReportSection crashReportSection = crashReport.addElement("Block model being tessellated"); + if (state != null) { + crashReportSection.add("Block", state::toString); + } + + crashReportSection.add("Block location", (() -> CrashReportSection.createPositionString(blockInfo.blockView, pos))); + throw new CrashException(crashReport); + } finally { + blockInfo.release(); + matrices = null; + this.vertexConsumers = null; + } + } +} 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 new file mode 100644 index 000000000..21c492f8f --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractRenderContext.java @@ -0,0 +1,63 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import net.modificationstation.stationapi.api.client.render.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.mesh.QuadEmitter; +import net.modificationstation.stationapi.api.util.math.MatrixStack; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableQuadViewImpl; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +public abstract class AbstractRenderContext { + private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() { + { + data = new int[EncodingFormat.TOTAL_STRIDE]; + clear(); + } + + @Override + protected void emitDirectly() { + bufferQuad(this); + } + }; + + private final Vector4f posVec = new Vector4f(); + private final Vector3f normalVec = new Vector3f(); + + protected MatrixStack.Entry matrices; + + protected QuadEmitter getEmitter() { + editorQuad.clear(); + return editorQuad; + } + + protected abstract void bufferQuad(MutableQuadViewImpl quad); + + /** final output step, common to all renders. */ + protected void bufferQuad(MutableQuadViewImpl quad, VertexConsumer vertexConsumer) { + final Vector4f posVec = this.posVec; + final Vector3f normalVec = this.normalVec; + final MatrixStack.Entry matrices = this.matrices; + final Matrix4f posMatrix = matrices.getPositionMatrix(); + final boolean useNormals = quad.hasVertexNormals(); + + if (useNormals) { + quad.populateMissingNormals(); + } else { + matrices.transformNormal(quad.faceNormal(), normalVec); + } + + for (int i = 0; i < 4; i++) { + posVec.set(quad.x(i), quad.y(i), quad.z(i), 1.0f); + posVec.mul(posMatrix); + + if (useNormals) { + quad.copyNormal(i, normalVec); + matrices.transformNormal(normalVec, normalVec); + } + + vertexConsumer.vertex(posVec.x(), posVec.y(), posVec.z(), quad.color(i), quad.u(i), quad.v(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java new file mode 100644 index 000000000..1d1984770 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java @@ -0,0 +1,170 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import com.google.common.primitives.Ints; +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.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; +import net.modificationstation.stationapi.api.client.render.material.ShadeMode; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; +import net.modificationstation.stationapi.api.util.math.ColorHelper; +import net.modificationstation.stationapi.api.util.math.MatrixStack; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.aocalc.LightingCalculatorImpl; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableQuadViewImpl; + +import java.nio.ByteOrder; +import java.util.Random; + +public abstract class AbstractTerrainRenderContext extends AbstractRenderContext { + protected final BlockRenderInfo blockInfo = new BlockRenderInfo(); + protected final BlockInputContextImpl inputContext = new BlockInputContextImpl(); + private final LightingCalculatorImpl aoCalc = new LightingCalculatorImpl(3); + + private int cachedTintIndex = -1; + private int cachedTint; + + protected abstract VertexConsumer getVertexConsumer(int layer); + + /** Must be called before buffering a block model. */ + protected void prepare(BlockPos pos, BlockState state) { + blockInfo.prepareForBlock(pos, state); +// aoCalc.clear(); + cachedTintIndex = -1; + } + + private float redI2F(int color) { + return ((color >> 16) & 255) / 255F; + } + + private float greenI2F(int color) { + return ((color >> 8) & 255) / 255F; + } + + private float blueI2F(int color) { + return (color & 255) / 255F; + } + + private int colorF2I(float r, float g, float b) { + final int ri = colorChannelF2I(r), gi = colorChannelF2I(g), bi = colorChannelF2I(b); + return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? + (0xFF << 24) | (bi << 16) | (gi << 8) | ri : + (ri << 24) | (gi << 16) | (bi << 8) | 0xFF; + } + + private int colorChannelF2I(float colorChannel) { + return Ints.constrainToRange((int) (colorChannel * 255), 0, 255); + } + + @Override + protected void bufferQuad(MutableQuadViewImpl quad) { + if (blockInfo.shouldCullSide(quad.cullFace())) { + return; + } + + final RenderMaterial mat = quad.material(); + final boolean ao = blockInfo.effectiveAo(mat.ambientOcclusion()); + final boolean emissive = mat.emissive(); + final boolean vanillaShade = mat.shadeMode() == ShadeMode.VANILLA; + final VertexConsumer vertexConsumer = getVertexConsumer(blockInfo.effectiveRenderLayer(mat.renderLayer())); + + tintQuad(quad); + aoCalc.initialize(blockInfo.blockState.getBlock(), blockInfo.blockView, blockInfo.blockPos.x, blockInfo.blockPos.y, blockInfo.blockPos.z, ao); + shadeQuad(quad, ao, emissive, vanillaShade); + bufferQuad(quad, vertexConsumer); + } + + private void tintQuad(MutableQuadViewImpl quad) { + int tintIndex = quad.tintIndex(); + + if (tintIndex != -1) { + final int tint; + + if (tintIndex == cachedTintIndex) { + tint = cachedTint; + } else { + cachedTint = tint = blockInfo.blockColor(tintIndex); + cachedTintIndex = tintIndex; + } + + for (int i = 0; i < 4; i++) { + quad.color(i, ColorHelper.Argb.mixColor(quad.color(i), tint)); + } + } + } + + private void shadeQuad(MutableQuadViewImpl quad, boolean ao, boolean emissive, boolean vanillaShade) { + float[] light = aoCalc.light; + + for (int i = 0; i < 4; i++) { + float brightnessFactor = ao ? light[i] : 1.0F; // Apply ambient occlusion light scaling if enabled + if (emissive) { + brightnessFactor = 1.0F; // Force maximum brightness if the material is emissive + } + + float red = redI2F(quad.color(i)) * brightnessFactor; + float green = greenI2F(quad.color(i)) * brightnessFactor; + float blue = blueI2F(quad.color(i)) * brightnessFactor; + + quad.color(i, colorF2I(red, green, blue)); // Update the vertex color with adjusted brightness + } + } + + public class BlockInputContextImpl implements BakedModel.BlockInputContext { + + private boolean fluidModel; + private BlockState blockState; + private BlockPos pos; + private BlockView blockView; + private MatrixStack matrixStack; + private Random random; + + public void prepare(boolean fluidModel, BlockState blockState, BlockPos pos, BlockView blockView, MatrixStack matrixStack, Random random) { + this.fluidModel = fluidModel; + this.blockState = blockState; + this.pos = pos; + this.blockView = blockView; + this.matrixStack = matrixStack; + this.random = random; + } + + public void release() { + this.fluidModel = false; + this.blockState = null; + this.pos = null; + this.blockView = null; + this.matrixStack = null; + this.random = null; + } + + @Override + public boolean isFluidModel() { + return this.fluidModel; + } + + @Override + public BlockState blockState() { + return this.blockState; + } + + @Override + public BlockPos pos() { + return this.pos; + } + + @Override + public BlockView blockView() { + return this.blockView; + } + + @Override + public MatrixStack matrixStack() { + return this.matrixStack; + } + + @Override + public Random random() { + return this.random; + } + } +} 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 5c72c68da..6e9bfc759 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 @@ -83,31 +83,12 @@ public boolean renderBlock(VertexConsumer consumer, BlockState state, BlockPos p @Override public boolean render(VertexConsumer consumer, 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)); - 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(null, consumer, world, state, pos, q, qlight); - } - } - } - return rendered; + TerrainRenderContext renderer = TerrainRenderContext.POOL.get(); + renderer.prepare(world, random, renderLayer -> Tessellator.INSTANCE); + renderer.bufferModel(StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state), state, pos); + renderer.release(); + + return true; } private float redI2F(int color) { @@ -179,24 +160,24 @@ public ItemModels getItemModels() { } private void renderBakedItemModel(BakedModel model, ItemStack stack, float brightness) { - for (Direction direction : Direction.values()) { - random.setSeed(42L); - renderBakedItemQuads(model.getQuads(null, direction, random), stack, brightness); - } - random.setSeed(42L); - renderBakedItemQuads(model.getQuads(null, null, random), stack, brightness); +// for (Direction direction : Direction.values()) { +// random.setSeed(42L); +// renderBakedItemQuads(model.getQuads(null, direction, random), stack, brightness); +// } +// random.setSeed(42L); +// renderBakedItemQuads(model.getQuads(null, null, random), stack, brightness); } private void renderBakedItemModelFlat(BakedModel model, ItemStack stack, float brightness) { - random.setSeed(42L); - boolean bl = stack != null && stack.itemId != 0 && stack.count > 0; - for (BakedQuad bakedQuad : model.getQuads(null, null, random)) { - if (bakedQuad.face() != Direction.WEST) continue; - int i = bl && bakedQuad.hasTint() ? this.itemColors.getColor(stack, bakedQuad.tintIndex()) : -1; - float light = MathHelper.lerp(bakedQuad.lightEmission(), brightness, 1F); - i = colorF2I(redI2F(i) * light, greenI2F(i) * light, blueI2F(i) * light); - tessellator.quad(bakedQuad, 0, 0, 0, i, i, i, i, 0, 1, 0, false); - } +// random.setSeed(42L); +// boolean bl = stack != null && stack.itemId != 0 && stack.count > 0; +// for (BakedQuad bakedQuad : model.getQuads(null, null, random)) { +// if (bakedQuad.face() != Direction.WEST) continue; +// int i = bl && bakedQuad.hasTint() ? this.itemColors.getColor(stack, bakedQuad.tintIndex()) : -1; +// float light = MathHelper.lerp(bakedQuad.lightEmission(), brightness, 1F); +// i = colorF2I(redI2F(i) * light, greenI2F(i) * light, blueI2F(i) * light); +// tessellator.quad(bakedQuad, 0, 0, 0, i, i, i, i, 0, 1, 0, false); +// } } @Override 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 new file mode 100644 index 000000000..62ad89b5d --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/BlockRenderInfo.java @@ -0,0 +1,100 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import net.minecraft.block.Block; +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.TriState; +import net.modificationstation.stationapi.api.util.math.Direction; +import net.modificationstation.stationapi.api.util.math.MutableBlockPos; +import net.modificationstation.stationapi.api.world.BlockStateView; +import org.jetbrains.annotations.Nullable; + +/** + * Holds, manages, and provides access to the block/world related state + * needed to buffer quads. + */ +public class BlockRenderInfo { + private final BlockColors blockColorMap = StationRenderAPI.getBlockColors(); + private final MutableBlockPos searchPos = new MutableBlockPos(); + + public BlockView blockView; + public BlockPos blockPos; + public BlockState blockState; + + private boolean useAo; + private boolean defaultAo; + private int defaultLayer; + + private boolean enableCulling; + private int cullCompletionFlags; + private int cullResultFlags; + + public void prepareForWorld(BlockView blockView, boolean enableCulling) { + this.blockView = blockView; + this.enableCulling = enableCulling; + } + + public void prepareForBlock(BlockPos blockPos, BlockState blockState) { + this.blockPos = blockPos; + this.blockState = blockState; + + useAo = Minecraft.method_2148(); + defaultAo = useAo && blockState.getLuminance() == 0; + + defaultLayer = blockState.getBlock().getRenderLayer(); + + cullCompletionFlags = 0; + cullResultFlags = 0; + } + + public void release() { + blockView = null; + blockPos = null; + blockState = null; + } + + public int blockColor(int tintIndex) { + return 0xFF000000 | blockColorMap.getColor(blockState, blockView, blockPos, tintIndex); + } + + public boolean effectiveAo(TriState aoMode) { + return useAo && aoMode.orElse(defaultAo); + } + +// public RenderLayer effectiveRenderLayer(BlendMode blendMode) { +// return blendMode == BlendMode.DEFAULT ? defaultLayer : blendMode.blockRenderLayer; +// } + + public int effectiveRenderLayer(int layer) { + return layer == 1 ? defaultLayer : layer; + } + + public boolean shouldDrawSide(@Nullable Direction side) { + if (side == null || !enableCulling) { + return true; + } + + final int mask = 1 << side.getId(); + + if ((cullCompletionFlags & mask) == 0) { + cullCompletionFlags |= mask; + + if (blockState.getBlock().isSideVisible(blockView, searchPos.getX(), searchPos.getY(), searchPos.getZ(), side.ordinal())) { + cullResultFlags |= mask; + return true; + } else { + return false; + } + } else { + return (cullResultFlags & mask) != 0; + } + } + + public boolean shouldCullSide(@Nullable Direction side) { + return !shouldDrawSide(side); + } +} 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 new file mode 100644 index 000000000..8df4fb98c --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/ItemRenderContext.java @@ -0,0 +1,12 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableQuadViewImpl; + +public class ItemRenderContext extends AbstractRenderContext { + public static final ThreadLocal POOL = ThreadLocal.withInitial(ItemRenderContext::new); + + @Override + protected void bufferQuad(MutableQuadViewImpl quad) { + + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/SimpleBlockRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/SimpleBlockRenderContext.java new file mode 100644 index 000000000..24dd2f0cf --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/SimpleBlockRenderContext.java @@ -0,0 +1,114 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +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.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; +import net.modificationstation.stationapi.api.util.math.ColorHelper; +import net.modificationstation.stationapi.api.util.math.MathHelper; +import net.modificationstation.stationapi.api.util.math.MatrixStack; +import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableQuadViewImpl; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; +import java.util.function.IntFunction; + +public class SimpleBlockRenderContext extends AbstractRenderContext { + public static final ThreadLocal POOL = ThreadLocal.withInitial(SimpleBlockRenderContext::new); + + private final Random random = new Random(); + + private IntFunction vertexConsumers; + private int defaultRenderLayer; + private float red; + private float green; + private float blue; + private int light; + + @Nullable + private int lastRenderLayer; + @Nullable + private VertexConsumer lastVertexConsumer; + + @Override + protected void bufferQuad(MutableQuadViewImpl quad) { + final RenderMaterial mat = quad.material(); + final int renderLayer = mat.renderLayer(); + final VertexConsumer vertexConsumer; + + if (renderLayer == lastRenderLayer) { + vertexConsumer = lastVertexConsumer; + } else { + lastVertexConsumer = vertexConsumer = vertexConsumers.apply(renderLayer); + lastRenderLayer = renderLayer; + } + + tintQuad(quad); +// shadeQuad(quad, mat.emissive()); + bufferQuad(quad, vertexConsumer); + } + + private void tintQuad(MutableQuadViewImpl quad) { + if (quad.tintIndex() != -1) { + final float red = this.red; + final float green = this.green; + final float blue = this.blue; + + for (int i = 0; i < 4; i++) { + quad.color(i, ColorHelper.Argb.scaleRgb(quad.color(i), red, green, blue)); + } + } + } + + public void bufferModel(MatrixStack entry, IntFunction vertexConsumers, BakedModel model, float red, float green, float blue, int light, BlockView blockView, BlockPos pos, BlockState state) { + matrices = entry.peek(); + + this.vertexConsumers = vertexConsumers; + this.defaultRenderLayer = state.getBlock().getRenderLayer(); + this.red = MathHelper.clamp(red, 0, 1); + this.green = MathHelper.clamp(green, 0, 1); + this.blue = MathHelper.clamp(blue, 0, 1); + this.light = light; + + random.setSeed(42L); + + model.emitBlockQuads(new BakedModel.BlockInputContext() { + @Override + public boolean isFluidModel() { + return false; + } + + @Override + public BlockState blockState() { + return state; + } + + @Override + public BlockPos pos() { + return pos; + } + + @Override + public BlockView blockView() { + return blockView; + } + + @Override + public MatrixStack matrixStack() { + return entry; + } + + @Override + public Random random() { + return random; + } + }, getEmitter()); + + matrices = null; + this.vertexConsumers = null; + lastRenderLayer = 1; + lastVertexConsumer = null; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java new file mode 100644 index 000000000..d3cf45d5a --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java @@ -0,0 +1,89 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.block.BlockState; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; +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.api.util.math.MatrixStack; +import net.modificationstation.stationapi.impl.util.math.ChunkSectionPos; +import org.lwjgl.opengl.GL11; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Random; +import java.util.function.IntFunction; + +/** + * Used during section block buffering to invoke {@link BakedModel#emitBlockQuads}. + */ +public class TerrainRenderContext extends AbstractTerrainRenderContext { + public static final ThreadLocal POOL = ThreadLocal.withInitial(TerrainRenderContext::new); + + private MatrixStack matrixStack = new MatrixStack(); + private Random random; + private IntFunction bufferFunc; + + @Override + protected VertexConsumer getVertexConsumer(int layer) { + return bufferFunc.apply(layer); + } + + public void prepare(BlockView blockView, Random random, IntFunction bufferFunc) { + blockInfo.prepareForWorld(blockView, true); + inputContext.prepare(false, blockInfo.blockState, blockInfo.blockPos, blockView, matrixStack, random); + + this.random = random; + this.bufferFunc = bufferFunc; + + // Retrieve OpenGL's model matrix and set it to the MatrixStack + FloatBuffer openglMatrix = ByteBuffer.allocateDirect(Float.BYTES * 16).asFloatBuffer(); + GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, openglMatrix); + + // Convert the OpenGL matrix to Matrix4f and apply it to the MatrixStack + matrixStack.peek().getPositionMatrix().set(openglMatrix); + } + + public void release() { + matrices = null; + random = null; + bufferFunc = null; + + blockInfo.release(); + inputContext.release(); + } + + /** Called from section builder hook. */ + public void bufferModel(BakedModel model, BlockState blockState, BlockPos blockPos) { + matrixStack.push(); + + try { + matrixStack.translate(ChunkSectionPos.getLocalCoord(blockPos.getX()), ChunkSectionPos.getLocalCoord(blockPos.getY()), ChunkSectionPos.getLocalCoord(blockPos.getZ())); + if (blockState.hasModelOffset()) { + Vec3d offset = blockState.getModelOffset(blockPos); + matrixStack.translate(offset.x, offset.y, offset.z); + } + matrices = matrixStack.peek(); + + random.setSeed(blockState.getRenderingSeed(blockPos)); + + prepare(blockPos, blockState); + model.emitBlockQuads(inputContext, getEmitter()); + } catch (Throwable throwable) { + CrashReport crashReport = CrashReport.create(throwable, "Tessellating block in world - Indigo Renderer"); + CrashReportSection crashReportSection = crashReport.addElement("Block being tessellated"); + if (blockState != null) { + crashReportSection.add("Block", blockState::toString); + } + + crashReportSection.add("Block location", (() -> CrashReportSection.createPositionString(blockInfo.blockView, blockPos))); + throw new CrashException(crashReport); + } finally { + matrixStack.pop(); + } + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoCalculator.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoCalculator.java new file mode 100644 index 000000000..86bb30a50 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoCalculator.java @@ -0,0 +1,4 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.aocalc; + +public class AoCalculator { +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoFaceData.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoFaceData.java new file mode 100644 index 000000000..cee24ec69 --- /dev/null +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/aocalc/AoFaceData.java @@ -0,0 +1,86 @@ +package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.aocalc; + +/** + * Holds per-corner results for a single block face. + * Handles caching and provides various utility methods to simplify code elsewhere. + */ +class AoFaceData { + float a0; + float a1; + float a2; + float a3; + int b0; + int b1; + int b2; + int b3; + int s0; + int s1; + int s2; + int s3; + + void l0(int l0) { + this.b0 = l0 & 0xFFFF; + this.s0 = (l0 >>> 16) & 0xFFFF; + } + + void l1(int l1) { + this.b1 = l1 & 0xFFFF; + this.s1 = (l1 >>> 16) & 0xFFFF; + } + + void l2(int l2) { + this.b2 = l2 & 0xFFFF; + this.s2 = (l2 >>> 16) & 0xFFFF; + } + + void l3(int l3) { + this.b3 = l3 & 0xFFFF; + this.s3 = (l3 >>> 16) & 0xFFFF; + } + + int weigtedBlockLight(float[] w) { + return (int) (b0 * w[0] + b1 * w[1] + b2 * w[2] + b3 * w[3]) & 0xFF; + } + + int weigtedSkyLight(float[] w) { + return (int) (s0 * w[0] + s1 * w[1] + s2 * w[2] + s3 * w[3]) & 0xFF; + } + + int weightedCombinedLight(float[] w) { + return weigtedSkyLight(w) << 16 | weigtedBlockLight(w); + } + + float weigtedAo(float[] w) { + return a0 * w[0] + a1 * w[1] + a2 * w[2] + a3 * w[3]; + } + + void toArray(float[] aOut, int[] bOut, int[] vertexMap) { + aOut[vertexMap[0]] = a0; + aOut[vertexMap[1]] = a1; + aOut[vertexMap[2]] = a2; + aOut[vertexMap[3]] = a3; + bOut[vertexMap[0]] = s0 << 16 | b0; + bOut[vertexMap[1]] = s1 << 16 | b1; + bOut[vertexMap[2]] = s2 << 16 | b2; + bOut[vertexMap[3]] = s3 << 16 | b3; + } + + static AoFaceData weightedMean(AoFaceData in0, float w0, AoFaceData in1, float w1, AoFaceData out) { + out.a0 = in0.a0 * w0 + in1.a0 * w1; + out.a1 = in0.a1 * w0 + in1.a1 * w1; + out.a2 = in0.a2 * w0 + in1.a2 * w1; + out.a3 = in0.a3 * w0 + in1.a3 * w1; + + out.b0 = (int) (in0.b0 * w0 + in1.b0 * w1); + out.b1 = (int) (in0.b1 * w0 + in1.b1 * w1); + out.b2 = (int) (in0.b2 * w0 + in1.b2 * w1); + out.b3 = (int) (in0.b3 * w0 + in1.b3 * w1); + + out.s0 = (int) (in0.s0 * w0 + in1.s0 * w1); + out.s1 = (int) (in0.s1 * w0 + in1.s1 * w1); + out.s2 = (int) (in0.s2 * w0 + in1.s2 * w1); + out.s3 = (int) (in0.s3 * w0 + in1.s3 * w1); + + return out; + } +} diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java index 51cf26e97..7c501d213 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java @@ -32,7 +32,6 @@ private EncodingFormat() { } static final int VERTEX_COLOR; static final int VERTEX_U; static final int VERTEX_V; - static final int VERTEX_LIGHTMAP; static final int VERTEX_NORMAL; public static final int VERTEX_STRIDE; @@ -48,9 +47,8 @@ private EncodingFormat() { } VERTEX_COLOR = HEADER_STRIDE + 3; VERTEX_U = HEADER_STRIDE + 4; VERTEX_V = VERTEX_U + 1; - VERTEX_LIGHTMAP = HEADER_STRIDE + 6; VERTEX_NORMAL = HEADER_STRIDE + 7; - VERTEX_STRIDE = format.getVertexSize() / 4; + VERTEX_STRIDE = 8;//format.getVertexSize() / 4; QUAD_STRIDE = VERTEX_STRIDE * 4; QUAD_STRIDE_BYTES = QUAD_STRIDE * 4; TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE; diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java index 5713e2053..9e1cbfb92 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/MutableQuadViewImpl.java @@ -1,10 +1,10 @@ package net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_BITS; +import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_STRIDE; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TAG; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TINT_INDEX; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_COLOR; -import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_LIGHTMAP; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_NORMAL; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_STRIDE; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_U; @@ -18,6 +18,7 @@ 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.render.helper.ColorHelper; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.NormalHelper; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.helper.TextureHelper; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.material.RenderMaterialImpl; @@ -105,12 +106,6 @@ public final MutableQuadViewImpl spriteBake(Sprite sprite, int bakeFlags) { return this; } - @Override - public final MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) { - data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap; - return this; - } - protected final void normalFlags(int flags) { data[baseIndex + HEADER_BITS] = EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS], flags); } @@ -186,54 +181,30 @@ public final MutableQuadViewImpl copyFrom(QuadView quad) { return this; } -// @Override -// public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) { -// System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, VANILLA_QUAD_STRIDE); -// isGeometryInvalid = true; -// -// int normalFlags = 0; -// int colorIndex = baseIndex + VERTEX_COLOR; -// int normalIndex = baseIndex + VERTEX_NORMAL; -// -// for (int i = 0; i < 4; i++) { -// data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]); -// -// // Set normal flag if normal is not zero, ignoring W component -// if ((data[normalIndex] & 0xFFFFFF) != 0) { -// normalFlags |= 1 << i; -// } -// -// colorIndex += VERTEX_STRIDE; -// normalIndex += VERTEX_STRIDE; -// } -// -// normalFlags(normalFlags); -// return this; -// } -// -// @Override -// public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) { -// fromVanilla(quad.vertexData(), 0); -// cullFace(cullFace); -// nominalFace(quad.face()); -// tintIndex(quad.tintIndex()); -// -// if (!quad.shade()) { -// material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true); -// } -// -// int lightEmission = quad.lightEmission(); -// -// if (lightEmission > 0) { -// for (int i = 0; i < 4; i++) { -//// lightmap(i, LightmapTextureManager.applyEmission(lightmap(i), lightEmission)); -// } -// } -// -// material(material); -// tag(0); -// return this; -// } + @Override + public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) { + System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, VANILLA_QUAD_STRIDE); + isGeometryInvalid = true; + + int normalFlags = 0; + int colorIndex = baseIndex + VERTEX_COLOR; + int normalIndex = baseIndex + VERTEX_NORMAL; + + for (int i = 0; i < 4; i++) { + data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]); + + // Set normal flag if normal is not zero, ignoring W component + if ((data[normalIndex] & 0xFFFFFF) != 0) { + normalFlags |= 1 << i; + } + + colorIndex += VERTEX_STRIDE; + normalIndex += VERTEX_STRIDE; + } + + normalFlags(normalFlags); + return this; + } @Override public void pushTransform(QuadTransform transform) { diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java index f0ec099c6..8135d6f9f 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/QuadViewImpl.java @@ -7,7 +7,6 @@ import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.HEADER_TINT_INDEX; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.QUAD_STRIDE; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_COLOR; -import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_LIGHTMAP; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_NORMAL; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_STRIDE; import static net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.EncodingFormat.VERTEX_U; @@ -137,11 +136,6 @@ public final Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) { return target; } - @Override - public final int lightmap(int vertexIndex) { - return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP]; - } - public final int normalFlags() { return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]); } From 1afb989ba921291fc263b9e31de25cfbc468a636 Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 7 Apr 2025 21:57:19 -0500 Subject: [PATCH 07/14] Fix oopise --- .../stationapi/impl/recipe/JsonRecipeParserInit.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java index 739b22411..d3d3dd91d 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java @@ -45,8 +45,8 @@ private static void registerJsonRecipeParsers(JsonRecipeParserRegistryEvent even private static void parseAndRegisterRecipe(RecipeRegisterEvent event) { Consumer jsonRecipeParser = JsonRecipeParserRegistry.INSTANCE.get(event.recipeId); Set jsonRecipes = JsonRecipesRegistry.INSTANCE.get(event.recipeId); -// if (jsonRecipeParser != null && jsonRecipes != null) -// jsonRecipes.forEach(jsonRecipeParser); + if (jsonRecipeParser != null && jsonRecipes != null) + jsonRecipes.forEach(jsonRecipeParser); } private static void parseCraftingShaped(URL recipe) { From 17fc5e154660f122a041c307f36097bb75bad154 Mon Sep 17 00:00:00 2001 From: alpha Date: Mon, 7 Apr 2025 22:49:16 -0500 Subject: [PATCH 08/14] It actually somewhat works --- .../renderer/render/TerrainRenderContext.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java index d3cf45d5a..d7052876f 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java @@ -40,12 +40,12 @@ public void prepare(BlockView blockView, Random random, IntFunction Date: Wed, 9 Apr 2025 17:03:17 -0500 Subject: [PATCH 09/14] Fix quad EncodingFormat --- .../client/render/VertexFormatElement.java | 12 ++++++------ .../api/client/render/VertexFormats.java | 3 ++- .../renderer/render/mesh/EncodingFormat.java | 19 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java index 122d0f88e..720faf9e5 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormatElement.java @@ -16,12 +16,12 @@ public record VertexFormatElement(int id, int index, Type type, Usage usage, int private static final VertexFormatElement[] BY_ID = new VertexFormatElement[MAX_COUNT]; private static final List ELEMENTS = new ArrayList<>(MAX_COUNT); - public static final VertexFormatElement POSITION = register(0, 0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, 3); - public static final VertexFormatElement COLOR = register(1, 0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, 4); - public static final VertexFormatElement UV0 = register(2, 0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.UV, 2); - public static final VertexFormatElement UV1 = register(3, 1, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.UV, 2); - public static final VertexFormatElement UV2 = register(4, 2, VertexFormatElement.Type.SHORT, VertexFormatElement.Usage.UV, 2); - public static final VertexFormatElement NORMAL = register(5, 0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.NORMAL, 3); + public static final VertexFormatElement POSITION = register(0, 0, Type.FLOAT, Usage.POSITION, 3); + public static final VertexFormatElement COLOR = register(1, 0, Type.INT, VertexFormatElement.Usage.COLOR, 1); + public static final VertexFormatElement UV0 = register(2, 0, Type.FLOAT, Usage.UV, 2); + public static final VertexFormatElement UV1 = register(3, 1, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement UV2 = register(4, 2, Type.SHORT, Usage.UV, 2); + public static final VertexFormatElement NORMAL = register(5, 0, Type.INT, Usage.NORMAL, 1); public VertexFormatElement(int id, int index, Type type, Usage usage, int count) { if (id < 0 || id >= BY_ID.length) { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java index 023a5b065..c3b64c0ca 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexFormats.java @@ -3,8 +3,9 @@ public class VertexFormats { public static final VertexFormat BLOCK = VertexFormat.builder() .add("Position", VertexFormatElement.POSITION) - .add("Color", VertexFormatElement.COLOR) .add("UV0", VertexFormatElement.UV0) + .add("Color", VertexFormatElement.COLOR) .add("Normal", VertexFormatElement.NORMAL) + .padding(4) .build(); } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java index 7c501d213..fe858c9e1 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/mesh/EncodingFormat.java @@ -2,6 +2,7 @@ import com.google.common.base.Preconditions; import net.modificationstation.stationapi.api.client.render.VertexFormat; +import net.modificationstation.stationapi.api.client.render.VertexFormatElement; import net.modificationstation.stationapi.api.client.render.VertexFormats; import net.modificationstation.stationapi.api.client.render.mesh.QuadView; import net.modificationstation.stationapi.api.client.render.model.ModelHelper; @@ -29,9 +30,10 @@ private EncodingFormat() { } 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_COLOR; static final int VERTEX_NORMAL; public static final int VERTEX_STRIDE; @@ -41,14 +43,15 @@ private EncodingFormat() { } static { final VertexFormat format = VertexFormats.BLOCK; - VERTEX_X = HEADER_STRIDE + 0; - VERTEX_Y = HEADER_STRIDE + 1; - VERTEX_Z = HEADER_STRIDE + 2; - VERTEX_COLOR = HEADER_STRIDE + 3; - VERTEX_U = HEADER_STRIDE + 4; + VERTEX_X = HEADER_STRIDE + format.getOffset(VertexFormatElement.POSITION) / 4; + VERTEX_Y = VERTEX_X + 1; + VERTEX_Z = VERTEX_Y + 1; + + VERTEX_U = HEADER_STRIDE + format.getOffset(VertexFormatElement.UV0) / 4; VERTEX_V = VERTEX_U + 1; - VERTEX_NORMAL = HEADER_STRIDE + 7; - VERTEX_STRIDE = 8;//format.getVertexSize() / 4; + VERTEX_COLOR = HEADER_STRIDE + format.getOffset(VertexFormatElement.COLOR) / 4; + VERTEX_NORMAL = HEADER_STRIDE + format.getOffset(VertexFormatElement.NORMAL) / 4; + VERTEX_STRIDE = format.getVertexSize() / 4; QUAD_STRIDE = VERTEX_STRIDE * 4; QUAD_STRIDE_BYTES = QUAD_STRIDE * 4; TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE; From 2b3b5263a5999737d2df6e508007b80be15678e2 Mon Sep 17 00:00:00 2001 From: alpha Date: Wed, 9 Apr 2025 17:26:59 -0500 Subject: [PATCH 10/14] Models now render correctly --- .../modificationstation/sltest/SLTest.java | 2 +- .../impl/recipe/JsonRecipeParserInit.java | 4 +- .../api/client/render/VertexConsumer.java | 2 +- .../api/client/render/mesh/QuadView.java | 2 +- .../client/render/model/BakedQuadFactory.java | 77 ++++++++----------- .../aocalc/LightingCalculatorImpl.java | 38 +++++---- .../render/AbstractTerrainRenderContext.java | 22 +++--- .../render/BakedModelRendererImpl.java | 4 +- .../renderer/render/TerrainRenderContext.java | 11 --- 9 files changed, 72 insertions(+), 90 deletions(-) diff --git a/src/test/java/net/modificationstation/sltest/SLTest.java b/src/test/java/net/modificationstation/sltest/SLTest.java index 4d4d96d59..7ae75a274 100644 --- a/src/test/java/net/modificationstation/sltest/SLTest.java +++ b/src/test/java/net/modificationstation/sltest/SLTest.java @@ -10,7 +10,7 @@ import org.apache.logging.log4j.Logger; public class SLTest { - public static final Namespace NAMESPACE = Namespace.resolve(); + public static final Namespace NAMESPACE = Namespace.of("sltest"); public static final Logger LOGGER = NAMESPACE.getLogger(); diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java index d3d3dd91d..739b22411 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java @@ -45,8 +45,8 @@ private static void registerJsonRecipeParsers(JsonRecipeParserRegistryEvent even private static void parseAndRegisterRecipe(RecipeRegisterEvent event) { Consumer jsonRecipeParser = JsonRecipeParserRegistry.INSTANCE.get(event.recipeId); Set jsonRecipes = JsonRecipesRegistry.INSTANCE.get(event.recipeId); - if (jsonRecipeParser != null && jsonRecipes != null) - jsonRecipes.forEach(jsonRecipeParser); +// if (jsonRecipeParser != null && jsonRecipes != null) +// jsonRecipes.forEach(jsonRecipeParser); } private static void parseCraftingShaped(URL recipe) { diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java index ba7891c40..9b567cd1e 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/VertexConsumer.java @@ -85,9 +85,9 @@ default void vertex(float x, float y, float z, int color, float u, float v, int } default void vertex(float x, float y, float z, int color, float u, float v, float normalX, float normalY, float normalZ) { + setTexture(u, v); setVertex(x, y, z); setColor(color); - setTexture(u, v); setNormal(normalX, normalY, normalZ); } diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java index dc6447a10..0781c22c3 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/mesh/QuadView.java @@ -20,7 +20,7 @@ */ public interface QuadView { /** Count of integers in a conventional (un-modded) block or item vertex. */ - int VANILLA_VERTEX_STRIDE = 8;//VertexFormats.BLOCK.getVertexSize() / 4; + int VANILLA_VERTEX_STRIDE = VertexFormats.BLOCK.getVertexSize() / 4; /** Count of integers in a conventional (un-modded) block or item quad. */ int VANILLA_QUAD_STRIDE = VANILLA_VERTEX_STRIDE * 4; diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java index d3933baac..4273ce063 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedQuadFactory.java @@ -6,6 +6,7 @@ import net.modificationstation.stationapi.api.client.render.material.MaterialFinder; 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.mesh.QuadView; import net.modificationstation.stationapi.api.client.render.model.json.ModelElementFace; import net.modificationstation.stationapi.api.client.render.model.json.ModelElementTexture; import net.modificationstation.stationapi.api.client.texture.Sprite; @@ -36,9 +37,9 @@ public void emitQuad(QuadEmitter emitter, Vector3f from, Vector3f to, ModelEleme modelElementTexture.uvs[2] = MathHelper.lerp(f, modelElementTexture.uvs[2], g); modelElementTexture.uvs[1] = MathHelper.lerp(f, modelElementTexture.uvs[1], h); modelElementTexture.uvs[3] = MathHelper.lerp(f, modelElementTexture.uvs[3], h); - int[] quadData = this.packVertexData(modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); - emitter.fromVanilla(quadData, 0); - Direction direction = decodeDirection(quadData); + this.packVertexData(emitter, modelElementTexture, texture, side, this.getPositionMatrix(from, to), settings.getRotation(), rotation, shade); + + Direction direction = decodeDirection(emitter); System.arraycopy(fs, 0, modelElementTexture.uvs, 0, fs.length); if (rotation == null) { emitter.nominalFace(direction); @@ -55,7 +56,7 @@ public void emitQuad(QuadEmitter emitter, Vector3f from, Vector3f to, ModelEleme if (face.cullFace != null) emitter.cullFace(Direction.transform(settings.getRotation().copyMatrix(), face.cullFace)); - emitter.spriteBake(texture, MutableQuadView.BAKE_ROTATE_NONE); +// emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); emitter.material(finder.find()); emitter.tag(0); @@ -101,14 +102,10 @@ public static ModelElementTexture uvLock(ModelElementTexture texture, Direction return new ModelElementTexture(new float[]{p, t, q, u}, w); } - private int[] packVertexData(ModelElementTexture texture, Sprite sprite, Direction direction, float[] positionMatrix, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { - int[] is = new int[32]; - + private void packVertexData(QuadEmitter emitter, ModelElementTexture texture, Sprite sprite, Direction direction, float[] positionMatrix, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { for(int i = 0; i < 4; ++i) { - this.packVertexData(is, i, direction, texture, positionMatrix, sprite, orientation, rotation, shaded); + this.packVertexData(emitter, i, direction, texture, positionMatrix, sprite, orientation, rotation, shaded); } - - return is; } private float[] getPositionMatrix(Vector3f from, Vector3f to) { @@ -122,25 +119,21 @@ private float[] getPositionMatrix(Vector3f from, Vector3f to) { return fs; } - private void packVertexData(int[] vertices, int cornerIndex, Direction direction, ModelElementTexture texture, float[] positionMatrix, Sprite sprite, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { + private void packVertexData(QuadEmitter emitter, int cornerIndex, Direction direction, ModelElementTexture texture, float[] positionMatrix, Sprite sprite, AffineTransformation orientation, @Nullable ModelRotation rotation, boolean shaded) { CubeFace.Corner corner = CubeFace.getFace(direction).getCorner(cornerIndex); Vector3f vector3f = new Vector3f(positionMatrix[corner.xSide], positionMatrix[corner.ySide], positionMatrix[corner.zSide]); this.rotateVertex(vector3f, rotation); this.transformVertex(vector3f, orientation); - this.packVertexData(vertices, cornerIndex, vector3f, sprite, texture); + this.packVertexData(emitter, cornerIndex, vector3f, sprite, texture); } - private void packVertexData(int[] vertices, int cornerIndex, Vector3f position, Sprite sprite, ModelElementTexture modelElementTexture) { - int i = cornerIndex * 8; - vertices[i] = Float.floatToRawIntBits(position.x()); - vertices[i + 1] = Float.floatToRawIntBits(position.y()); - vertices[i + 2] = Float.floatToRawIntBits(position.z()); -// vertices[i + 3] = -1; - vertices[i + 3] = Float.floatToRawIntBits(sprite.getFrameU(modelElementTexture.getU(cornerIndex))); - vertices[i + 3 + 1] = Float.floatToRawIntBits(sprite.getFrameV(modelElementTexture.getV(cornerIndex))); + private void packVertexData(QuadEmitter emitter, int vertexIndex, Vector3f position, Sprite sprite, ModelElementTexture modelElementTexture) { + emitter.pos(vertexIndex, position); + + emitter.uv(vertexIndex, sprite.getFrameU(modelElementTexture.getU(vertexIndex)), sprite.getFrameV(modelElementTexture.getV(vertexIndex))); } - private void rotateVertex(Vector3f vector, @Nullable ModelRotation rotation) { + private void rotateVertex(Vector3f position, @Nullable ModelRotation rotation) { if (rotation != null) { Vector3f axis; Vector3f scale; @@ -160,7 +153,7 @@ private void rotateVertex(Vector3f vector, @Nullable ModelRotation rotation) { default -> throw new IllegalArgumentException("There are only 3 axes"); } - Quaternionf quaternion = (new Quaternionf()).rotationAxis(rotation.angle() * ((float)Math.PI / 180F), axis); + Quaternionf quat = new Quaternionf().rotationAxis(rotation.angle() * ((float)Math.PI / 180F), axis); if (rotation.rescale()) { if (Math.abs(rotation.angle()) == 22.5F) { scale.mul(MIN_SCALE); @@ -173,40 +166,40 @@ private void rotateVertex(Vector3f vector, @Nullable ModelRotation rotation) { scale.set(1.0F, 1.0F, 1.0F); } - this.transformVertex(vector, new Vector3f(rotation.origin()), new Matrix4f().rotation(quaternion), scale); + this.transformVertex(position, new Vector3f(rotation.origin()), new Matrix4f().rotation(quat), scale); } } - public void transformVertex(Vector3f vertex, AffineTransformation transformation) { + public void transformVertex(Vector3f position, AffineTransformation transformation) { if (transformation != AffineTransformation.identity()) { - this.transformVertex(vertex, new Vector3f(0.5F, 0.5F, 0.5F), transformation.getMatrix(), new Vector3f(1.0F, 1.0F, 1.0F)); + this.transformVertex(position, new Vector3f(0.5F, 0.5F, 0.5F), transformation.getMatrix(), new Vector3f(1.0F, 1.0F, 1.0F)); } } - private void transformVertex(Vector3f vertex, Vector3fc origin, Matrix4fc transformationMatrix, Vector3fc scale) { - Vector4f vector4f = transformationMatrix.transform(new Vector4f(vertex.x() - origin.x(), vertex.y() - origin.y(), vertex.z() - origin.z(), 1.0F)); + private void transformVertex(Vector3f position, Vector3fc origin, Matrix4fc transformationMatrix, Vector3fc scale) { + Vector4f vector4f = transformationMatrix.transform(new Vector4f(position.x() - origin.x(), position.y() - origin.y(), position.z() - origin.z(), 1.0F)); vector4f.mul(new Vector4f(scale, 1)); - vertex.set(vector4f.x() + origin.x(), vector4f.y() + origin.y(), vector4f.z() + origin.z()); + position.set(vector4f.x() + origin.x(), vector4f.y() + origin.y(), vector4f.z() + origin.z()); } - private static Direction decodeDirection(int[] rotationMatrix) { - Vector3f vector3f = bakeVectors(rotationMatrix, 0); - Vector3f vector3f2 = bakeVectors(rotationMatrix, 8); - Vector3f vector3f3 = bakeVectors(rotationMatrix, 16); - Vector3f vector3f4 = (new Vector3f(vector3f)).sub(vector3f2); - Vector3f vector3f5 = (new Vector3f(vector3f3)).sub(vector3f2); - Vector3f vector3f6 = (new Vector3f(vector3f5)).cross(vector3f4).normalize(); + private static Direction decodeDirection(QuadView quad) { + Vector3f pos1 = new Vector3f(quad.x(0), quad.y(0), quad.z(0)); + Vector3f pos2 = new Vector3f(quad.x(1), quad.y(1), quad.z(1)); + Vector3f pos3 = new Vector3f(quad.x(2), quad.y(2), quad.z(2)); + Vector3f vector3f4 = new Vector3f(pos1).sub(pos2); + Vector3f vector3f5 = new Vector3f(pos3).sub(pos2); + Vector3f vector3f6 = new Vector3f(vector3f5).cross(vector3f4).normalize(); if (!vector3f6.isFinite()) { return Direction.UP; } else { Direction direction = null; float f = 0.0F; - for(Direction direction2 : Direction.values()) { - float g = vector3f6.dot(direction2.getFloatVector()); + for(Direction dir : Direction.values()) { + float g = vector3f6.dot(dir.getFloatVector()); if (g >= 0.0F && g > f) { f = g; - direction = direction2; + direction = dir; } } @@ -218,8 +211,8 @@ private static Direction decodeDirection(int[] rotationMatrix) { } } - private static float bakeVectorX(int[] is, int i) { - return Float.intBitsToFloat(is[i]); + private static float bakeVectorX(int[] rotationMatrix, int cornerIndex) { + return Float.intBitsToFloat(rotationMatrix[cornerIndex]); } private static float bakeVectorY(int[] is, int i) { @@ -230,10 +223,6 @@ private static float bakeVectorZ(int[] is, int i) { return Float.intBitsToFloat(is[i + 2]); } - private static Vector3f bakeVectors(int[] is, int i) { - return new Vector3f(bakeVectorX(is, i), bakeVectorY(is, i), bakeVectorZ(is, i)); - } - private static void encodeDirection(int[] rotationMatrix, Direction direction) { int[] is = new int[rotationMatrix.length]; System.arraycopy(rotationMatrix, 0, is, 0, rotationMatrix.length); 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 a03304621..cad28c520 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,6 +2,9 @@ import net.minecraft.block.Block; import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.client.render.material.MaterialView; +import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; +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.MathHelper; @@ -78,30 +81,31 @@ private int toIndex(int x, int y, int z) { return ((x + cacheRadius) * cacheDiameter + y + cacheRadius) * cacheDiameter + z + cacheRadius; } - public void calculateForQuad(BakedQuad q) { - float emission = q.lightEmission(); + public void calculateForQuad(QuadView q) { + float emission = 0;//q.lightEmission(); + MaterialView material = q.material(); - if (emission == 1) { + if (material.emissive()) { System.arraycopy(FULL_BRIGHTNESS, 0, light, 0, light.length); return; } - Direction face = q.face(); + Direction face = q.nominalFace(); calculateForQuad( face, - x + Float.intBitsToFloat(q.vertexData()[0]), - y + Float.intBitsToFloat(q.vertexData()[1]), - z + Float.intBitsToFloat(q.vertexData()[2]), - x + Float.intBitsToFloat(q.vertexData()[8]), - y + Float.intBitsToFloat(q.vertexData()[9]), - z + Float.intBitsToFloat(q.vertexData()[10]), - x + Float.intBitsToFloat(q.vertexData()[16]), - y + Float.intBitsToFloat(q.vertexData()[17]), - z + Float.intBitsToFloat(q.vertexData()[18]), - x + Float.intBitsToFloat(q.vertexData()[24]), - y + Float.intBitsToFloat(q.vertexData()[25]), - z + Float.intBitsToFloat(q.vertexData()[26]), - q.shade() + 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), + !material.disableDiffuse() ); if (emission == 0) return; diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java index 1d1984770..8afbcb103 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/AbstractTerrainRenderContext.java @@ -4,6 +4,7 @@ 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.render.VertexConsumer; import net.modificationstation.stationapi.api.client.render.material.RenderMaterial; import net.modificationstation.stationapi.api.client.render.material.ShadeMode; @@ -94,19 +95,18 @@ private void tintQuad(MutableQuadViewImpl quad) { } private void shadeQuad(MutableQuadViewImpl quad, boolean ao, boolean emissive, boolean vanillaShade) { - float[] light = aoCalc.light; + aoCalc.calculateForQuad(quad); - for (int i = 0; i < 4; i++) { - float brightnessFactor = ao ? light[i] : 1.0F; // Apply ambient occlusion light scaling if enabled - if (emissive) { - brightnessFactor = 1.0F; // Force maximum brightness if the material is emissive - } + int color = quad.tintIndex(); + float[] brightness = aoCalc.light; + + float + r = redI2F(color), + g = greenI2F(color), + b = blueI2F(color); - float red = redI2F(quad.color(i)) * brightnessFactor; - float green = greenI2F(quad.color(i)) * brightnessFactor; - float blue = blueI2F(quad.color(i)) * brightnessFactor; - - quad.color(i, colorF2I(red, green, blue)); // Update the vertex color with adjusted brightness + for (int i = 0; i < 4; i++) { + quad.color(i, colorF2I(r * brightness[0], g * brightness[0], b * brightness[0])); } } 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 6e9bfc759..2a65e369d 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 @@ -120,11 +120,11 @@ public void renderDamage(VertexConsumer consumer, BlockState state, BlockPos pos // return; // } BakedModel bakedModel = StationRenderAPI.getBakedModelManager().getBlockModels().getModel(state); - long l = state.getRenderingSeed(pos); + long seed = state.getRenderingSeed(pos); damage = true; //noinspection deprecation StationTextureManager.get(((Minecraft) FabricLoader.getInstance().getGameInstance()).textureManager).getTexture(ModelLoader.BLOCK_DESTRUCTION_STAGE_TEXTURES.get((int) (progress * 10))).bindTexture(); - render(consumer, world, bakedModel, state, pos, true, this.random, l); + render(consumer, world, bakedModel, state, pos, true, this.random, seed); damage = false; } diff --git a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java index d7052876f..98ebe6e54 100644 --- a/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java +++ b/station-renderer-arsenic/src/main/java/net/modificationstation/stationapi/impl/client/arsenic/renderer/render/TerrainRenderContext.java @@ -10,11 +10,7 @@ import net.modificationstation.stationapi.api.util.crash.CrashReport; import net.modificationstation.stationapi.api.util.crash.CrashReportSection; import net.modificationstation.stationapi.api.util.math.MatrixStack; -import net.modificationstation.stationapi.impl.util.math.ChunkSectionPos; -import org.lwjgl.opengl.GL11; -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; import java.util.Random; import java.util.function.IntFunction; @@ -39,13 +35,6 @@ public void prepare(BlockView blockView, Random random, IntFunction Date: Wed, 9 Apr 2025 17:28:22 -0500 Subject: [PATCH 11/14] fixup! Models now render correctly --- .../stationapi/impl/recipe/JsonRecipeParserInit.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java index 739b22411..d3d3dd91d 100644 --- a/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java +++ b/station-recipes-v0/src/main/java/net/modificationstation/stationapi/impl/recipe/JsonRecipeParserInit.java @@ -45,8 +45,8 @@ private static void registerJsonRecipeParsers(JsonRecipeParserRegistryEvent even private static void parseAndRegisterRecipe(RecipeRegisterEvent event) { Consumer jsonRecipeParser = JsonRecipeParserRegistry.INSTANCE.get(event.recipeId); Set jsonRecipes = JsonRecipesRegistry.INSTANCE.get(event.recipeId); -// if (jsonRecipeParser != null && jsonRecipes != null) -// jsonRecipes.forEach(jsonRecipeParser); + if (jsonRecipeParser != null && jsonRecipes != null) + jsonRecipes.forEach(jsonRecipeParser); } private static void parseCraftingShaped(URL recipe) { From ddbdd8c8f311bc5d2ee8f9858821dd069af8954c Mon Sep 17 00:00:00 2001 From: alpha Date: Wed, 9 Apr 2025 17:50:52 -0500 Subject: [PATCH 12/14] Fix item rendering for now --- .../api/client/render/model/BakedModel.java | 6 ++ .../render/BakedModelRendererImpl.java | 6 +- .../renderer/render/ItemRenderContext.java | 65 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java index d5b434a65..482df6fec 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/BakedModel.java @@ -2,11 +2,13 @@ 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.mesh.QuadEmitter; 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 org.jetbrains.annotations.Nullable; public interface BakedModel { @@ -38,5 +40,9 @@ interface BlockInputContext extends InputContext { interface ItemInputContext extends InputContext { ItemStack itemStack(); + + @Nullable + @Override + BlockView blockView(); } } 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 2a65e369d..a7dd18fba 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 @@ -160,6 +160,8 @@ public ItemModels getItemModels() { } private void renderBakedItemModel(BakedModel model, ItemStack stack, float brightness) { + ItemRenderContext context = ItemRenderContext.POOL.get(); + context.renderItem(Tessellator.INSTANCE, stack, model, random, brightness); // for (Direction direction : Direction.values()) { // random.setSeed(42L); // renderBakedItemQuads(model.getQuads(null, direction, random), stack, brightness); @@ -169,7 +171,9 @@ private void renderBakedItemModel(BakedModel model, ItemStack stack, float brigh } private void renderBakedItemModelFlat(BakedModel model, ItemStack stack, float brightness) { -// random.setSeed(42L); + ItemRenderContext context = ItemRenderContext.POOL.get(); + context.renderItem(Tessellator.INSTANCE, stack, model, random, brightness); + random.setSeed(42L); // boolean bl = stack != null && stack.itemId != 0 && stack.count > 0; // for (BakedQuad bakedQuad : model.getQuads(null, null, random)) { // if (bakedQuad.face() != Direction.WEST) continue; 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 index 8df4fb98c..2de01f95d 100644 --- 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 @@ -1,12 +1,77 @@ package net.modificationstation.stationapi.impl.client.arsenic.renderer.render; +import net.minecraft.client.render.Tessellator; +import net.minecraft.item.ItemStack; +import net.minecraft.world.BlockView; +import net.modificationstation.stationapi.api.client.render.VertexConsumer; +import net.modificationstation.stationapi.api.client.render.model.BakedModel; +import net.modificationstation.stationapi.api.util.math.MatrixStack; import net.modificationstation.stationapi.impl.client.arsenic.renderer.render.mesh.MutableQuadViewImpl; +import java.util.Random; + public class ItemRenderContext extends AbstractRenderContext { public static final ThreadLocal POOL = ThreadLocal.withInitial(ItemRenderContext::new); + private VertexConsumer vertexConsumer; @Override protected void bufferQuad(MutableQuadViewImpl quad) { + bufferQuad(quad, vertexConsumer); + } + + public void renderItem(VertexConsumer vertexConsumer, ItemStack item, BakedModel model, Random random, float brightness) { + renderItem(new MatrixStack(), vertexConsumer, item, model, random, brightness); + } + + public void renderItem(MatrixStack matrixStack, VertexConsumer vertexConsumer, ItemStack item, BakedModel model, Random random, float brightness) { + this.vertexConsumer = vertexConsumer; + this.matrices = matrixStack.peek(); + model.emitItemQuads(new BakedModel.ItemInputContext() { + @Override + public ItemStack itemStack() { + return item; + } + + @Override + public BlockView blockView() { + return null; + } + + @Override + public MatrixStack matrixStack() { + return matrixStack; + } + + @Override + public Random random() { + return random; + } + }, getEmitter()); + } + + private void tintQuad(MutableQuadViewImpl quad) { +// int tintIndex = quad.tintIndex(); +// +// if (tintIndex >= 0 && tintIndex < tints.length) { +// final int tint = tints[tintIndex]; +// +// for (int i = 0; i < 4; i++) { +// quad.color(i, net.minecraft.util.math.ColorHelper.mix(quad.color(i), tint)); +// } +// } + } + private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) { +// if (emissive) { +// for (int i = 0; i < 4; i++) { +// quad.lightmap(i, LightmapTextureManager.MAX_LIGHT_COORDINATE); +// } +// } else { +// final int light = this.light; +// +// for (int i = 0; i < 4; i++) { +// quad.lightmap(i, ColorHelper.maxLight(quad.lightmap(i), light)); +// } +// } } } From 9bb2ae8137647b91315742bd7d63e51d90311921 Mon Sep 17 00:00:00 2001 From: alpha Date: Thu, 10 Apr 2025 14:53:11 -0500 Subject: [PATCH 13/14] Lightmap start --- .../render/dimension/LightmapDimension.java | 7 ++ .../render/model/LightmapTextureManager.java | 94 +++++++++++++++++++ .../texture/NativeImageBackedTexture.java | 4 +- 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/dimension/LightmapDimension.java create mode 100644 station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/dimension/LightmapDimension.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/dimension/LightmapDimension.java new file mode 100644 index 000000000..ed63ccc51 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/dimension/LightmapDimension.java @@ -0,0 +1,7 @@ +package net.modificationstation.stationapi.api.client.render.dimension; + +public interface LightmapDimension { + float ambientLight(); + + void adjustLightmap(float delta); +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java new file mode 100644 index 000000000..3f7717d72 --- /dev/null +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java @@ -0,0 +1,94 @@ +package net.modificationstation.stationapi.api.client.render.model; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.World; +import net.modificationstation.stationapi.api.client.render.dimension.LightmapDimension; +import net.modificationstation.stationapi.api.client.texture.NativeImage; +import net.modificationstation.stationapi.api.client.texture.NativeImageBackedTexture; +import net.modificationstation.stationapi.api.client.texture.StationTextureManager; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.api.util.math.MathHelper; +import org.joml.Vector3f; + +public class LightmapTextureManager { + /** + * Represents the maximum lightmap coordinate, where both sky light and block light equals {@code 15}. + * The value of this maximum lightmap coordinate is {@value}. + */ + public static final int MAX_LIGHT_COORDINATE = 15728880; + /** + * Represents the maximum sky-light-wise lightmap coordinate whose value is {@value}. + * This is equivalent to a {@code 15} sky light and {@code 0} block light. + */ + public static final int MAX_SKY_LIGHT_COORDINATE = 15728640; + /** + * Represents the maximum block-light-wise lightmap coordinate whose value is {@value}. + * This is equivalent to a {@code 0} sky light and {@code 15} block light. + */ + public static final int MAX_BLOCK_LIGHT_COORDINATE = 240; + + private final NativeImageBackedTexture texture; + private final NativeImage image; + private final Identifier textureIdentifier; + private final Minecraft client; + + public LightmapTextureManager(Minecraft client) { + StationTextureManager textureManager = StationTextureManager.get(client.textureManager); + + this.client = client; + + this.texture = new NativeImageBackedTexture(16, 16, false); + this.textureIdentifier = textureManager.registerDynamicTexture("light_map", this.texture); + this.image = this.texture.getImage(); + + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + this.image.setColor(x, y, -1); + } + } + + this.texture.upload(); + } + + public void update(float delta) { + World world = this.client.world; + + if (world != null) { + float skyDarken = world.method_151(1); + + for (int yPixel = 0; yPixel < 16; yPixel++) { + for (int xPixel = 0; xPixel < 16; xPixel++) { + Vector3f color = new Vector3f(); + + int x = (int) color.x(); + int y = (int) color.y(); + int z = (int) color.z(); + + this.image.setColor(xPixel, yPixel, 0xFF000000 | z << 16 | y << 8 | x); + } + } + } + } + + public static float getBrightness(LightmapDimension type, int lightLevel) { + return getBrightness(type.ambientLight(), lightLevel); + } + + public static float getBrightness(float ambientLight, int lightLevel) { + float level = lightLevel / 15.0F; + float curved_level = level / (4.0F - 3.0F * level); + return MathHelper.lerp(ambientLight, curved_level, 1.0F); + } + + public static int pack(int block, int sky) { + return block << 4 | sky << 20; + } + + public static int getBlockLightCoordinates(int light) { + return light >> 4 & (MAX_BLOCK_LIGHT_COORDINATE | 65295); + } + + public static int getSkyLightCoordinates(int light) { + return light >> 20 & (MAX_BLOCK_LIGHT_COORDINATE | 65295); + } +} diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java index 43a6ed874..c7663b6b3 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/NativeImageBackedTexture.java @@ -9,7 +9,7 @@ @Environment(EnvType.CLIENT) public class NativeImageBackedTexture extends AbstractTexture { - private static final Logger field_25794 = LogManager.getLogger(); + private static final Logger LOGGER = LogManager.getLogger(); @Nullable private NativeImage image; @@ -31,7 +31,7 @@ public void upload() { this.bindTexture(); this.image.upload(0, 0, 0, false); } else { - field_25794.warn("Trying to upload disposed texture {}", this.getGlId()); + LOGGER.warn("Trying to upload disposed texture {}", this.getGlId()); } } From 8afeb2ab506b60f1e5fb1964c4e0e27154567e9c Mon Sep 17 00:00:00 2001 From: alpha Date: Thu, 10 Apr 2025 16:01:02 -0500 Subject: [PATCH 14/14] Add enable and disable methods --- .../render/model/LightmapTextureManager.java | 23 +++++++++++++++++++ .../api/client/texture/AbstractTexture.java | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java index 3f7717d72..85d2a4f9b 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/render/model/LightmapTextureManager.java @@ -9,6 +9,8 @@ import net.modificationstation.stationapi.api.util.Identifier; import net.modificationstation.stationapi.api.util.math.MathHelper; import org.joml.Vector3f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; public class LightmapTextureManager { /** @@ -31,11 +33,32 @@ public class LightmapTextureManager { private final NativeImage image; private final Identifier textureIdentifier; private final Minecraft client; + private final StationTextureManager textureManager; + + private void disable() { + GL13.glClientActiveTexture(GL13.GL_TEXTURE2); + GL13.glActiveTexture(GL13.GL_TEXTURE2); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } + + public void enable() { + GL13.glClientActiveTexture(GL13.GL_TEXTURE2); + GL13.glActiveTexture(GL13.GL_TEXTURE2); + this.textureManager.bindTexture(this.textureIdentifier); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL13.glClientActiveTexture(GL13.GL_TEXTURE0); + GL13.glActiveTexture(GL13.GL_TEXTURE0); + } public LightmapTextureManager(Minecraft client) { StationTextureManager textureManager = StationTextureManager.get(client.textureManager); this.client = client; + this.textureManager = textureManager; this.texture = new NativeImageBackedTexture(16, 16, false); this.textureIdentifier = textureManager.registerDynamicTexture("light_map", this.texture); diff --git a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java index 8f40ca86f..b6d9de1ba 100644 --- a/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java +++ b/station-renderer-api-v1/src/main/java/net/modificationstation/stationapi/api/client/texture/AbstractTexture.java @@ -51,7 +51,7 @@ public void clearGlId() { public abstract void load(ResourceManager manager) throws IOException; public void bindTexture() { - GL11.glBindTexture(3553, this.getGlId()); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.getGlId()); } public void registerTexture(TextureManager textureManager, ResourceManager resourceManager, Identifier identifier, Executor executor) {