mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-08 21:14:41 -04:00
Add AtlasSourceTypeRegistry (#3504)
This commit is contained in:
parent
25e1b4769d
commit
0d29db7657
9 changed files with 322 additions and 4 deletions
fabric-rendering-v1/src
client
java/net/fabricmc/fabric
api/client/rendering/v1
impl/client/rendering
mixin/client/rendering
resources
testmod
testmodClient
java/net/fabricmc/fabric/test/rendering/client
resources/assets
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.rendering.v1;
|
||||
|
||||
import net.minecraft.client.texture.atlas.AtlasSourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.rendering.AtlasSourceTypeRegistryImpl;
|
||||
|
||||
/**
|
||||
* A registry for custom {@link AtlasSourceType}s. Registered types will be automatically available for use in atlas definition JSON files.
|
||||
*/
|
||||
public final class AtlasSourceTypeRegistry {
|
||||
private AtlasSourceTypeRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new {@link AtlasSourceType}.
|
||||
*
|
||||
* @param id the identifier of the atlas source type
|
||||
* @param type the atlas source type to register
|
||||
*/
|
||||
public static void register(Identifier id, AtlasSourceType type) {
|
||||
AtlasSourceTypeRegistryImpl.register(id, type);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.rendering;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.texture.atlas.AtlasSourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.mixin.client.rendering.AtlasSourceManagerAccessor;
|
||||
|
||||
public final class AtlasSourceTypeRegistryImpl {
|
||||
private AtlasSourceTypeRegistryImpl() {
|
||||
}
|
||||
|
||||
public static void register(Identifier id, AtlasSourceType type) {
|
||||
Objects.requireNonNull(id, "id must not be null!");
|
||||
Objects.requireNonNull(type, "type must not be null!");
|
||||
|
||||
AtlasSourceType oldType = AtlasSourceManagerAccessor.getSourceTypeById().putIfAbsent(id, type);
|
||||
|
||||
if (oldType != null) {
|
||||
throw new IllegalStateException("Duplicate registration " + id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.client.rendering;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.texture.atlas.AtlasSourceManager;
|
||||
import net.minecraft.client.texture.atlas.AtlasSourceType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
@Mixin(AtlasSourceManager.class)
|
||||
public interface AtlasSourceManagerAccessor {
|
||||
@Accessor("SOURCE_TYPE_BY_ID")
|
||||
static BiMap<Identifier, AtlasSourceType> getSourceTypeById() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
"compatibilityLevel": "JAVA_17",
|
||||
"client": [
|
||||
"ArmorFeatureRendererMixin",
|
||||
"AtlasSourceManagerAccessor",
|
||||
"BlockColorsMixin",
|
||||
"BlockEntityRendererFactoriesMixin",
|
||||
"BuiltinModelItemRendererMixin",
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.rendering;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
public class CustomAtlasSourcesTestInit implements ModInitializer {
|
||||
public static final Item DOUBLE_IRON_INGOT = new Item(new Item.Settings());
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Registry.register(Registries.ITEM, new Identifier("fabric-rendering-v1-testmod", "double_iron_ingot"), DOUBLE_IRON_INGOT);
|
||||
}
|
||||
}
|
|
@ -7,15 +7,17 @@
|
|||
"license": "Apache-2.0",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.rendering.CustomAtlasSourcesTestInit",
|
||||
"net.fabricmc.fabric.test.rendering.TooltipComponentTestInit"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.rendering.client.WorldRenderEventsTests",
|
||||
"net.fabricmc.fabric.test.rendering.client.ArmorRenderingTests",
|
||||
"net.fabricmc.fabric.test.rendering.client.FeatureRendererTest",
|
||||
"net.fabricmc.fabric.test.rendering.client.TooltipComponentTests",
|
||||
"net.fabricmc.fabric.test.rendering.client.CustomAtlasSourcesTest",
|
||||
"net.fabricmc.fabric.test.rendering.client.DimensionalRenderingTest",
|
||||
"net.fabricmc.fabric.test.rendering.client.HudAndShaderTest"
|
||||
"net.fabricmc.fabric.test.rendering.client.FeatureRendererTest",
|
||||
"net.fabricmc.fabric.test.rendering.client.HudAndShaderTest",
|
||||
"net.fabricmc.fabric.test.rendering.client.TooltipComponentTests",
|
||||
"net.fabricmc.fabric.test.rendering.client.WorldRenderEventsTests"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.rendering.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
import net.minecraft.client.texture.SpriteContents;
|
||||
import net.minecraft.client.texture.SpriteDimensions;
|
||||
import net.minecraft.client.texture.SpriteOpener;
|
||||
import net.minecraft.client.texture.atlas.AtlasSource;
|
||||
import net.minecraft.client.texture.atlas.AtlasSourceType;
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.metadata.ResourceMetadata;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.AtlasSourceTypeRegistry;
|
||||
|
||||
public class CustomAtlasSourcesTest implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
AtlasSourceTypeRegistry.register(new Identifier("fabric-rendering-v1-testmod", "double"), DoubleAtlasSource.TYPE);
|
||||
}
|
||||
|
||||
private static class DoubleAtlasSource implements AtlasSource {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final Codec<DoubleAtlasSource> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Identifier.CODEC.fieldOf("resource").forGetter(source -> source.resource),
|
||||
Identifier.CODEC.fieldOf("sprite").forGetter(source -> source.sprite)
|
||||
).apply(instance, DoubleAtlasSource::new));
|
||||
public static final AtlasSourceType TYPE = new AtlasSourceType(CODEC);
|
||||
|
||||
private final Identifier resource;
|
||||
private final Identifier sprite;
|
||||
|
||||
DoubleAtlasSource(Identifier resource, Identifier sprite) {
|
||||
this.resource = resource;
|
||||
this.sprite = sprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ResourceManager resourceManager, SpriteRegions regions) {
|
||||
Identifier resourceId = RESOURCE_FINDER.toResourcePath(resource);
|
||||
Optional<Resource> optionalResource = resourceManager.getResource(resourceId);
|
||||
|
||||
if (optionalResource.isPresent()) {
|
||||
regions.add(sprite, new DoubleSpriteRegion(resourceId, optionalResource.get(), sprite));
|
||||
} else {
|
||||
LOGGER.warn("Missing sprite: {}", resourceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AtlasSourceType getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private static class DoubleSpriteRegion implements AtlasSource.SpriteRegion {
|
||||
private final Identifier resourceId;
|
||||
private final Resource resource;
|
||||
private final Identifier spriteId;
|
||||
|
||||
DoubleSpriteRegion(Identifier resourceId, Resource resource, Identifier spriteId) {
|
||||
this.resourceId = resourceId;
|
||||
this.resource = resource;
|
||||
this.spriteId = spriteId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteContents apply(SpriteOpener spriteOpener) {
|
||||
ResourceMetadata metadata;
|
||||
|
||||
try {
|
||||
metadata = resource.getMetadata();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Unable to parse metadata from {}", resourceId, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
NativeImage image;
|
||||
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
image = NativeImage.read(inputStream);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Using missing texture, unable to load {}", resourceId, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
int imageWidth = image.getWidth();
|
||||
int imageHeight = image.getHeight();
|
||||
AnimationResourceMetadata animationMetadata = metadata.decode(AnimationResourceMetadata.READER).orElse(AnimationResourceMetadata.EMPTY);
|
||||
SpriteDimensions dimensions = animationMetadata.getSize(imageWidth, imageHeight);
|
||||
int frameWidth = dimensions.width();
|
||||
int frameHeight = dimensions.height();
|
||||
|
||||
if (!MathHelper.isMultipleOf(imageWidth, frameWidth) || !MathHelper.isMultipleOf(imageHeight, dimensions.height())) {
|
||||
LOGGER.error("Image {} size {},{} is not multiple of frame size {},{}", resourceId, imageWidth, imageHeight, frameWidth, frameHeight);
|
||||
image.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
int frameCountX = imageWidth / frameWidth;
|
||||
int frameCountY = imageHeight / frameHeight;
|
||||
int offsetX = frameWidth / 16;
|
||||
int offsetY = frameHeight / 16;
|
||||
|
||||
NativeImage doubleImage = new NativeImage(image.getFormat(), image.getWidth(), image.getHeight(), false);
|
||||
|
||||
for (int frameY = 0; frameY < frameCountY; frameY++) {
|
||||
for (int frameX = 0; frameX < frameCountX; frameX++) {
|
||||
blendRect(image, doubleImage, frameX * frameWidth + offsetX, frameY * frameHeight + offsetY, frameX * frameWidth, frameY * frameHeight, frameWidth - offsetX, frameHeight - offsetY);
|
||||
blendRect(image, doubleImage, frameX * frameWidth, frameY * frameHeight, frameX * frameWidth + offsetX, frameY * frameHeight + offsetY, frameWidth - offsetX, frameHeight - offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
return new SpriteContents(spriteId, dimensions, doubleImage, metadata);
|
||||
}
|
||||
|
||||
private static void blendRect(NativeImage src, NativeImage dst, int srcX, int srcY, int destX, int destY, int width, int height) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int c = src.getColor(srcX + x, srcY + y);
|
||||
dst.blend(destX + x, destY + y, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "fabric-rendering-v1-testmod:item/double_iron_ingot"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"sources": [
|
||||
{
|
||||
"type": "fabric-rendering-v1-testmod:double",
|
||||
"resource": "minecraft:item/iron_ingot",
|
||||
"sprite": "fabric-rendering-v1-testmod:item/double_iron_ingot"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Reference in a new issue