Render: support for BlockRotations

This commit is contained in:
Lukas 2020-11-10 15:45:14 +01:00
parent 364f2736cb
commit 4c52ebab97
13 changed files with 265 additions and 250 deletions

View File

@ -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
View File

@ -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>

View File

@ -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;
}
} }

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
} }
} }

View File

@ -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];

View File

@ -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("#")) {

View File

@ -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);
} }

View File

@ -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);
} }
*/
} }

View File

@ -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());

View File

@ -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) {