added support for tinted textures

This commit is contained in:
Lukas 2020-08-12 18:17:43 +02:00
parent c4f3c25d2a
commit 95ad0f0535
11 changed files with 298 additions and 194 deletions

View File

@ -48,6 +48,7 @@ public class MainWindow {
renderMode = MAIN_MENU; renderMode = MAIN_MENU;
mainMenu = new MainMenu(openGLWindow.getWidth(), openGLWindow.getHeight()); mainMenu = new MainMenu(openGLWindow.getWidth(), openGLWindow.getHeight());
mainLoop(); mainLoop();
System.exit(0);
}); });
guiThread.start(); guiThread.start();
} }

View File

@ -20,7 +20,6 @@ import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.render.blockModels.BlockModelLoader; import de.bixilon.minosoft.render.blockModels.BlockModelLoader;
import de.bixilon.minosoft.render.blockModels.Face; import de.bixilon.minosoft.render.blockModels.Face;
import de.bixilon.minosoft.render.fullFace.FaceOrientation; import de.bixilon.minosoft.render.fullFace.FaceOrientation;
import de.bixilon.minosoft.render.texture.TextureLoader;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -30,13 +29,10 @@ import static de.bixilon.minosoft.render.fullFace.RenderConstants.faceDir;
import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.*;
public class WorldRenderer { public class WorldRenderer {
private final TextureLoader textureLoader;
private final HashMap<BlockPosition, HashSet<Face>> faces; private final HashMap<BlockPosition, HashSet<Face>> faces;
private final int faceCount = 0;
private BlockModelLoader modelLoader; private BlockModelLoader modelLoader;
public WorldRenderer() { public WorldRenderer() {
textureLoader = new TextureLoader(MainWindow.getOpenGLWindow().getWindow());
faces = new HashMap<>(); faces = new HashMap<>();
} }
@ -87,7 +83,7 @@ public class WorldRenderer {
public void draw() { public void draw() {
glPushMatrix(); glPushMatrix();
glBindTexture(GL_TEXTURE_2D, textureLoader.getTextureID()); glBindTexture(GL_TEXTURE_2D, modelLoader.getTextureLoader().getTextureID());
glBegin(GL_QUADS); glBegin(GL_QUADS);
synchronized (faces) { synchronized (faces) {
for (Map.Entry<BlockPosition, HashSet<Face>> entry : faces.entrySet()) { for (Map.Entry<BlockPosition, HashSet<Face>> entry : faces.entrySet()) {
@ -100,10 +96,6 @@ public class WorldRenderer {
glPopMatrix(); glPopMatrix();
} }
public TextureLoader getTextureLoader() {
return textureLoader;
}
public BlockModelLoader getModelLoader() { public BlockModelLoader getModelLoader() {
return modelLoader; return modelLoader;
} }

View File

@ -18,6 +18,7 @@ import com.google.gson.JsonObject;
import de.bixilon.minosoft.Config; import de.bixilon.minosoft.Config;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.render.fullFace.FaceOrientation; import de.bixilon.minosoft.render.fullFace.FaceOrientation;
import de.bixilon.minosoft.render.texture.TextureLoader;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -31,23 +32,29 @@ public class BlockDescription {
boolean isFull; boolean isFull;
public BlockDescription(JsonElement child, String identifier, String mod) { public BlockDescription(JsonElement child, String identifier, String mod) {
if (child.getAsString().equals("invisible")) { blockConfigurationStates = new HashMap<>();
if (child.isJsonPrimitive() && child.getAsString().equals("invisible")) {
defaultState = new HashSet<>();
return; return;
} else if (child.getAsString().equals("regular")) { } else if (child.isJsonPrimitive() && child.getAsString().equals("regular")) {
defaultState = load(mod, identifier, new HashMap<>()); defaultState = load(mod, identifier);
} else { } else if (child.isJsonPrimitive()) {
defaultState = load(mod, child.getAsString());
} else if (child.isJsonObject()) {
JsonObject childJson = child.getAsJsonObject(); JsonObject childJson = child.getAsJsonObject();
for (String state : childJson.keySet()) { for (String state : childJson.keySet()) {
if (state.equals("else")) { if (state.equals("else")) {
defaultState = load(mod, childJson.get("else").getAsString(), new HashMap<>()); defaultState = load(mod, childJson.get("else").getAsString(), new HashMap<>());
} }
blockConfigurationStates.put(new BlockConfiguration(state), BlockConfiguration configuration = new BlockConfiguration(state);
blockConfigurationStates.put(configuration,
load(mod, childJson.get(state).getAsString())); load(mod, childJson.get(state).getAsString()));
} }
} }
for (SubBlock subBlock : defaultState) { for (SubBlock subBlock : defaultState) {
if (subBlock.isFull()) { if (subBlock.isFull()) {
isFull = true; isFull = true;
break;
} }
} }
} }
@ -102,4 +109,18 @@ public class BlockDescription {
} }
return result; return result;
} }
public HashSet<String> getAllTextures() {
HashSet<String> result = new HashSet<>();
for (SubBlock subBlock : defaultState) {
result.addAll(subBlock.getTextures());
}
return result;
}
public void applyTextures(String mod, TextureLoader loader) {
for (SubBlock subBlock : defaultState) {
subBlock.applyTextures(mod, loader);
}
}
} }

View File

@ -20,51 +20,88 @@ import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks; import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks;
import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.Log;
import de.bixilon.minosoft.render.fullFace.FaceOrientation; import de.bixilon.minosoft.render.fullFace.FaceOrientation;
import de.bixilon.minosoft.render.texture.TextureLoader;
import org.apache.commons.collections.primitives.ArrayFloatList;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import static de.bixilon.minosoft.util.Util.readJsonFromFile; import static de.bixilon.minosoft.util.Util.readJsonFromFile;
public class BlockModelLoader { public class BlockModelLoader {
private final HashMap<String, HashMap<String, BlockDescription>> blockDescriptionMap;
TextureLoader textureLoader;
public BlockModelLoader() { public BlockModelLoader() {
blockDescriptionMap = new HashMap<>(); blockDescriptionMap = new HashMap<>();
HashMap<String, HashMap<String, float[]>> tints = new HashMap<>();
HashMap<String, HashSet<String>> textures = new HashMap<>();
try { try {
String folderPath = Config.homeDir + "assets/mapping/blockModels/"; String folderPath = Config.homeDir + "assets/mapping/blockModels/";
for (File file : new File(folderPath).listFiles()) { for (File file : new File(folderPath).listFiles()) {
JsonObject blockList = readJsonFromFile(file.getAbsolutePath()); JsonObject json = readJsonFromFile(file.getAbsolutePath());
String mod = file.getName().substring(0, file.getName().lastIndexOf('.')); String mod = file.getName().substring(0, file.getName().lastIndexOf('.'));
loadModels(blockList, mod); tints.put(mod, readTints(json));
textures.put(mod, loadModels(json.get("blocks").getAsJsonObject(), mod));
} }
} catch (IOException | NullPointerException e) { textureLoader = new TextureLoader(textures, tints);
applyTextures();
} catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
Log.info("finished loading all block descriptions"); Log.info("finished loading all blocks");
} }
final HashMap<String, HashMap<String, BlockDescription>> blockDescriptionMap; private void applyTextures() {
for (Map.Entry<String, HashMap<String, BlockDescription>> mod : blockDescriptionMap.entrySet()) {
for (Map.Entry<String, BlockDescription> block : mod.getValue().entrySet()) {
block.getValue().applyTextures(mod.getKey(), textureLoader);
}
}
}
private void loadModels(JsonObject blockList, String mod) { private HashMap<String, float[]> readTints(JsonObject json) {
HashMap<String, float[]> result = new HashMap<>();
if (json.has("tinted_textures")) {
JsonObject textures = json.get("tinted_textures").getAsJsonObject();
for (String textureName : textures.keySet()) {
ArrayFloatList colorValues = new ArrayFloatList();
for (JsonElement colorValue : textures.get(textureName).getAsJsonArray()) {
colorValues.add(colorValue.getAsFloat());
}
float[] color = colorValues.toArray();
result.put(textureName, color);
}
}
return result;
}
private HashSet<String> loadModels(JsonObject blockList, String mod) {
HashSet<String> result = new HashSet<>();
blockDescriptionMap.put(mod, new HashMap<>()); blockDescriptionMap.put(mod, new HashMap<>());
for (String identifier : blockList.keySet()) { for (String identifier : blockList.keySet()) {
JsonElement child = blockList.get(identifier); JsonElement child = blockList.get(identifier);
loadModel(mod, identifier, child); result.addAll(loadModel(mod, identifier, child));
} }
return result;
} }
private void loadModel(String mod, String identifier, JsonElement child) { private HashSet<String> loadModel(String mod, String identifier, JsonElement child) {
HashSet<String> result = new HashSet<>();
try { try {
HashMap<String, BlockDescription> modList = blockDescriptionMap.get(mod); HashMap<String, BlockDescription> modList = blockDescriptionMap.get(mod);
BlockDescription description = new BlockDescription(child, identifier, mod); BlockDescription description = new BlockDescription(child, identifier, mod);
result.addAll(description.getAllTextures());
modList.put(identifier, description); modList.put(identifier, description);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
System.out.println(mod + ":" + identifier); System.out.println(mod + ":" + identifier);
System.exit(-1); System.exit(-1);
} }
return result;
} }
public BlockDescription getBlockDescription(Block block) { public BlockDescription getBlockDescription(Block block) {
@ -98,4 +135,8 @@ public class BlockModelLoader {
} }
return description.prepare(block, adjacentBlocks); return description.prepare(block, adjacentBlocks);
} }
public TextureLoader getTextureLoader() {
return textureLoader;
}
} }

View File

@ -1,18 +0,0 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Lukas Eisenhauer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.render.blockModels;
public interface BlockRenderInterface {
void draw();
}

View File

@ -36,7 +36,7 @@ public class DrawDescription {
Map<FaceOrientation, Pair<Float, Float>> faces; Map<FaceOrientation, Pair<Float, Float>> faces;
boolean full = false; // is the block a completely filled block? boolean full = false; // is the block a completely filled block?
public DrawDescription(JsonObject json) { public DrawDescription(JsonObject json, String mod) {
if (!(json.has("parent") && json.has("textures"))) return; if (!(json.has("parent") && json.has("textures"))) return;
faces = new HashMap<>(); faces = new HashMap<>();
@ -49,7 +49,7 @@ public class DrawDescription {
Pair<Float, Float> texturePair; Pair<Float, Float> texturePair;
try { try {
texturePair = MainWindow.getRenderer().getTextureLoader().getTexture(texture); texturePair = MainWindow.getRenderer().getModelLoader().getTextureLoader().getTexture(mod, texture);
} catch (Exception e) { } catch (Exception e) {
continue; continue;
} }

View File

@ -32,7 +32,7 @@ public class Face {
public Face(FaceOrientation orientation, Pair<Float, Float> texture, InFaceUV uv, SubBlock subBlock) { public Face(FaceOrientation orientation, Pair<Float, Float> texture, InFaceUV uv, SubBlock subBlock) {
this.orientation = orientation; this.orientation = orientation;
float step = MainWindow.getRenderer().getTextureLoader().getStep(); float step = MainWindow.getRenderer().getModelLoader().getTextureLoader().getStep();
u1 = texture.getKey();// + (float) uv.u1 / (float) texturePackRes * step; u1 = texture.getKey();// + (float) uv.u1 / (float) texturePackRes * step;
u2 = texture.getValue();// - (float) (texturePackRes - uv.u2) / (float) texturePackRes * step; u2 = texture.getValue();// - (float) (texturePackRes - uv.u2) / (float) texturePackRes * step;
v1 = (float) uv.v1 / (float) texturePackRes; v1 = (float) uv.v1 / (float) texturePackRes;

View File

@ -1,29 +0,0 @@
/*
* Codename Minosoft
* Copyright (C) 2020 Lukas Eisenhauer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.render.blockModels;
import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Block;
import de.bixilon.minosoft.game.datatypes.world.BlockPosition;
import de.bixilon.minosoft.game.datatypes.world.World;
public class FullBlock implements BlockRenderInterface {
public FullBlock(BlockPosition position, Block block, World world) {
}
@Override
public void draw() {
}
}

View File

@ -14,19 +14,21 @@
package de.bixilon.minosoft.render.blockModels; package de.bixilon.minosoft.render.blockModels;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import de.bixilon.minosoft.render.MainWindow;
import de.bixilon.minosoft.render.fullFace.FaceOrientation; import de.bixilon.minosoft.render.fullFace.FaceOrientation;
import de.bixilon.minosoft.render.fullFace.InFaceUV; import de.bixilon.minosoft.render.fullFace.InFaceUV;
import de.bixilon.minosoft.render.texture.TextureLoader;
import javafx.util.Pair; import javafx.util.Pair;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
public class SubBlock { public class SubBlock {
SubBlockPosition pos1; // the most negative Point of the SubBlock SubBlockPosition pos1; // the most negative Point of the SubBlock
SubBlockPosition pos2; // the most positive Point of the SubBlock SubBlockPosition pos2; // the most positive Point of the SubBlock
HashMap<FaceOrientation, Pair<Float, Float>> textures; HashMap<FaceOrientation, Pair<Float, Float>> textureCoordinates;
HashMap<FaceOrientation, String> textures;
HashMap<FaceOrientation, Boolean> cullFaceTextures; HashMap<FaceOrientation, Boolean> cullFaceTextures;
HashMap<FaceOrientation, InFaceUV> uv; HashMap<FaceOrientation, InFaceUV> uv;
@ -35,6 +37,7 @@ public class SubBlock {
public SubBlock(JsonObject json, HashMap<String, String> variables) { public SubBlock(JsonObject json, HashMap<String, String> variables) {
uv = new HashMap<>(); uv = new HashMap<>();
textures = new HashMap<>(); textures = new HashMap<>();
textureCoordinates = new HashMap<>();
cullFaceTextures = new HashMap<>(); cullFaceTextures = new HashMap<>();
pos1 = new SubBlockPosition(json.getAsJsonArray("from")); pos1 = new SubBlockPosition(json.getAsJsonArray("from"));
@ -50,6 +53,7 @@ public class SubBlock {
} }
private static String getRealTextureName(String textureName, HashMap<String, String> variables) { private static String getRealTextureName(String textureName, HashMap<String, String> variables) {
// read the variables and find the real texture name
if (textureName.contains("#")) { if (textureName.contains("#")) {
if (variables.containsKey(textureName)) { if (variables.containsKey(textureName)) {
String newName = variables.get(textureName); String newName = variables.get(textureName);
@ -68,6 +72,15 @@ public class SubBlock {
} }
} }
public void applyTextures(String mod, TextureLoader loader) {
for (Map.Entry<FaceOrientation, String> entry : textures.entrySet()) {
Pair<Float, Float> texture = loader.getTexture(mod, entry.getValue());
textureCoordinates.put(entry.getKey(), texture);
}
// clean up
textures.clear();
}
private void applyTexture(JsonObject faceJson, FaceOrientation orientation, HashMap<String, String> variables) { private void applyTexture(JsonObject faceJson, FaceOrientation orientation, HashMap<String, String> variables) {
try { try {
uv.put(orientation, new InFaceUV(faceJson.getAsJsonArray("uv"))); uv.put(orientation, new InFaceUV(faceJson.getAsJsonArray("uv")));
@ -76,21 +89,18 @@ public class SubBlock {
} }
String textureName = getRealTextureName(faceJson.get("texture").getAsString(), variables); String textureName = getRealTextureName(faceJson.get("texture").getAsString(), variables);
Pair<Float, Float> texture = MainWindow.getRenderer().getTextureLoader().getTexture(textureName); textures.put(orientation, textureName);
cullFaceTextures.put(orientation, faceJson.has("cullface")); cullFaceTextures.put(orientation, faceJson.has("cullface"));
textures.put(orientation, texture);
} }
public HashSet<Face> getFaces(HashMap<FaceOrientation, Boolean> adjacentBlocks) { public HashSet<Face> getFaces(HashMap<FaceOrientation, Boolean> adjacentBlocks) {
HashSet<Face> result = new HashSet<>(); HashSet<Face> result = new HashSet<>();
for (FaceOrientation orientation : FaceOrientation.values()) { for (FaceOrientation orientation : FaceOrientation.values()) {
if (!textures.containsKey(orientation)) { if (!textureCoordinates.containsKey(orientation)) {
continue; continue;
} }
if (!(adjacentBlocks.get(orientation) && cullFaceTextures.get(orientation))) { if (!(adjacentBlocks.get(orientation) && cullFaceTextures.get(orientation))) {
result.add(new Face(orientation, textures.get(orientation), result.add(new Face(orientation, textureCoordinates.get(orientation),
uv.get(orientation), this)); uv.get(orientation), this));
} }
} }
@ -100,4 +110,12 @@ public class SubBlock {
public boolean isFull() { public boolean isFull() {
return isFull; return isFull;
} }
public HashSet<String> getTextures() {
HashSet<String> result = new HashSet<>();
for (Map.Entry<FaceOrientation, String> texture : textures.entrySet()) {
result.add(texture.getValue());
}
return result;
}
} }

View File

@ -18,34 +18,34 @@ import de.matthiasmann.twl.utils.PNGDecoder;
import javafx.util.Pair; import javafx.util.Pair;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.HashSet;
import java.util.Map;
import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL30.glGenerateMipmap; import static org.lwjgl.opengl.GL30.glGenerateMipmap;
public class TextureLoader { public class TextureLoader {
int textureID;
int length; //describes the amount of loaded textures
private final int TEXTURE_PACK_RES = 16; private final int TEXTURE_PACK_RES = 16;
private HashMap<String, Integer> textureCoordinates; private final HashMap<String, HashMap<String, Integer>> textureCoordinates;
int imageLength = 1; int textureID;
float step; float step;
int totalTextures = 0;
HashMap<String, HashMap<String, BufferedImage>> images;
public TextureLoader(long window) { public TextureLoader(HashMap<String, HashSet<String>> textures, HashMap<String, HashMap<String, float[]>> tints) {
try { textureCoordinates = new HashMap<>();
textureCoordinates = new HashMap<>(); images = new HashMap<>();
loadTextures(Config.homeDir + "assets/minecraft/textures/block"); for (String mod : textures.keySet()) {
} catch (IOException ioException) { loadTextures(mod, textures.get(mod), tints.get(mod));
ioException.printStackTrace();
} }
combineTextures();
try { try {
PNGDecoder decoder = new PNGDecoder(new FileInputStream( PNGDecoder decoder = new PNGDecoder(new FileInputStream(
Config.homeDir + "assets/allTextures.png")); Config.homeDir + "assets/allTextures.png"));
@ -54,59 +54,77 @@ public class TextureLoader {
textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight()); textureID = bindTexture(buf, decoder.getWidth(), decoder.getHeight());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
System.exit(5);
} }
} }
private void loadTextures(String textureFolder) throws IOException { private static void tintImage(BufferedImage image, float[] tintColor) {
// Any animated block will be stationary for (int x = 0; x < image.getWidth(); x++) {
File[] textureFiles = new File(textureFolder).listFiles(); for (int y = 0; y < image.getHeight(); y++) {
Color color = new Color(image.getRGB(x, y));
if (textureFiles == null) { int r = (int) (color.getRed() * tintColor[0]);
throw new IOException("Failed to load textures: Texture folder empty"); int g = (int) (color.getGreen() * tintColor[1]);
} int b = (int) (color.getBlue() * tintColor[2]);
List<Pair<BufferedImage, String>> allTextures = new ArrayList<>(); int rgba = (color.getAlpha() << 24) | (r << 16) | (g << 8) | b;
for (int i = 0; i < textureFiles.length; i++) { image.setRGB(x, y, rgba);
String fileName = textureFiles[i].getName();
String textureName = fileName.substring(0, fileName.lastIndexOf('.'));
String fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1);
if (fileExtension.equals("png")) {
InputStream textureInputStream = new FileInputStream(textureFiles[i]);
BufferedImage img = ImageIO.read(textureInputStream);
allTextures.add(new Pair<>(img, textureName));
} }
//else we have a .mcmeta file describing animated blocks
} }
}
private void loadTextures(String mod, HashSet<String> textureNames, HashMap<String, float[]> tint) {
HashMap<String, BufferedImage> modTextureMap = new HashMap<>();
for (String textureName : textureNames) {
String path = Config.homeDir + "assets/" + mod + "/textures/" + textureName + ".png";
try {
BufferedImage image = ImageIO.read(new File(path));
if (tint.containsKey(textureName)) {
tintImage(image, tint.get(textureName));
}
modTextureMap.put(textureName, image);
} catch (IOException e) {
System.out.println(textureName);
System.out.println(path);
e.printStackTrace();
System.exit(6);
}
totalTextures++;
}
images.put(mod, modTextureMap);
}
private void combineTextures() {
// CONVERT ALL THE IMAGES INTO A SINGLE, VERY LONG IMAGE // CONVERT ALL THE IMAGES INTO A SINGLE, VERY LONG IMAGE
// greatly improves performance in opengl // greatly improves performance in opengl
// TEXTURE_PACK_RESxTEXTURE_PACK_RES textures only // TEXTURE_PACK_RESxTEXTURE_PACK_RES textures only
length = allTextures.size(); int imageLength = 1;
while (totalTextures * TEXTURE_PACK_RES > imageLength) {
imageLength *= 2; //figure out the right length for the image
}
BufferedImage totalImage = new BufferedImage(imageLength, TEXTURE_PACK_RES,
BufferedImage.TYPE_4BYTE_ABGR);
while (length * TEXTURE_PACK_RES > imageLength) imageLength *= 2; //figure out the right length for the image int currentPos = 0;
for (Map.Entry<String, HashMap<String, BufferedImage>> mod : images.entrySet()) {
BufferedImage totalImage = new BufferedImage(imageLength, TEXTURE_PACK_RES, BufferedImage.TYPE_4BYTE_ABGR); HashMap<String, Integer> modMap = new HashMap<>();
for (int xPos = 0; xPos < length; xPos++) { for (Map.Entry<String, BufferedImage> texture : mod.getValue().entrySet()) {
//copy the image into a part of the long image for (int y = 0; y < TEXTURE_PACK_RES; y++) {
BufferedImage img = allTextures.get(xPos).getKey(); for (int xPixel = 0; xPixel < TEXTURE_PACK_RES; xPixel++) {
for (int y = 0; y < TEXTURE_PACK_RES; y++) { int rgb = texture.getValue().getRGB(xPixel, y);
for (int xPixel = 0; xPixel < TEXTURE_PACK_RES; xPixel++) { totalImage.setRGB(currentPos * TEXTURE_PACK_RES + xPixel, y, rgb);
int rgb = img.getRGB(xPixel, y); }
totalImage.setRGB(xPos * TEXTURE_PACK_RES + xPixel, y, rgb);
} }
modMap.put(texture.getKey(), currentPos++);
} }
String textureName = allTextures.get(xPos).getValue(); textureCoordinates.put(mod.getKey(), modMap);
textureCoordinates.put(textureName, xPos);
} }
try { try {
// save our long image to reload it later
File outputFile = new File(Config.homeDir + "assets/allTextures.png"); File outputFile = new File(Config.homeDir + "assets/allTextures.png");
ImageIO.write(totalImage, "png", outputFile); ImageIO.write(totalImage, "png", outputFile);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
step = (float) 1 / (float) imageLength; step = (float) 1 / (float) imageLength * TEXTURE_PACK_RES;
} }
private int bindTexture(ByteBuffer buf, int width, int height) { private int bindTexture(ByteBuffer buf, int width, int height) {
@ -123,24 +141,23 @@ public class TextureLoader {
return textureID; return textureID;
} }
public Pair<Float, Float> getTexture(String name) { public Pair<Float, Float> getTexture(String mod, String textureName) {
// returns the start and end u-coordinate of a specific texture to access it // returns the start and end u-coordinate of a specific texture to access it
if (name == null) { HashMap<String, Integer> modMap = textureCoordinates.get(mod);
throw new NullPointerException("received null string as texture name"); if (modMap == null) {
} System.out.println("no mod " + mod + " loaded");
if (name.contains("block/")) { System.exit(9);
name = name.substring(name.lastIndexOf('/') + 1);
} }
Integer pos = modMap.get(textureName);
Integer pos = textureCoordinates.get(name);
if (pos == null) { if (pos == null) {
// the texture does not exist System.out.println("failed to find texture " + textureName);
throw new IllegalArgumentException(String.format("could not find texture %s", name)); System.exit(10);
} }
return new Pair<Float, Float>( return new Pair<>(
(float) pos / ((float) imageLength / (float) TEXTURE_PACK_RES), pos * step,
(float) (pos + 1) / ((float) imageLength / (float) TEXTURE_PACK_RES) (pos + 1) * step
); );
} }

View File

@ -1,59 +1,120 @@
{ {
"stone": "regular", "blocks": {
"granite": "regular", "stone": "regular",
"polished_granite": "regular", "granite": "regular",
"diorite": "regular", "polished_granite": "regular",
"polished_diorite": "regular", "diorite": "regular",
"andesite": "regular", "polished_diorite": "regular",
"polished_andesite": "regular", "andesite": "regular",
"grass_block": "regular", "polished_andesite": "regular",
"dirt": "regular", "grass_block": "regular",
"coarse_dirt": "regular", "dirt": "regular",
"podzol": "regular", "coarse_dirt": "regular",
"cobblestone": "regular", "podzol": "regular",
"oak_planks": "regular", "cobblestone": "regular",
"spruce_planks": "regular", "oak_planks": "regular",
"birch_planks": "regular", "spruce_planks": "regular",
"jungle_planks": "regular", "birch_planks": "regular",
"acacia_planks": "regular", "jungle_planks": "regular",
"dark_oak_planks": "regular", "acacia_planks": "regular",
"oak_sapling": "regular", "dark_oak_planks": "regular",
"spruce_sapling": "regular", "oak_sapling": "regular",
"birch_sapling": "regular", "spruce_sapling": "regular",
"jungle_sapling": "regular", "birch_sapling": "regular",
"acacia_sapling": "regular", "jungle_sapling": "regular",
"dark_oak_sapling": "regular", "acacia_sapling": "regular",
"bedrock": "regular", "dark_oak_sapling": "regular",
"sand": "regular", "bedrock": "regular",
"red_sand": "regular", "sand": "regular",
"gravel": "regular", "red_sand": "regular",
"gold_ore": "regular", "gravel": "regular",
"iron_ore": "regular", "gold_ore": "regular",
"coal_ore": "regular", "iron_ore": "regular",
"spruce_log": "regular", "coal_ore": "regular",
"birch_log": "regular", "spruce_log": "regular",
"jungle_log": "regular", "birch_log": "regular",
"dark_oak_log": "regular", "jungle_log": "regular",
"oak_leaves": "regular", "dark_oak_log": "regular",
"spruce_leaves": "regular", "oak_leaves": "regular",
"jungle_leaves": "regular", "spruce_leaves": "regular",
"birch_leaves": "regular", "jungle_leaves": "regular",
"dark_oak_leaves": "regular", "birch_leaves": "regular",
"sponge": "regular", "dark_oak_leaves": "regular",
"wet_sponge": "regular", "sponge": "regular",
"glass": "regular", "wet_sponge": "regular",
"lapis_ore": "regular", "glass": "regular",
"lapis_block": "regular", "lapis_ore": "regular",
"dispenser": { "lapis_block": "regular",
"orientation:vertical": "dispenser_vertical", "dispenser": {
"else": "dispenser" "orientation:vertical": "dispenser_vertical",
"else": "dispenser"
},
"sandstone": "regular",
"chiseled_sandstone": "regular",
"smooth_sandstone": "regular",
"note_block": "regular",
"bed": "invisible",
"powered_rail": {
"else": "powered_rail",
"not_powered": "powered_rail",
"powered": "powered_rail_on",
"powered,ascending_south": "powered_rail_on_raised_ne",
"powered,ascending_north": "powered_rail_on_raised_ne",
"powered,ascending_east": "powered_rail_on_raised_sw",
"powered,ascending_west": "powered_rail_on_raised_sw",
"not_powered,ascending_south": "powered_rail_raised_ne",
"not_powered,ascending_north": "powered_rail_raised_ne",
"not_powered,ascending_east": "powered_rail_raised_sw",
"not_powered,ascending_west": "powered_rail_raised_sw"
},
"detector_rail": {
"else": "detector_rail",
"not_powered": "detector_rail",
"powered": "detector_rail_on",
"powered,ascending_south": "detector_rail_on_raised_ne",
"powered,ascending_north": "detector_rail_on_raised_ne",
"powered,ascending_east": "detector_rail_on_raised_sw",
"powered,ascending_west": "detector_rail_on_raised_sw",
"not_powered,ascending_south": "detector_rail_raised_ne",
"not_powered,ascending_north": "detector_rail_raised_ne",
"not_powered,ascending_east": "detector_rail_raised_sw",
"not_powered,ascending_west": "detector_rail_raised_sw"
},
"sticky_piston": "regular",
"cobweb": "regular",
"shrub": "dead_bush",
"grass": "regular",
"fern": "regular",
"dead_bush": "regular",
"piston": "regular",
"piston_head": "regular",
"white_wool": "regular",
"orange_wool": "regular",
"magenta_wool": "regular",
"light_blue_wool": "regular",
"yellow_wool": "regular",
"lime_wool": "regular",
"pink_wool": "regular",
"gray_wool": "regular",
"light_gray_wool": "regular",
"cyan_wool": "regular",
"purple_wool": "regular",
"blue_wool": "regular",
"brown_wool": "regular",
"green_wool": "regular",
"red_wool": "regular",
"black_wool": "regular",
"dandelion": "regular",
"poppy": "regular",
"blue_orchid": "regular",
"allium": "regular",
"azure_bluet": "regular"
}, },
"sandstone": "regular", "tinted_textures": {
"chiseled_sandstone": "regular", "block/grass_block_top": [
"smooth_sandstone": "regular", 0,
"note_block": "regular", 1,
"bed": "regular", 0
"powered_rail": { ]
""
} }
} }