Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0decc515e4 | ||
|
|
b3e1e89c88 | ||
|
|
32bff85526 | ||
|
|
02fc95f239 | ||
|
|
07fd6d78a0 | ||
|
|
87aa853f81 | ||
|
|
ab69eea654 | ||
|
|
edccf63b66 | ||
|
|
80413fb3de |
No files matched your search
@@ -0,0 +1,14 @@
|
||||
# Description or your *PR* and other info
|
||||
<!-- Please include a summary of the change -->
|
||||
<!-- Any details that you think are important to review this PR? -->
|
||||
<!-- Are there any Issues / PRs related to this one? -->
|
||||
|
||||
<!-- Add a screenshot or a video demonstration for new features -->
|
||||
|
||||
<details open><summary>Template</summary> <!-- OPEN is intentional -->
|
||||
|
||||
### Before submitting a *pull request* make sure you have:
|
||||
- [ ] Read the [AI Contribution Policy](https://github.com/GTNewHorizons/Angelica/blob/master/AI_POLICY.md)
|
||||
- [ ] At least [skimmed](https://github.com/GTNewHorizons/Angelica/search?q=is%3Apr&type=Issues) the tracker for similar pull requests
|
||||
|
||||
</details>
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
: "${REPO:?REPO required}"
|
||||
: "${TAG:?TAG required}"
|
||||
|
||||
if [ -z "${DISCORD_WEBHOOK_URL:-}" ]; then
|
||||
echo "DISCORD_WEBHOOK_URL not set, skipping"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! release_json=$(gh release view "$TAG" --repo "$REPO" --json body,url,publishedAt 2>&1); then
|
||||
echo "Could not read release $TAG in $REPO; skipping:"
|
||||
printf '%s\n' "$release_json"
|
||||
exit 0
|
||||
fi
|
||||
body=$(jq -r '.body // ""' <<<"$release_json")
|
||||
url=$(jq -r '.url' <<<"$release_json")
|
||||
ts=$(jq -r '.publishedAt // ""' <<<"$release_json")
|
||||
[ -n "$ts" ] || ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
payload=$(jq -n \
|
||||
--arg title "$TAG" \
|
||||
--arg url "$url" \
|
||||
--arg desc "$body" \
|
||||
--arg ts "$ts" \
|
||||
'{
|
||||
embeds: [{
|
||||
title: ("Angelica " + $title + " released"),
|
||||
url: $url,
|
||||
description: (if ($desc | length) > 3900
|
||||
then $desc[0:3900] + "\n\n...[full changelog](" + $url + ")"
|
||||
else $desc end),
|
||||
color: 3066993,
|
||||
footer: { text: "GitHub Releases" },
|
||||
timestamp: $ts
|
||||
}]
|
||||
}')
|
||||
|
||||
curl -fsS -X POST -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK_URL"
|
||||
@@ -12,3 +12,22 @@ jobs:
|
||||
release-tags:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/release-tags.yml@master
|
||||
secrets: inherit
|
||||
|
||||
notify-discord:
|
||||
needs: [release-tags]
|
||||
runs-on: ubuntu-24.04
|
||||
if: >-
|
||||
${{ !endsWith(github.ref_name, '-snapshot')
|
||||
&& !contains(github.event.head_commit.message, '[snapshot]')
|
||||
&& !endsWith(github.ref_name, '-pre') }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
- name: Announce release to Discord
|
||||
shell: bash
|
||||
env:
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_RELEASE_WEBHOOK_URL }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: bash .github/scripts/announce-release.sh
|
||||
@@ -0,0 +1,55 @@
|
||||
# AI Usage Policy
|
||||
|
||||
This project has strict rules for AI usage:
|
||||
|
||||
* **The human-in-the-loop must fully understand all code.** If you
|
||||
can't explain what your changes do and how they interact with the
|
||||
greater system without the aid of AI tools, do not contribute
|
||||
those changes.
|
||||
|
||||
* **Issues and discussions can use AI assistance but must have a full
|
||||
human-in-the-loop.** This means that any content generated with AI
|
||||
must have been reviewed *and edited* by a human before submission.
|
||||
The author must do their research and trim this down.
|
||||
|
||||
* **No AI-generated media is allowed (textures, videos, audio, etc.).**
|
||||
Text and code are the only acceptable AI-generated content, per the
|
||||
other rules in this policy.
|
||||
|
||||
* **Commit messages, PR descriptions must read in your own voice.**
|
||||
No AI-authored or AI co-authored commits, including Co-authored-by AI tags.
|
||||
|
||||
* **Only contribute fixes for bugs you have personally hit in-game.**
|
||||
If you haven’t experienced or reproduced a bug firsthand, and don’t
|
||||
already know the relevant code well, don’t throw AI at it and forward it to us.
|
||||
Patches written for problems the author never actually experienced themselves
|
||||
tend to fix the wrong thing and/or produce another.
|
||||
|
||||
* **The voice and intent of written content must be yours.**
|
||||
For documentation and especially quests, the tone and the point you're trying to make
|
||||
has to come from you, not an AI. Use AI to help with phrasing or cleanup if you like,
|
||||
but if the substance and voice aren't yours, don't contribute it.
|
||||
|
||||
* **Bad AI use may be blocked.** People who produce bad contributions
|
||||
that are clearly AI (slop) may be blocked from making future contributions.
|
||||
We love to help junior developers learn and grow, but if you're interested
|
||||
in that, don't use AI and we'll help you. We're sorry that bad AI
|
||||
users have ruined this for you.
|
||||
|
||||
|
||||
## There are Humans Here
|
||||
|
||||
Please remember that this project is maintained by humans.
|
||||
|
||||
Every discussion, issue, and pull request is read and reviewed by
|
||||
humans (and sometimes machines, too). It is a boundary point at which
|
||||
people interact with each other and work is done. It is rude and
|
||||
disrespectful to approach this boundary with low-effort, unqualified
|
||||
work, since it puts the burden of validation on the maintainer.
|
||||
|
||||
In a perfect world, AI would produce high-quality, accurate work
|
||||
every time. But today, that reality depends on the user of the AI.
|
||||
And today, many users of AI do not use it well. So, until that
|
||||
changes, we need to have strict rules to protect maintainers.
|
||||
|
||||
Based on https://github.com/ghostty-org/ghostty/blob/main/AI_POLICY.md
|
||||
@@ -83,7 +83,7 @@ dependencies {
|
||||
shadowImplementation("net.minecraftforge:eventbus:7.0-beta.15")
|
||||
|
||||
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
|
||||
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-32.g7dd88a4-GTNH") {
|
||||
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-33.g3ec381e") {
|
||||
exclude module: "antlr4" // we only want to shadow the runtime module
|
||||
}
|
||||
shadowImplementation("org.antlr:antlr4-runtime:4.13.2")
|
||||
|
||||
@@ -638,6 +638,9 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.bindVertexArray(defaultVAO);
|
||||
boundVAO = defaultVAO;
|
||||
VAOManager.init(defaultVAO);
|
||||
if (defaultVAO != 0) {
|
||||
RENDER_BACKEND.provokingVertex(GL32.GL_LAST_VERTEX_CONVENTION);
|
||||
}
|
||||
if (initCallback != null) {
|
||||
initCallback.run();
|
||||
}
|
||||
@@ -2237,6 +2240,10 @@ public class GLStateManager {
|
||||
FeedbackManager.processDrawElements(mode, indices);
|
||||
return;
|
||||
}
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadElementsAsTriangles(indices.remaining(), GL11.GL_UNSIGNED_BYTE, indices);
|
||||
return;
|
||||
}
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawElements(mode, indices);
|
||||
}
|
||||
@@ -2350,10 +2357,29 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadElementsAsTrianglesInstanced(count, type, indices, primcount);
|
||||
return;
|
||||
}
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawElementsInstanced(mode, count, type, indices, primcount);
|
||||
}
|
||||
|
||||
public static void glDrawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
if (mode == GL11.GL_QUADS) {
|
||||
QuadConverter.drawQuadsAsTrianglesInstanced(first, count, primcount);
|
||||
} else if (mode == GL11.GL_QUAD_STRIP) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArraysInstanced(GL11.GL_TRIANGLE_STRIP, first, count & ~1, primcount);
|
||||
} else if (mode == GL11.GL_POLYGON) {
|
||||
preDraw();
|
||||
RENDER_BACKEND.drawArraysInstanced(GL11.GL_TRIANGLE_FAN, first, count, primcount);
|
||||
} else {
|
||||
preDraw(mode);
|
||||
RENDER_BACKEND.drawArraysInstanced(mode, first, count, primcount);
|
||||
}
|
||||
}
|
||||
|
||||
private static void prepareClientArrays() {
|
||||
if (VAOManager.hasAnyClientSideEnabledAttrib()) {
|
||||
VAOManager.uploadClientArraysToVBO();
|
||||
@@ -6004,15 +6030,15 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glUniform1(int location, IntBuffer values) {
|
||||
if (values.remaining() >= 1) RENDER_BACKEND.uniform1i(location, values.get(values.position()));
|
||||
RENDER_BACKEND.uniform1iv(location, values);
|
||||
}
|
||||
|
||||
public static void glUniform2(int location, FloatBuffer values) {
|
||||
if (values.remaining() >= 2) RENDER_BACKEND.uniform2f(location, values.get(values.position()), values.get(values.position() + 1));
|
||||
RENDER_BACKEND.uniform2(location, values);
|
||||
}
|
||||
|
||||
public static void glUniform2(int location, IntBuffer values) {
|
||||
if (values.remaining() >= 2) RENDER_BACKEND.uniform2i(location, values.get(values.position()), values.get(values.position() + 1));
|
||||
RENDER_BACKEND.uniform2iv(location, values);
|
||||
}
|
||||
|
||||
public static void glUniform3(int location, FloatBuffer values) {
|
||||
@@ -6020,7 +6046,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glUniform3(int location, IntBuffer values) {
|
||||
if (values.remaining() >= 3) RENDER_BACKEND.uniform3i(location, values.get(values.position()), values.get(values.position() + 1), values.get(values.position() + 2));
|
||||
RENDER_BACKEND.uniform3iv(location, values);
|
||||
}
|
||||
|
||||
public static void glUniform4(int location, FloatBuffer values) {
|
||||
@@ -6028,7 +6054,7 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glUniform4(int location, IntBuffer values) {
|
||||
if (values.remaining() >= 4) RENDER_BACKEND.uniform4i(location, values.get(values.position()), values.get(values.position() + 1), values.get(values.position() + 2), values.get(values.position() + 3));
|
||||
RENDER_BACKEND.uniform4iv(location, values);
|
||||
}
|
||||
|
||||
public static void glUniformMatrix2(int location, boolean transpose, FloatBuffer matrices) {
|
||||
|
||||
@@ -83,6 +83,14 @@ public final class QuadConverter {
|
||||
* @param vertexCount number of vertices (must be multiple of 4)
|
||||
*/
|
||||
public static void drawQuadsAsTriangles(int first, int vertexCount) {
|
||||
drawSharedQuadEbo(first, vertexCount, 1, false);
|
||||
}
|
||||
|
||||
public static void drawQuadsAsTrianglesInstanced(int first, int vertexCount, int primcount) {
|
||||
drawSharedQuadEbo(first, vertexCount, primcount, true);
|
||||
}
|
||||
|
||||
private static void drawSharedQuadEbo(int first, int vertexCount, int primcount, boolean instanced) {
|
||||
GLStateManager.preDraw();
|
||||
assert first % 4 == 0 : "QuadConverter: first (" + first + ") must be a multiple of 4";
|
||||
assert vertexCount % 4 == 0 : "QuadConverter: vertexCount (" + vertexCount + ") must be a multiple of 4";
|
||||
@@ -92,7 +100,11 @@ public final class QuadConverter {
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||
// Index offset: first vertex / 4 quads * 6 indices * 4 bytes per int
|
||||
final long indexOffset = (long) (first / 4) * 6 * 4;
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset);
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset);
|
||||
}
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
}
|
||||
|
||||
@@ -107,6 +119,10 @@ public final class QuadConverter {
|
||||
* @param bytesPerIndex bytes per index element
|
||||
*/
|
||||
private static void uploadAndDraw(ByteBuffer dst, int triIndexCount, int indexType, int bytesPerIndex) {
|
||||
uploadAndDraw(dst, triIndexCount, indexType, bytesPerIndex, 1, false);
|
||||
}
|
||||
|
||||
private static void uploadAndDraw(ByteBuffer dst, int triIndexCount, int indexType, int bytesPerIndex, int primcount, boolean instanced) {
|
||||
GLStateManager.preDraw();
|
||||
final int needed = triIndexCount * bytesPerIndex;
|
||||
final int prevEbo = GLStateManager.getBoundEBO();
|
||||
@@ -126,7 +142,11 @@ public final class QuadConverter {
|
||||
}
|
||||
RENDER_BACKEND.bufferSubData(GL15.GL_ELEMENT_ARRAY_BUFFER, 0, dst);
|
||||
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L);
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L);
|
||||
}
|
||||
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
memFree(dst);
|
||||
@@ -141,6 +161,14 @@ public final class QuadConverter {
|
||||
* @param offset byte offset into the currently bound EBO
|
||||
*/
|
||||
public static void drawQuadElementsAsTriangles(int indexCount, int type, long offset) {
|
||||
drawQuadElementsFromEbo(indexCount, type, offset, 1, false);
|
||||
}
|
||||
|
||||
public static void drawQuadElementsAsTrianglesInstanced(int indexCount, int type, long offset, int primcount) {
|
||||
drawQuadElementsFromEbo(indexCount, type, offset, primcount, true);
|
||||
}
|
||||
|
||||
private static void drawQuadElementsFromEbo(int indexCount, int type, long offset, int primcount, boolean instanced) {
|
||||
if (indexCount == 0) return;
|
||||
assert indexCount % 4 == 0 : "QuadConverter: indexCount must be multiple of 4";
|
||||
final int quadCount = indexCount / 4;
|
||||
@@ -155,7 +183,7 @@ public final class QuadConverter {
|
||||
triangulateQuads(memAddress0(src), type, memAddress0(dst), GL11.GL_UNSIGNED_INT, quadCount);
|
||||
|
||||
memFree(src);
|
||||
uploadAndDraw(dst, triIndexCount, GL11.GL_UNSIGNED_INT, 4);
|
||||
uploadAndDraw(dst, triIndexCount, GL11.GL_UNSIGNED_INT, 4, primcount, instanced);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -310,6 +310,16 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
GL31.glDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
GL31.glDrawArraysInstanced(mode, first, count, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provokingVertex(int provokeMode) {
|
||||
GL32.glProvokingVertex(provokeMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
org.lwjgl.opengl.GL43.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
@@ -812,6 +822,11 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
GL20.glUniform4i(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform2(int location, FloatBuffer value) {
|
||||
GL20.glUniform2(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform3(int location, FloatBuffer value) {
|
||||
GL20.glUniform3(location, value);
|
||||
@@ -822,6 +837,26 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
GL20.glUniform4(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform1iv(int location, IntBuffer value) {
|
||||
GL20.glUniform1(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform2iv(int location, IntBuffer value) {
|
||||
GL20.glUniform2(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform3iv(int location, IntBuffer value) {
|
||||
GL20.glUniform3(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform4iv(int location, IntBuffer value) {
|
||||
GL20.glUniform4(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniformMatrix3(int location, boolean transpose, FloatBuffer value) {
|
||||
GL20.glUniformMatrix3(location, transpose, value);
|
||||
|
||||
@@ -87,6 +87,8 @@ public abstract class RenderBackend {
|
||||
public abstract void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride);
|
||||
public abstract void copyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size);
|
||||
public abstract void drawElementsInstanced(int mode, int count, int type, long indices, int primcount);
|
||||
public abstract void drawArraysInstanced(int mode, int first, int count, int primcount);
|
||||
public void provokingVertex(int provokeMode) {}
|
||||
public abstract void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex);
|
||||
public abstract void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex);
|
||||
public abstract void drawBuffer(int mode);
|
||||
@@ -199,8 +201,13 @@ public abstract class RenderBackend {
|
||||
public abstract void uniform3i(int location, int v0, int v1, int v2);
|
||||
public abstract void uniform4f(int location, float v0, float v1, float v2, float v3);
|
||||
public abstract void uniform4i(int location, int v0, int v1, int v2, int v3);
|
||||
public abstract void uniform2(int location, FloatBuffer value);
|
||||
public abstract void uniform3(int location, FloatBuffer value);
|
||||
public abstract void uniform4(int location, FloatBuffer value);
|
||||
public abstract void uniform1iv(int location, IntBuffer value);
|
||||
public abstract void uniform2iv(int location, IntBuffer value);
|
||||
public abstract void uniform3iv(int location, IntBuffer value);
|
||||
public abstract void uniform4iv(int location, IntBuffer value);
|
||||
public abstract void uniformMatrix3(int location, boolean transpose, FloatBuffer value);
|
||||
public abstract void uniformMatrix4(int location, boolean transpose, FloatBuffer value);
|
||||
public void uniformMatrix2(int location, boolean transpose, FloatBuffer matrices) {}
|
||||
|
||||
@@ -46,6 +46,8 @@ public class GLSMRedirector {
|
||||
private static final String ARBMultiTexture = "org/lwjgl/opengl/ARBMultitexture";
|
||||
private static final String ARBShaderObjects = "org/lwjgl/opengl/ARBShaderObjects";
|
||||
private static final String ARBInstancedArrays = "org/lwjgl/opengl/ARBInstancedArrays";
|
||||
private static final String ARBDrawInstanced = "org/lwjgl/opengl/ARBDrawInstanced";
|
||||
private static final String EXTDrawInstanced = "org/lwjgl/opengl/EXTDrawInstanced";
|
||||
|
||||
// Redirect VAO related calls from NHLib
|
||||
private static final String UniversalVAO = "com/gtnewhorizon/gtnhlib/client/opengl/UniversalVAO";
|
||||
@@ -356,7 +358,8 @@ public class GLSMRedirector {
|
||||
.add("glGetFramebufferAttachmentParameteri")
|
||||
.add("glBlitFramebuffer");
|
||||
final var gl31 = RedirectMap.newMap()
|
||||
.add("glDrawElementsInstanced");
|
||||
.add("glDrawElementsInstanced")
|
||||
.add("glDrawArraysInstanced");
|
||||
final var gl32 = RedirectMap.newMap()
|
||||
.add("glFramebufferTexture");
|
||||
final var gl33 = RedirectMap.newMap()
|
||||
@@ -459,6 +462,14 @@ public class GLSMRedirector {
|
||||
methodRedirects.put(ARBInstancedArrays, RedirectMap.newMap()
|
||||
.add("glVertexAttribDivisorARB")
|
||||
);
|
||||
methodRedirects.put(ARBDrawInstanced, RedirectMap.newMap()
|
||||
.add("glDrawArraysInstancedARB", "glDrawArraysInstanced")
|
||||
.add("glDrawElementsInstancedARB", "glDrawElementsInstanced")
|
||||
);
|
||||
methodRedirects.put(EXTDrawInstanced, RedirectMap.newMap()
|
||||
.add("glDrawArraysInstancedEXT", "glDrawArraysInstanced")
|
||||
.add("glDrawElementsInstancedEXT", "glDrawElementsInstanced")
|
||||
);
|
||||
|
||||
// APPLE
|
||||
methodRedirects.put(APPLEVertexArrayObject, RedirectMap.newMap()
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(GLSMCoreExtension.class)
|
||||
class ArrayUniformUploadGLTest {
|
||||
|
||||
private static int compile(int type, String src) {
|
||||
final int s = GL20.glCreateShader(type);
|
||||
GL20.glShaderSource(s, src);
|
||||
GL20.glCompileShader(s);
|
||||
assertEquals(GL11.GL_TRUE, GL20.glGetShaderi(s, GL20.GL_COMPILE_STATUS), () -> "shader compile failed: " + GL20.glGetShaderInfoLog(s, 4096));
|
||||
return s;
|
||||
}
|
||||
|
||||
private static int link(String vs, String fs) {
|
||||
final int v = compile(GL20.GL_VERTEX_SHADER, vs);
|
||||
final int f = compile(GL20.GL_FRAGMENT_SHADER, fs);
|
||||
final int p = GL20.glCreateProgram();
|
||||
GL20.glAttachShader(p, v);
|
||||
GL20.glAttachShader(p, f);
|
||||
GL20.glLinkProgram(p);
|
||||
assertEquals(GL11.GL_TRUE, GL20.glGetProgrami(p, GL20.GL_LINK_STATUS), () -> "link failed: " + GL20.glGetProgramInfoLog(p, 4096));
|
||||
GL20.glDeleteShader(v);
|
||||
GL20.glDeleteShader(f);
|
||||
return p;
|
||||
}
|
||||
|
||||
private static final String VS = "#version 330 core\nvoid main(){ gl_Position = vec4(0.0); }\n";
|
||||
|
||||
@Test
|
||||
void glUniform2FloatBufferUploadsWholeArray() {
|
||||
// Runtime index keeps the whole array active so element locations stay queryable.
|
||||
final String fs = "#version 330 core\n"
|
||||
+ "uniform vec2 cosmicuvs[10];\n"
|
||||
+ "uniform int idx;\n"
|
||||
+ "out vec4 o;\n"
|
||||
+ "void main(){ o = vec4(cosmicuvs[idx], cosmicuvs[(idx+1)%10]); }\n";
|
||||
final int p = link(VS, fs);
|
||||
try {
|
||||
GL20.glUseProgram(p);
|
||||
|
||||
final FloatBuffer buf = BufferUtils.createFloatBuffer(20);
|
||||
for (int i = 0; i < 20; i++) buf.put(i + 1.0f); // 1..20, all distinct, all non-zero
|
||||
buf.flip();
|
||||
|
||||
GLStateManager.glUniform2(GL20.glGetUniformLocation(p, "cosmicuvs"), buf);
|
||||
|
||||
final FloatBuffer read = BufferUtils.createFloatBuffer(2);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
final int loc = GL20.glGetUniformLocation(p, "cosmicuvs[" + i + "]");
|
||||
assertTrue(loc >= 0, "element " + i + " optimized out");
|
||||
read.clear();
|
||||
GL20.glGetUniform(p, loc, read);
|
||||
assertEquals(2 * i + 1.0f, read.get(0), 0.0f, "cosmicuvs[" + i + "].x");
|
||||
assertEquals(2 * i + 2.0f, read.get(1), 0.0f, "cosmicuvs[" + i + "].y");
|
||||
}
|
||||
} finally {
|
||||
GL20.glUseProgram(0);
|
||||
GL20.glDeleteProgram(p);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void glUniform1IntBufferUploadsWholeArray() {
|
||||
final String fs = "#version 330 core\n"
|
||||
+ "uniform int vals[4];\n"
|
||||
+ "uniform int idx;\n"
|
||||
+ "out vec4 o;\n"
|
||||
+ "void main(){ o = vec4(float(vals[idx])); }\n";
|
||||
final int p = link(VS, fs);
|
||||
try {
|
||||
GL20.glUseProgram(p);
|
||||
|
||||
final IntBuffer buf = BufferUtils.createIntBuffer(4);
|
||||
buf.put(11).put(22).put(33).put(44).flip();
|
||||
GLStateManager.glUniform1(GL20.glGetUniformLocation(p, "vals"), buf);
|
||||
|
||||
final IntBuffer read = BufferUtils.createIntBuffer(1);
|
||||
final int[] expect = {11, 22, 33, 44};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
final int loc = GL20.glGetUniformLocation(p, "vals[" + i + "]");
|
||||
assertTrue(loc >= 0, "element " + i + " optimized out");
|
||||
read.clear();
|
||||
GL20.glGetUniform(p, loc, read);
|
||||
assertEquals(expect[i], read.get(0), "vals[" + i + "]");
|
||||
}
|
||||
} finally {
|
||||
GL20.glUseProgram(0);
|
||||
GL20.glDeleteProgram(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class CompatUniformManagerTest {
|
||||
void cleanup() {
|
||||
if (program != 0) {
|
||||
GL20.glUseProgram(0);
|
||||
GL20.glDeleteProgram(program);
|
||||
GLStateManager.glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLDebug;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@ExtendWith(GLSMCoreExtension.class)
|
||||
class InstancedQuadDrawGLTest {
|
||||
|
||||
private static final String VS = "#version 330 core\nlayout(location=0) in vec2 aPos;\nvoid main(){ gl_Position = vec4(aPos, 0.0, 1.0); }\n";
|
||||
private static final String FS = "#version 330 core\nout vec4 o;\nvoid main(){ o = vec4(1.0); }\n";
|
||||
|
||||
private int program;
|
||||
private int vbo;
|
||||
private int ebo;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
program = buildProgram();
|
||||
GLStateManager.glUseProgram(program);
|
||||
|
||||
final FloatBuffer verts = BufferUtils.createFloatBuffer(8);
|
||||
verts.put(new float[] {0, 0, 1, 0, 1, 1, 0, 1}).flip();
|
||||
vbo = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, verts, GL15.GL_STATIC_DRAW);
|
||||
GLStateManager.glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 0, 0L);
|
||||
GLStateManager.glEnableVertexAttribArray(0);
|
||||
|
||||
final IntBuffer idx = BufferUtils.createIntBuffer(4);
|
||||
idx.put(new int[] {0, 1, 2, 3}).flip();
|
||||
ebo = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
GLStateManager.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, idx, GL15.GL_STATIC_DRAW);
|
||||
|
||||
drainErrors();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
GLStateManager.glUseProgram(0);
|
||||
if (program != 0) GL20.glDeleteProgram(program);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (vbo != 0) GLStateManager.glDeleteBuffers(vbo);
|
||||
if (ebo != 0) GLStateManager.glDeleteBuffers(ebo);
|
||||
drainErrors();
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawArraysInstanced_quads_noInvalidEnum() {
|
||||
GLStateManager.glDrawArraysInstanced(GL11.GL_QUADS, 0, 4, 3);
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "GL_QUADS instanced array draw must be emulated, not rejected");
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawArraysInstanced_triangles_fastPathClean() {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glDrawArraysInstanced(GL11.GL_TRIANGLES, 0, 3, 3);
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "non-quad instanced array draw passes through cleanly");
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawElementsInstanced_quads_noInvalidEnum() {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
GLStateManager.glDrawElementsInstanced(GL11.GL_QUADS, 4, GL11.GL_UNSIGNED_INT, 0L, 3);
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "GL_QUADS instanced element draw must be emulated, not rejected");
|
||||
}
|
||||
|
||||
private static int buildProgram() {
|
||||
final int vs = compile(GL20.GL_VERTEX_SHADER, VS);
|
||||
final int fs = compile(GL20.GL_FRAGMENT_SHADER, FS);
|
||||
final int p = GL20.glCreateProgram();
|
||||
GL20.glAttachShader(p, vs);
|
||||
GL20.glAttachShader(p, fs);
|
||||
GL20.glLinkProgram(p);
|
||||
assertNotEquals(0, GL20.glGetProgrami(p, GL20.GL_LINK_STATUS), "test shader must link: " + GL20.glGetProgramInfoLog(p, 1024));
|
||||
GL20.glDeleteShader(vs);
|
||||
GL20.glDeleteShader(fs);
|
||||
return p;
|
||||
}
|
||||
|
||||
private static int compile(int type, String src) {
|
||||
final int s = GL20.glCreateShader(type);
|
||||
GL20.glShaderSource(s, src);
|
||||
GL20.glCompileShader(s);
|
||||
assertNotEquals(0, GL20.glGetShaderi(s, GL20.GL_COMPILE_STATUS), "test shader must compile: " + GL20.glGetShaderInfoLog(s, 1024));
|
||||
return s;
|
||||
}
|
||||
|
||||
private static void drainErrors() {
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) { /* clear */ }
|
||||
}
|
||||
}
|
||||
@@ -348,6 +348,16 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
GL31C.glDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
GL31C.glDrawArraysInstanced(mode, first, count, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provokingVertex(int provokeMode) {
|
||||
GL32C.glProvokingVertex(provokeMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
GL43C.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
@@ -856,6 +866,11 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
GL20C.glUniform4i(location, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform2(int location, FloatBuffer value) {
|
||||
GL20C.glUniform2fv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform3(int location, FloatBuffer value) {
|
||||
GL20C.glUniform3fv(location, value);
|
||||
@@ -866,6 +881,26 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
GL20C.glUniform4fv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform1iv(int location, IntBuffer value) {
|
||||
GL20C.glUniform1iv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform2iv(int location, IntBuffer value) {
|
||||
GL20C.glUniform2iv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform3iv(int location, IntBuffer value) {
|
||||
GL20C.glUniform3iv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniform4iv(int location, IntBuffer value) {
|
||||
GL20C.glUniform4iv(location, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uniformMatrix3(int location, boolean transpose, FloatBuffer value) {
|
||||
GL20C.glUniformMatrix3fv(location, transpose, value);
|
||||
|
||||
@@ -16,7 +16,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhsettingsconvention") version ("2.0.25")
|
||||
id("com.gtnewhorizons.gtnhsettingsconvention") version ("2.0.26")
|
||||
}
|
||||
|
||||
include("glsm")
|
||||
|
||||
@@ -25,6 +25,7 @@ public class DeferredDrawBatcher {
|
||||
|
||||
@Getter private static boolean active = false;
|
||||
private static DeferredBatchTessellator batchTessellator;
|
||||
private static long entryStateKey;
|
||||
|
||||
private DeferredDrawBatcher() {}
|
||||
|
||||
@@ -41,13 +42,14 @@ public class DeferredDrawBatcher {
|
||||
batchTessellator.clearRanges();
|
||||
batchTessellator.setParentTessellator(Tessellator.instance);
|
||||
batchTessellator.snapshotDefaultModelview();
|
||||
entryStateKey = captureStateKey();
|
||||
TessellatorManager.startCapturingDirect(batchTessellator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit deferred mode and flush all captured batches. Groups entries by state key
|
||||
* and vertex format, issues one draw per unique group. Restores the GL state that
|
||||
* was active for the last group so vanilla sees consistent state.
|
||||
* and vertex format, issues one draw per unique group. Restores the bracket's entry
|
||||
* state so the trailing vanilla Tessellator.draw() renders with the layer atlas.
|
||||
*/
|
||||
public static void exitAndFlush() {
|
||||
active = false;
|
||||
@@ -56,6 +58,7 @@ public class DeferredDrawBatcher {
|
||||
if (!ranges.isEmpty()) {
|
||||
ranges.sort(Comparator.comparingLong(DeferredBatchTessellator.DrawRange::stateKey));
|
||||
flushSorted(ranges);
|
||||
applyStateKey(entryStateKey);
|
||||
}
|
||||
|
||||
TessellatorManager.stopCapturingDirect();
|
||||
@@ -147,7 +150,8 @@ public class DeferredDrawBatcher {
|
||||
* - fog state (mode, color, start/end — constant for the frame)
|
||||
*/
|
||||
static long captureStateKey() {
|
||||
final int textureId = GLStateManager.getTextures().getTextureUnitBindings(0).getBinding();
|
||||
final int activeUnit = GLStateManager.getActiveTextureUnit();
|
||||
final int textureId = GLStateManager.getTextures().getTextureUnitBindings(activeUnit).getBinding();
|
||||
final int srcRgb = GLStateManager.getBlendState().getSrcRgb();
|
||||
final int dstRgb = GLStateManager.getBlendState().getDstRgb();
|
||||
final boolean blendEnabled = GLStateManager.getBlendMode().isEnabled();
|
||||
|
||||
@@ -269,6 +269,13 @@ public class AngelicaConfig {
|
||||
@Config.DefaultStringList({"jewelrycraft2:blockCrystal"})
|
||||
public static String[] alwaysTranslucentSprites;
|
||||
|
||||
@Config.Comment({"TileEntity classnames whose render bounds change at runtime (e.g. OpenBlocks Guide).",
|
||||
"These are always rendered and frustum-tested against their live bounds instead of the cached."})
|
||||
@Config.DefaultStringList({"openblocks.common.tileentity.TileEntityGuide",
|
||||
"openblocks.common.tileentity.TileEntityBuilderGuide"})
|
||||
@Config.RequiresMcRestart
|
||||
public static String[] dynamicBoundsTileEntities;
|
||||
|
||||
@Config.Comment("Register HardcodedCustomUniforms in Iris Shaders. May help with compatibility in certain shader packs")
|
||||
@Config.DefaultBoolean(false)
|
||||
public static boolean enableHardcodedCustomUniforms;
|
||||
@@ -350,4 +357,8 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean disableErrorChecks;
|
||||
|
||||
@Config.Comment("Fixes various issues with entity overlays, such as z-fighting, damage animations and eyes.")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean entityOverlayFixes;
|
||||
}
|
||||
@@ -47,9 +47,7 @@ public enum Mixins implements IMixins {
|
||||
, "angelica.bugfixes.MixinRenderGlobal_DestroyBlock"
|
||||
, "angelica.bugfixes.MixinRenderMooshroom_MushroomTint"
|
||||
, "angelica.bugfixes.MixinRendererLivingEntity_DeferredEntityOverlay"
|
||||
, "angelica.bugfixes.MixinRendererLivingEntity_OverlayTint"
|
||||
, "angelica.bugfixes.MixinRenderWither_ArmorCentering"
|
||||
, "angelica.bugfixes.MixinRendererLivingEntity_EyeDepth"
|
||||
, "angelica.debug.MixinMinecraft_FPSCap"
|
||||
, "angelica.ffp.MixinTessellator_CoreProfile"
|
||||
, "angelica.glsm.MixinSplashProgressCaching"
|
||||
@@ -60,6 +58,16 @@ public enum Mixins implements IMixins {
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_ENTITY_OVERLAYS(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.entityOverlayFixes)
|
||||
.addExcludedMod(TargetedMod.CUSTOM_PLAYER_MODELS)
|
||||
.addClientMixins(
|
||||
"angelica.bugfixes.MixinRendererLivingEntity_EyeDepth"
|
||||
, "angelica.bugfixes.MixinRendererLivingEntity_OverlayTint"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_VBO_CLOUDS(
|
||||
new MixinBuilder()
|
||||
.setApplyIf(() -> AngelicaConfig.enableVBOClouds)
|
||||
|
||||
@@ -28,6 +28,7 @@ public enum TargetedMod implements ITargetMod {
|
||||
TINKERS_CONSTRUCT(null, "TConstruct"),
|
||||
TWILIGHT_FOREST(null, "TwilightForest"),
|
||||
BIOMES_O_PLENTY(null, "BiomesOPlenty"),
|
||||
CUSTOM_PLAYER_MODELS("com.tom.cpmcore.CPMLoadingPlugin", "customplayermodels"),
|
||||
WITCHERY(null, "witchery");
|
||||
|
||||
private final TargetModBuilder builder;
|
||||
|
||||
@@ -5,5 +5,5 @@ import net.minecraft.util.AxisAlignedBB;
|
||||
public interface ITileEntityBoundingBoxCache {
|
||||
AxisAlignedBB angelica$getCachedRenderBoundingBox();
|
||||
|
||||
boolean angelica$isInfiniteExtent();
|
||||
byte angelica$boundsClass();
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.gtnewhorizons.angelica.common.BlockError;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.bettercrashes.BetterCrashesCompat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.rendering.TileEntityRenderBoundsRegistry;
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.config.ConfigMigrator;
|
||||
import com.gtnewhorizons.angelica.debug.F3Direction;
|
||||
@@ -102,6 +103,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
@Override
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
ModStatus.preInit();
|
||||
for (String name : AngelicaConfig.dynamicBoundsTileEntities) TileEntityRenderBoundsRegistry.registerDynamicClass(name);
|
||||
super.preInit(event);
|
||||
FMLCommonHandler.instance().bus().register(this);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
|
||||
@@ -4,48 +4,60 @@ import it.unimi.dsi.fastutil.objects.Reference2ByteOpenHashMap;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Registry for tracking which TileEntity classes always return INFINITE_EXTENT_AABB.
|
||||
* Registry for tracking which TileEntity classes always return INFINITE_EXTENT_AABB or are known to change at runtime
|
||||
*/
|
||||
public final class TileEntityRenderBoundsRegistry {
|
||||
private static final byte UNKNOWN = 0;
|
||||
private static final byte FINITE = 1;
|
||||
private static final byte INFINITE = 2;
|
||||
public static final byte STATIC = 1;
|
||||
public static final byte INFINITE = 2;
|
||||
public static final byte DYNAMIC = 3;
|
||||
|
||||
private static final Reference2ByteOpenHashMap<Class<? extends TileEntity>> classRegistry = new Reference2ByteOpenHashMap<>();
|
||||
|
||||
private static final Set<String> dynamicClassNames = ConcurrentHashMap.newKeySet();
|
||||
|
||||
static {
|
||||
classRegistry.defaultReturnValue(UNKNOWN);
|
||||
}
|
||||
|
||||
private TileEntityRenderBoundsRegistry() {}
|
||||
|
||||
public static void registerDynamicClass(String className) {
|
||||
if (className != null && !className.isEmpty()) dynamicClassNames.add(className);
|
||||
}
|
||||
|
||||
public static boolean isInfiniteExtentsBox(AxisAlignedBB box) {
|
||||
return box == null || Double.isInfinite(box.minX) || Double.isInfinite(box.minY) || Double.isInfinite(box.minZ) || Double.isInfinite(box.maxX) || Double.isInfinite(box.maxY) || Double.isInfinite(box.maxZ);
|
||||
}
|
||||
|
||||
public static boolean isAlwaysInfiniteExtent(TileEntity te) {
|
||||
public static byte classify(TileEntity te) {
|
||||
final Class<? extends TileEntity> clazz = te.getClass();
|
||||
synchronized (classRegistry) {
|
||||
final byte result = classRegistry.getByte(clazz);
|
||||
if (result != UNKNOWN) return result == INFINITE;
|
||||
final byte cached = classRegistry.getByte(clazz);
|
||||
if (cached != UNKNOWN) return cached;
|
||||
}
|
||||
return probeAndCache(te, clazz);
|
||||
}
|
||||
|
||||
private static boolean probeAndCache(TileEntity te, Class<? extends TileEntity> clazz) {
|
||||
boolean isInfinite;
|
||||
try {
|
||||
final AxisAlignedBB aabb = te.getRenderBoundingBox();
|
||||
isInfinite = isInfiniteExtentsBox(aabb);
|
||||
} catch (Throwable t) {
|
||||
isInfinite = true;
|
||||
final byte result;
|
||||
if (dynamicClassNames.contains(clazz.getName())) {
|
||||
result = DYNAMIC;
|
||||
} else {
|
||||
boolean isInfinite;
|
||||
try {
|
||||
isInfinite = isInfiniteExtentsBox(te.getRenderBoundingBox());
|
||||
} catch (Throwable t) {
|
||||
isInfinite = true;
|
||||
}
|
||||
result = isInfinite ? INFINITE : STATIC;
|
||||
}
|
||||
|
||||
synchronized (classRegistry) {
|
||||
classRegistry.put(clazz, isInfinite ? INFINITE : FINITE);
|
||||
classRegistry.put(clazz, result);
|
||||
}
|
||||
return isInfinite;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
|
||||
@@ -151,7 +151,8 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
final TileEntity tileEntity = region.getTileEntity(x, y, z);
|
||||
if (tileEntity != null && TileEntityRendererDispatcher.instance.hasSpecialRenderer(tileEntity)) {
|
||||
final boolean isGlobal;
|
||||
if (TileEntityRenderBoundsRegistry.isAlwaysInfiniteExtent(tileEntity)) {
|
||||
final byte boundsClass = TileEntityRenderBoundsRegistry.classify(tileEntity);
|
||||
if (boundsClass == TileEntityRenderBoundsRegistry.INFINITE || boundsClass == TileEntityRenderBoundsRegistry.DYNAMIC) {
|
||||
isGlobal = true;
|
||||
} else {
|
||||
AxisAlignedBB aabb;
|
||||
|
||||
@@ -346,8 +346,9 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
|
||||
final ITileEntityBoundingBoxCache teCache = (ITileEntityBoundingBoxCache) tileEntity;
|
||||
|
||||
if (!teCache.angelica$isInfiniteExtent()) {
|
||||
final AxisAlignedBB aabb = teCache.angelica$getCachedRenderBoundingBox();
|
||||
final byte boundsClass = teCache.angelica$boundsClass();
|
||||
if (boundsClass != TileEntityRenderBoundsRegistry.INFINITE) {
|
||||
final AxisAlignedBB aabb = boundsClass == TileEntityRenderBoundsRegistry.DYNAMIC ? tileEntity.getRenderBoundingBox() : teCache.angelica$getCachedRenderBoundingBox();
|
||||
if (aabb != null && !this.currentViewport.isBoxVisible(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.prupe.mcpatcher.ctm;
|
||||
|
||||
import com.prupe.mcpatcher.ctm.TileOverrideImpl.CTMCompactExpanded;
|
||||
import com.prupe.mcpatcher.mal.tile.TileLoader;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class CTMTextureGenerator {
|
||||
|
||||
public static void generateTextures(BufferedImage[] compactIcons, CTMCompactExpanded override,
|
||||
ResourceLocation propsLoc, ResourceLocation blankResource){
|
||||
BufferedImage cFull = compactIcons[0]; // Full
|
||||
BufferedImage cNone = compactIcons[1]; // None
|
||||
BufferedImage cVert = compactIcons[2]; // Vertical
|
||||
BufferedImage cHori = compactIcons[3]; // Horizontal
|
||||
BufferedImage cCorn = compactIcons[4]; // Corner
|
||||
|
||||
BufferedImage[] expanded = new BufferedImage[47];
|
||||
|
||||
// Generate all 47 textures to match normal CTM
|
||||
expanded[0] = cFull;
|
||||
expanded[1] = generate(cFull, cHori, cFull, cHori);
|
||||
expanded[2] = cHori;
|
||||
expanded[3] = generate(cHori, cFull, cHori, cFull);
|
||||
expanded[4] = generate(cFull, cHori, cVert, cCorn);
|
||||
expanded[5] = generate(cHori, cFull, cCorn, cVert);
|
||||
expanded[6] = generate(cVert, cCorn, cVert, cCorn);
|
||||
expanded[7] = generate(cHori, cHori, cCorn, cCorn);
|
||||
expanded[8] = generate(cCorn, cNone, cCorn, cCorn);
|
||||
expanded[9] = generate(cCorn, cCorn, cCorn, cNone);
|
||||
expanded[10] = generate(cNone, cCorn, cNone, cCorn);
|
||||
expanded[11] = generate(cNone, cNone, cCorn, cCorn);
|
||||
expanded[12] = generate(cFull, cFull, cVert, cVert);
|
||||
expanded[13] = generate(cFull, cHori, cVert, cNone);
|
||||
expanded[14] = generate(cHori, cHori, cNone, cNone);
|
||||
expanded[15] = generate(cHori, cFull, cNone, cVert);
|
||||
expanded[16] = generate(cVert, cCorn, cFull, cHori);
|
||||
expanded[17] = generate(cCorn, cVert, cHori, cFull);
|
||||
expanded[18] = generate(cCorn, cCorn, cHori, cHori);
|
||||
expanded[19] = generate(cCorn, cVert, cCorn, cVert);
|
||||
expanded[20] = generate(cNone, cCorn, cCorn, cCorn);
|
||||
expanded[21] = generate(cCorn, cCorn, cNone, cCorn);
|
||||
expanded[22] = generate(cCorn, cCorn, cNone, cNone);
|
||||
expanded[23] = generate(cCorn, cNone, cCorn, cNone);
|
||||
expanded[24] = cVert;
|
||||
expanded[25] = generate(cVert, cNone, cVert, cNone);
|
||||
expanded[26] = cNone;
|
||||
expanded[27] = generate(cNone, cVert, cNone, cVert);
|
||||
expanded[28] = generate(cVert, cCorn, cVert, cNone);
|
||||
expanded[29] = generate(cHori, cHori, cNone, cCorn);
|
||||
expanded[30] = generate(cVert, cNone, cVert, cCorn);
|
||||
expanded[31] = generate(cHori, cHori, cCorn, cNone);
|
||||
expanded[32] = generate(cNone, cNone, cNone, cCorn);
|
||||
expanded[33] = generate(cNone, cNone, cCorn, cNone);
|
||||
expanded[34] = generate(cCorn, cNone, cNone, cCorn);
|
||||
expanded[35] = generate(cNone, cCorn, cCorn, cNone);
|
||||
expanded[36] = generate(cVert, cVert, cFull, cFull);
|
||||
expanded[37] = generate(cVert, cNone, cFull, cHori);
|
||||
expanded[38] = generate(cNone, cNone, cHori, cHori);
|
||||
expanded[39] = generate(cNone, cVert, cHori, cFull);
|
||||
expanded[40] = generate(cCorn, cNone, cHori, cHori);
|
||||
expanded[41] = generate(cNone, cVert, cNone, cVert);
|
||||
expanded[42] = generate(cNone, cCorn, cHori, cHori);
|
||||
expanded[43] = generate(cCorn, cVert, cNone, cVert);
|
||||
expanded[44] = generate(cNone, cCorn, cNone, cNone);
|
||||
expanded[45] = generate(cCorn, cNone, cNone, cNone);
|
||||
expanded[46] = cCorn;
|
||||
|
||||
for (int i = 0; i < expanded.length; i++){
|
||||
ResourceLocation resource =
|
||||
TileLoader.parseTileAddress(propsLoc, String.valueOf(i), blankResource);
|
||||
override.addIcon(resource, expanded[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferedImage generate(BufferedImage tl, BufferedImage tr, BufferedImage bl, BufferedImage br){
|
||||
int w = tl.getWidth();
|
||||
int hw = w/2;
|
||||
BufferedImage img = new BufferedImage(tl.getWidth(), tl.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
int numFrames = tl.getHeight() / tl.getWidth();
|
||||
Graphics2D g = img.createGraphics();
|
||||
for (int i = 0; i < numFrames; i++){
|
||||
int yOff = w * i;
|
||||
copy(tl, g, 0, yOff, hw);
|
||||
copy(tr, g, hw, yOff, hw);
|
||||
copy(bl, g, 0, yOff + hw, hw);
|
||||
copy(br, g, hw, yOff + hw, hw);
|
||||
}
|
||||
g.dispose();
|
||||
return img;
|
||||
}
|
||||
|
||||
private static void copy(BufferedImage src, Graphics2D g, int x, int y, int s){
|
||||
g.drawImage(src, x, y, x+s, y+s, x, y, x+s, y+s, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,12 +10,12 @@ import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
|
||||
import com.github.bsideup.jabel.Desugar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import com.github.bsideup.jabel.Desugar;
|
||||
import com.prupe.mcpatcher.MCLogger;
|
||||
import com.prupe.mcpatcher.MCPatcherUtils;
|
||||
import com.prupe.mcpatcher.mal.block.BlockAPI;
|
||||
@@ -32,7 +32,7 @@ import jss.notfine.config.MCPatcherForgeConfig;
|
||||
|
||||
public class CTMUtils {
|
||||
|
||||
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
|
||||
public static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
|
||||
|
||||
private static class Overrides {
|
||||
private final List<TileOverride> all = new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.prupe.mcpatcher.ctm;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.prupe.mcpatcher.mal.tile.TileLoader;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import jss.notfine.render.InterpolatedIcon;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.SimpleResource;
|
||||
import net.minecraft.client.resources.data.AnimationMetadataSection;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GeneratedCTMAtlasSprite extends InterpolatedIcon {
|
||||
|
||||
private final TileLoader loader;
|
||||
private final boolean aniFiltering;
|
||||
private boolean interpolated;
|
||||
|
||||
public GeneratedCTMAtlasSprite(TileLoader loader, boolean aniFiltering, String name) {
|
||||
super(name);
|
||||
this.loader = loader;
|
||||
this.aniFiltering = aniFiltering;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
|
||||
if(interpolated) super.updateAnimationInterpolated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean load(IResourceManager manager, ResourceLocation location) {
|
||||
BufferedImage img = loader.getImageForPath(location);
|
||||
if(img == null) return true;
|
||||
try {
|
||||
ResourceLocation metaLoc = getMetaLoc(location);
|
||||
IResource iresource = manager.getResource(metaLoc);
|
||||
AnimationMetadataSection anim = (AnimationMetadataSection)iresource.getMetadata("animation");
|
||||
interpolated = anim != null && AngelicaConfig.enableNotFineFeatures && shouldInterpolate(iresource);
|
||||
loadSprite(new BufferedImage[]{img, null, null, null, null}, anim, aniFiltering);
|
||||
}catch (Exception exception){
|
||||
CTMUtils.logger.error("Error loading sprite for " + location);
|
||||
exception.printStackTrace();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean shouldInterpolate(IResource resource){
|
||||
try {
|
||||
if (resource instanceof SimpleResource simple) {
|
||||
return simple.mcmetaJson.getAsJsonObject("animation")
|
||||
.getAsJsonPrimitive("interpolate").getAsBoolean();
|
||||
}
|
||||
}catch (Exception _){}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the mcmeta file associated with 0.png
|
||||
*/
|
||||
private static ResourceLocation getMetaLoc(ResourceLocation location) {
|
||||
String path = location.getResourcePath();
|
||||
int index = path.lastIndexOf('/');
|
||||
if(index == -1) return new ResourceLocation(location.getResourceDomain(), "0.png");
|
||||
path = path.substring(0, index) + "/0.png";
|
||||
return new ResourceLocation(location.getResourceDomain(), path);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import static com.prupe.mcpatcher.ctm.RenderBlockState.CONNECT_BY_MATERIAL;
|
||||
import static com.prupe.mcpatcher.ctm.RenderBlockState.CONNECT_BY_TILE;
|
||||
import static com.prupe.mcpatcher.ctm.RenderBlockState.NORMALS;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
@@ -32,10 +33,10 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
|
||||
private static final MCLogger logger = MCLogger.getLogger(MCLogger.Category.CONNECTED_TEXTURES, "CTM");
|
||||
|
||||
private final PropertiesFile properties;
|
||||
protected final PropertiesFile properties;
|
||||
private final String baseFilename;
|
||||
private final TileLoader tileLoader;
|
||||
private final int renderPass;
|
||||
protected final TileLoader tileLoader;
|
||||
protected final int renderPass;
|
||||
private final int weight;
|
||||
private final List<BlockStateMatcher> matchBlocks;
|
||||
private final Set<String> matchTiles;
|
||||
@@ -45,7 +46,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
private final BitSet biomes;
|
||||
private final BitSet height;
|
||||
|
||||
private final List<ResourceLocation> tileNames = new ArrayList<>();
|
||||
protected final List<ResourceLocation> tileNames = new ArrayList<>();
|
||||
protected IIcon[] icons;
|
||||
|
||||
// Index into this array is formed from these bit values:
|
||||
@@ -103,6 +104,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
case "sandstone", "top" -> override = new TileOverrideImpl.Top(properties, tileLoader);
|
||||
case "repeat", "pattern" -> override = new TileOverrideImpl.Repeat(properties, tileLoader);
|
||||
case "ctm_compact", "compact" -> override = new TileOverrideImpl.CTMCompact(properties, tileLoader);
|
||||
case "compact_expanded" -> override = new TileOverrideImpl.CTMCompactExpanded(properties, tileLoader);
|
||||
default -> properties.error("unknown method \"%s\"", method);
|
||||
}
|
||||
|
||||
@@ -196,7 +198,12 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
return tileLoader.preloadTile(resource, renderPass > RenderPassAPI.MAX_BASE_RENDER_PASS);
|
||||
}
|
||||
|
||||
private void loadIcons() {
|
||||
public void addIcon(ResourceLocation resource, BufferedImage img){
|
||||
tileNames.add(resource);
|
||||
tileLoader.addTile(resource, img, null, true);
|
||||
}
|
||||
|
||||
protected void loadIcons() {
|
||||
tileNames.clear();
|
||||
String tileList = properties.getString("tiles", "");
|
||||
ResourceLocation blankResource = RenderPassAPI.instance.getBlankResource(renderPass);
|
||||
@@ -221,16 +228,7 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
try {
|
||||
int from = Integer.parseInt(matcher.group(1));
|
||||
int to = Integer.parseInt(matcher.group(2));
|
||||
for (int i = from; i <= to; i++) {
|
||||
ResourceLocation resource = TileLoader
|
||||
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
|
||||
if (TexturePackAPI.hasResource(resource)) {
|
||||
addIcon(resource);
|
||||
} else {
|
||||
properties.warning("could not find image %s", resource);
|
||||
tileNames.add(null);
|
||||
}
|
||||
}
|
||||
loadOverrideIcons(from, to, blankResource);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -250,6 +248,19 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadOverrideIcons(int from, int to, ResourceLocation blankResource){
|
||||
for (int i = from; i <= to; i++) {
|
||||
ResourceLocation resource = TileLoader
|
||||
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
|
||||
if (TexturePackAPI.hasResource(resource)) {
|
||||
addIcon(resource);
|
||||
} else {
|
||||
properties.warning("could not find image %s", resource);
|
||||
tileNames.add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<BlockStateMatcher> getBlockList(String property, String defaultMetadata) {
|
||||
List<BlockStateMatcher> blocks = new ArrayList<>();
|
||||
if (!MCPatcherUtils.isNullOrEmpty(defaultMetadata)) {
|
||||
|
||||
@@ -12,15 +12,22 @@ import static com.prupe.mcpatcher.ctm.RenderBlockState.REL_UL;
|
||||
import static com.prupe.mcpatcher.ctm.RenderBlockState.REL_UR;
|
||||
import static com.prupe.mcpatcher.ctm.RenderBlockState.TOP_FACE;
|
||||
|
||||
import com.prupe.mcpatcher.mal.block.RenderPassAPI;
|
||||
import com.prupe.mcpatcher.mal.resource.TexturePackAPI;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
import com.prupe.mcpatcher.mal.resource.PropertiesFile;
|
||||
import com.prupe.mcpatcher.mal.tile.TileLoader;
|
||||
import com.prupe.mcpatcher.mal.util.WeightedIndex;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TileOverrideImpl {
|
||||
|
||||
final static class CTM extends TileOverride {
|
||||
static class CTM extends TileOverride {
|
||||
|
||||
CTM(PropertiesFile properties, TileLoader tileLoader) {
|
||||
super(properties, tileLoader);
|
||||
@@ -505,4 +512,48 @@ public class TileOverrideImpl {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
final public static class CTMCompactExpanded extends CTM {
|
||||
|
||||
CTMCompactExpanded(PropertiesFile propertiesFile, TileLoader tileLoader) {
|
||||
super(propertiesFile, tileLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
String checkTileMap() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMethod() {
|
||||
return "compact_expanded";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadOverrideIcons(int from, int to, ResourceLocation blankResource) {
|
||||
List<BufferedImage> compactIcons = new ArrayList<>();
|
||||
if(from != 0){
|
||||
properties.error("expanded compact CTM requires range to start at 0, starts at %d", from);
|
||||
}
|
||||
if(to - from + 1 != 5){
|
||||
properties.error("expanded compact CTM requires exactly 5 icons, got range %d - %d", from, to);
|
||||
}
|
||||
for (int i = from; i <= to; i++) {
|
||||
ResourceLocation resource = TileLoader
|
||||
.parseTileAddress(properties.getResource(), String.valueOf(i), blankResource);
|
||||
if (TexturePackAPI.hasResource(resource)) {
|
||||
compactIcons.add(tileLoader.loadResourceImage(resource,
|
||||
renderPass > RenderPassAPI.MAX_BASE_RENDER_PASS));
|
||||
} else {
|
||||
// Promote from warning to error for compact CTM
|
||||
properties.error("could not find image %s, required for expanded compact CTM", resource);
|
||||
tileNames.add(null);
|
||||
}
|
||||
}
|
||||
if(compactIcons.size() == 5){
|
||||
CTMTextureGenerator.generateTextures(compactIcons.toArray(new BufferedImage[0]),
|
||||
this, properties.getResource(), blankResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.prupe.mcpatcher.ctm.GeneratedCTMAtlasSprite;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
@@ -44,6 +45,7 @@ public class TileLoader {
|
||||
private TextureMap baseTextureMap;
|
||||
private final Map<String, TextureAtlasSprite> baseTexturesByName = new HashMap<>();
|
||||
private final Set<ResourceLocation> tilesToRegister = new HashSet<>();
|
||||
private final Set<ResourceLocation> generatedTiles = new HashSet<>();
|
||||
private final Map<ResourceLocation, BufferedImage> tileImages = new HashMap<>();
|
||||
private final Map<String, IIcon> iconMap = new HashMap<>();
|
||||
|
||||
@@ -119,6 +121,10 @@ public class TileLoader {
|
||||
logger.fine("after registerIcons(%s) %d icons", mapName, map.size());
|
||||
}
|
||||
|
||||
public BufferedImage getImageForPath(ResourceLocation rl) {
|
||||
return tileImages.get(rl);
|
||||
}
|
||||
|
||||
public static String getOverridePath(String prefix, String basePath, String name, String ext) {
|
||||
String path;
|
||||
if (name.endsWith(".png")) {
|
||||
@@ -218,6 +224,22 @@ public class TileLoader {
|
||||
if (tileImages.containsKey(resource)) {
|
||||
return true;
|
||||
}
|
||||
return addTile(resource, loadResourceImage(resource, alternate), special, false);
|
||||
}
|
||||
|
||||
public boolean addTile(ResourceLocation resource, BufferedImage image, String special, boolean generated) {
|
||||
tilesToRegister.add(resource);
|
||||
tileImages.put(resource, image);
|
||||
if(generated){
|
||||
generatedTiles.add(resource);
|
||||
}
|
||||
if (special != null) {
|
||||
specialTextures.put(resource.toString(), special);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public BufferedImage loadResourceImage(ResourceLocation resource, boolean alternate){
|
||||
BufferedImage image = null;
|
||||
if (!MCPatcherForgeConfig.ConnectedTextures.debugTextures) {
|
||||
image = TexturePackAPI.getImage(resource);
|
||||
@@ -228,12 +250,7 @@ public class TileLoader {
|
||||
if (image == null) {
|
||||
image = generateDebugTexture(resource.getResourcePath(), 64, 64, alternate);
|
||||
}
|
||||
tilesToRegister.add(resource);
|
||||
tileImages.put(resource, image);
|
||||
if (special != null) {
|
||||
specialTextures.put(resource.toString(), special);
|
||||
}
|
||||
return true;
|
||||
return image;
|
||||
}
|
||||
|
||||
public boolean preloadTile(ResourceLocation resource, boolean alternate) {
|
||||
@@ -287,8 +304,14 @@ public class TileLoader {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
IIcon icon = textureMap.registerIcon(name);
|
||||
map.put(name, (TextureAtlasSprite) icon);
|
||||
TextureAtlasSprite icon;
|
||||
if(generatedTiles.contains(resource)){
|
||||
icon = new GeneratedCTMAtlasSprite(this, textureMap.anisotropicFiltering > 1, name);
|
||||
textureMap.setTextureEntry(name, icon);
|
||||
}else{
|
||||
icon = (TextureAtlasSprite)textureMap.registerIcon(name);
|
||||
}
|
||||
map.put(name, icon);
|
||||
iconMap.put(name, icon);
|
||||
String extra = (width == height ? "" : ", " + (height / width) + " frames");
|
||||
subLogger.finer("%s -> %s icon %dx%d%s", name, mapName, width, width, extra);
|
||||
@@ -299,6 +322,7 @@ public class TileLoader {
|
||||
public void finish() {
|
||||
tilesToRegister.clear();
|
||||
tileImages.clear();
|
||||
generatedTiles.clear();
|
||||
}
|
||||
|
||||
public IIcon getIcon(String name) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class InterpolatedIcon extends TextureAtlasSprite {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
|
||||
protected void updateAnimationInterpolated() throws IllegalArgumentException, IllegalAccessException {
|
||||
|
||||
double d0 = 1.0D - tickCounter / (double) animationMetadata.getFrameTimeSingle(frameCounter);
|
||||
int i = animationMetadata.getFrameIndex(frameCounter);
|
||||
|
||||
|
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 554 B |
|
Before Width: | Height: | Size: 551 B |
|
Before Width: | Height: | Size: 597 B |
|
Before Width: | Height: | Size: 586 B |
|
Before Width: | Height: | Size: 561 B |
|
Before Width: | Height: | Size: 595 B |
|
Before Width: | Height: | Size: 591 B |
|
Before Width: | Height: | Size: 594 B |
|
Before Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 591 B |
|
Before Width: | Height: | Size: 587 B After Width: | Height: | Size: 595 B |
|
Before Width: | Height: | Size: 554 B |
|
Before Width: | Height: | Size: 553 B |
|
Before Width: | Height: | Size: 551 B |
|
Before Width: | Height: | Size: 549 B |
|
Before Width: | Height: | Size: 595 B |
|
Before Width: | Height: | Size: 579 B |
|
Before Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 587 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 562 B |
|
Before Width: | Height: | Size: 550 B |
|
Before Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 550 B |
|
Before Width: | Height: | Size: 552 B |
|
Before Width: | Height: | Size: 598 B |
|
Before Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 592 B |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 553 B |
|
Before Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 591 B |
|
Before Width: | Height: | Size: 551 B |
|
Before Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 553 B |
|
Before Width: | Height: | Size: 593 B |
|
Before Width: | Height: | Size: 582 B |
|
Before Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 551 B |
|
Before Width: | Height: | Size: 552 B |
@@ -1,6 +1,6 @@
|
||||
matchBlocks=minecraft:glass minecraft:glass_pane
|
||||
matchBlocks=glass
|
||||
metadata=0
|
||||
method=ctm
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-46
|
||||
connect=block
|
||||
tiles=0-4
|
||||
connect=block
|
||||
@@ -0,0 +1,6 @@
|
||||
matchBlocks=glass_pane
|
||||
metadata=0
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=sides
|
||||
|
After Width: | Height: | Size: 203 B |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 255 B |
|
After Width: | Height: | Size: 252 B |
|
After Width: | Height: | Size: 254 B |
@@ -0,0 +1,6 @@
|
||||
matchBlocks=stained_glass
|
||||
metadata=15
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=block
|
||||
@@ -0,0 +1,6 @@
|
||||
matchBlocks=stained_glass_pane
|
||||
metadata=15
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=sides
|
||||
|
After Width: | Height: | Size: 206 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 249 B |
@@ -0,0 +1,6 @@
|
||||
matchBlocks=stained_glass
|
||||
metadata=11
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=block
|
||||
@@ -0,0 +1,6 @@
|
||||
matchBlocks=stained_glass_pane
|
||||
metadata=11
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=sides
|
||||
|
After Width: | Height: | Size: 205 B |
|
After Width: | Height: | Size: 234 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 260 B |
|
After Width: | Height: | Size: 258 B |
@@ -0,0 +1,6 @@
|
||||
matchBlocks=stained_glass
|
||||
metadata=12
|
||||
method=compact
|
||||
faces=all
|
||||
tiles=0-4
|
||||
connect=block
|
||||