-
Notifications
You must be signed in to change notification settings - Fork 1
Texture Stretch
New file: src/main/java/decok/dfcdvadstf/catframe/ui/util/TextureStretching.java
Design: Strategy interface + built-in implementations + static convenience methods + external data-driven configuration.
public final class TextureStretching {
// Strategy interface (extensible)
public interface StretchStrategy {
void draw(ResourceLocation tex, int x, int y, int w, int h);
}
// ── Built-in implementation 1: Nine-patch ──
// 4 corners fixed, 4 edges tiled, center tiled
public static void drawNinePatch(ResourceLocation tex, int x, int y, int w, int h,
int edgeL, int edgeT, int edgeR, int edgeB,
int texW, int texH);
// ── Built-in implementation 2: fixed ends, repeated middle ──
// left edgeL pixels fixed, right edgeR pixels fixed, middle repeats with tileW pixels
public static void drawFixedEndRepeat(ResourceLocation tex, int x, int y, int w, int h,
int edgeL, int edgeR, int tileW,
int texW, int texH);
// ── Generic tiling (extracted from ContentPanelRenderer/TabBar) ──
public static void drawTiled(ResourceLocation tex, int x, int y, int w, int h,
int tileW, int tileH);
}Refactor existing code (reduce duplication):
-
ContentPanelRenderer.drawTiledTexture()→ delegate toTextureStretching.drawTiled() -
TabBar.drawTiledBackground()→ delegate toTextureStretching.drawTiled() - The left-middle-right logic of
TabBar.drawSingleTabButton()→ delegate toTextureStretching.drawFixedEndRepeat()
//Below are the user's ideas
This data-driven approach was derived from vanilla's design. The default is envisioned similar to the *.png.mcmeta files introduced by dynamic textures, defining the following types:
Example:
{
"stretching":{
"type": "three_patch",
"default":{
"width": 16,
"hight": 16
},
"edge":{
"up": 2,
"down": 3,
"left": 2,
"right": 2
},
"limit":{
"width": 20,
"hight": 6
},
"inner":{
"will_stretch": false,
"height": 11,
"width": 12
}
}
}Definition:
It must be defined inside the streching key. It also requires a corresponding *.png.mcmeta file. It is not combined with dynamic textures. (Basically, when writing GUIs you don't need that combination either.)
The contents are as follows:
| Key | Possible values | Required? (if not, write the size in parentheses) | Description |
|---|---|---|---|
| type |
nine_patch/three_patch/tile/static
|
No (static) | Defines which transformation is applied: nine_patch -> nine-patch stretching, three_patch -> fixed ends with repeated middle, tile -> tiling/generic, static -> static, no processing (this corresponds to the StretchType part of the interface I wrote) |
| default | {"width": 16,"hight":16} | Yes | Defines the default size of this texture; integers suffice. If either width or height written here doesn't match the actual texture size, the texture is stretched to fit the tiling unit's height, and then tiled. |
| edge | Can be an object or an integer | Yes; when an integer, >=0 | Defines the edge width of this texture; integers suffice. If the integer form is used, it is equivalent to setting all inner values to this value. If it's an object, all four side widths (up/down/left/right) must be written. For three_patch, only the left and right edges need to be defined. |
| limit | Object | No; all inner values default to 0 | Defines the minimum texture size. If the data is invalid (i.e. the width/height passed into the method < limit), throw TextureStretchLimitException directly |
| inner | See below | See below | Handling for the interior |
| will_strech | Boolean | No (default false) | false means the default: no stretching, treated as tiling; true means stretching is applied. |
| inner.width, inner.height | Integer | No; default 0 | The width/height of one tiling unit. The texture is stretched to fit the tiling unit's width/height, and then tiled. If the width/hight values here, with will_stretch set to false, plus the corresponding direction's width/height exceed the width/hight in default, also throw a TextureStretchLimitException
|
//User's remark: it's not something where you just know what it does from the input data; it's more like a data marker, marking its properties: what you can do, what you can't do. //User's review: by the way, the method you wrote doesn't seem to define width/height yet, so I wrote it this way. //And you could also implement the content through the built-in interface implementations, but that's a later concern. Not implementing it for now.