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>
<version>3.8.1</version>
<configuration>
<source>15</source>
<target>15</target>
<compilerArgs>--enable-preview</compilerArgs>
<source>
14
</source>
<target>
14
</target>
<compilerArgs>
--enable-preview
</compilerArgs>
</configuration>
</plugin>
</plugins>

View File

@ -1,6 +1,6 @@
/*
* 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.
*
@ -13,88 +13,55 @@
package de.bixilon.minosoft.render.blockModels;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
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.logging.Log;
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 de.bixilon.minosoft.render.texture.TextureLoader;
import org.apache.commons.collections.primitives.ArrayFloatList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.stream.Collectors;
public class BlockModel {
private ArrayList<SubBlock> subBlocks;
private boolean[] full; // minor memory improvement over a Map
public class BlockModel implements BlockModelInterface {
private final HashMap<HashSet<String>, HashSet<SubBlock>> stateMap;
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) {
subBlocks = load(block, allModels);
}
public BlockModel(BlockModel blockModel, JsonObject json) {
if (blockModel != null) {
subBlocks = blockModel.getSubBlocks();
} else {
subBlocks = new ArrayList<>();
}
if (json.has("x")) {
rotate(Axis.X, json.get("x").getAsInt());
}
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());
public BlockModel(HashMap<String, HashSet<SubBlock>> blockModels, JsonArray states) {
stateMap = new HashMap<>();
full = new HashMap<>();
for (JsonElement element : states) {
JsonObject state = element.getAsJsonObject();
HashSet<SubBlock> model = blockModels.get(state.get("model").getAsString()).stream().map(SubBlock::new).collect(Collectors.toCollection(HashSet::new));
HashSet<String> properties = new HashSet<>();
for (Map.Entry<String, JsonElement> property : state.getAsJsonObject("properties").entrySet()) {
if (Blocks.getPropertiesMapping().containsKey(property.getKey())) {
properties.add(Blocks.getPropertiesMapping().get(property.getKey()).get(property.getValue().getAsString()).name());
} else if (Blocks.getRotationMapping().containsKey(property.getValue().getAsString())) {
properties.add(Blocks.getRotationMapping().get(property.getValue().getAsString()).name());
}
}
}
if (json.has("elements")) {
for (JsonElement subBlockJson : json.get("elements").getAsJsonArray()) {
result.add(new SubBlock(subBlockJson.getAsJsonObject(), variables));
for (Axis axis : Axis.values()) {
String lowercase = axis.name().toLowerCase();
if (state.has(lowercase)) {
BlockModelInterface.rotateModel(model, axis, state.get(lowercase).getAsInt());
}
}
} else if (json.has("parent") && !json.get("parent").getAsString().equals("block/block")) {
String parent = json.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));
stateMap.put(properties, model);
full.put(properties, createFullValues(model));
}
return result;
}
static ArrayList<SubBlock> load(JsonObject json, JsonObject allModels) {
return load(json, allModels, new HashMap<>());
}
private boolean[] createFullValues() {
private static boolean[] createFullValues(HashSet<SubBlock> subBlocks) {
boolean[] result = new boolean[6];
outer:
for (FaceOrientation orientation : FaceOrientation.values()) {
@ -108,41 +75,60 @@ public class BlockModel {
return result;
}
public boolean isFull(FaceOrientation orientation) {
return full[orientation.getId()];
private static HashSet<String> getProperties(Block block) {
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) {
ArrayFloatList result = new ArrayFloatList();
for (SubBlock subBlock : subBlocks) {
result.addAll(subBlock.getFaces(facesToDraw, position));
HashSet<String> properties = getProperties(block);
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;
}
}
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() {
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.world.BlockPosition;
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.util.Util;
import org.apache.commons.collections.primitives.ArrayFloatList;
@ -29,14 +30,13 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class BlockModelLoader {
HashMap<BlockModelBlockWrapper, BlockModel> blockMap;
TextureLoader textureLoader;
public static BlockModelLoader blockModelLoader;
HashMap<String, HashMap<String, BlockModelInterface>> modelMap;
public BlockModelLoader() {
blockMap = new HashMap<>();
modelMap = new HashMap<>();
HashSet<JsonObject> mods = new HashSet<>();
HashMap<String, HashMap<String, float[]>> tints = new HashMap<>();
try {
@ -45,10 +45,14 @@ public class BlockModelLoader {
} catch (IOException e) {
e.printStackTrace();
}
HashMap<String, HashMap<String, BlockModel>> blockModels = new HashMap<>();
HashMap<String, HashMap<String, HashSet<SubBlock>>> blockModels = new HashMap<>();
for (JsonObject mod : mods) {
blockModels.put(mod.get("mod").getAsString(), loadModels(mod));
tints.put(mod.get("mod").getAsString(), readTints(mod));
String modName = mod.get("mod").getAsString();
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);
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()) {
JsonObject block = blockEntry.getValue().getAsJsonObject();
if (block.has("states")) {
JsonArray states = block.get("states").getAsJsonArray();
for (JsonElement state : 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()));
}
modelMap.get(mod.get("mod").getAsString()).put(blockEntry.getKey(), new BlockModel(blockModels, states));
} else if (block.has("conditional")) {
Block wrapper = new Block(mod.get("mod").getAsString(), blockEntry.getKey());
blockMap.put(new BlockModelBlockWrapper(wrapper), new ConditionalModel(blockModels, block.get("conditional").getAsJsonArray()));
modelMap.get(mod.get("mod").getAsString()).put(blockEntry.getKey(), new ConditionalModel(blockModels, block.get("conditional").getAsJsonArray()));
}
}
}
private HashMap<String, BlockModel> loadModels(JsonObject mod) {
HashMap<String, BlockModel> modMap = new HashMap<>();
for (Map.Entry<String, JsonElement> block : mod.get("blockModels").getAsJsonObject().entrySet()) {
modMap.put(block.getKey(), new BlockModel(block.getValue().getAsJsonObject(), mod.get("blockModels").getAsJsonObject()));
private HashMap<String, HashSet<SubBlock>> loadModels(JsonObject mod) {
HashMap<String, HashSet<SubBlock>> modMap = new HashMap<>();
for (Map.Entry<String, JsonElement> block : mod.getAsJsonObject("blockModels").entrySet()) {
modMap.put(block.getKey(), BlockModelInterface.load(block.getValue().getAsJsonObject(), mod.getAsJsonObject("blockModels")));
}
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<>();
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<>();
for (BlockModel blockModel : mod.getValue().values()) {
modTextures.addAll(blockModel.getAllTextures());
for (HashSet<SubBlock> subBlocks : mod.getValue().values()) {
for (SubBlock subBlock : subBlocks) {
modTextures.addAll(subBlock.getTextures());
}
}
textures.put(mod.getKey(), modTextures);
}
return textures;
}
public void applyTextures(HashMap<String, HashMap<String, BlockModel>> blockModels) {
for (Map.Entry<String, HashMap<String, BlockModel>> mod : blockModels.entrySet()) {
for (Map.Entry<String, BlockModel> block : mod.getValue().entrySet()) {
block.getValue().applyTextures(mod.getKey(), textureLoader);
public void applyTextures(HashMap<String, HashMap<String, HashSet<SubBlock>>> blockModels) {
for (Map.Entry<String, HashMap<String, HashSet<SubBlock>>> mod : blockModels.entrySet()) {
for (Map.Entry<String, HashSet<SubBlock>> block : mod.getValue().entrySet()) {
for (SubBlock subBlock : block.getValue()) {
subBlock.applyTextures(mod.getKey(), textureLoader);
}
}
}
}
@ -118,19 +121,19 @@ public class BlockModelLoader {
return result;
}
public BlockModel getBlockModel(Block block) {
BlockModel model = blockMap.get(new BlockModelBlockWrapper(block));
public BlockModelInterface getBlockModel(Block block) {
BlockModelInterface model = modelMap.get(block.getMod()).get(block.getIdentifier());
if (model == null) {
throw new RuntimeException("block " + block + " could not be found");
}
return blockMap.get(new BlockModelBlockWrapper(block));
return model;
}
public boolean isFull(Block block, FaceOrientation orientation) {
if (block == null || block.equals(Blocks.nullBlock)) {
return false;
}
return getBlockModel(block).isFull(orientation);
return getBlockModel(block).full(block, orientation);
}
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.world.BlockPosition;
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;
import java.util.Map;
public class ConditionalModel extends BlockModel {
HashMap<BlockCondition, BlockModel> conditionMap;
public class ConditionalModel implements BlockModelInterface {
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<>();
for (JsonElement element : elements) {
JsonObject block = element.getAsJsonObject();
@ -38,29 +39,31 @@ public class ConditionalModel extends BlockModel {
} else {
condition = BlockCondition.trueCondition;
}
BlockModel model = blockModels.get(block.get("model").getAsString());
conditionMap.put(condition, new BlockModel(model, block));
HashSet<SubBlock> model = blockModels.get(block.get("model").getAsString());
conditionMap.put(condition, model);
}
}
@Override
public ArrayFloatList prepare(HashSet<FaceOrientation> facesToDraw, BlockPosition position, Block block) {
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)) {
result.addAll(entry.getValue().prepare(facesToDraw, position, block));
for (SubBlock subBlock : entry.getValue()) {
result.addAll(subBlock.getFaces(facesToDraw, position));
}
}
}
return result;
}
@Override
public boolean isFull() {
public boolean full(Block block, FaceOrientation orientation) {
return false;
}
@Override
public boolean isFull(FaceOrientation orientation) {
public boolean isFull() {
return false;
}
}

View File

@ -13,7 +13,7 @@
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.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) {
int[] positionIds = facePositionMapTemplate[orientation.getId()];
SubBlockPosition[] result = new SubBlockPosition[positionIds.length];

View File

@ -1,6 +1,6 @@
/*
* 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.
*
@ -27,7 +27,7 @@ import java.util.Map;
public class SubBlock {
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 boolean[] full;
private final HashMap<FaceOrientation, InFaceUV> uv;
@ -56,6 +56,14 @@ public class SubBlock {
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) {
// read the variables and find the real texture name
if (textureName.contains("#")) {

View File

@ -41,6 +41,10 @@ public class SubBlockPosition {
this.vector = vector;
}
public SubBlockPosition(SubBlockPosition position) {
vector = new Vec3(position.vector);
}
public SubBlockPosition rotated(Axis axis, int rotation) {
return new SubBlockRotation(middlePos, axis, rotation).apply(this);
}

View File

@ -1,6 +1,6 @@
/*
* 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.
*
@ -16,73 +16,52 @@ package de.bixilon.minosoft.render.blockModels.subBlocks;
import com.google.gson.JsonObject;
import de.bixilon.minosoft.render.blockModels.Face.Axis;
import de.bixilon.minosoft.render.utility.Vec3;
import javafx.util.Pair;
public class SubBlockRotation {
private final Vec3 origin;
private final double angle;
private final Vec3 direction;
private final Axis axis;
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.direction = switch (direction) {
case X -> new Vec3(1, 0, 0);
case Y -> new Vec3(0, 1, 0);
case Z -> new Vec3(0, 0, 1);
};
this.angle = angle;
this.axis = axis;
double angleRad = Math.toRadians(angle);
sin = Math.sin(angleRad);
cos = Math.cos(angleRad);
}
public SubBlockRotation(JsonObject rotation) {
origin = new SubBlockPosition(rotation.get("origin").getAsJsonArray()).getVector();
String axis = rotation.get("axis").getAsString();
direction = switch (axis) {
case "x" -> new Vec3(1, 0, 0);
case "y" -> new Vec3(0, 1, 0);
case "z" -> new Vec3(0, 0, 1);
default -> throw new IllegalStateException("Unexpected value: " + axis);
String direction = rotation.get("axis").getAsString();
axis = switch (direction) {
case "x" -> Axis.X;
case "y" -> Axis.Y;
case "z" -> Axis.Z;
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) {
Vec3 transformed = Vec3.add(position.getVector(), Vec3.mul(origin, -1));
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);
private Pair<Double, Double> rotate(double x, double y) {
double newX = x * cos - y * sin;
double newY = x * sin + y * cos;
return new Pair<>(newX, newY);
}
public SubBlockPosition apply(SubBlockPosition position) {
SubBlockPosition transformed = SubBlockPosition.subtract(position, origin);
Pair<Float, Float> rotated;
switch (direction) {
case X -> {
rotated = rotate(transformed.y, transformed.z, angle);
transformed.y = rotated.getKey();
transformed.z = rotated.getValue();
}
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);
Vec3 transformedPosition = Vec3.add(position.getVector(), Vec3.mul(origin, -1));
return switch (axis) {
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));
case Y:
Pair<Double, Double> rotateY = rotate(transformedPosition.x, transformedPosition.z); transformedPosition.x = rotateY.getKey(); transformedPosition.z = rotateY.getValue(); yield new SubBlockPosition(Vec3.add(transformedPosition, origin));
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));
};
}
*/
}

View File

@ -64,6 +64,7 @@ public class PlayerController {
applyVelocity(deltaTime);
if (gameMode == GameModes.SPECTATOR) {
glTranslated(-playerPos.x, -(playerPos.y + playerHeight - 0.2f), -playerPos.z);
return;
}
handleCollisions(connection.getPlayer().getWorld());

View File

@ -35,6 +35,12 @@ public class Vec3 {
z = (float) location.getZ();
}
public Vec3(Vec3 vector) {
x = vector.x;
y = vector.y;
z = vector.z;
}
public static Vec3 add(Vec3... vectors) {
Vec3 result = new Vec3(0, 0, 0);
for (Vec3 vector : vectors) {