mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-14 09:56:37 -04:00
Render: support for BlockRotations
This commit is contained in:
parent
364f2736cb
commit
4c52ebab97
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="Python" name="Python">
|
|
||||||
<configuration sdkName="" />
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
12
pom.xml
12
pom.xml
@ -25,9 +25,15 @@
|
|||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.8.1</version>
|
<version>3.8.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>15</source>
|
<source>
|
||||||
<target>15</target>
|
14
|
||||||
<compilerArgs>--enable-preview</compilerArgs>
|
</source>
|
||||||
|
<target>
|
||||||
|
14
|
||||||
|
</target>
|
||||||
|
<compilerArgs>
|
||||||
|
--enable-preview
|
||||||
|
</compilerArgs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* 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 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.
|
||||||
*
|
*
|
||||||
@ -13,88 +13,55 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.render.blockModels;
|
package de.bixilon.minosoft.render.blockModels;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.BlockProperties;
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.BlockRotations;
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.Blocks;
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||||
|
import de.bixilon.minosoft.logging.Log;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
||||||
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
|
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
|
||||||
import de.bixilon.minosoft.render.texture.TextureLoader;
|
|
||||||
import org.apache.commons.collections.primitives.ArrayFloatList;
|
import org.apache.commons.collections.primitives.ArrayFloatList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BlockModel {
|
public class BlockModel implements BlockModelInterface {
|
||||||
private ArrayList<SubBlock> subBlocks;
|
private final HashMap<HashSet<String>, HashSet<SubBlock>> stateMap;
|
||||||
private boolean[] full; // minor memory improvement over a Map
|
private final HashMap<HashSet<String>, boolean[]> full; // minor memory improvement over a Map FaceOrientation -> boolean and also performance should be boosted
|
||||||
|
|
||||||
public BlockModel(JsonObject block, JsonObject allModels) {
|
public BlockModel(HashMap<String, HashSet<SubBlock>> blockModels, JsonArray states) {
|
||||||
subBlocks = load(block, allModels);
|
stateMap = new HashMap<>();
|
||||||
}
|
full = new HashMap<>();
|
||||||
|
for (JsonElement element : states) {
|
||||||
public BlockModel(BlockModel blockModel, JsonObject json) {
|
JsonObject state = element.getAsJsonObject();
|
||||||
if (blockModel != null) {
|
HashSet<SubBlock> model = blockModels.get(state.get("model").getAsString()).stream().map(SubBlock::new).collect(Collectors.toCollection(HashSet::new));
|
||||||
subBlocks = blockModel.getSubBlocks();
|
HashSet<String> properties = new HashSet<>();
|
||||||
} else {
|
for (Map.Entry<String, JsonElement> property : state.getAsJsonObject("properties").entrySet()) {
|
||||||
subBlocks = new ArrayList<>();
|
if (Blocks.getPropertiesMapping().containsKey(property.getKey())) {
|
||||||
}
|
properties.add(Blocks.getPropertiesMapping().get(property.getKey()).get(property.getValue().getAsString()).name());
|
||||||
if (json.has("x")) {
|
} else if (Blocks.getRotationMapping().containsKey(property.getValue().getAsString())) {
|
||||||
rotate(Axis.X, json.get("x").getAsInt());
|
properties.add(Blocks.getRotationMapping().get(property.getValue().getAsString()).name());
|
||||||
}
|
|
||||||
if (json.has("y")) {
|
|
||||||
rotate(Axis.Y, json.get("y").getAsInt());
|
|
||||||
}
|
|
||||||
if (json.has("z")) {
|
|
||||||
rotate(Axis.Z, json.get("z").getAsInt());
|
|
||||||
}
|
|
||||||
full = createFullValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void rotate(Axis axis, int rotation) {
|
|
||||||
for (SubBlock subBlock : subBlocks) {
|
|
||||||
subBlock.rotate(axis, rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockModel() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static ArrayList<SubBlock> load(JsonObject json, JsonObject allModels, HashMap<String, String> variables) {
|
|
||||||
ArrayList<SubBlock> result = new ArrayList<>();
|
|
||||||
if (json.has("textures")) {
|
|
||||||
// read the textures into a variable hashmap
|
|
||||||
JsonObject textures = json.getAsJsonObject("textures");
|
|
||||||
for (String texture : textures.keySet()) {
|
|
||||||
if (texture.contains("#") && variables.containsKey(texture)) {
|
|
||||||
variables.put("#" + texture, variables.get(texture));
|
|
||||||
} else {
|
|
||||||
variables.put("#" + texture, textures.get(texture).getAsString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (Axis axis : Axis.values()) {
|
||||||
if (json.has("elements")) {
|
String lowercase = axis.name().toLowerCase();
|
||||||
for (JsonElement subBlockJson : json.get("elements").getAsJsonArray()) {
|
if (state.has(lowercase)) {
|
||||||
result.add(new SubBlock(subBlockJson.getAsJsonObject(), variables));
|
BlockModelInterface.rotateModel(model, axis, state.get(lowercase).getAsInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (json.has("parent") && !json.get("parent").getAsString().equals("block/block")) {
|
stateMap.put(properties, model);
|
||||||
String parent = json.get("parent").getAsString();
|
full.put(properties, createFullValues(model));
|
||||||
if (parent.equals("block/block")) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
String parentIdentifier = parent.substring(parent.lastIndexOf("/") + 1);
|
|
||||||
result.addAll(load(allModels.get(parentIdentifier).getAsJsonObject(), allModels, variables));
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ArrayList<SubBlock> load(JsonObject json, JsonObject allModels) {
|
private static boolean[] createFullValues(HashSet<SubBlock> subBlocks) {
|
||||||
return load(json, allModels, new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean[] createFullValues() {
|
|
||||||
boolean[] result = new boolean[6];
|
boolean[] result = new boolean[6];
|
||||||
outer:
|
outer:
|
||||||
for (FaceOrientation orientation : FaceOrientation.values()) {
|
for (FaceOrientation orientation : FaceOrientation.values()) {
|
||||||
@ -108,41 +75,60 @@ public class BlockModel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFull(FaceOrientation orientation) {
|
private static HashSet<String> getProperties(Block block) {
|
||||||
return full[orientation.getId()];
|
HashSet<String> result = new HashSet<>();
|
||||||
|
if (block.getRotation() != BlockRotations.NONE) {
|
||||||
|
result.add(block.getRotation().name());
|
||||||
|
}
|
||||||
|
for (BlockProperties property : block.getProperties()) {
|
||||||
|
result.add(property.name());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean full(Block block, FaceOrientation orientation) {
|
||||||
|
HashSet<String> properties = getProperties(block);
|
||||||
|
for (Map.Entry<HashSet<String>, boolean[]> entry : full.entrySet()) {
|
||||||
|
if (properties.containsAll(entry.getKey())) {
|
||||||
|
return entry.getValue()[orientation.getId()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties.add(BlockRotations.NONE.name());
|
||||||
|
for (Map.Entry<HashSet<String>, boolean[]> entry : full.entrySet()) {
|
||||||
|
if (properties.containsAll(entry.getKey())) {
|
||||||
|
return entry.getValue()[orientation.getId()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.warn(String.format("could not find a corresponding block model for block %s", block.toString()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block) {
|
public ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block) {
|
||||||
ArrayFloatList result = new ArrayFloatList();
|
HashSet<String> properties = getProperties(block);
|
||||||
for (SubBlock subBlock : subBlocks) {
|
for (Map.Entry<HashSet<String>, HashSet<SubBlock>> entry : stateMap.entrySet()) {
|
||||||
result.addAll(subBlock.getFaces(facesToDraw, position));
|
if (properties.containsAll(entry.getKey())) {
|
||||||
|
ArrayFloatList result = new ArrayFloatList();
|
||||||
|
for (SubBlock subBlock : entry.getValue()) {
|
||||||
|
result.addAll(subBlock.getFaces(facesToDraw, position));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
properties.add(BlockRotations.NONE.name());
|
||||||
|
for (Map.Entry<HashSet<String>, HashSet<SubBlock>> entry : stateMap.entrySet()) {
|
||||||
|
if (properties.containsAll(entry.getKey())) {
|
||||||
|
ArrayFloatList result = new ArrayFloatList();
|
||||||
|
for (SubBlock subBlock : entry.getValue()) {
|
||||||
|
result.addAll(subBlock.getFaces(facesToDraw, position));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.warn(String.format("could not find a corresponding block model for block %s", block.toString()));
|
||||||
|
return new ArrayFloatList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFull() {
|
public boolean isFull() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<String> getAllTextures() {
|
|
||||||
HashSet<String> result = new HashSet<>();
|
|
||||||
for (SubBlock subBlock : subBlocks) {
|
|
||||||
result.addAll(subBlock.getTextures());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyTextures(String mod, TextureLoader loader) {
|
|
||||||
for (SubBlock subBlock : subBlocks) {
|
|
||||||
subBlock.applyTextures(mod, loader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<SubBlock> getSubBlocks() {
|
|
||||||
return subBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean[] getFull() {
|
|
||||||
return full;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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.data.mappings.blocks.Block;
|
|
||||||
import de.bixilon.minosoft.data.mappings.blocks.BlockRotations;
|
|
||||||
|
|
||||||
public class BlockModelBlockWrapper {
|
|
||||||
Block block;
|
|
||||||
|
|
||||||
public BlockModelBlockWrapper(Block block) {
|
|
||||||
this.block = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block getBlock() {
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return block.getMod().hashCode() * block.getIdentifier().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (super.equals(obj)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
BlockModelBlockWrapper their = (BlockModelBlockWrapper) obj;
|
|
||||||
if (block.equals(their.getBlock())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(block.getMod().equals(their.getBlock().getMod()) && block.getIdentifier().equals(their.getBlock().getIdentifier()))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (block.getRotation() == BlockRotations.NONE || their.getBlock().getRotation() == BlockRotations.NONE || block.getProperties().size() == 0 || their.getBlock().getProperties().size() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return block.getProperties().equals(their.getBlock().getProperties()) && block.getMod().equals(their.getBlock().getMod());
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* minosoft
|
||||||
|
* Copyright (C) 2020 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||||
|
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||||
|
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
||||||
|
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
||||||
|
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
|
||||||
|
import org.apache.commons.collections.primitives.ArrayFloatList;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public interface BlockModelInterface {
|
||||||
|
static HashSet<SubBlock> load(JsonObject block, JsonObject allModels, HashMap<String, String> variables) {
|
||||||
|
HashSet<SubBlock> result = new HashSet<>();
|
||||||
|
if (block.has("textures")) {
|
||||||
|
// read the textures into a variable hashmap
|
||||||
|
JsonObject textures = block.getAsJsonObject("textures");
|
||||||
|
for (String texture : textures.keySet()) {
|
||||||
|
if (texture.contains("#") && variables.containsKey(texture)) {
|
||||||
|
variables.put("#" + texture, variables.get(texture));
|
||||||
|
} else {
|
||||||
|
variables.put("#" + texture, textures.get(texture).getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (block.has("elements")) {
|
||||||
|
for (JsonElement subBlockJson : block.get("elements").getAsJsonArray()) {
|
||||||
|
result.add(new SubBlock(subBlockJson.getAsJsonObject(), variables));
|
||||||
|
}
|
||||||
|
} else if (block.has("parent") && !block.get("parent").getAsString().equals("block/block")) {
|
||||||
|
String parent = block.get("parent").getAsString();
|
||||||
|
if (parent.equals("block/block")) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
String parentIdentifier = parent.substring(parent.lastIndexOf("/") + 1);
|
||||||
|
result.addAll(load(allModels.get(parentIdentifier).getAsJsonObject(), allModels, variables));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HashSet<SubBlock> load(JsonObject json, JsonObject allModels) {
|
||||||
|
return load(json, allModels, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rotateModel(HashSet<SubBlock> subBlocks, Axis axis, int rotation) {
|
||||||
|
for (SubBlock subBlock : subBlocks) {
|
||||||
|
subBlock.rotate(axis, rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean full(Block block, FaceOrientation orientation);
|
||||||
|
|
||||||
|
boolean isFull();
|
||||||
|
|
||||||
|
ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block);
|
||||||
|
}
|
@ -20,6 +20,7 @@ import de.bixilon.minosoft.data.mappings.blocks.Block;
|
|||||||
import de.bixilon.minosoft.data.mappings.blocks.Blocks;
|
import de.bixilon.minosoft.data.mappings.blocks.Blocks;
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
||||||
|
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
|
||||||
import de.bixilon.minosoft.render.texture.TextureLoader;
|
import de.bixilon.minosoft.render.texture.TextureLoader;
|
||||||
import de.bixilon.minosoft.util.Util;
|
import de.bixilon.minosoft.util.Util;
|
||||||
import org.apache.commons.collections.primitives.ArrayFloatList;
|
import org.apache.commons.collections.primitives.ArrayFloatList;
|
||||||
@ -29,14 +30,13 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
public class BlockModelLoader {
|
public class BlockModelLoader {
|
||||||
HashMap<BlockModelBlockWrapper, BlockModel> blockMap;
|
|
||||||
TextureLoader textureLoader;
|
TextureLoader textureLoader;
|
||||||
public static BlockModelLoader blockModelLoader;
|
public static BlockModelLoader blockModelLoader;
|
||||||
|
HashMap<String, HashMap<String, BlockModelInterface>> modelMap;
|
||||||
|
|
||||||
public BlockModelLoader() {
|
public BlockModelLoader() {
|
||||||
blockMap = new HashMap<>();
|
modelMap = new HashMap<>();
|
||||||
HashSet<JsonObject> mods = new HashSet<>();
|
HashSet<JsonObject> mods = new HashSet<>();
|
||||||
HashMap<String, HashMap<String, float[]>> tints = new HashMap<>();
|
HashMap<String, HashMap<String, float[]>> tints = new HashMap<>();
|
||||||
try {
|
try {
|
||||||
@ -45,10 +45,14 @@ public class BlockModelLoader {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
HashMap<String, HashMap<String, BlockModel>> blockModels = new HashMap<>();
|
HashMap<String, HashMap<String, HashSet<SubBlock>>> blockModels = new HashMap<>();
|
||||||
for (JsonObject mod : mods) {
|
for (JsonObject mod : mods) {
|
||||||
blockModels.put(mod.get("mod").getAsString(), loadModels(mod));
|
String modName = mod.get("mod").getAsString();
|
||||||
tints.put(mod.get("mod").getAsString(), readTints(mod));
|
if (!modelMap.containsKey(mod.get("mod").getAsString())) {
|
||||||
|
modelMap.put(modName, new HashMap<>());
|
||||||
|
}
|
||||||
|
blockModels.put(modName, loadModels(mod));
|
||||||
|
tints.put(modName, readTints(mod));
|
||||||
}
|
}
|
||||||
textureLoader = new TextureLoader(getTextures(blockModels), tints);
|
textureLoader = new TextureLoader(getTextures(blockModels), tints);
|
||||||
applyTextures(blockModels);
|
applyTextures(blockModels);
|
||||||
@ -57,47 +61,46 @@ public class BlockModelLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadBlocks(JsonObject mod, HashMap<String, BlockModel> blockModels) {
|
private void loadBlocks(JsonObject mod, HashMap<String, HashSet<SubBlock>> blockModels) {
|
||||||
for (Map.Entry<String, JsonElement> blockEntry : mod.get("blockStates").getAsJsonObject().entrySet()) {
|
for (Map.Entry<String, JsonElement> blockEntry : mod.get("blockStates").getAsJsonObject().entrySet()) {
|
||||||
JsonObject block = blockEntry.getValue().getAsJsonObject();
|
JsonObject block = blockEntry.getValue().getAsJsonObject();
|
||||||
if (block.has("states")) {
|
if (block.has("states")) {
|
||||||
JsonArray states = block.get("states").getAsJsonArray();
|
JsonArray states = block.get("states").getAsJsonArray();
|
||||||
for (JsonElement state : states) {
|
modelMap.get(mod.get("mod").getAsString()).put(blockEntry.getKey(), new BlockModel(blockModels, states));
|
||||||
BlockModel model = blockModels.get(state.getAsJsonObject().get("model").getAsString());
|
|
||||||
Block wrapper = new Block(mod.get("mod").getAsString(), blockEntry.getKey(), state.getAsJsonObject().get("properties").getAsJsonObject());
|
|
||||||
blockMap.put(new BlockModelBlockWrapper(wrapper), new BlockModel(model, state.getAsJsonObject()));
|
|
||||||
}
|
|
||||||
} else if (block.has("conditional")) {
|
} else if (block.has("conditional")) {
|
||||||
Block wrapper = new Block(mod.get("mod").getAsString(), blockEntry.getKey());
|
modelMap.get(mod.get("mod").getAsString()).put(blockEntry.getKey(), new ConditionalModel(blockModels, block.get("conditional").getAsJsonArray()));
|
||||||
blockMap.put(new BlockModelBlockWrapper(wrapper), new ConditionalModel(blockModels, block.get("conditional").getAsJsonArray()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, BlockModel> loadModels(JsonObject mod) {
|
private HashMap<String, HashSet<SubBlock>> loadModels(JsonObject mod) {
|
||||||
HashMap<String, BlockModel> modMap = new HashMap<>();
|
HashMap<String, HashSet<SubBlock>> modMap = new HashMap<>();
|
||||||
for (Map.Entry<String, JsonElement> block : mod.get("blockModels").getAsJsonObject().entrySet()) {
|
for (Map.Entry<String, JsonElement> block : mod.getAsJsonObject("blockModels").entrySet()) {
|
||||||
modMap.put(block.getKey(), new BlockModel(block.getValue().getAsJsonObject(), mod.get("blockModels").getAsJsonObject()));
|
modMap.put(block.getKey(), BlockModelInterface.load(block.getValue().getAsJsonObject(), mod.getAsJsonObject("blockModels")));
|
||||||
}
|
}
|
||||||
return modMap;
|
return modMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<String, HashSet<String>> getTextures(HashMap<String, HashMap<String, BlockModel>> blockModels) {
|
public HashMap<String, HashSet<String>> getTextures(HashMap<String, HashMap<String, HashSet<SubBlock>>> blockModels) {
|
||||||
HashMap<String, HashSet<String>> textures = new HashMap<>();
|
HashMap<String, HashSet<String>> textures = new HashMap<>();
|
||||||
for (Map.Entry<String, HashMap<String, BlockModel>> mod : blockModels.entrySet()) {
|
for (Map.Entry<String, HashMap<String, HashSet<SubBlock>>> mod : blockModels.entrySet()) {
|
||||||
HashSet<String> modTextures = new HashSet<>();
|
HashSet<String> modTextures = new HashSet<>();
|
||||||
for (BlockModel blockModel : mod.getValue().values()) {
|
for (HashSet<SubBlock> subBlocks : mod.getValue().values()) {
|
||||||
modTextures.addAll(blockModel.getAllTextures());
|
for (SubBlock subBlock : subBlocks) {
|
||||||
|
modTextures.addAll(subBlock.getTextures());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
textures.put(mod.getKey(), modTextures);
|
textures.put(mod.getKey(), modTextures);
|
||||||
}
|
}
|
||||||
return textures;
|
return textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyTextures(HashMap<String, HashMap<String, BlockModel>> blockModels) {
|
public void applyTextures(HashMap<String, HashMap<String, HashSet<SubBlock>>> blockModels) {
|
||||||
for (Map.Entry<String, HashMap<String, BlockModel>> mod : blockModels.entrySet()) {
|
for (Map.Entry<String, HashMap<String, HashSet<SubBlock>>> mod : blockModels.entrySet()) {
|
||||||
for (Map.Entry<String, BlockModel> block : mod.getValue().entrySet()) {
|
for (Map.Entry<String, HashSet<SubBlock>> block : mod.getValue().entrySet()) {
|
||||||
block.getValue().applyTextures(mod.getKey(), textureLoader);
|
for (SubBlock subBlock : block.getValue()) {
|
||||||
|
subBlock.applyTextures(mod.getKey(), textureLoader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,19 +121,19 @@ public class BlockModelLoader {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModel getBlockModel(Block block) {
|
public BlockModelInterface getBlockModel(Block block) {
|
||||||
BlockModel model = blockMap.get(new BlockModelBlockWrapper(block));
|
BlockModelInterface model = modelMap.get(block.getMod()).get(block.getIdentifier());
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw new RuntimeException("block " + block + " could not be found");
|
throw new RuntimeException("block " + block + " could not be found");
|
||||||
}
|
}
|
||||||
return blockMap.get(new BlockModelBlockWrapper(block));
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFull(Block block, FaceOrientation orientation) {
|
public boolean isFull(Block block, FaceOrientation orientation) {
|
||||||
if (block == null || block.equals(Blocks.nullBlock)) {
|
if (block == null || block.equals(Blocks.nullBlock)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return getBlockModel(block).isFull(orientation);
|
return getBlockModel(block).full(block, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFull(Block block) {
|
public boolean isFull(Block block) {
|
||||||
|
@ -19,16 +19,17 @@ import com.google.gson.JsonObject;
|
|||||||
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
import de.bixilon.minosoft.data.mappings.blocks.Block;
|
||||||
import de.bixilon.minosoft.data.world.BlockPosition;
|
import de.bixilon.minosoft.data.world.BlockPosition;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
||||||
|
import de.bixilon.minosoft.render.blockModels.subBlocks.SubBlock;
|
||||||
import org.apache.commons.collections.primitives.ArrayFloatList;
|
import org.apache.commons.collections.primitives.ArrayFloatList;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ConditionalModel extends BlockModel {
|
public class ConditionalModel implements BlockModelInterface {
|
||||||
HashMap<BlockCondition, BlockModel> conditionMap;
|
HashMap<BlockCondition, HashSet<SubBlock>> conditionMap;
|
||||||
|
|
||||||
public ConditionalModel(HashMap<String, BlockModel> blockModels, JsonArray elements) {
|
public ConditionalModel(HashMap<String, HashSet<SubBlock>> blockModels, JsonArray elements) {
|
||||||
conditionMap = new HashMap<>();
|
conditionMap = new HashMap<>();
|
||||||
for (JsonElement element : elements) {
|
for (JsonElement element : elements) {
|
||||||
JsonObject block = element.getAsJsonObject();
|
JsonObject block = element.getAsJsonObject();
|
||||||
@ -38,29 +39,31 @@ public class ConditionalModel extends BlockModel {
|
|||||||
} else {
|
} else {
|
||||||
condition = BlockCondition.trueCondition;
|
condition = BlockCondition.trueCondition;
|
||||||
}
|
}
|
||||||
BlockModel model = blockModels.get(block.get("model").getAsString());
|
HashSet<SubBlock> model = blockModels.get(block.get("model").getAsString());
|
||||||
conditionMap.put(condition, new BlockModel(model, block));
|
conditionMap.put(condition, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block) {
|
public ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block) {
|
||||||
ArrayFloatList result = new ArrayFloatList();
|
ArrayFloatList result = new ArrayFloatList();
|
||||||
for (Map.Entry<BlockCondition, BlockModel> entry : conditionMap.entrySet()) {
|
for (Map.Entry<BlockCondition, HashSet<SubBlock>> entry : conditionMap.entrySet()) {
|
||||||
if (entry.getKey().contains(block)) {
|
if (entry.getKey().contains(block)) {
|
||||||
result.addAll(entry.getValue().prepare(facesToDraw, position, block));
|
for (SubBlock subBlock : entry.getValue()) {
|
||||||
|
result.addAll(subBlock.getFaces(facesToDraw, position));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFull() {
|
public boolean full(Block block, FaceOrientation orientation) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFull(FaceOrientation orientation) {
|
public boolean isFull() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.render.blockModels.subBlocks;
|
package de.bixilon.minosoft.render.blockModels.subBlocks;
|
||||||
|
|
||||||
// a 3d object with 8 corners, 6 faces and 12 edges (example: cube, but can be deformed)
|
// a 3d object with 8 corners, 6 faces and 12 edges (cube, but can be deformed)
|
||||||
|
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
import de.bixilon.minosoft.render.blockModels.Face.FaceOrientation;
|
||||||
@ -47,6 +47,13 @@ public class Cuboid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cuboid(Cuboid cuboid) {
|
||||||
|
positions = new SubBlockPosition[cuboid.positions.length];
|
||||||
|
for (int i = 0; i < positions.length; i++) {
|
||||||
|
positions[i] = new SubBlockPosition(cuboid.positions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SubBlockPosition[] getFacePositions(FaceOrientation orientation) {
|
public SubBlockPosition[] getFacePositions(FaceOrientation orientation) {
|
||||||
int[] positionIds = facePositionMapTemplate[orientation.getId()];
|
int[] positionIds = facePositionMapTemplate[orientation.getId()];
|
||||||
SubBlockPosition[] result = new SubBlockPosition[positionIds.length];
|
SubBlockPosition[] result = new SubBlockPosition[positionIds.length];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* 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 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.
|
||||||
*
|
*
|
||||||
@ -27,7 +27,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class SubBlock {
|
public class SubBlock {
|
||||||
private final HashMap<FaceOrientation, Float> textureCoordinates;
|
private final HashMap<FaceOrientation, Float> textureCoordinates;
|
||||||
private final HashMap<FaceOrientation, String> textures;
|
private HashMap<FaceOrientation, String> textures;
|
||||||
private final HashMap<FaceOrientation, Integer> textureRotations;
|
private final HashMap<FaceOrientation, Integer> textureRotations;
|
||||||
private final boolean[] full;
|
private final boolean[] full;
|
||||||
private final HashMap<FaceOrientation, InFaceUV> uv;
|
private final HashMap<FaceOrientation, InFaceUV> uv;
|
||||||
@ -56,6 +56,14 @@ public class SubBlock {
|
|||||||
full = createFull();
|
full = createFull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubBlock(SubBlock subBlock) {
|
||||||
|
textureCoordinates = subBlock.textureCoordinates;
|
||||||
|
textureRotations = subBlock.textureRotations;
|
||||||
|
uv = subBlock.uv;
|
||||||
|
cuboid = new Cuboid(subBlock.cuboid);
|
||||||
|
full = createFull();
|
||||||
|
}
|
||||||
|
|
||||||
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
|
// read the variables and find the real texture name
|
||||||
if (textureName.contains("#")) {
|
if (textureName.contains("#")) {
|
||||||
|
@ -41,6 +41,10 @@ public class SubBlockPosition {
|
|||||||
this.vector = vector;
|
this.vector = vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubBlockPosition(SubBlockPosition position) {
|
||||||
|
vector = new Vec3(position.vector);
|
||||||
|
}
|
||||||
|
|
||||||
public SubBlockPosition rotated(Axis axis, int rotation) {
|
public SubBlockPosition rotated(Axis axis, int rotation) {
|
||||||
return new SubBlockRotation(middlePos, axis, rotation).apply(this);
|
return new SubBlockRotation(middlePos, axis, rotation).apply(this);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* 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 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.
|
||||||
*
|
*
|
||||||
@ -16,73 +16,52 @@ package de.bixilon.minosoft.render.blockModels.subBlocks;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
import de.bixilon.minosoft.render.blockModels.Face.Axis;
|
||||||
import de.bixilon.minosoft.render.utility.Vec3;
|
import de.bixilon.minosoft.render.utility.Vec3;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
|
||||||
public class SubBlockRotation {
|
public class SubBlockRotation {
|
||||||
private final Vec3 origin;
|
private final Vec3 origin;
|
||||||
private final double angle;
|
private final Axis axis;
|
||||||
private final Vec3 direction;
|
private final double sin;
|
||||||
|
private final double cos;
|
||||||
|
|
||||||
public SubBlockRotation(SubBlockPosition origin, Axis direction, float angle) {
|
public SubBlockRotation(SubBlockPosition origin, Axis axis, float angle) {
|
||||||
this.origin = origin.getVector();
|
this.origin = origin.getVector();
|
||||||
this.direction = switch (direction) {
|
this.axis = axis;
|
||||||
case X -> new Vec3(1, 0, 0);
|
double angleRad = Math.toRadians(angle);
|
||||||
case Y -> new Vec3(0, 1, 0);
|
sin = Math.sin(angleRad);
|
||||||
case Z -> new Vec3(0, 0, 1);
|
cos = Math.cos(angleRad);
|
||||||
};
|
|
||||||
this.angle = angle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlockRotation(JsonObject rotation) {
|
public SubBlockRotation(JsonObject rotation) {
|
||||||
origin = new SubBlockPosition(rotation.get("origin").getAsJsonArray()).getVector();
|
origin = new SubBlockPosition(rotation.get("origin").getAsJsonArray()).getVector();
|
||||||
String axis = rotation.get("axis").getAsString();
|
String direction = rotation.get("axis").getAsString();
|
||||||
direction = switch (axis) {
|
axis = switch (direction) {
|
||||||
case "x" -> new Vec3(1, 0, 0);
|
case "x" -> Axis.X;
|
||||||
case "y" -> new Vec3(0, 1, 0);
|
case "y" -> Axis.Y;
|
||||||
case "z" -> new Vec3(0, 0, 1);
|
case "z" -> Axis.Z;
|
||||||
default -> throw new IllegalStateException("Unexpected value: " + axis);
|
default -> throw new IllegalStateException("Unexpected value: " + direction);
|
||||||
};
|
};
|
||||||
angle = Math.toRadians(rotation.get("angle").getAsFloat());
|
double angleRad = Math.toRadians(rotation.get("angle").getAsDouble());
|
||||||
|
sin = Math.sin(angleRad);
|
||||||
|
cos = Math.cos(angleRad);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubBlockPosition apply(SubBlockPosition position) {
|
private Pair<Double, Double> rotate(double x, double y) {
|
||||||
Vec3 transformed = Vec3.add(position.getVector(), Vec3.mul(origin, -1));
|
double newX = x * cos - y * sin;
|
||||||
|
double newY = x * sin + y * cos;
|
||||||
Vec3 result = Vec3.mul(transformed, Math.cos(angle));
|
|
||||||
result.add(Vec3.mul(Vec3.cross(direction, transformed), Math.sin(angle)));
|
|
||||||
//result.add(Vec3.mul(direction, direction, transformed, ));
|
|
||||||
return new SubBlockPosition(Vec3.add(transformed, origin));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static Pair<Float, Float> rotate(float x, float y, float angle) {
|
|
||||||
float angleRad = (float) Math.toRadians(angle);
|
|
||||||
float newX = x * (float) StrictMath.cos(angleRad) + y * (float) StrictMath.sin(angleRad);
|
|
||||||
float newY = - x * (float) StrictMath.sin(angleRad) + y * (float) StrictMath.cos(angleRad);
|
|
||||||
return new Pair<>(newX, newY);
|
return new Pair<>(newX, newY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SubBlockPosition apply(SubBlockPosition position) {
|
public SubBlockPosition apply(SubBlockPosition position) {
|
||||||
SubBlockPosition transformed = SubBlockPosition.subtract(position, origin);
|
Vec3 transformedPosition = Vec3.add(position.getVector(), Vec3.mul(origin, -1));
|
||||||
Pair<Float, Float> rotated;
|
return switch (axis) {
|
||||||
switch (direction) {
|
case X:
|
||||||
case X -> {
|
Pair<Double, Double> rotateX = rotate(transformedPosition.y, transformedPosition.z); transformedPosition.y = rotateX.getKey(); transformedPosition.z = rotateX.getValue(); yield new SubBlockPosition(Vec3.add(transformedPosition, origin));
|
||||||
rotated = rotate(transformed.y, transformed.z, angle);
|
case Y:
|
||||||
transformed.y = rotated.getKey();
|
Pair<Double, Double> rotateY = rotate(transformedPosition.x, transformedPosition.z); transformedPosition.x = rotateY.getKey(); transformedPosition.z = rotateY.getValue(); yield new SubBlockPosition(Vec3.add(transformedPosition, origin));
|
||||||
transformed.z = rotated.getValue();
|
case Z:
|
||||||
}
|
Pair<Double, Double> rotateZ = rotate(transformedPosition.x, transformedPosition.y); transformedPosition.x = rotateZ.getKey(); transformedPosition.y = rotateZ.getValue(); yield new SubBlockPosition(Vec3.add(transformedPosition, origin));
|
||||||
case Y -> {
|
};
|
||||||
rotated = rotate(transformed.x, transformed.z, angle);
|
|
||||||
transformed.x = rotated.getKey();
|
|
||||||
transformed.z = rotated.getValue();
|
|
||||||
}
|
|
||||||
case Z -> {
|
|
||||||
rotated = rotate(transformed.x, transformed.y, angle);
|
|
||||||
transformed.x = rotated.getKey();
|
|
||||||
transformed.y = rotated.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SubBlockPosition.add(transformed, origin);
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ public class PlayerController {
|
|||||||
applyVelocity(deltaTime);
|
applyVelocity(deltaTime);
|
||||||
|
|
||||||
if (gameMode == GameModes.SPECTATOR) {
|
if (gameMode == GameModes.SPECTATOR) {
|
||||||
|
glTranslated(-playerPos.x, -(playerPos.y + playerHeight - 0.2f), -playerPos.z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleCollisions(connection.getPlayer().getWorld());
|
handleCollisions(connection.getPlayer().getWorld());
|
||||||
|
@ -35,6 +35,12 @@ public class Vec3 {
|
|||||||
z = (float) location.getZ();
|
z = (float) location.getZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vec3(Vec3 vector) {
|
||||||
|
x = vector.x;
|
||||||
|
y = vector.y;
|
||||||
|
z = vector.z;
|
||||||
|
}
|
||||||
|
|
||||||
public static Vec3 add(Vec3... vectors) {
|
public static Vec3 add(Vec3... vectors) {
|
||||||
Vec3 result = new Vec3(0, 0, 0);
|
Vec3 result = new Vec3(0, 0, 0);
|
||||||
for (Vec3 vector : vectors) {
|
for (Vec3 vector : vectors) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user