Skip to content

Commit 10ec663

Browse files
committed
feat: Inherit normal/specular animation metadata from base texture
1 parent 2f98008 commit 10ec663

File tree

2 files changed

+71
-31
lines changed

2 files changed

+71
-31
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Added
6+
7+
- Normals/Speculars can now inherit animations from the base texture
8+
39
## [1.2.3] - 2025-10-27
410

511
### Changed

src/main/java/com/ventooth/swansong/mixin/mixins/client/texture/TextureAtlasSpriteMixin.java

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
package com.ventooth.swansong.mixin.mixins.client.texture;
1212

1313
import com.google.common.collect.Lists;
14+
import com.ventooth.swansong.Share;
1415
import com.ventooth.swansong.config.ShadersConfig;
1516
import com.ventooth.swansong.mixin.extensions.TextureAtlasSpriteExt;
1617
import com.ventooth.swansong.mixin.interfaces.ShadersTextureAtlasSprite;
1718
import lombok.val;
1819
import org.apache.commons.io.IOUtils;
20+
import org.jetbrains.annotations.Nullable;
1921
import org.spongepowered.asm.mixin.Final;
2022
import org.spongepowered.asm.mixin.Mixin;
2123
import org.spongepowered.asm.mixin.Shadow;
@@ -116,19 +118,25 @@ private void loadShadersSprite(BufferedImage[] p_147964_1_,
116118
if (swan$isBaseSprite()) {
117119
val s$mipmapLevels = Minecraft.getMinecraft()
118120
.getTextureMapBlocks().mipmapLevels;
121+
AnimationMetadataSection animBase = null;
122+
try {
123+
val locBase = s$getIconResource(this.iconName);
124+
val resBase = swan$getResource(locBase);
125+
animBase = (AnimationMetadataSection) resBase.getMetadata("animation");
126+
} catch (Exception e) {
127+
Share.log.warn("Error retrieving base animations for: {}", this.iconName);
128+
Share.log.warn("{}: {}", e.getClass().getName(), e.getMessage());
129+
}
119130
if (ShadersConfig.NormalMapping.value) {
120131
String nameNormal = this.iconName + "_n";
121-
ResourceLocation locNormal = new ResourceLocation(nameNormal);
122-
locNormal = Minecraft.getMinecraft()
123-
.getTextureMapBlocks()
124-
.completeResourceLocation(locNormal, 0);
132+
ResourceLocation locNormal = s$getIconResource(this.iconName + "_n");
125133
if (swan$hasResource(locNormal)) {
126134
try {
127135
val sprite = TextureAtlasSpriteExt.newInstance(nameNormal);
128136
@SuppressWarnings("DataFlowIssue") val spriteM = (TextureAtlasSpriteMixin) (Object) sprite;
129137
spriteM.s$isShadersSprite = true;
130138
sprite.copyFrom((TextureAtlasSprite) (Object) this);
131-
spriteM.s$loadShaderSpriteFrames(locNormal, s$mipmapLevels + 1);
139+
spriteM.s$loadShaderSpriteFrames(animBase, locNormal, s$mipmapLevels + 1);
132140
sprite.generateMipmaps(s$mipmapLevels);
133141
this.s$spriteNormal = sprite;
134142
} catch (IOException e) {
@@ -143,17 +151,14 @@ private void loadShadersSprite(BufferedImage[] p_147964_1_,
143151

144152
if (ShadersConfig.SpecularMapping.value) {
145153
String nameSpecular = this.iconName + "_s";
146-
ResourceLocation locSpecular = new ResourceLocation(nameSpecular);
147-
locSpecular = Minecraft.getMinecraft()
148-
.getTextureMapBlocks()
149-
.completeResourceLocation(locSpecular, 0);
154+
ResourceLocation locSpecular = s$getIconResource(this.iconName + "_s");
150155
if (swan$hasResource(locSpecular)) {
151156
try {
152157
val sprite = TextureAtlasSpriteExt.newInstance(nameSpecular);
153158
@SuppressWarnings("DataFlowIssue") val spriteM = (TextureAtlasSpriteMixin) (Object) sprite;
154159
spriteM.s$isShadersSprite = true;
155160
sprite.copyFrom((TextureAtlasSprite) (Object) this);
156-
spriteM.s$loadShaderSpriteFrames(locSpecular, s$mipmapLevels + 1);
161+
spriteM.s$loadShaderSpriteFrames(animBase, locSpecular, s$mipmapLevels + 1);
157162
sprite.generateMipmaps(s$mipmapLevels);
158163
s$spriteSpecular = sprite;
159164
} catch (IOException e) {
@@ -169,7 +174,15 @@ private void loadShadersSprite(BufferedImage[] p_147964_1_,
169174
}
170175

171176
@Unique
172-
private void s$loadShaderSpriteFrames(ResourceLocation loc, int mipmaplevels) throws IOException {
177+
private static ResourceLocation s$getIconResource(String iconName) {
178+
val res = new ResourceLocation(iconName);
179+
return Minecraft.getMinecraft()
180+
.getTextureMapBlocks()
181+
.completeResourceLocation(res, 0);
182+
}
183+
184+
@Unique
185+
private void s$loadShaderSpriteFrames(@Nullable AnimationMetadataSection baseAnim, ResourceLocation loc, int mipmaplevels) throws IOException {
173186
IResource resource = swan$getResource(loc);
174187
BufferedImage bufferedimage = swan$readBufferedImage(resource.getInputStream());
175188
if (this.width != bufferedimage.getWidth()) {
@@ -187,33 +200,54 @@ private void loadShadersSprite(BufferedImage[] p_147964_1_,
187200
0,
188201
bufferedimage.getWidth());
189202
if (animationmetadatasection == null) {
190-
this.framesTextureData.add(aint);
203+
if (baseAnim == null) {
204+
this.framesTextureData.add(aint);
205+
} else {
206+
try {
207+
s$readAnimations(bufferedimage, baseAnim, aint);
208+
} catch (Exception ignored) {
209+
this.framesTextureData.clear();
210+
this.framesTextureData.add(aint);
211+
}
212+
}
191213
} else {
192-
int i = bufferedimage.getHeight() / this.width;
193-
if (animationmetadatasection.getFrameCount() > 0) {
194-
for (int j : animationmetadatasection.getFrameIndexSet()) {
195-
if (j >= i) {
196-
throw new RuntimeException("invalid frameindex " + j);
197-
}
214+
s$readAnimations(bufferedimage, animationmetadatasection, aint);
215+
}
216+
}
198217

199-
this.allocateFrameTextureData(j);
200-
this.framesTextureData.set(j, getFrameTextureData(aint, this.width, this.width, j));
218+
@Unique
219+
private void s$readAnimations(BufferedImage bufferedimage,
220+
AnimationMetadataSection animationmetadatasection,
221+
int[][] aint) {
222+
int i = bufferedimage.getHeight() / this.width;
223+
if (animationmetadatasection.getFrameCount() > 0) {
224+
for (int j : animationmetadatasection.getFrameIndexSet()) {
225+
if (j >= i) {
226+
throw new RuntimeException("invalid frameindex " + j);
201227
}
202228

203-
this.animationMetadata = animationmetadatasection;
204-
} else {
205-
List<AnimationFrame> list = Lists.newArrayList();
229+
this.allocateFrameTextureData(j);
230+
this.framesTextureData.set(j, getFrameTextureData(aint, this.width, this.width, j));
231+
}
206232

207-
for (int k = 0; k < i; ++k) {
208-
this.framesTextureData.add(getFrameTextureData(aint, this.width, this.width, k));
209-
list.add(new AnimationFrame(k, -1));
210-
}
233+
this.animationMetadata = animationmetadatasection;
234+
} else {
235+
if (i == 1) {
236+
this.framesTextureData.add(aint);
237+
return;
238+
}
211239

212-
this.animationMetadata = new AnimationMetadataSection(list,
213-
this.width,
214-
this.height,
215-
animationmetadatasection.getFrameTime());
240+
List<AnimationFrame> list = Lists.newArrayList();
241+
242+
for (int k = 0; k < i; ++k) {
243+
this.framesTextureData.add(getFrameTextureData(aint, this.width, this.width, k));
244+
list.add(new AnimationFrame(k, -1));
216245
}
246+
247+
this.animationMetadata = new AnimationMetadataSection(list,
248+
this.width,
249+
this.height,
250+
animationmetadatasection.getFrameTime());
217251
}
218252
}
219253

0 commit comments

Comments
 (0)