mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-27 21:24:47 +01:00
Add per-map view-settings and optimized flat-view only maps
This commit is contained in:
parent
f08c7946a0
commit
4d58cc25e3
@ -123,7 +123,6 @@ private static class Settings {
|
|||||||
|
|
||||||
private boolean useCookies = true;
|
private boolean useCookies = true;
|
||||||
|
|
||||||
private boolean enableFreeFlight = true;
|
|
||||||
private boolean defaultToFlatView = false;
|
private boolean defaultToFlatView = false;
|
||||||
|
|
||||||
private String startLocation = null;
|
private String startLocation = null;
|
||||||
@ -150,7 +149,6 @@ private static class Settings {
|
|||||||
|
|
||||||
public void setFrom(WebappConfig config) {
|
public void setFrom(WebappConfig config) {
|
||||||
this.useCookies = config.isUseCookies();
|
this.useCookies = config.isUseCookies();
|
||||||
this.enableFreeFlight = config.isEnableFreeFlight();
|
|
||||||
this.defaultToFlatView = config.isDefaultToFlatView();
|
this.defaultToFlatView = config.isDefaultToFlatView();
|
||||||
this.startLocation = config.getStartLocation().orElse(null);
|
this.startLocation = config.getStartLocation().orElse(null);
|
||||||
this.resolutionDefault = config.getResolutionDefault();
|
this.resolutionDefault = config.getResolutionDefault();
|
||||||
|
@ -75,7 +75,10 @@ public class MapConfig implements MapSettings {
|
|||||||
|
|
||||||
private boolean renderEdges = true;
|
private boolean renderEdges = true;
|
||||||
|
|
||||||
private boolean saveHiresLayer = true;
|
private boolean enablePerspectiveView = true;
|
||||||
|
private boolean enableFlatView = true;
|
||||||
|
private boolean enableFreeFlightView = true;
|
||||||
|
private boolean enableHires = true;
|
||||||
|
|
||||||
private String storage = "file";
|
private String storage = "file";
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ public class WebappConfig {
|
|||||||
|
|
||||||
private boolean useCookies = true;
|
private boolean useCookies = true;
|
||||||
|
|
||||||
private boolean enableFreeFlight = true;
|
|
||||||
private boolean defaultToFlatView = false;
|
private boolean defaultToFlatView = false;
|
||||||
|
|
||||||
private String startLocation = null;
|
private String startLocation = null;
|
||||||
@ -82,10 +81,6 @@ public boolean isUseCookies() {
|
|||||||
return useCookies;
|
return useCookies;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnableFreeFlight() {
|
|
||||||
return enableFreeFlight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDefaultToFlatView() {
|
public boolean isDefaultToFlatView() {
|
||||||
return defaultToFlatView;
|
return defaultToFlatView;
|
||||||
}
|
}
|
||||||
|
@ -96,13 +96,28 @@ min-inhabited-time: 0
|
|||||||
# Default is true
|
# Default is true
|
||||||
render-edges: true
|
render-edges: true
|
||||||
|
|
||||||
# Whether the hires-layer will be saved to the storage.
|
# Whether the perspective view will be enabled for this map.
|
||||||
|
# Changing this to true requires a re-render of the map, only if the hires-layer is enabled and free-flight view is disabled.
|
||||||
|
# Default is true
|
||||||
|
enable-perspective-view: true
|
||||||
|
|
||||||
|
# Whether the flat (isometric, top-down) view will be enabled for this map.
|
||||||
|
# Having only flat-view enabled while disabling free-flight and perspective will speed up the render and reduce the maps storage-size.
|
||||||
|
# Default is true
|
||||||
|
enable-flat-view: true
|
||||||
|
|
||||||
|
# Whether the free-flight view will be enabled for this map.
|
||||||
|
# Changing this to true requires a re-render of the map, only if the hires-layer is enabled and perspective view is disabled.
|
||||||
|
# Default is true
|
||||||
|
enable-free-flight-view: true
|
||||||
|
|
||||||
|
# Whether the hires-layer will be enabled.
|
||||||
# Disabling this will speed up rendering and reduce the size of the map-files a lot.
|
# Disabling this will speed up rendering and reduce the size of the map-files a lot.
|
||||||
# But you will not be able to see the full 3d-models if you zoom in on the map.
|
# But you will not be able to see the full 3d-models if you zoom in on the map.
|
||||||
# Changing this to false will not remove any existing tiles, existing tiles just won't get updated anymore.
|
# Changing this to false will not remove any existing tiles, existing tiles just won't get updated anymore.
|
||||||
# Changing this to true will require a re-render of the map.
|
# Changing this to true will require a re-render of the map.
|
||||||
# Default is true
|
# Default is true
|
||||||
save-hires-layer: true
|
enable-hires: true
|
||||||
|
|
||||||
# This defines the storage-config that will be used to save this map.
|
# This defines the storage-config that will be used to save this map.
|
||||||
# You can find your storage configs next to this config file in the 'storages'-folder.
|
# You can find your storage configs next to this config file in the 'storages'-folder.
|
||||||
|
@ -22,10 +22,6 @@ update-settings-file: true
|
|||||||
# Default is true
|
# Default is true
|
||||||
use-cookies: true
|
use-cookies: true
|
||||||
|
|
||||||
# If the free-flight-mode in the web-application is enabled or not.
|
|
||||||
# Default is true
|
|
||||||
enable-free-flight: true
|
|
||||||
|
|
||||||
# If the webapp will default to flat-view instead of perspective-view.
|
# If the webapp will default to flat-view instead of perspective-view.
|
||||||
# Default is false
|
# Default is false
|
||||||
default-to-flat-view: false
|
default-to-flat-view: false
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="controls-switch">
|
<div class="controls-switch" v-if="showViewControls">
|
||||||
<SvgButton :active="isPerspectiveView" @action="setPerspectiveView" :title="$t('controls.perspective.tooltip')">
|
<SvgButton v-if="mapViewer.map.perspectiveView" :active="isPerspectiveView" @action="setPerspectiveView" :title="$t('controls.perspective.tooltip')">
|
||||||
<svg viewBox="0 0 30 30">
|
<svg viewBox="0 0 30 30">
|
||||||
<path d="M19.475,10.574c-0.166-0.021-0.337-0.036-0.51-0.045c-0.174-0.009-0.35-0.013-0.525-0.011
|
<path d="M19.475,10.574c-0.166-0.021-0.337-0.036-0.51-0.045c-0.174-0.009-0.35-0.013-0.525-0.011
|
||||||
c-0.176,0.002-0.353,0.01-0.526,0.024c-0.175,0.015-0.347,0.036-0.515,0.063l-13.39,2.189
|
c-0.176,0.002-0.353,0.01-0.526,0.024c-0.175,0.015-0.347,0.036-0.515,0.063l-13.39,2.189
|
||||||
@ -13,12 +13,12 @@
|
|||||||
c-0.116-0.051-0.243-0.097-0.381-0.138c-0.137-0.041-0.283-0.078-0.438-0.108C19.803,10.621,19.641,10.595,19.475,10.574"/>
|
c-0.116-0.051-0.243-0.097-0.381-0.138c-0.137-0.041-0.283-0.078-0.438-0.108C19.803,10.621,19.641,10.595,19.475,10.574"/>
|
||||||
</svg>
|
</svg>
|
||||||
</SvgButton>
|
</SvgButton>
|
||||||
<SvgButton :active="isFlatView" @action="setFlatView" :title="$t('controls.flatView.tooltip')">
|
<SvgButton v-if="mapViewer.map.flatView" :active="isFlatView" @action="setFlatView" :title="$t('controls.flatView.tooltip')">
|
||||||
<svg viewBox="0 0 30 30">
|
<svg viewBox="0 0 30 30">
|
||||||
<path d="M22.371,4.158c1.65,0,3,1.35,3,3v15.684c0,1.65-1.35,3-3,3H7.629c-1.65,0-3-1.35-3-3V7.158c0-1.65,1.35-3,3-3H22.371z"/>
|
<path d="M22.371,4.158c1.65,0,3,1.35,3,3v15.684c0,1.65-1.35,3-3,3H7.629c-1.65,0-3-1.35-3-3V7.158c0-1.65,1.35-3,3-3H22.371z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</SvgButton>
|
</SvgButton>
|
||||||
<SvgButton v-if="controls.enableFreeFlight" :active="isFreeFlight" @action="setFreeFlight" :title="$t('controls.freeFlight.tooltip')">
|
<SvgButton v-if="mapViewer.map.freeFlightView" :active="isFreeFlight" @action="setFreeFlight" :title="$t('controls.freeFlight.tooltip')">
|
||||||
<svg viewBox="0 0 30 30">
|
<svg viewBox="0 0 30 30">
|
||||||
<path d="M21.927,11.253c-0.256-0.487-0.915-0.885-1.465-0.885h-2.004c-0.55,0-0.726-0.356-0.39-0.792c0,0,0.698-0.905,0.698-2.041
|
<path d="M21.927,11.253c-0.256-0.487-0.915-0.885-1.465-0.885h-2.004c-0.55,0-0.726-0.356-0.39-0.792c0,0,0.698-0.905,0.698-2.041
|
||||||
c0-2.08-1.687-3.767-3.767-3.767s-3.767,1.687-3.767,3.767c0,1.136,0.698,2.041,0.698,2.041c0.336,0.436,0.161,0.794-0.389,0.797
|
c0-2.08-1.687-3.767-3.767-3.767s-3.767,1.687-3.767,3.767c0,1.136,0.698,2.041,0.698,2.041c0.336,0.436,0.161,0.794-0.389,0.797
|
||||||
@ -40,6 +40,7 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
controls: this.$bluemap.appState.controls,
|
controls: this.$bluemap.appState.controls,
|
||||||
|
mapViewer: this.$bluemap.mapViewer.data
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -51,6 +52,10 @@
|
|||||||
},
|
},
|
||||||
isFreeFlight() {
|
isFreeFlight() {
|
||||||
return this.controls.state === "free";
|
return this.controls.state === "free";
|
||||||
|
},
|
||||||
|
showViewControls() {
|
||||||
|
if (!this.mapViewer.map) return 0;
|
||||||
|
return this.mapViewer.map.views.length > 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Group :title="$t('controls.title')">
|
<Group :title="$t('controls.title')">
|
||||||
<SimpleButton :active="appState.controls.state === 'perspective'" @action="$bluemap.setPerspectiveView(500, appState.controls.state === 'free' ? 100 : 0)">{{$t('controls.perspective.button')}}</SimpleButton>
|
<SimpleButton v-if="mapViewer.map.perspectiveView" :active="appState.controls.state === 'perspective'" @action="$bluemap.setPerspectiveView(500, appState.controls.state === 'free' ? 100 : 0)">{{$t('controls.perspective.button')}}</SimpleButton>
|
||||||
<SimpleButton :active="appState.controls.state === 'flat'" @action="$bluemap.setFlatView(500, appState.controls.state === 'free' ? 100 : 0)">{{$t('controls.flatView.button')}}</SimpleButton>
|
<SimpleButton v-if="mapViewer.map.flatView" :active="appState.controls.state === 'flat'" @action="$bluemap.setFlatView(500, appState.controls.state === 'free' ? 100 : 0)">{{$t('controls.flatView.button')}}</SimpleButton>
|
||||||
<SimpleButton v-if="appState.controls.enableFreeFlight" :active="appState.controls.state === 'free'" @action="$bluemap.setFreeFlight(500)">{{$t('controls.freeFlight.button')}}</SimpleButton>
|
<SimpleButton v-if="mapViewer.map.freeFlightView" :active="appState.controls.state === 'free'" @action="$bluemap.setFreeFlight(500)">{{$t('controls.freeFlight.button')}}</SimpleButton>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group :title="$t('lighting.title')">
|
<Group :title="$t('lighting.title')">
|
||||||
|
@ -59,7 +59,6 @@ export class BlueMapApp {
|
|||||||
/** @type {{
|
/** @type {{
|
||||||
* version: string,
|
* version: string,
|
||||||
* useCookies: boolean,
|
* useCookies: boolean,
|
||||||
* enableFreeFlight: boolean,
|
|
||||||
* defaultToFlatView: boolean,
|
* defaultToFlatView: boolean,
|
||||||
* resolutionDefault: number,
|
* resolutionDefault: number,
|
||||||
* minZoomDistance: number,
|
* minZoomDistance: number,
|
||||||
@ -96,7 +95,6 @@ export class BlueMapApp {
|
|||||||
mouseSensitivity: 1,
|
mouseSensitivity: 1,
|
||||||
showZoomButtons: true,
|
showZoomButtons: true,
|
||||||
invertMouse: false,
|
invertMouse: false,
|
||||||
enableFreeFlight: false,
|
|
||||||
pauseTileLoading: false
|
pauseTileLoading: false
|
||||||
},
|
},
|
||||||
menu: this.mainMenu,
|
menu: this.mainMenu,
|
||||||
@ -139,7 +137,6 @@ export class BlueMapApp {
|
|||||||
await this.getSettings();
|
await this.getSettings();
|
||||||
this.mapControls.minDistance = this.settings.minZoomDistance;
|
this.mapControls.minDistance = this.settings.minZoomDistance;
|
||||||
this.mapControls.maxDistance = this.settings.maxZoomDistance;
|
this.mapControls.maxDistance = this.settings.maxZoomDistance;
|
||||||
this.appState.controls.enableFreeFlight = this.settings.enableFreeFlight;
|
|
||||||
|
|
||||||
// load settings-styles
|
// load settings-styles
|
||||||
if (this.settings.styles) for (let styleUrl of this.settings.styles) {
|
if (this.settings.styles) for (let styleUrl of this.settings.styles) {
|
||||||
@ -259,7 +256,9 @@ export class BlueMapApp {
|
|||||||
|
|
||||||
await this.mapViewer.switchMap(map)
|
await this.mapViewer.switchMap(map)
|
||||||
|
|
||||||
if (resetCamera) this.resetCamera();
|
if (resetCamera || !this.mapViewer.map.hasView(this.appState.controls.state))
|
||||||
|
this.resetCamera();
|
||||||
|
|
||||||
this.updatePageAddress();
|
this.updatePageAddress();
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -283,10 +282,18 @@ export class BlueMapApp {
|
|||||||
|
|
||||||
controls.controls = this.mapControls;
|
controls.controls = this.mapControls;
|
||||||
this.appState.controls.state = "perspective";
|
this.appState.controls.state = "perspective";
|
||||||
if (this.settings.defaultToFlatView) {
|
|
||||||
|
if (this.settings.defaultToFlatView && map.hasView("flat")) {
|
||||||
this.setFlatView();
|
this.setFlatView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (!map.hasView("perspective")) {
|
||||||
|
if (map.hasView("flat"))
|
||||||
|
this.setFlatView();
|
||||||
|
else
|
||||||
|
this.setFreeFlight();
|
||||||
|
}
|
||||||
|
|
||||||
this.updatePageAddress();
|
this.updatePageAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +335,6 @@ export class BlueMapApp {
|
|||||||
this.settings = {
|
this.settings = {
|
||||||
version: "?",
|
version: "?",
|
||||||
useCookies: false,
|
useCookies: false,
|
||||||
enableFreeFlight: true,
|
|
||||||
defaultToFlatView: false,
|
defaultToFlatView: false,
|
||||||
resolutionDefault: 1.0,
|
resolutionDefault: 1.0,
|
||||||
minZoomDistance: 5,
|
minZoomDistance: 5,
|
||||||
@ -451,6 +457,7 @@ export class BlueMapApp {
|
|||||||
|
|
||||||
setPerspectiveView(transition = 0, minDistance = 5) {
|
setPerspectiveView(transition = 0, minDistance = 5) {
|
||||||
if (!this.mapViewer.map) return;
|
if (!this.mapViewer.map) return;
|
||||||
|
if (!this.mapViewer.map.data.perspectiveView) return;
|
||||||
if (this.viewAnimation) this.viewAnimation.cancel();
|
if (this.viewAnimation) this.viewAnimation.cancel();
|
||||||
|
|
||||||
let cm = this.mapViewer.controlsManager;
|
let cm = this.mapViewer.controlsManager;
|
||||||
@ -488,6 +495,7 @@ export class BlueMapApp {
|
|||||||
|
|
||||||
setFlatView(transition = 0, minDistance = 5) {
|
setFlatView(transition = 0, minDistance = 5) {
|
||||||
if (!this.mapViewer.map) return;
|
if (!this.mapViewer.map) return;
|
||||||
|
if (!this.mapViewer.map.data.flatView) return;
|
||||||
if (this.viewAnimation) this.viewAnimation.cancel();
|
if (this.viewAnimation) this.viewAnimation.cancel();
|
||||||
|
|
||||||
let cm = this.mapViewer.controlsManager;
|
let cm = this.mapViewer.controlsManager;
|
||||||
@ -521,7 +529,7 @@ export class BlueMapApp {
|
|||||||
|
|
||||||
setFreeFlight(transition = 0, targetY = undefined) {
|
setFreeFlight(transition = 0, targetY = undefined) {
|
||||||
if (!this.mapViewer.map) return;
|
if (!this.mapViewer.map) return;
|
||||||
if (!this.settings.enableFreeFlight) return this.setPerspectiveView(transition);
|
if (!this.mapViewer.map.data.freeFlightView) return;
|
||||||
if (this.viewAnimation) this.viewAnimation.cancel();
|
if (this.viewAnimation) this.viewAnimation.cancel();
|
||||||
|
|
||||||
let cm = this.mapViewer.controlsManager;
|
let cm = this.mapViewer.controlsManager;
|
||||||
|
@ -78,7 +78,11 @@ export class Map {
|
|||||||
tileSize: {x: 32, z: 32},
|
tileSize: {x: 32, z: 32},
|
||||||
lodFactor: 5,
|
lodFactor: 5,
|
||||||
lodCount: 3
|
lodCount: 3
|
||||||
}
|
},
|
||||||
|
perspectiveView: false,
|
||||||
|
flatView: false,
|
||||||
|
freeFlightView: false,
|
||||||
|
views: ["perspective", "flat", "free"]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.raycaster = new Raycaster();
|
this.raycaster = new Raycaster();
|
||||||
@ -198,6 +202,15 @@ export class Map {
|
|||||||
lodCount: worldSettings.lowres.lodCount !== undefined ? worldSettings.lowres.lodCount : this.data.lowres.lodCount
|
lodCount: worldSettings.lowres.lodCount !== undefined ? worldSettings.lowres.lodCount : this.data.lowres.lodCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.data.perspectiveView = worldSettings.perspectiveView !== undefined ? worldSettings.perspectiveView : this.data.perspectiveView;
|
||||||
|
this.data.flatView = worldSettings.flatView !== undefined ? worldSettings.flatView : this.data.flatView;
|
||||||
|
this.data.freeFlightView = worldSettings.freeFlightView !== undefined ? worldSettings.freeFlightView : this.data.freeFlightView;
|
||||||
|
|
||||||
|
this.data.views = [];
|
||||||
|
if (this.data.perspectiveView) this.data.views.push("perspective");
|
||||||
|
if (this.data.flatView) this.data.views.push("flat");
|
||||||
|
if (this.data.freeFlightView) this.data.views.push("free");
|
||||||
|
|
||||||
alert(this.events, `Settings for map '${this.data.id}' loaded.`, "fine");
|
alert(this.events, `Settings for map '${this.data.id}' loaded.`, "fine");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -472,6 +485,10 @@ export class Map {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasView(view) {
|
||||||
|
return this.data.views.some(v => v === view)
|
||||||
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this.unload();
|
this.unload();
|
||||||
}
|
}
|
||||||
|
@ -52,4 +52,22 @@ public interface MapSettings extends RenderSettings {
|
|||||||
|
|
||||||
float getSkyLight();
|
float getSkyLight();
|
||||||
|
|
||||||
|
boolean isEnablePerspectiveView();
|
||||||
|
|
||||||
|
boolean isEnableFlatView();
|
||||||
|
|
||||||
|
boolean isEnableFreeFlightView();
|
||||||
|
|
||||||
|
boolean isEnableHires();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean isSaveHiresLayer() {
|
||||||
|
return isEnableHires();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean isRenderTopOnly() {
|
||||||
|
return !isEnableHires() || (!isEnablePerspectiveView() && !isEnableFreeFlightView());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,11 @@ public JsonElement serialize(BmMap map, Type typeOfSrc, JsonSerializationContext
|
|||||||
root.addProperty("ambientLight", map.getMapSettings().getAmbientLight());
|
root.addProperty("ambientLight", map.getMapSettings().getAmbientLight());
|
||||||
root.addProperty("skyLight", map.getMapSettings().getSkyLight());
|
root.addProperty("skyLight", map.getMapSettings().getSkyLight());
|
||||||
|
|
||||||
|
// view settings
|
||||||
|
root.addProperty("perspectiveView", map.getMapSettings().isEnablePerspectiveView());
|
||||||
|
root.addProperty("flatView", map.getMapSettings().isEnableFlatView());
|
||||||
|
root.addProperty("freeFlightView", map.getMapSettings().isEnableFreeFlightView());
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,498 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package de.bluecolored.bluemap.core.map.hires;
|
||||||
|
|
||||||
|
import com.flowpowered.math.TrigMath;
|
||||||
|
import de.bluecolored.bluemap.core.util.InstancePool;
|
||||||
|
import de.bluecolored.bluemap.core.util.MergeSort;
|
||||||
|
import de.bluecolored.bluemap.core.util.math.MatrixM3f;
|
||||||
|
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
|
||||||
|
|
||||||
|
public class ArrayTileModel implements TileModel {
|
||||||
|
private static final double GROW_MULTIPLIER = 1.5;
|
||||||
|
|
||||||
|
private static final InstancePool<ArrayTileModel> INSTANCE_POOL = new InstancePool<>(
|
||||||
|
() -> new ArrayTileModel(100),
|
||||||
|
ArrayTileModel::clear
|
||||||
|
);
|
||||||
|
|
||||||
|
// attributes per-vertex * per-face
|
||||||
|
static final int
|
||||||
|
FI_POSITION = 3 * 3,
|
||||||
|
FI_UV = 2 * 3,
|
||||||
|
FI_AO = 3,
|
||||||
|
FI_COLOR = 3 ,
|
||||||
|
FI_SUNLIGHT = 1 ,
|
||||||
|
FI_BLOCKLIGHT = 1 ,
|
||||||
|
FI_MATERIAL_INDEX = 1 ;
|
||||||
|
|
||||||
|
private int capacity;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
float[] position;
|
||||||
|
float[] color, uv, ao;
|
||||||
|
byte[] sunlight, blocklight;
|
||||||
|
int[] materialIndex, materialIndexSort, materialIndexSortSupport;
|
||||||
|
|
||||||
|
public ArrayTileModel(int initialCapacity) {
|
||||||
|
if (initialCapacity < 0) throw new IllegalArgumentException("initialCapacity is negative");
|
||||||
|
setCapacity(initialCapacity);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int add(int count) {
|
||||||
|
ensureCapacity(count);
|
||||||
|
int start = this.size;
|
||||||
|
this.size += count;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setPositions(
|
||||||
|
int face,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
float x3, float y3, float z3
|
||||||
|
){
|
||||||
|
int index = face * FI_POSITION;
|
||||||
|
|
||||||
|
position[index ] = x1;
|
||||||
|
position[index + 1] = y1;
|
||||||
|
position[index + 2] = z1;
|
||||||
|
|
||||||
|
position[index + 3 ] = x2;
|
||||||
|
position[index + 3 + 1] = y2;
|
||||||
|
position[index + 3 + 2] = z2;
|
||||||
|
|
||||||
|
position[index + 6 ] = x3;
|
||||||
|
position[index + 6 + 1] = y3;
|
||||||
|
position[index + 6 + 2] = z3;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setUvs(
|
||||||
|
int face,
|
||||||
|
float u1, float v1,
|
||||||
|
float u2, float v2,
|
||||||
|
float u3, float v3
|
||||||
|
){
|
||||||
|
int index = face * FI_UV;
|
||||||
|
|
||||||
|
uv[index ] = u1;
|
||||||
|
uv[index + 1] = v1;
|
||||||
|
|
||||||
|
uv[index + 2 ] = u2;
|
||||||
|
uv[index + 2 + 1] = v2;
|
||||||
|
|
||||||
|
uv[index + 4 ] = u3;
|
||||||
|
uv[index + 4 + 1] = v3;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setAOs(
|
||||||
|
int face,
|
||||||
|
float ao1, float ao2, float ao3
|
||||||
|
) {
|
||||||
|
int index = face * FI_AO;
|
||||||
|
|
||||||
|
ao[index ] = ao1;
|
||||||
|
ao[index + 1] = ao2;
|
||||||
|
ao[index + 2] = ao3;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setColor(
|
||||||
|
int face,
|
||||||
|
float r, float g, float b
|
||||||
|
){
|
||||||
|
int index = face * FI_COLOR;
|
||||||
|
|
||||||
|
color[index ] = r;
|
||||||
|
color[index + 1] = g;
|
||||||
|
color[index + 2] = b;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setSunlight(int face, int sl) {
|
||||||
|
sunlight[face * FI_SUNLIGHT] = (byte) sl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setBlocklight(int face, int bl) {
|
||||||
|
blocklight[face * FI_BLOCKLIGHT] = (byte) bl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel setMaterialIndex(int face, int m) {
|
||||||
|
materialIndex[face * FI_MATERIAL_INDEX] = m;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel rotate(
|
||||||
|
int start, int count,
|
||||||
|
float angle, float axisX, float axisY, float axisZ
|
||||||
|
) {
|
||||||
|
|
||||||
|
// create quaternion
|
||||||
|
double halfAngle = Math.toRadians(angle) * 0.5;
|
||||||
|
double q = TrigMath.sin(halfAngle) / Math.sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
|
||||||
|
|
||||||
|
double //quaternion
|
||||||
|
qx = axisX * q,
|
||||||
|
qy = axisY * q,
|
||||||
|
qz = axisZ * q,
|
||||||
|
qw = TrigMath.cos(halfAngle),
|
||||||
|
qLength = Math.sqrt(qx * qx + qy * qy + qz * qz + qw * qw);
|
||||||
|
|
||||||
|
// normalize quaternion
|
||||||
|
qx /= qLength;
|
||||||
|
qy /= qLength;
|
||||||
|
qz /= qLength;
|
||||||
|
qw /= qLength;
|
||||||
|
|
||||||
|
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel rotate(
|
||||||
|
int start, int count,
|
||||||
|
float pitch, float yaw, float roll
|
||||||
|
) {
|
||||||
|
|
||||||
|
double
|
||||||
|
halfYaw = Math.toRadians(yaw) * 0.5,
|
||||||
|
qy1 = TrigMath.sin(halfYaw),
|
||||||
|
qw1 = TrigMath.cos(halfYaw),
|
||||||
|
|
||||||
|
halfPitch = Math.toRadians(pitch) * 0.5,
|
||||||
|
qx2 = TrigMath.sin(halfPitch),
|
||||||
|
qw2 = TrigMath.cos(halfPitch),
|
||||||
|
|
||||||
|
halfRoll = Math.toRadians(roll) * 0.5,
|
||||||
|
qz3 = TrigMath.sin(halfRoll),
|
||||||
|
qw3 = TrigMath.cos(halfRoll);
|
||||||
|
|
||||||
|
// multiply 1 with 2
|
||||||
|
double
|
||||||
|
qxA = qw1 * qx2,
|
||||||
|
qyA = qy1 * qw2,
|
||||||
|
qzA = - qy1 * qx2,
|
||||||
|
qwA = qw1 * qw2;
|
||||||
|
|
||||||
|
// multiply with 3
|
||||||
|
double
|
||||||
|
qx = qxA * qw3 + qyA * qz3,
|
||||||
|
qy = qyA * qw3 - qxA * qz3,
|
||||||
|
qz = qwA * qz3 + qzA * qw3,
|
||||||
|
qw = qwA * qw3 - qzA * qz3;
|
||||||
|
|
||||||
|
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel rotateByQuaternion(
|
||||||
|
int start, int count,
|
||||||
|
double qx, double qy, double qz, double qw
|
||||||
|
) {
|
||||||
|
double x, y, z, px, py, pz, pw;
|
||||||
|
int end = start + count, index;
|
||||||
|
for (int face = start; face < end; face++) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
index = face * FI_POSITION + i * 3;
|
||||||
|
|
||||||
|
x = position[index];
|
||||||
|
y = position[index + 1];
|
||||||
|
z = position[index + 2];
|
||||||
|
|
||||||
|
px = qw * x + qy * z - qz * y;
|
||||||
|
py = qw * y + qz * x - qx * z;
|
||||||
|
pz = qw * z + qx * y - qy * x;
|
||||||
|
pw = -qx * x - qy * y - qz * z;
|
||||||
|
|
||||||
|
position[index] = (float) (pw * -qx + px * qw - py * qz + pz * qy);
|
||||||
|
position[index + 1] = (float) (pw * -qy + py * qw - pz * qx + px * qz);
|
||||||
|
position[index + 2] = (float) (pw * -qz + pz * qw - px * qy + py * qx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel scale(
|
||||||
|
int start, int count,
|
||||||
|
float sx, float sy, float sz
|
||||||
|
) {
|
||||||
|
int end = start + count, index;
|
||||||
|
for (int face = start; face < end; face++) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
index = face * FI_POSITION + i * 3;
|
||||||
|
position[index ] *= sx;
|
||||||
|
position[index + 1] *= sy;
|
||||||
|
position[index + 2] *= sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel translate(
|
||||||
|
int start, int count,
|
||||||
|
float dx, float dy, float dz
|
||||||
|
) {
|
||||||
|
int end = start + count, index;
|
||||||
|
for (int face = start; face < end; face++) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
index = face * FI_POSITION + i * 3;
|
||||||
|
position[index ] += dx;
|
||||||
|
position[index + 1] += dy;
|
||||||
|
position[index + 2] += dz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel transform(int start, int count, MatrixM3f t) {
|
||||||
|
return transform(start, count,
|
||||||
|
t.m00, t.m01, t.m02,
|
||||||
|
t.m10, t.m11, t.m12,
|
||||||
|
t.m20, t.m21, t.m22
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel transform(
|
||||||
|
int start, int count,
|
||||||
|
float m00, float m01, float m02,
|
||||||
|
float m10, float m11, float m12,
|
||||||
|
float m20, float m21, float m22
|
||||||
|
) {
|
||||||
|
return transform(start, count,
|
||||||
|
m00, m01, m02, 0,
|
||||||
|
m10, m11, m12, 0,
|
||||||
|
m20, m21, m22, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel transform(int start, int count, MatrixM4f t) {
|
||||||
|
return transform(start, count,
|
||||||
|
t.m00, t.m01, t.m02, t.m03,
|
||||||
|
t.m10, t.m11, t.m12, t.m13,
|
||||||
|
t.m20, t.m21, t.m22, t.m23,
|
||||||
|
t.m30, t.m31, t.m32, t.m33
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel transform(
|
||||||
|
int start, int count,
|
||||||
|
float m00, float m01, float m02, float m03,
|
||||||
|
float m10, float m11, float m12, float m13,
|
||||||
|
float m20, float m21, float m22, float m23,
|
||||||
|
float m30, float m31, float m32, float m33
|
||||||
|
) {
|
||||||
|
int end = start + count, index;
|
||||||
|
float x, y, z;
|
||||||
|
for (int face = start; face < end; face++) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
index = face * FI_POSITION + i * 3;
|
||||||
|
x = position[index ];
|
||||||
|
y = position[index + 1];
|
||||||
|
z = position[index + 2];
|
||||||
|
|
||||||
|
position[index ] = m00 * x + m01 * y + m02 * z + m03;
|
||||||
|
position[index + 1] = m10 * x + m11 * y + m12 * z + m13;
|
||||||
|
position[index + 2] = m20 * x + m21 * y + m22 * z + m23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel reset(int size) {
|
||||||
|
this.size = size;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayTileModel clear() {
|
||||||
|
this.size = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureCapacity(int count) {
|
||||||
|
if (size + count > capacity){
|
||||||
|
float[] _position = position;
|
||||||
|
float[] _color = color, _uv = uv, _ao = ao;
|
||||||
|
byte[] _sunlight = sunlight, _blocklight = blocklight;
|
||||||
|
int[] _materialIndex = materialIndex;
|
||||||
|
|
||||||
|
int newCapacity = (int) (capacity * GROW_MULTIPLIER) + count;
|
||||||
|
setCapacity(newCapacity);
|
||||||
|
|
||||||
|
System.arraycopy(_position, 0, position, 0, size * FI_POSITION);
|
||||||
|
System.arraycopy(_uv, 0, uv, 0, size * FI_UV);
|
||||||
|
System.arraycopy(_ao, 0, ao, 0, size * FI_AO);
|
||||||
|
|
||||||
|
System.arraycopy(_color, 0, color, 0, size * FI_COLOR);
|
||||||
|
System.arraycopy(_sunlight, 0, sunlight, 0, size * FI_SUNLIGHT);
|
||||||
|
System.arraycopy(_blocklight, 0, blocklight, 0, size * FI_BLOCKLIGHT);
|
||||||
|
System.arraycopy(_materialIndex, 0, materialIndex, 0, size * FI_MATERIAL_INDEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCapacity(int capacity) {
|
||||||
|
this.capacity = capacity;
|
||||||
|
|
||||||
|
// attributes capacity * per-vertex * per-face
|
||||||
|
position = new float [capacity * FI_POSITION];
|
||||||
|
uv = new float [capacity * FI_UV];
|
||||||
|
ao = new float [capacity * FI_AO];
|
||||||
|
|
||||||
|
color = new float [capacity * FI_COLOR];
|
||||||
|
sunlight = new byte [capacity * FI_SUNLIGHT];
|
||||||
|
blocklight = new byte [capacity * FI_BLOCKLIGHT];
|
||||||
|
materialIndex = new int [capacity * FI_MATERIAL_INDEX];
|
||||||
|
|
||||||
|
materialIndexSort = new int[materialIndex.length];
|
||||||
|
materialIndexSortSupport = new int [materialIndex.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort() {
|
||||||
|
if (size <= 1) return; // nothing to sort
|
||||||
|
|
||||||
|
// initialize material-index-sort
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
materialIndexSort[i] = i;
|
||||||
|
materialIndexSortSupport[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort
|
||||||
|
MergeSort.mergeSortInt(materialIndexSort, 0, size, this::compareMaterialIndex, materialIndexSortSupport);
|
||||||
|
|
||||||
|
// move
|
||||||
|
int s, c;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
s = materialIndexSort[i]; c = 0;
|
||||||
|
while (s < i) {
|
||||||
|
s = materialIndexSort[s];
|
||||||
|
|
||||||
|
// should never happen, just making absolutely sure this can't get stuck in an endless loop
|
||||||
|
if (c++ > size) throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
swap(i, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int compareMaterialIndex(int i1, int i2) {
|
||||||
|
return Integer.compare(materialIndex[i1], materialIndex[i2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap(int face1, int face2) {
|
||||||
|
int i, if1, if2, vi;
|
||||||
|
float vf;
|
||||||
|
byte vb;
|
||||||
|
|
||||||
|
//swap positions
|
||||||
|
if1 = face1 * FI_POSITION;
|
||||||
|
if2 = face2 * FI_POSITION;
|
||||||
|
for (i = 0; i < FI_POSITION; i++){
|
||||||
|
vf = position[if1 + i];
|
||||||
|
position[if1 + i] = position[if2 + i];
|
||||||
|
position[if2 + i] = vf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//swap uv
|
||||||
|
if1 = face1 * FI_UV;
|
||||||
|
if2 = face2 * FI_UV;
|
||||||
|
for (i = 0; i < FI_UV; i++){
|
||||||
|
vf = uv[if1 + i];
|
||||||
|
uv[if1 + i] = uv[if2 + i];
|
||||||
|
uv[if2 + i] = vf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//swap ao
|
||||||
|
if1 = face1 * FI_AO;
|
||||||
|
if2 = face2 * FI_AO;
|
||||||
|
for (i = 0; i < FI_AO; i++){
|
||||||
|
vf = ao[if1 + i];
|
||||||
|
ao[if1 + i] = ao[if2 + i];
|
||||||
|
ao[if2 + i] = vf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//swap color
|
||||||
|
if1 = face1 * FI_COLOR;
|
||||||
|
if2 = face2 * FI_COLOR;
|
||||||
|
for (i = 0; i < FI_COLOR; i++){
|
||||||
|
vf = color[if1 + i];
|
||||||
|
color[if1 + i] = color[if2 + i];
|
||||||
|
color[if2 + i] = vf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//swap sunlight (assuming FI_SUNLIGHT = 1)
|
||||||
|
vb = sunlight[face1];
|
||||||
|
sunlight[face1] = sunlight[face2];
|
||||||
|
sunlight[face2] = vb;
|
||||||
|
|
||||||
|
//swap blocklight (assuming FI_BLOCKLIGHT = 1)
|
||||||
|
vb = blocklight[face1];
|
||||||
|
blocklight[face1] = blocklight[face2];
|
||||||
|
blocklight[face2] = vb;
|
||||||
|
|
||||||
|
//swap material-index (assuming FI_MATERIAL_INDEX = 1)
|
||||||
|
vi = materialIndex[face1];
|
||||||
|
materialIndex[face1] = materialIndex[face2];
|
||||||
|
materialIndex[face2] = vi;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InstancePool<ArrayTileModel> instancePool() {
|
||||||
|
return INSTANCE_POOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -68,16 +68,19 @@ public void render(World world, Vector2i tile, TileMetaConsumer tileMetaConsumer
|
|||||||
Vector3i modelMin = new Vector3i(tileMin.getX(), Integer.MIN_VALUE, tileMin.getY());
|
Vector3i modelMin = new Vector3i(tileMin.getX(), Integer.MIN_VALUE, tileMin.getY());
|
||||||
Vector3i modelMax = new Vector3i(tileMax.getX(), Integer.MAX_VALUE, tileMax.getY());
|
Vector3i modelMax = new Vector3i(tileMax.getX(), Integer.MAX_VALUE, tileMax.getY());
|
||||||
|
|
||||||
TileModel model = TileModel.instancePool().claimInstance();
|
if (save) {
|
||||||
|
ArrayTileModel model = ArrayTileModel.instancePool().claimInstance();
|
||||||
|
|
||||||
renderer.render(world, modelMin, modelMax, model, tileMetaConsumer);
|
renderer.render(world, modelMin, modelMax, model, tileMetaConsumer);
|
||||||
|
|
||||||
if (save){
|
|
||||||
model.sort();
|
model.sort();
|
||||||
save(model, tile);
|
save(model, tile);
|
||||||
|
|
||||||
|
ArrayTileModel.instancePool().recycleInstance(model);
|
||||||
|
} else {
|
||||||
|
renderer.render(world, modelMin, modelMax, VoidTileModel.INSTANCE, tileMetaConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileModel.instancePool().recycleInstance(model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +100,7 @@ public void unrender(Vector2i tile, TileMetaConsumer tileMetaConsumer) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save(final TileModel model, Vector2i tile) {
|
private void save(final ArrayTileModel model, Vector2i tile) {
|
||||||
try (
|
try (
|
||||||
OutputStream out = storage.write(tile.getX(), tile.getY());
|
OutputStream out = storage.write(tile.getX(), tile.getY());
|
||||||
PRBMWriter modelWriter = new PRBMWriter(out)
|
PRBMWriter modelWriter = new PRBMWriter(out)
|
||||||
|
@ -90,9 +90,6 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel
|
|||||||
//update topBlockLight
|
//update topBlockLight
|
||||||
topBlockLight = Math.max(topBlockLight, block.getBlockLightLevel() * (1 - columnColor.a));
|
topBlockLight = Math.max(topBlockLight, block.getBlockLightLevel() * (1 - columnColor.a));
|
||||||
|
|
||||||
// skip empty blocks
|
|
||||||
if (blockModel.getSize() <= 0) continue;
|
|
||||||
|
|
||||||
// move block-model to correct position
|
// move block-model to correct position
|
||||||
blockModel.translate(x - modelAnchor.getX(), y - modelAnchor.getY(), z - modelAnchor.getZ());
|
blockModel.translate(x - modelAnchor.getX(), y - modelAnchor.getY(), z - modelAnchor.getZ());
|
||||||
|
|
||||||
@ -102,7 +99,8 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel
|
|||||||
columnColor.underlay(blockColor.premultiplied());
|
columnColor.underlay(blockColor.premultiplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (blockColor.a > 0.999 && block.getProperties().isCulling()) break;
|
if (renderSettings.isRenderTopOnly() && blockColor.a > 0.999 && block.getProperties().isCulling())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public PRBMWriter(OutputStream out) {
|
|||||||
this.out = new CountingOutputStream(out);
|
this.out = new CountingOutputStream(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(TileModel model) throws IOException {
|
public void write(ArrayTileModel model) throws IOException {
|
||||||
out.write(FORMAT_VERSION); // version - 1 byte
|
out.write(FORMAT_VERSION); // version - 1 byte
|
||||||
out.write(HEADER_BITS); // format info - 1 byte
|
out.write(HEADER_BITS); // format info - 1 byte
|
||||||
write3byteValue(model.size * 3); // number of values - 3 bytes
|
write3byteValue(model.size * 3); // number of values - 3 bytes
|
||||||
@ -85,7 +85,7 @@ public void close() throws IOException {
|
|||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writePositionArray(TileModel model) throws IOException {
|
private void writePositionArray(ArrayTileModel model) throws IOException {
|
||||||
float[] position = model.position;
|
float[] position = model.position;
|
||||||
|
|
||||||
writeString("position");
|
writeString("position");
|
||||||
@ -98,13 +98,13 @@ private void writePositionArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int posSize = model.size * TileModel.FI_POSITION;
|
int posSize = model.size * ArrayTileModel.FI_POSITION;
|
||||||
for (int i = 0; i < posSize; i++) {
|
for (int i = 0; i < posSize; i++) {
|
||||||
writeFloat(position[i]);
|
writeFloat(position[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeNormalArray(TileModel model) throws IOException {
|
private void writeNormalArray(ArrayTileModel model) throws IOException {
|
||||||
VectorM3f normal = new VectorM3f(0, 0, 0);
|
VectorM3f normal = new VectorM3f(0, 0, 0);
|
||||||
float[] position = model.position;
|
float[] position = model.position;
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ private void writeNormalArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
int pi, i, j;
|
int pi, i, j;
|
||||||
for (i = 0; i < model.size; i++) {
|
for (i = 0; i < model.size; i++) {
|
||||||
pi = i * TileModel.FI_POSITION;
|
pi = i * ArrayTileModel.FI_POSITION;
|
||||||
calculateSurfaceNormal(
|
calculateSurfaceNormal(
|
||||||
position[pi], position[pi + 1], position[pi + 2],
|
position[pi], position[pi + 1], position[pi + 2],
|
||||||
position[pi + 3], position[pi + 4], position[pi + 5],
|
position[pi + 3], position[pi + 4], position[pi + 5],
|
||||||
@ -136,7 +136,7 @@ private void writeNormalArray(TileModel model) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeColorArray(TileModel model) throws IOException {
|
private void writeColorArray(ArrayTileModel model) throws IOException {
|
||||||
float[] color = model.color;
|
float[] color = model.color;
|
||||||
|
|
||||||
writeString("color");
|
writeString("color");
|
||||||
@ -149,7 +149,7 @@ private void writeColorArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int colorSize = model.size * TileModel.FI_COLOR, i, j;
|
int colorSize = model.size * ArrayTileModel.FI_COLOR, i, j;
|
||||||
for (i = 0; i < colorSize; i += 3) {
|
for (i = 0; i < colorSize; i += 3) {
|
||||||
for (j = 0; j < 3; j++) {
|
for (j = 0; j < 3; j++) {
|
||||||
writeNormalizedUnsignedByteValue(color[i]);
|
writeNormalizedUnsignedByteValue(color[i]);
|
||||||
@ -159,7 +159,7 @@ private void writeColorArray(TileModel model) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeUvArray(TileModel model) throws IOException {
|
private void writeUvArray(ArrayTileModel model) throws IOException {
|
||||||
float[] uv = model.uv;
|
float[] uv = model.uv;
|
||||||
|
|
||||||
writeString("uv");
|
writeString("uv");
|
||||||
@ -172,13 +172,13 @@ private void writeUvArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int uvSize = model.size * TileModel.FI_UV;
|
int uvSize = model.size * ArrayTileModel.FI_UV;
|
||||||
for (int i = 0; i < uvSize; i++) {
|
for (int i = 0; i < uvSize; i++) {
|
||||||
writeFloat(uv[i]);
|
writeFloat(uv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAoArray(TileModel model) throws IOException {
|
private void writeAoArray(ArrayTileModel model) throws IOException {
|
||||||
float[] ao = model.ao;
|
float[] ao = model.ao;
|
||||||
|
|
||||||
writeString("ao");
|
writeString("ao");
|
||||||
@ -191,13 +191,13 @@ private void writeAoArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int uvSize = model.size * TileModel.FI_AO;
|
int uvSize = model.size * ArrayTileModel.FI_AO;
|
||||||
for (int i = 0; i < uvSize; i++) {
|
for (int i = 0; i < uvSize; i++) {
|
||||||
writeNormalizedUnsignedByteValue(ao[i]);
|
writeNormalizedUnsignedByteValue(ao[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeBlocklightArray(TileModel model) throws IOException {
|
private void writeBlocklightArray(ArrayTileModel model) throws IOException {
|
||||||
byte[] blocklight = model.blocklight;
|
byte[] blocklight = model.blocklight;
|
||||||
|
|
||||||
writeString("blocklight");
|
writeString("blocklight");
|
||||||
@ -210,7 +210,7 @@ private void writeBlocklightArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int blSize = model.size * TileModel.FI_BLOCKLIGHT;
|
int blSize = model.size * ArrayTileModel.FI_BLOCKLIGHT;
|
||||||
for (int i = 0; i < blSize; i++) {
|
for (int i = 0; i < blSize; i++) {
|
||||||
out.write(blocklight[i]);
|
out.write(blocklight[i]);
|
||||||
out.write(blocklight[i]);
|
out.write(blocklight[i]);
|
||||||
@ -218,7 +218,7 @@ private void writeBlocklightArray(TileModel model) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeSunlightArray(TileModel model) throws IOException {
|
private void writeSunlightArray(ArrayTileModel model) throws IOException {
|
||||||
byte[] sunlight = model.sunlight;
|
byte[] sunlight = model.sunlight;
|
||||||
|
|
||||||
writeString("sunlight");
|
writeString("sunlight");
|
||||||
@ -231,7 +231,7 @@ private void writeSunlightArray(TileModel model) throws IOException {
|
|||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
int slSize = model.size * TileModel.FI_SUNLIGHT;
|
int slSize = model.size * ArrayTileModel.FI_SUNLIGHT;
|
||||||
for (int i = 0; i < slSize; i++) {
|
for (int i = 0; i < slSize; i++) {
|
||||||
out.write(sunlight[i]);
|
out.write(sunlight[i]);
|
||||||
out.write(sunlight[i]);
|
out.write(sunlight[i]);
|
||||||
@ -239,14 +239,14 @@ private void writeSunlightArray(TileModel model) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeMaterialGroups(TileModel model) throws IOException {
|
private void writeMaterialGroups(ArrayTileModel model) throws IOException {
|
||||||
|
|
||||||
writePadding();
|
writePadding();
|
||||||
|
|
||||||
if (model.size > 0) {
|
if (model.size > 0) {
|
||||||
int[] materialIndex = model.materialIndex;
|
int[] materialIndex = model.materialIndex;
|
||||||
|
|
||||||
int miSize = model.size * TileModel.FI_MATERIAL_INDEX,
|
int miSize = model.size * ArrayTileModel.FI_MATERIAL_INDEX,
|
||||||
lastMaterial = materialIndex[0],
|
lastMaterial = materialIndex[0],
|
||||||
material = lastMaterial, groupStart = 0;
|
material = lastMaterial, groupStart = 0;
|
||||||
|
|
||||||
|
@ -125,4 +125,6 @@ default Predicate<Vector2i> getCellRenderBoundariesFilter(Grid grid, boolean all
|
|||||||
|
|
||||||
boolean isSaveHiresLayer();
|
boolean isSaveHiresLayer();
|
||||||
|
|
||||||
|
boolean isRenderTopOnly();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,480 +1,92 @@
|
|||||||
/*
|
|
||||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
|
||||||
* Copyright (c) contributors
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
package de.bluecolored.bluemap.core.map.hires;
|
package de.bluecolored.bluemap.core.map.hires;
|
||||||
|
|
||||||
import com.flowpowered.math.TrigMath;
|
|
||||||
import de.bluecolored.bluemap.core.util.InstancePool;
|
|
||||||
import de.bluecolored.bluemap.core.util.MergeSort;
|
|
||||||
import de.bluecolored.bluemap.core.util.math.MatrixM3f;
|
import de.bluecolored.bluemap.core.util.math.MatrixM3f;
|
||||||
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
|
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
|
||||||
|
|
||||||
public class TileModel {
|
public interface TileModel {
|
||||||
private static final double GROW_MULTIPLIER = 1.5;
|
|
||||||
|
|
||||||
// attributes per-vertex * per-face
|
int size();
|
||||||
static final int
|
|
||||||
FI_POSITION = 3 * 3,
|
|
||||||
FI_UV = 2 * 3,
|
|
||||||
FI_AO = 3,
|
|
||||||
FI_COLOR = 3 ,
|
|
||||||
FI_SUNLIGHT = 1 ,
|
|
||||||
FI_BLOCKLIGHT = 1 ,
|
|
||||||
FI_MATERIAL_INDEX = 1 ;
|
|
||||||
|
|
||||||
private static final InstancePool<TileModel> INSTANCE_POOL = new InstancePool<>(
|
int add(int count);
|
||||||
() -> new TileModel(100),
|
|
||||||
TileModel::clear
|
|
||||||
);
|
|
||||||
|
|
||||||
private int capacity;
|
TileModel setPositions(
|
||||||
int size;
|
|
||||||
|
|
||||||
float[] position;
|
|
||||||
float[] color, uv, ao;
|
|
||||||
byte[] sunlight, blocklight;
|
|
||||||
int[] materialIndex, materialIndexSort, materialIndexSortSupport;
|
|
||||||
|
|
||||||
float[] indexedPosition;
|
|
||||||
int[] positionIndex;
|
|
||||||
|
|
||||||
public TileModel(int initialCapacity) {
|
|
||||||
if (initialCapacity < 0) throw new IllegalArgumentException("initialCapacity is negative");
|
|
||||||
setCapacity(initialCapacity);
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int add(int count) {
|
|
||||||
ensureCapacity(count);
|
|
||||||
int start = this.size;
|
|
||||||
this.size += count;
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setPositions(
|
|
||||||
int face,
|
int face,
|
||||||
float x1, float y1, float z1,
|
float x1, float y1, float z1,
|
||||||
float x2, float y2, float z2,
|
float x2, float y2, float z2,
|
||||||
float x3, float y3, float z3
|
float x3, float y3, float z3
|
||||||
){
|
);
|
||||||
int index = face * FI_POSITION;
|
|
||||||
|
|
||||||
position[index ] = x1;
|
TileModel setUvs(
|
||||||
position[index + 1] = y1;
|
|
||||||
position[index + 2] = z1;
|
|
||||||
|
|
||||||
position[index + 3 ] = x2;
|
|
||||||
position[index + 3 + 1] = y2;
|
|
||||||
position[index + 3 + 2] = z2;
|
|
||||||
|
|
||||||
position[index + 6 ] = x3;
|
|
||||||
position[index + 6 + 1] = y3;
|
|
||||||
position[index + 6 + 2] = z3;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setUvs(
|
|
||||||
int face,
|
int face,
|
||||||
float u1, float v1,
|
float u1, float v1,
|
||||||
float u2, float v2,
|
float u2, float v2,
|
||||||
float u3, float v3
|
float u3, float v3
|
||||||
){
|
);
|
||||||
int index = face * FI_UV;
|
|
||||||
|
|
||||||
uv[index ] = u1;
|
TileModel setAOs(
|
||||||
uv[index + 1] = v1;
|
|
||||||
|
|
||||||
uv[index + 2 ] = u2;
|
|
||||||
uv[index + 2 + 1] = v2;
|
|
||||||
|
|
||||||
uv[index + 4 ] = u3;
|
|
||||||
uv[index + 4 + 1] = v3;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setAOs(
|
|
||||||
int face,
|
int face,
|
||||||
float ao1, float ao2, float ao3
|
float ao1, float ao2, float ao3
|
||||||
) {
|
);
|
||||||
int index = face * FI_AO;
|
|
||||||
|
|
||||||
ao[index ] = ao1;
|
TileModel setColor(
|
||||||
ao[index + 1] = ao2;
|
|
||||||
ao[index + 2] = ao3;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setColor(
|
|
||||||
int face,
|
int face,
|
||||||
float r, float g, float b
|
float r, float g, float b
|
||||||
){
|
);
|
||||||
int index = face * FI_COLOR;
|
|
||||||
|
|
||||||
color[index ] = r;
|
TileModel setSunlight(int face, int sl);
|
||||||
color[index + 1] = g;
|
|
||||||
color[index + 2] = b;
|
|
||||||
|
|
||||||
return this;
|
TileModel setBlocklight(int face, int bl);
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setSunlight(int face, int sl) {
|
TileModel setMaterialIndex(int face, int m);
|
||||||
sunlight[face * FI_SUNLIGHT] = (byte) sl;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setBlocklight(int face, int bl) {
|
TileModel rotate(
|
||||||
blocklight[face * FI_BLOCKLIGHT] = (byte) bl;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel setMaterialIndex(int face, int m) {
|
|
||||||
materialIndex[face * FI_MATERIAL_INDEX] = m;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel rotate(
|
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float angle, float axisX, float axisY, float axisZ
|
float angle, float axisX, float axisY, float axisZ
|
||||||
) {
|
);
|
||||||
|
|
||||||
// create quaternion
|
TileModel rotate(
|
||||||
double halfAngle = Math.toRadians(angle) * 0.5;
|
|
||||||
double q = TrigMath.sin(halfAngle) / Math.sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
|
|
||||||
|
|
||||||
double //quaternion
|
|
||||||
qx = axisX * q,
|
|
||||||
qy = axisY * q,
|
|
||||||
qz = axisZ * q,
|
|
||||||
qw = TrigMath.cos(halfAngle),
|
|
||||||
qLength = Math.sqrt(qx * qx + qy * qy + qz * qz + qw * qw);
|
|
||||||
|
|
||||||
// normalize quaternion
|
|
||||||
qx /= qLength;
|
|
||||||
qy /= qLength;
|
|
||||||
qz /= qLength;
|
|
||||||
qw /= qLength;
|
|
||||||
|
|
||||||
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel rotate(
|
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float pitch, float yaw, float roll
|
float pitch, float yaw, float roll
|
||||||
) {
|
);
|
||||||
|
|
||||||
double
|
TileModel rotateByQuaternion(
|
||||||
halfYaw = Math.toRadians(yaw) * 0.5,
|
|
||||||
qy1 = TrigMath.sin(halfYaw),
|
|
||||||
qw1 = TrigMath.cos(halfYaw),
|
|
||||||
|
|
||||||
halfPitch = Math.toRadians(pitch) * 0.5,
|
|
||||||
qx2 = TrigMath.sin(halfPitch),
|
|
||||||
qw2 = TrigMath.cos(halfPitch),
|
|
||||||
|
|
||||||
halfRoll = Math.toRadians(roll) * 0.5,
|
|
||||||
qz3 = TrigMath.sin(halfRoll),
|
|
||||||
qw3 = TrigMath.cos(halfRoll);
|
|
||||||
|
|
||||||
// multiply 1 with 2
|
|
||||||
double
|
|
||||||
qxA = qw1 * qx2,
|
|
||||||
qyA = qy1 * qw2,
|
|
||||||
qzA = - qy1 * qx2,
|
|
||||||
qwA = qw1 * qw2;
|
|
||||||
|
|
||||||
// multiply with 3
|
|
||||||
double
|
|
||||||
qx = qxA * qw3 + qyA * qz3,
|
|
||||||
qy = qyA * qw3 - qxA * qz3,
|
|
||||||
qz = qwA * qz3 + qzA * qw3,
|
|
||||||
qw = qwA * qw3 - qzA * qz3;
|
|
||||||
|
|
||||||
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel rotateByQuaternion(
|
|
||||||
int start, int count,
|
int start, int count,
|
||||||
double qx, double qy, double qz, double qw
|
double qx, double qy, double qz, double qw
|
||||||
) {
|
);
|
||||||
double x, y, z, px, py, pz, pw;
|
|
||||||
int end = start + count, index;
|
|
||||||
for (int face = start; face < end; face++) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
index = face * FI_POSITION + i * 3;
|
|
||||||
|
|
||||||
x = position[index];
|
TileModel scale(
|
||||||
y = position[index + 1];
|
|
||||||
z = position[index + 2];
|
|
||||||
|
|
||||||
px = qw * x + qy * z - qz * y;
|
|
||||||
py = qw * y + qz * x - qx * z;
|
|
||||||
pz = qw * z + qx * y - qy * x;
|
|
||||||
pw = -qx * x - qy * y - qz * z;
|
|
||||||
|
|
||||||
position[index] = (float) (pw * -qx + px * qw - py * qz + pz * qy);
|
|
||||||
position[index + 1] = (float) (pw * -qy + py * qw - pz * qx + px * qz);
|
|
||||||
position[index + 2] = (float) (pw * -qz + pz * qw - px * qy + py * qx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel scale(
|
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float sx, float sy, float sz
|
float sx, float sy, float sz
|
||||||
) {
|
);
|
||||||
int end = start + count, index;
|
|
||||||
for (int face = start; face < end; face++) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
index = face * FI_POSITION + i * 3;
|
|
||||||
position[index ] *= sx;
|
|
||||||
position[index + 1] *= sy;
|
|
||||||
position[index + 2] *= sz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
TileModel translate(
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel translate(
|
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float dx, float dy, float dz
|
float dx, float dy, float dz
|
||||||
) {
|
|
||||||
int end = start + count, index;
|
|
||||||
for (int face = start; face < end; face++) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
index = face * FI_POSITION + i * 3;
|
|
||||||
position[index ] += dx;
|
|
||||||
position[index + 1] += dy;
|
|
||||||
position[index + 2] += dz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel transform(int start, int count, MatrixM3f t) {
|
|
||||||
return transform(start, count,
|
|
||||||
t.m00, t.m01, t.m02,
|
|
||||||
t.m10, t.m11, t.m12,
|
|
||||||
t.m20, t.m21, t.m22
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel transform(
|
TileModel transform(int start, int count, MatrixM3f t);
|
||||||
|
|
||||||
|
TileModel transform(
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float m00, float m01, float m02,
|
float m00, float m01, float m02,
|
||||||
float m10, float m11, float m12,
|
float m10, float m11, float m12,
|
||||||
float m20, float m21, float m22
|
float m20, float m21, float m22
|
||||||
) {
|
|
||||||
return transform(start, count,
|
|
||||||
m00, m01, m02, 0,
|
|
||||||
m10, m11, m12, 0,
|
|
||||||
m20, m21, m22, 0,
|
|
||||||
0, 0, 0, 1
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel transform(int start, int count, MatrixM4f t) {
|
TileModel transform(int start, int count, MatrixM4f t);
|
||||||
return transform(start, count,
|
|
||||||
t.m00, t.m01, t.m02, t.m03,
|
|
||||||
t.m10, t.m11, t.m12, t.m13,
|
|
||||||
t.m20, t.m21, t.m22, t.m23,
|
|
||||||
t.m30, t.m31, t.m32, t.m33
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel transform(
|
TileModel transform(
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float m00, float m01, float m02, float m03,
|
float m00, float m01, float m02, float m03,
|
||||||
float m10, float m11, float m12, float m13,
|
float m10, float m11, float m12, float m13,
|
||||||
float m20, float m21, float m22, float m23,
|
float m20, float m21, float m22, float m23,
|
||||||
float m30, float m31, float m32, float m33
|
float m30, float m31, float m32, float m33
|
||||||
) {
|
);
|
||||||
int end = start + count, index;
|
|
||||||
float x, y, z;
|
|
||||||
for (int face = start; face < end; face++) {
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
index = face * FI_POSITION + i * 3;
|
|
||||||
x = position[index ];
|
|
||||||
y = position[index + 1];
|
|
||||||
z = position[index + 2];
|
|
||||||
|
|
||||||
position[index ] = m00 * x + m01 * y + m02 * z + m03;
|
TileModel reset(int size);
|
||||||
position[index + 1] = m10 * x + m11 * y + m12 * z + m13;
|
|
||||||
position[index + 2] = m20 * x + m21 * y + m22 * z + m23;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
TileModel clear();
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel reset(int size) {
|
void sort();
|
||||||
this.size = size;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileModel clear() {
|
|
||||||
this.size = 0;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureCapacity(int count) {
|
|
||||||
if (size + count > capacity){
|
|
||||||
float[] _position = position;
|
|
||||||
float[] _color = color, _uv = uv, _ao = ao;
|
|
||||||
byte[] _sunlight = sunlight, _blocklight = blocklight;
|
|
||||||
int[] _materialIndex = materialIndex;
|
|
||||||
|
|
||||||
int newCapacity = (int) (capacity * GROW_MULTIPLIER) + count;
|
|
||||||
setCapacity(newCapacity);
|
|
||||||
|
|
||||||
System.arraycopy(_position, 0, position, 0, size * FI_POSITION);
|
|
||||||
System.arraycopy(_uv, 0, uv, 0, size * FI_UV);
|
|
||||||
System.arraycopy(_ao, 0, ao, 0, size * FI_AO);
|
|
||||||
|
|
||||||
System.arraycopy(_color, 0, color, 0, size * FI_COLOR);
|
|
||||||
System.arraycopy(_sunlight, 0, sunlight, 0, size * FI_SUNLIGHT);
|
|
||||||
System.arraycopy(_blocklight, 0, blocklight, 0, size * FI_BLOCKLIGHT);
|
|
||||||
System.arraycopy(_materialIndex, 0, materialIndex, 0, size * FI_MATERIAL_INDEX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCapacity(int capacity) {
|
|
||||||
this.capacity = capacity;
|
|
||||||
|
|
||||||
// attributes capacity * per-vertex * per-face
|
|
||||||
position = new float [capacity * FI_POSITION];
|
|
||||||
uv = new float [capacity * FI_UV];
|
|
||||||
ao = new float [capacity * FI_AO];
|
|
||||||
|
|
||||||
color = new float [capacity * FI_COLOR];
|
|
||||||
sunlight = new byte [capacity * FI_SUNLIGHT];
|
|
||||||
blocklight = new byte [capacity * FI_BLOCKLIGHT];
|
|
||||||
materialIndex = new int [capacity * FI_MATERIAL_INDEX];
|
|
||||||
|
|
||||||
materialIndexSort = new int[materialIndex.length];
|
|
||||||
materialIndexSortSupport = new int [materialIndex.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sort() {
|
|
||||||
if (size <= 1) return; // nothing to sort
|
|
||||||
|
|
||||||
// initialize material-index-sort
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
materialIndexSort[i] = i;
|
|
||||||
materialIndexSortSupport[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort
|
|
||||||
MergeSort.mergeSortInt(materialIndexSort, 0, size, this::compareMaterialIndex, materialIndexSortSupport);
|
|
||||||
|
|
||||||
// move
|
|
||||||
int s, c;
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
s = materialIndexSort[i]; c = 0;
|
|
||||||
while (s < i) {
|
|
||||||
s = materialIndexSort[s];
|
|
||||||
|
|
||||||
// should never happen, just making absolutely sure this can't get stuck in an endless loop
|
|
||||||
if (c++ > size) throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
swap(i, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int compareMaterialIndex(int i1, int i2) {
|
|
||||||
return Integer.compare(materialIndex[i1], materialIndex[i2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void swap(int face1, int face2) {
|
|
||||||
int i, if1, if2, vi;
|
|
||||||
float vf;
|
|
||||||
byte vb;
|
|
||||||
|
|
||||||
//swap positions
|
|
||||||
if1 = face1 * FI_POSITION;
|
|
||||||
if2 = face2 * FI_POSITION;
|
|
||||||
for (i = 0; i < FI_POSITION; i++){
|
|
||||||
vf = position[if1 + i];
|
|
||||||
position[if1 + i] = position[if2 + i];
|
|
||||||
position[if2 + i] = vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//swap uv
|
|
||||||
if1 = face1 * FI_UV;
|
|
||||||
if2 = face2 * FI_UV;
|
|
||||||
for (i = 0; i < FI_UV; i++){
|
|
||||||
vf = uv[if1 + i];
|
|
||||||
uv[if1 + i] = uv[if2 + i];
|
|
||||||
uv[if2 + i] = vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//swap ao
|
|
||||||
if1 = face1 * FI_AO;
|
|
||||||
if2 = face2 * FI_AO;
|
|
||||||
for (i = 0; i < FI_AO; i++){
|
|
||||||
vf = ao[if1 + i];
|
|
||||||
ao[if1 + i] = ao[if2 + i];
|
|
||||||
ao[if2 + i] = vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//swap color
|
|
||||||
if1 = face1 * FI_COLOR;
|
|
||||||
if2 = face2 * FI_COLOR;
|
|
||||||
for (i = 0; i < FI_COLOR; i++){
|
|
||||||
vf = color[if1 + i];
|
|
||||||
color[if1 + i] = color[if2 + i];
|
|
||||||
color[if2 + i] = vf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//swap sunlight (assuming FI_SUNLIGHT = 1)
|
|
||||||
vb = sunlight[face1];
|
|
||||||
sunlight[face1] = sunlight[face2];
|
|
||||||
sunlight[face2] = vb;
|
|
||||||
|
|
||||||
//swap blocklight (assuming FI_BLOCKLIGHT = 1)
|
|
||||||
vb = blocklight[face1];
|
|
||||||
blocklight[face1] = blocklight[face2];
|
|
||||||
blocklight[face2] = vb;
|
|
||||||
|
|
||||||
//swap material-index (assuming FI_MATERIAL_INDEX = 1)
|
|
||||||
vi = materialIndex[face1];
|
|
||||||
materialIndex[face1] = materialIndex[face2];
|
|
||||||
materialIndex[face2] = vi;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InstancePool<TileModel> instancePool() {
|
|
||||||
return INSTANCE_POOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
package de.bluecolored.bluemap.core.map.hires;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.core.util.math.MatrixM3f;
|
||||||
|
import de.bluecolored.bluemap.core.util.math.MatrixM4f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An empty tile-model discarding any actions
|
||||||
|
*/
|
||||||
|
public class VoidTileModel implements TileModel {
|
||||||
|
|
||||||
|
public static final TileModel INSTANCE = new VoidTileModel();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int add(int count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setPositions(
|
||||||
|
int face,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
float x3, float y3, float z3
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setUvs(
|
||||||
|
int face,
|
||||||
|
float u1, float v1,
|
||||||
|
float u2, float v2,
|
||||||
|
float u3, float v3
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setAOs(
|
||||||
|
int face,
|
||||||
|
float ao1, float ao2, float ao3
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setColor(
|
||||||
|
int face,
|
||||||
|
float r, float g, float b
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setSunlight(int face, int sl) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setBlocklight(int face, int bl) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel setMaterialIndex(int face, int m) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel rotate(
|
||||||
|
int start, int count,
|
||||||
|
float angle,
|
||||||
|
float axisX, float axisY, float axisZ
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel rotate(
|
||||||
|
int start, int count,
|
||||||
|
float pitch, float yaw, float roll
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel rotateByQuaternion(
|
||||||
|
int start, int count,
|
||||||
|
double qx, double qy, double qz, double qw
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel scale(
|
||||||
|
int start, int count,
|
||||||
|
float sx, float sy, float sz
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel translate(
|
||||||
|
int start, int count,
|
||||||
|
float dx, float dy, float dz
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel transform(int start, int count, MatrixM3f t) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel transform(
|
||||||
|
int start, int count,
|
||||||
|
float m00, float m01, float m02,
|
||||||
|
float m10, float m11, float m12,
|
||||||
|
float m20, float m21, float m22
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel transform(int start, int count, MatrixM4f t) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel transform(
|
||||||
|
int start, int count,
|
||||||
|
float m00, float m01, float m02, float m03,
|
||||||
|
float m10, float m11, float m12, float m13,
|
||||||
|
float m20, float m21, float m22, float m23,
|
||||||
|
float m30, float m31, float m32, float m33
|
||||||
|
) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel reset(int size) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileModel clear() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sort() { }
|
||||||
|
|
||||||
|
}
|
@ -99,7 +99,7 @@ private void renderModel(BlockNeighborhood<?> block, BlockState blockState, Tile
|
|||||||
variantColor.set(0f, 0f, 0f, 0f, true);
|
variantColor.set(0f, 0f, 0f, 0f, true);
|
||||||
|
|
||||||
blockRenderers.get(modelResource.getRenderer())
|
blockRenderers.get(modelResource.getRenderer())
|
||||||
.render(block, variant, blockModel.initialize(), blockColor);
|
.render(block, variant, blockModel.initialize(), variantColor);
|
||||||
|
|
||||||
if (variantColor.a > blockColorOpacity)
|
if (variantColor.a > blockColorOpacity)
|
||||||
blockColorOpacity = variantColor.a;
|
blockColorOpacity = variantColor.a;
|
||||||
|
@ -203,7 +203,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
|
|||||||
makeRotationRelative(faceRotationVector);
|
makeRotationRelative(faceRotationVector);
|
||||||
|
|
||||||
// face culling
|
// face culling
|
||||||
//if (faceRotationVector.y < 0.01) return;
|
if (renderSettings.isRenderTopOnly() && faceRotationVector.y < 0.01) return;
|
||||||
if (face.getCullface() != null) {
|
if (face.getCullface() != null) {
|
||||||
ExtendedBlock<?> b = getRotationRelativeBlock(face.getCullface());
|
ExtendedBlock<?> b = getRotationRelativeBlock(face.getCullface());
|
||||||
BlockProperties p = b.getProperties();
|
BlockProperties p = b.getProperties();
|
||||||
|
@ -5,7 +5,7 @@ junit = "5.8.2"
|
|||||||
spongegradle = "2.2.0"
|
spongegradle = "2.2.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
aircompressor = { module = "io.airlift:aircompressor", version = "0.24" }
|
aircompressor = { module = "io.airlift:aircompressor", version = "0.27" }
|
||||||
bluenbt = { module = "de.bluecolored.bluenbt:BlueNBT", version = "3.0.1" }
|
bluenbt = { module = "de.bluecolored.bluenbt:BlueNBT", version = "3.0.1" }
|
||||||
brigadier = { module = "com.mojang:brigadier", version = "1.0.17" }
|
brigadier = { module = "com.mojang:brigadier", version = "1.0.17" }
|
||||||
bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" }
|
bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" }
|
||||||
|
Loading…
Reference in New Issue
Block a user