mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 10:35:16 +01:00
[breaking] Switch hires tile format to prbm (modified prwm)
This commit is contained in:
parent
3a1e723a51
commit
6e68a8f0e0
@ -33,9 +33,9 @@ dependencies {
|
|||||||
api ("de.bluecolored.bluemap.core:BlueMapCore")
|
api ("de.bluecolored.bluemap.core:BlueMapCore")
|
||||||
|
|
||||||
compileOnly ("org.jetbrains:annotations:16.0.2")
|
compileOnly ("org.jetbrains:annotations:16.0.2")
|
||||||
compileOnly ("org.projectlombok:lombok:1.18.28")
|
compileOnly ("org.projectlombok:lombok:1.18.30")
|
||||||
|
|
||||||
annotationProcessor ("org.projectlombok:lombok:1.18.28")
|
annotationProcessor ("org.projectlombok:lombok:1.18.30")
|
||||||
|
|
||||||
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
|
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||||
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||||
|
@ -133,18 +133,7 @@ public HttpResponse handle(HttpRequest request) {
|
|||||||
return new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR);
|
return new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.endsWith(".png")) {
|
return new HttpResponse(HttpStatusCode.NO_CONTENT);
|
||||||
return new HttpResponse(HttpStatusCode.NO_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.endsWith(".json")) {
|
|
||||||
HttpResponse response = new HttpResponse(HttpStatusCode.OK);
|
|
||||||
response.addHeader("Content-Type", "application/json");
|
|
||||||
response.setData("{}");
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String calculateETag(String path, TileInfo tileInfo) {
|
private String calculateETag(String path, TileInfo tileInfo) {
|
||||||
|
@ -23,13 +23,14 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import {pathFromCoords} from "../util/Utils";
|
import {pathFromCoords} from "../util/Utils";
|
||||||
import {BufferGeometryLoader, FileLoader, Mesh} from "three";
|
import {BufferGeometryLoader, FileLoader, Mesh, Material} from "three";
|
||||||
|
import {PRBMLoader} from "./hires/PRBMLoader";
|
||||||
|
|
||||||
export class TileLoader {
|
export class TileLoader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tilePath {string}
|
* @param tilePath {string}
|
||||||
* @param material {THREE.Material | THREE.Material[]}
|
* @param material {Material | Material[]}
|
||||||
* @param tileSettings {{
|
* @param tileSettings {{
|
||||||
* tileSize: {x: number, z: number},
|
* tileSize: {x: number, z: number},
|
||||||
* scale: {x: number, z: number},
|
* scale: {x: number, z: number},
|
||||||
@ -50,23 +51,17 @@ export class TileLoader {
|
|||||||
this.loadBlocker = loadBlocker;
|
this.loadBlocker = loadBlocker;
|
||||||
|
|
||||||
this.fileLoader = new FileLoader();
|
this.fileLoader = new FileLoader();
|
||||||
this.fileLoader.setResponseType('json');
|
this.fileLoader.setResponseType('arraybuffer');
|
||||||
|
|
||||||
this.bufferGeometryLoader = new BufferGeometryLoader();
|
this.bufferGeometryLoader = new PRBMLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
load = (tileX, tileZ, cancelCheck = () => false) => {
|
load = (tileX, tileZ, cancelCheck = () => false) => {
|
||||||
let tileUrl = this.tilePath + pathFromCoords(tileX, tileZ) + '.json';
|
let tileUrl = this.tilePath + pathFromCoords(tileX, tileZ) + '.prbm';
|
||||||
|
|
||||||
//await this.loadBlocker();
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.fileLoader.load(tileUrl + '?' + this.tileCacheHash,
|
this.fileLoader.load(tileUrl + '?' + this.tileCacheHash,
|
||||||
async json => {
|
async data => {
|
||||||
let geometryJson = json.tileGeometry || {};
|
|
||||||
if (!geometryJson.type || geometryJson.type !== 'BufferGeometry'){
|
|
||||||
reject({status: "empty"});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.loadBlocker();
|
await this.loadBlocker();
|
||||||
if (cancelCheck()){
|
if (cancelCheck()){
|
||||||
@ -74,7 +69,7 @@ export class TileLoader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let geometry = this.bufferGeometryLoader.parse(geometryJson);
|
let geometry = this.bufferGeometryLoader.parse(data);
|
||||||
|
|
||||||
let object = new Mesh(geometry, this.material);
|
let object = new Mesh(geometry, this.material);
|
||||||
|
|
||||||
|
307
BlueMapCommon/webapp/src/js/map/hires/PRBMLoader.js
Normal file
307
BlueMapCommon/webapp/src/js/map/hires/PRBMLoader.js
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||||
|
* Copyright (c) Kevin Chapelier <https://github.com/kchapelier>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Adapted version of PRWM by Kevin Chapelier
|
||||||
|
* See https://github.com/kchapelier/PRWM for more informations about this file format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
DefaultLoadingManager,
|
||||||
|
BufferGeometry,
|
||||||
|
BufferAttribute,
|
||||||
|
FloatType
|
||||||
|
} from "three"
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let bigEndianPlatform = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the endianness of the platform is big-endian (most significant bit first)
|
||||||
|
* @returns {boolean} True if big-endian, false if little-endian
|
||||||
|
*/
|
||||||
|
function isBigEndianPlatform() {
|
||||||
|
if ( bigEndianPlatform === null ) {
|
||||||
|
let buffer = new ArrayBuffer( 2 ),
|
||||||
|
uint8Array = new Uint8Array( buffer ),
|
||||||
|
uint16Array = new Uint16Array( buffer );
|
||||||
|
|
||||||
|
uint8Array[ 0 ] = 0xAA; // set first byte
|
||||||
|
uint8Array[ 1 ] = 0xBB; // set second byte
|
||||||
|
bigEndianPlatform = ( uint16Array[ 0 ] === 0xAABB );
|
||||||
|
}
|
||||||
|
|
||||||
|
return bigEndianPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// match the values defined in the spec to the TypedArray types
|
||||||
|
let InvertedEncodingTypes = [
|
||||||
|
null,
|
||||||
|
Float32Array,
|
||||||
|
null,
|
||||||
|
Int8Array,
|
||||||
|
Int16Array,
|
||||||
|
null,
|
||||||
|
Int32Array,
|
||||||
|
Uint8Array,
|
||||||
|
Uint16Array,
|
||||||
|
null,
|
||||||
|
Uint32Array
|
||||||
|
];
|
||||||
|
|
||||||
|
// define the method to use on a DataView, corresponding the TypedArray type
|
||||||
|
let getMethods = {
|
||||||
|
Uint16Array: 'getUint16',
|
||||||
|
Uint32Array: 'getUint32',
|
||||||
|
Int16Array: 'getInt16',
|
||||||
|
Int32Array: 'getInt32',
|
||||||
|
Float32Array: 'getFloat32',
|
||||||
|
Float64Array: 'getFloat64'
|
||||||
|
};
|
||||||
|
|
||||||
|
function copyFromBuffer( sourceArrayBuffer, viewType, position, length, fromBigEndian ) {
|
||||||
|
let bytesPerElement = viewType.BYTES_PER_ELEMENT,
|
||||||
|
result;
|
||||||
|
|
||||||
|
if ( fromBigEndian === isBigEndianPlatform() || bytesPerElement === 1 ) {
|
||||||
|
result = new viewType( sourceArrayBuffer, position, length );
|
||||||
|
} else {
|
||||||
|
console.debug("PRWM file has opposite encoding, loading will be slow...");
|
||||||
|
|
||||||
|
let readView = new DataView( sourceArrayBuffer, position, length * bytesPerElement ),
|
||||||
|
getMethod = getMethods[ viewType.name ],
|
||||||
|
littleEndian = ! fromBigEndian,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
result = new viewType( length );
|
||||||
|
|
||||||
|
for ( ; i < length; i ++ ) {
|
||||||
|
result[ i ] = readView[ getMethod ]( i * bytesPerElement, littleEndian );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param buffer {ArrayBuffer}
|
||||||
|
* @param offset {number}
|
||||||
|
*/
|
||||||
|
function decodePrwm( buffer, offset ) {
|
||||||
|
offset = offset || 0;
|
||||||
|
|
||||||
|
let array = new Uint8Array( buffer, offset ),
|
||||||
|
version = array[ 0 ],
|
||||||
|
flags = array[ 1 ],
|
||||||
|
indexedGeometry = !! ( flags >> 7 & 0x01 ),
|
||||||
|
indicesType = flags >> 6 & 0x01,
|
||||||
|
bigEndian = ( flags >> 5 & 0x01 ) === 1,
|
||||||
|
attributesNumber = flags & 0x1F,
|
||||||
|
valuesNumber = 0,
|
||||||
|
indicesNumber = 0;
|
||||||
|
|
||||||
|
if ( bigEndian ) {
|
||||||
|
valuesNumber = ( array[ 2 ] << 16 ) + ( array[ 3 ] << 8 ) + array[ 4 ];
|
||||||
|
indicesNumber = ( array[ 5 ] << 16 ) + ( array[ 6 ] << 8 ) + array[ 7 ];
|
||||||
|
} else {
|
||||||
|
valuesNumber = array[ 2 ] + ( array[ 3 ] << 8 ) + ( array[ 4 ] << 16 );
|
||||||
|
indicesNumber = array[ 5 ] + ( array[ 6 ] << 8 ) + ( array[ 7 ] << 16 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PRELIMINARY CHECKS **/
|
||||||
|
|
||||||
|
if ( offset / 4 % 1 !== 0 ) {
|
||||||
|
throw new Error( 'PRWM decoder: Offset should be a multiple of 4, received ' + offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( version === 0 ) {
|
||||||
|
throw new Error( 'PRWM decoder: Invalid format version: 0' );
|
||||||
|
} else if ( version !== 1 ) {
|
||||||
|
throw new Error( 'PRWM decoder: Unsupported format version: ' + version );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! indexedGeometry ) {
|
||||||
|
if ( indicesType !== 0 ) {
|
||||||
|
throw new Error( 'PRWM decoder: Indices type must be set to 0 for non-indexed geometries' );
|
||||||
|
} else if ( indicesNumber !== 0 ) {
|
||||||
|
throw new Error( 'PRWM decoder: Number of indices must be set to 0 for non-indexed geometries' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** PARSING **/
|
||||||
|
|
||||||
|
let pos = 8;
|
||||||
|
|
||||||
|
let attributes = {},
|
||||||
|
attributeName,
|
||||||
|
char,
|
||||||
|
attributeType,
|
||||||
|
cardinality,
|
||||||
|
encodingType,
|
||||||
|
normalized,
|
||||||
|
arrayType,
|
||||||
|
values,
|
||||||
|
indices,
|
||||||
|
groups,
|
||||||
|
next,
|
||||||
|
i;
|
||||||
|
|
||||||
|
for ( i = 0; i < attributesNumber; i ++ ) {
|
||||||
|
attributeName = '';
|
||||||
|
|
||||||
|
while ( pos < array.length ) {
|
||||||
|
char = array[ pos ];
|
||||||
|
pos ++;
|
||||||
|
|
||||||
|
if ( char === 0 ) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
attributeName += String.fromCharCode( char );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = array[ pos ];
|
||||||
|
|
||||||
|
attributeType = flags >> 7 & 0x01;
|
||||||
|
normalized = flags >> 6 & 0x01;
|
||||||
|
cardinality = ( flags >> 4 & 0x03 ) + 1;
|
||||||
|
encodingType = flags & 0x0F;
|
||||||
|
arrayType = InvertedEncodingTypes[ encodingType ];
|
||||||
|
|
||||||
|
pos ++;
|
||||||
|
|
||||||
|
// padding to next multiple of 4
|
||||||
|
pos = Math.ceil( pos / 4 ) * 4;
|
||||||
|
|
||||||
|
values = copyFromBuffer( buffer, arrayType, pos + offset, cardinality * valuesNumber, bigEndian );
|
||||||
|
|
||||||
|
pos += arrayType.BYTES_PER_ELEMENT * cardinality * valuesNumber;
|
||||||
|
|
||||||
|
attributes[ attributeName ] = {
|
||||||
|
type: attributeType,
|
||||||
|
cardinality: cardinality,
|
||||||
|
values: values,
|
||||||
|
normalized: normalized === 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
indices = null;
|
||||||
|
if ( indexedGeometry ) {
|
||||||
|
pos = Math.ceil( pos / 4 ) * 4;
|
||||||
|
indices = copyFromBuffer(
|
||||||
|
buffer,
|
||||||
|
indicesType === 1 ? Uint32Array : Uint16Array,
|
||||||
|
pos + offset,
|
||||||
|
indicesNumber,
|
||||||
|
bigEndian
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read groups
|
||||||
|
groups = [];
|
||||||
|
pos = Math.ceil( pos / 4 ) * 4;
|
||||||
|
while ( pos < array.length ) {
|
||||||
|
next = read4ByteInt(array, pos);
|
||||||
|
if (next === -1) {
|
||||||
|
pos += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
groups.push({
|
||||||
|
materialIndex: next,
|
||||||
|
start: read4ByteInt(array, pos + 4),
|
||||||
|
count: read4ByteInt(array, pos + 8)
|
||||||
|
});
|
||||||
|
pos += 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: version,
|
||||||
|
attributes: attributes,
|
||||||
|
indices: indices,
|
||||||
|
groups: groups
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function read4ByteInt(array, pos) {
|
||||||
|
return array[pos] |
|
||||||
|
array[pos + 1] << 8 |
|
||||||
|
array[pos + 2] << 16 |
|
||||||
|
array[pos + 3] << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PRBMLoader {
|
||||||
|
|
||||||
|
constructor ( manager ) {
|
||||||
|
this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
load ( url, onLoad, onProgress, onError ) {
|
||||||
|
let scope = this;
|
||||||
|
|
||||||
|
url = url.replace( /\*/g, isBigEndianPlatform() ? 'be' : 'le' );
|
||||||
|
|
||||||
|
let loader = new FileLoader( scope.manager );
|
||||||
|
loader.setPath( scope.path );
|
||||||
|
loader.setResponseType( 'arraybuffer' );
|
||||||
|
|
||||||
|
loader.load( url, function ( arrayBuffer ) {
|
||||||
|
onLoad( scope.parse( arrayBuffer ) );
|
||||||
|
}, onProgress, onError );
|
||||||
|
}
|
||||||
|
|
||||||
|
setPath ( value ) {
|
||||||
|
this.path = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse ( arrayBuffer, offset ) {
|
||||||
|
let data = decodePrwm( arrayBuffer, offset ),
|
||||||
|
attributesKey = Object.keys( data.attributes ),
|
||||||
|
bufferGeometry = new BufferGeometry(),
|
||||||
|
attribute,
|
||||||
|
bufferAttribute,
|
||||||
|
i;
|
||||||
|
|
||||||
|
for ( i = 0; i < attributesKey.length; i ++ ) {
|
||||||
|
attribute = data.attributes[ attributesKey[ i ] ];
|
||||||
|
bufferAttribute = new BufferAttribute( attribute.values, attribute.cardinality, attribute.normalized );
|
||||||
|
bufferAttribute.gpuType = FloatType;
|
||||||
|
bufferGeometry.setAttribute( attributesKey[ i ], bufferAttribute );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( data.indices !== null ) {
|
||||||
|
bufferGeometry.setIndex( new BufferAttribute( data.indices, 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferGeometry.groups = data.groups;
|
||||||
|
|
||||||
|
return bufferGeometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
isBigEndianPlatform () {
|
||||||
|
return isBigEndianPlatform();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -74,14 +74,14 @@ dependencies {
|
|||||||
api ("de.bluecolored.bluemap.api:BlueMapAPI")
|
api ("de.bluecolored.bluemap.api:BlueMapAPI")
|
||||||
|
|
||||||
compileOnly ("org.jetbrains:annotations:23.0.0")
|
compileOnly ("org.jetbrains:annotations:23.0.0")
|
||||||
compileOnly ("org.projectlombok:lombok:1.18.28")
|
compileOnly ("org.projectlombok:lombok:1.18.30")
|
||||||
|
|
||||||
annotationProcessor ("org.projectlombok:lombok:1.18.28")
|
annotationProcessor ("org.projectlombok:lombok:1.18.30")
|
||||||
|
|
||||||
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
|
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||||
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||||
testCompileOnly ("org.projectlombok:lombok:1.18.28")
|
testCompileOnly ("org.projectlombok:lombok:1.18.30")
|
||||||
testAnnotationProcessor ("org.projectlombok:lombok:1.18.28")
|
testAnnotationProcessor ("org.projectlombok:lombok:1.18.30")
|
||||||
}
|
}
|
||||||
|
|
||||||
spotless {
|
spotless {
|
||||||
|
@ -29,14 +29,14 @@
|
|||||||
|
|
||||||
public class BlockModelView {
|
public class BlockModelView {
|
||||||
|
|
||||||
private HiresTileModel hiresTile;
|
private TileModel hiresTile;
|
||||||
private int start, size;
|
private int start, size;
|
||||||
|
|
||||||
public BlockModelView(HiresTileModel hiresTile) {
|
public BlockModelView(TileModel hiresTile) {
|
||||||
initialize(hiresTile);
|
initialize(hiresTile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModelView initialize(HiresTileModel hiresTile, int start) {
|
public BlockModelView initialize(TileModel hiresTile, int start) {
|
||||||
this.hiresTile = hiresTile;
|
this.hiresTile = hiresTile;
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.size = hiresTile.size() - start;
|
this.size = hiresTile.size() - start;
|
||||||
@ -44,7 +44,7 @@ public BlockModelView initialize(HiresTileModel hiresTile, int start) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockModelView initialize(HiresTileModel hiresTile) {
|
public BlockModelView initialize(TileModel hiresTile) {
|
||||||
this.hiresTile = hiresTile;
|
this.hiresTile = hiresTile;
|
||||||
this.start = hiresTile.size();
|
this.start = hiresTile.size();
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
@ -138,7 +138,7 @@ public BlockModelView transform(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel getHiresTile() {
|
public TileModel getHiresTile() {
|
||||||
return hiresTile;
|
return hiresTile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
import de.bluecolored.bluemap.core.storage.Storage;
|
import de.bluecolored.bluemap.core.storage.Storage;
|
||||||
import de.bluecolored.bluemap.core.util.Grid;
|
import de.bluecolored.bluemap.core.util.Grid;
|
||||||
import de.bluecolored.bluemap.core.world.World;
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -41,6 +42,8 @@ public class HiresModelManager {
|
|||||||
|
|
||||||
private final Storage.TileStorage storage;
|
private final Storage.TileStorage storage;
|
||||||
private final HiresModelRenderer renderer;
|
private final HiresModelRenderer renderer;
|
||||||
|
|
||||||
|
@Getter
|
||||||
private final Grid tileGrid;
|
private final Grid tileGrid;
|
||||||
|
|
||||||
public HiresModelManager(Storage.TileStorage storage, ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings, Grid tileGrid) {
|
public HiresModelManager(Storage.TileStorage storage, ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings, Grid tileGrid) {
|
||||||
@ -64,7 +67,7 @@ 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());
|
||||||
|
|
||||||
HiresTileModel model = HiresTileModel.instancePool().claimInstance();
|
TileModel model = TileModel.instancePool().claimInstance();
|
||||||
|
|
||||||
renderer.render(world, modelMin, modelMax, model, tileMetaConsumer);
|
renderer.render(world, modelMin, modelMax, model, tileMetaConsumer);
|
||||||
|
|
||||||
@ -73,22 +76,18 @@ public void render(World world, Vector2i tile, TileMetaConsumer tileMetaConsumer
|
|||||||
save(model, tile);
|
save(model, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
HiresTileModel.instancePool().recycleInstance(model);
|
TileModel.instancePool().recycleInstance(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save(final HiresTileModel model, Vector2i tile) {
|
private void save(final TileModel model, Vector2i tile) {
|
||||||
try (OutputStream os = storage.write(tile)) {
|
try (
|
||||||
model.writeBufferGeometryJson(os);
|
OutputStream out = storage.write(tile);
|
||||||
|
PRBMWriter modelWriter = new PRBMWriter(out)
|
||||||
|
) {
|
||||||
|
modelWriter.write(model);
|
||||||
} catch (IOException e){
|
} catch (IOException e){
|
||||||
Logger.global.logError("Failed to save hires model: " + tile, e);
|
Logger.global.logError("Failed to save hires model: " + tile, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the tile-grid
|
|
||||||
*/
|
|
||||||
public Grid getTileGrid() {
|
|
||||||
return tileGrid;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,11 @@ public HiresModelRenderer(ResourcePack resourcePack, TextureGallery textureGalle
|
|||||||
this.renderSettings = renderSettings;
|
this.renderSettings = renderSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(World world, Vector3i modelMin, Vector3i modelMax, HiresTileModel model) {
|
public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel model) {
|
||||||
render(world, modelMin, modelMax, model, (x, z, c, h, l) -> {});
|
render(world, modelMin, modelMax, model, (x, z, c, h, l) -> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(World world, Vector3i modelMin, Vector3i modelMax, HiresTileModel model, TileMetaConsumer tileMetaConsumer) {
|
public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel model, TileMetaConsumer tileMetaConsumer) {
|
||||||
Vector3i min = modelMin.max(renderSettings.getMinPos());
|
Vector3i min = modelMin.max(renderSettings.getMinPos());
|
||||||
Vector3i max = modelMax.min(renderSettings.getMaxPos());
|
Vector3i max = modelMax.min(renderSettings.getMaxPos());
|
||||||
Vector3i modelAnchor = new Vector3i(modelMin.getX(), 0, modelMin.getZ());
|
Vector3i modelAnchor = new Vector3i(modelMin.getX(), 0, modelMin.getZ());
|
||||||
|
@ -0,0 +1,317 @@
|
|||||||
|
package de.bluecolored.bluemap.core.map.hires;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.core.util.math.VectorM3f;
|
||||||
|
import de.bluecolored.bluemap.core.util.stream.CountingOutputStream;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class PRBMWriter implements Closeable {
|
||||||
|
|
||||||
|
private static final int FORMAT_VERSION = 1;
|
||||||
|
private static final int HEADER_BITS = 0b0_0_0_00111; // indexed (no) _ indices-type (-) _ endianness (little) _ attribute-nr (7)
|
||||||
|
|
||||||
|
private static final int ATTRIBUTE_TYPE_FLOAT = 0;
|
||||||
|
private static final int ATTRIBUTE_TYPE_INTEGER = 1 << 7;
|
||||||
|
|
||||||
|
private static final int ATTRIBUTE_NOT_NORMALIZED = 0;
|
||||||
|
private static final int ATTRIBUTE_NORMALIZED = 1 << 6;
|
||||||
|
|
||||||
|
private static final int ATTRIBUTE_CARDINALITY_SCALAR = 0;
|
||||||
|
private static final int ATTRIBUTE_CARDINALITY_2D_VEC = 1 << 4;
|
||||||
|
private static final int ATTRIBUTE_CARDINALITY_3D_VEC = 2 << 4;
|
||||||
|
private static final int ATTRIBUTE_CARDINALITY_4D_VEC = 3 << 4;
|
||||||
|
|
||||||
|
private static final int ATTRIBUTE_ENCODING_SIGNED_32BIT_FLOAT = 1;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_SIGNED_8BIT_INT = 3;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_SIGNED_16BIT_INT = 4;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_SIGNED_32BIT_INT = 6;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_UNSIGNED_8BIT_INT = 7;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_UNSIGNED_16BIT_INT = 8;
|
||||||
|
private static final int ATTRIBUTE_ENCODING_UNSIGNED_32BIT_INT = 10;
|
||||||
|
|
||||||
|
private final CountingOutputStream out;
|
||||||
|
|
||||||
|
public PRBMWriter(OutputStream out) {
|
||||||
|
this.out = new CountingOutputStream(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(TileModel model) throws IOException {
|
||||||
|
out.write(FORMAT_VERSION); // version - 1 byte
|
||||||
|
out.write(HEADER_BITS); // format info - 1 byte
|
||||||
|
write3byteValue(model.size * 3); // number of values - 3 bytes
|
||||||
|
write3byteValue(0); // number of indices (0 for non-indexed) - 3 bytes
|
||||||
|
|
||||||
|
writePositionArray(model);
|
||||||
|
writeNormalArray(model);
|
||||||
|
writeColorArray(model);
|
||||||
|
writeUvArray(model);
|
||||||
|
writeAoArray(model);
|
||||||
|
writeBlocklightArray(model);
|
||||||
|
writeSunlightArray(model);
|
||||||
|
|
||||||
|
writeMaterialGroups(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writePositionArray(TileModel model) throws IOException {
|
||||||
|
float[] position = model.position;
|
||||||
|
|
||||||
|
writeString("position");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NOT_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_3D_VEC |
|
||||||
|
ATTRIBUTE_ENCODING_SIGNED_32BIT_FLOAT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int posSize = model.size * TileModel.FI_POSITION;
|
||||||
|
for (int i = 0; i < posSize; i++) {
|
||||||
|
writeFloat(position[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeNormalArray(TileModel model) throws IOException {
|
||||||
|
VectorM3f normal = new VectorM3f(0, 0, 0);
|
||||||
|
float[] position = model.position;
|
||||||
|
|
||||||
|
writeString("normal");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NOT_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_3D_VEC |
|
||||||
|
ATTRIBUTE_ENCODING_SIGNED_32BIT_FLOAT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int pi, i, j;
|
||||||
|
for (i = 0; i < model.size; i++) {
|
||||||
|
pi = i * TileModel.FI_POSITION;
|
||||||
|
calculateSurfaceNormal(
|
||||||
|
position[pi], position[pi + 1], position[pi + 2],
|
||||||
|
position[pi + 3], position[pi + 4], position[pi + 5],
|
||||||
|
position[pi + 6], position[pi + 7], position[pi + 8],
|
||||||
|
normal
|
||||||
|
);
|
||||||
|
|
||||||
|
for (j = 0; j < 3; j++) { // all 3 points
|
||||||
|
writeFloat(normal.x);
|
||||||
|
writeFloat(normal.y);
|
||||||
|
writeFloat(normal.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeColorArray(TileModel model) throws IOException {
|
||||||
|
float[] color = model.color;
|
||||||
|
|
||||||
|
writeString("color");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_3D_VEC |
|
||||||
|
ATTRIBUTE_ENCODING_UNSIGNED_8BIT_INT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int colorSize = model.size * TileModel.FI_COLOR, i, j;
|
||||||
|
for (i = 0; i < colorSize; i += 3) {
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
writeNormalizedUnsignedByteValue(color[i]);
|
||||||
|
writeNormalizedUnsignedByteValue(color[i + 1]);
|
||||||
|
writeNormalizedUnsignedByteValue(color[i + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeUvArray(TileModel model) throws IOException {
|
||||||
|
float[] uv = model.uv;
|
||||||
|
|
||||||
|
writeString("uv");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NOT_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_2D_VEC |
|
||||||
|
ATTRIBUTE_ENCODING_SIGNED_32BIT_FLOAT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int uvSize = model.size * TileModel.FI_UV;
|
||||||
|
for (int i = 0; i < uvSize; i++) {
|
||||||
|
writeFloat(uv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeAoArray(TileModel model) throws IOException {
|
||||||
|
float[] ao = model.ao;
|
||||||
|
|
||||||
|
writeString("ao");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_SCALAR |
|
||||||
|
ATTRIBUTE_ENCODING_UNSIGNED_8BIT_INT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int uvSize = model.size * TileModel.FI_AO;
|
||||||
|
for (int i = 0; i < uvSize; i++) {
|
||||||
|
writeNormalizedUnsignedByteValue(ao[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeBlocklightArray(TileModel model) throws IOException {
|
||||||
|
byte[] blocklight = model.blocklight;
|
||||||
|
|
||||||
|
writeString("blocklight");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NOT_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_SCALAR |
|
||||||
|
ATTRIBUTE_ENCODING_SIGNED_8BIT_INT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int blSize = model.size * TileModel.FI_BLOCKLIGHT;
|
||||||
|
for (int i = 0; i < blSize; i++) {
|
||||||
|
out.write(blocklight[i]);
|
||||||
|
out.write(blocklight[i]);
|
||||||
|
out.write(blocklight[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeSunlightArray(TileModel model) throws IOException {
|
||||||
|
byte[] sunlight = model.sunlight;
|
||||||
|
|
||||||
|
writeString("sunlight");
|
||||||
|
out.write(
|
||||||
|
ATTRIBUTE_TYPE_FLOAT |
|
||||||
|
ATTRIBUTE_NOT_NORMALIZED |
|
||||||
|
ATTRIBUTE_CARDINALITY_SCALAR |
|
||||||
|
ATTRIBUTE_ENCODING_SIGNED_8BIT_INT
|
||||||
|
);
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
int slSize = model.size * TileModel.FI_SUNLIGHT;
|
||||||
|
for (int i = 0; i < slSize; i++) {
|
||||||
|
out.write(sunlight[i]);
|
||||||
|
out.write(sunlight[i]);
|
||||||
|
out.write(sunlight[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeMaterialGroups(TileModel model) throws IOException {
|
||||||
|
|
||||||
|
writePadding();
|
||||||
|
|
||||||
|
if (model.size > 0) {
|
||||||
|
int[] materialIndex = model.materialIndex;
|
||||||
|
|
||||||
|
int miSize = model.size * TileModel.FI_MATERIAL_INDEX,
|
||||||
|
lastMaterial = materialIndex[0],
|
||||||
|
material = lastMaterial, groupStart = 0;
|
||||||
|
|
||||||
|
write4byteValue(material);
|
||||||
|
write4byteValue(0);
|
||||||
|
|
||||||
|
for (int i = 1; i < miSize; i++) {
|
||||||
|
material = materialIndex[i];
|
||||||
|
|
||||||
|
if (material != lastMaterial) {
|
||||||
|
write4byteValue((i - groupStart) * 3);
|
||||||
|
|
||||||
|
groupStart = i;
|
||||||
|
|
||||||
|
write4byteValue(material);
|
||||||
|
write4byteValue(groupStart * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastMaterial = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
write4byteValue((miSize - groupStart) * 3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
write4byteValue(-1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writePadding() throws IOException {
|
||||||
|
int paddingBytes = (int) (-out.getCount() & 0x3);
|
||||||
|
for (int i = 0; i < paddingBytes; i++) {
|
||||||
|
out.write(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write2byteValue(int value) throws IOException {
|
||||||
|
if (value > 0xFFFF) throw new IOException("Value too high: " + value);
|
||||||
|
out.write(value & 0xFF);
|
||||||
|
out.write((value >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write3byteValue(int value) throws IOException {
|
||||||
|
if (value > 0xFFFFFF) throw new IOException("Value too high: " + value);
|
||||||
|
out.write(value & 0xFF);
|
||||||
|
out.write((value >> 8) & 0xFF);
|
||||||
|
out.write((value >> 16) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write4byteValue(int value) throws IOException {
|
||||||
|
out.write(value & 0xFF);
|
||||||
|
out.write((value >> 8) & 0xFF);
|
||||||
|
out.write((value >> 16) & 0xFF);
|
||||||
|
out.write((value >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFloat(float value) throws IOException {
|
||||||
|
write4byteValue(Float.floatToIntBits(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeNormalizedUnsignedByteValue(float value) throws IOException {
|
||||||
|
int normalized = (int) (value * 0xFF);
|
||||||
|
out.write(normalized & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeString(String value) throws IOException {
|
||||||
|
out.write(value.getBytes(StandardCharsets.US_ASCII));
|
||||||
|
out.write(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateSurfaceNormal(
|
||||||
|
float p1x, float p1y, float p1z,
|
||||||
|
float p2x, float p2y, float p2z,
|
||||||
|
float p3x, float p3y, float p3z,
|
||||||
|
VectorM3f target
|
||||||
|
){
|
||||||
|
p2x -= p1x; p2y -= p1y; p2z -= p1z;
|
||||||
|
p3x -= p1x; p3y -= p1y; p3z -= p1z;
|
||||||
|
|
||||||
|
p1x = p2y * p3z - p2z * p3y;
|
||||||
|
p1y = p2z * p3x - p2x * p3z;
|
||||||
|
p1z = p2x * p3y - p2y * p3x;
|
||||||
|
|
||||||
|
float length = (float) Math.sqrt(p1x * p1x + p1y * p1y + p1z * p1z);
|
||||||
|
p1x /= length;
|
||||||
|
p1y /= length;
|
||||||
|
p1z /= length;
|
||||||
|
|
||||||
|
target.set(p1x, p1y, p1z);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,27 +25,16 @@
|
|||||||
package de.bluecolored.bluemap.core.map.hires;
|
package de.bluecolored.bluemap.core.map.hires;
|
||||||
|
|
||||||
import com.flowpowered.math.TrigMath;
|
import com.flowpowered.math.TrigMath;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
import de.bluecolored.bluemap.core.util.InstancePool;
|
import de.bluecolored.bluemap.core.util.InstancePool;
|
||||||
import de.bluecolored.bluemap.core.util.MergeSort;
|
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;
|
||||||
import de.bluecolored.bluemap.core.util.math.VectorM3f;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
public class TileModel {
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class HiresTileModel {
|
|
||||||
private static final double GROW_MULTIPLIER = 1.5;
|
private static final double GROW_MULTIPLIER = 1.5;
|
||||||
|
|
||||||
// attributes per-vertex * per-face
|
// attributes per-vertex * per-face
|
||||||
private static final int
|
static final int
|
||||||
FI_POSITION = 3 * 3,
|
FI_POSITION = 3 * 3,
|
||||||
FI_UV = 2 * 3,
|
FI_UV = 2 * 3,
|
||||||
FI_AO = 3,
|
FI_AO = 3,
|
||||||
@ -54,20 +43,23 @@ public class HiresTileModel {
|
|||||||
FI_BLOCKLIGHT = 1 ,
|
FI_BLOCKLIGHT = 1 ,
|
||||||
FI_MATERIAL_INDEX = 1 ;
|
FI_MATERIAL_INDEX = 1 ;
|
||||||
|
|
||||||
private static final InstancePool<HiresTileModel> INSTANCE_POOL = new InstancePool<>(
|
private static final InstancePool<TileModel> INSTANCE_POOL = new InstancePool<>(
|
||||||
() -> new HiresTileModel(100),
|
() -> new TileModel(100),
|
||||||
HiresTileModel::clear
|
TileModel::clear
|
||||||
);
|
);
|
||||||
|
|
||||||
private int capacity;
|
private int capacity;
|
||||||
private int size;
|
int size;
|
||||||
|
|
||||||
private float[] position;
|
float[] position;
|
||||||
private float[] color, uv, ao;
|
float[] color, uv, ao;
|
||||||
private byte[] sunlight, blocklight;
|
byte[] sunlight, blocklight;
|
||||||
private int[] materialIndex, materialIndexSort, materialIndexSortSupport;
|
int[] materialIndex, materialIndexSort, materialIndexSortSupport;
|
||||||
|
|
||||||
public HiresTileModel(int initialCapacity) {
|
float[] indexedPosition;
|
||||||
|
int[] positionIndex;
|
||||||
|
|
||||||
|
public TileModel(int initialCapacity) {
|
||||||
if (initialCapacity < 0) throw new IllegalArgumentException("initialCapacity is negative");
|
if (initialCapacity < 0) throw new IllegalArgumentException("initialCapacity is negative");
|
||||||
setCapacity(initialCapacity);
|
setCapacity(initialCapacity);
|
||||||
clear();
|
clear();
|
||||||
@ -84,7 +76,7 @@ public int add(int count) {
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setPositions(
|
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,
|
||||||
@ -107,7 +99,7 @@ public HiresTileModel setPositions(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setUvs(
|
public TileModel setUvs(
|
||||||
int face,
|
int face,
|
||||||
float u1, float v1,
|
float u1, float v1,
|
||||||
float u2, float v2,
|
float u2, float v2,
|
||||||
@ -127,7 +119,7 @@ public HiresTileModel setUvs(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setAOs(
|
public TileModel setAOs(
|
||||||
int face,
|
int face,
|
||||||
float ao1, float ao2, float ao3
|
float ao1, float ao2, float ao3
|
||||||
) {
|
) {
|
||||||
@ -140,7 +132,7 @@ public HiresTileModel setAOs(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setColor(
|
public TileModel setColor(
|
||||||
int face,
|
int face,
|
||||||
float r, float g, float b
|
float r, float g, float b
|
||||||
){
|
){
|
||||||
@ -153,22 +145,22 @@ public HiresTileModel setColor(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setSunlight(int face, int sl) {
|
public TileModel setSunlight(int face, int sl) {
|
||||||
sunlight[face * FI_SUNLIGHT] = (byte) sl;
|
sunlight[face * FI_SUNLIGHT] = (byte) sl;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setBlocklight(int face, int bl) {
|
public TileModel setBlocklight(int face, int bl) {
|
||||||
blocklight[face * FI_BLOCKLIGHT] = (byte) bl;
|
blocklight[face * FI_BLOCKLIGHT] = (byte) bl;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel setMaterialIndex(int face, int m) {
|
public TileModel setMaterialIndex(int face, int m) {
|
||||||
materialIndex[face * FI_MATERIAL_INDEX] = m;
|
materialIndex[face * FI_MATERIAL_INDEX] = m;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel rotate(
|
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
|
||||||
) {
|
) {
|
||||||
@ -193,7 +185,7 @@ public HiresTileModel rotate(
|
|||||||
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel rotate(
|
public TileModel rotate(
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float pitch, float yaw, float roll
|
float pitch, float yaw, float roll
|
||||||
) {
|
) {
|
||||||
@ -228,7 +220,7 @@ public HiresTileModel rotate(
|
|||||||
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
return rotateByQuaternion(start, count, qx, qy, qz, qw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel rotateByQuaternion(
|
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
|
||||||
) {
|
) {
|
||||||
@ -256,7 +248,7 @@ public HiresTileModel rotateByQuaternion(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel scale(
|
public TileModel scale(
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float sx, float sy, float sz
|
float sx, float sy, float sz
|
||||||
) {
|
) {
|
||||||
@ -273,7 +265,7 @@ public HiresTileModel scale(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel translate(
|
public TileModel translate(
|
||||||
int start, int count,
|
int start, int count,
|
||||||
float dx, float dy, float dz
|
float dx, float dy, float dz
|
||||||
) {
|
) {
|
||||||
@ -290,7 +282,7 @@ public HiresTileModel translate(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel transform(int start, int count, MatrixM3f t) {
|
public TileModel transform(int start, int count, MatrixM3f t) {
|
||||||
return transform(start, count,
|
return transform(start, count,
|
||||||
t.m00, t.m01, t.m02,
|
t.m00, t.m01, t.m02,
|
||||||
t.m10, t.m11, t.m12,
|
t.m10, t.m11, t.m12,
|
||||||
@ -298,7 +290,7 @@ public HiresTileModel transform(int start, int count, MatrixM3f t) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel transform(
|
public 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,
|
||||||
@ -312,7 +304,7 @@ public HiresTileModel transform(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel transform(int start, int count, MatrixM4f t) {
|
public TileModel transform(int start, int count, MatrixM4f t) {
|
||||||
return transform(start, count,
|
return transform(start, count,
|
||||||
t.m00, t.m01, t.m02, t.m03,
|
t.m00, t.m01, t.m02, t.m03,
|
||||||
t.m10, t.m11, t.m12, t.m13,
|
t.m10, t.m11, t.m12, t.m13,
|
||||||
@ -321,7 +313,7 @@ public HiresTileModel transform(int start, int count, MatrixM4f t) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel transform(
|
public 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,
|
||||||
@ -346,12 +338,12 @@ public HiresTileModel transform(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel reset(int size) {
|
public TileModel reset(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HiresTileModel clear() {
|
public TileModel clear() {
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -394,225 +386,6 @@ private void setCapacity(int capacity) {
|
|||||||
materialIndexSortSupport = new int [materialIndex.length];
|
materialIndexSortSupport = new int [materialIndex.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBufferGeometryJson(OutputStream out) throws IOException {
|
|
||||||
Gson gson = new GsonBuilder().create();
|
|
||||||
JsonWriter json = gson.newJsonWriter(new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8), 81920));
|
|
||||||
|
|
||||||
json.beginObject(); // main-object
|
|
||||||
json.name("tileGeometry").beginObject(); // tile-geometry-object
|
|
||||||
|
|
||||||
// set special values
|
|
||||||
json.name("type").value("BufferGeometry");
|
|
||||||
json.name("uuid").value(UUID.randomUUID().toString().toUpperCase());
|
|
||||||
|
|
||||||
json.name("data").beginObject(); // data
|
|
||||||
json.name("attributes").beginObject(); // attributes
|
|
||||||
|
|
||||||
writePositionArray(json);
|
|
||||||
writeNormalArray(json);
|
|
||||||
writeColorArray(json);
|
|
||||||
writeUvArray(json);
|
|
||||||
writeAoArray(json);
|
|
||||||
writeBlocklightArray(json);
|
|
||||||
writeSunlightArray(json);
|
|
||||||
|
|
||||||
json.endObject(); // attributes
|
|
||||||
|
|
||||||
writeMaterialGroups(json);
|
|
||||||
|
|
||||||
json.endObject(); // data
|
|
||||||
json.endObject(); // tile-geometry-object
|
|
||||||
json.endObject(); // main-object
|
|
||||||
|
|
||||||
// save and return
|
|
||||||
json.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePositionArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("position");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(3);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int posSize = size * FI_POSITION;
|
|
||||||
for (int i = 0; i < posSize; i++) {
|
|
||||||
writeRounded(json, position[i]);
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeNormalArray(JsonWriter json) throws IOException {
|
|
||||||
VectorM3f normal = new VectorM3f(0, 0, 0);
|
|
||||||
|
|
||||||
json.name("normal");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(3);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
|
|
||||||
int pi, i, j;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
pi = i * FI_POSITION;
|
|
||||||
calculateSurfaceNormal(
|
|
||||||
position[pi ], position[pi + 1], position[pi + 2],
|
|
||||||
position[pi + 3], position[pi + 4], position[pi + 5],
|
|
||||||
position[pi + 6], position[pi + 7], position[pi + 8],
|
|
||||||
normal
|
|
||||||
);
|
|
||||||
|
|
||||||
for (j = 0; j < 3; j++) { // all 3 points
|
|
||||||
writeRounded(json, normal.x);
|
|
||||||
writeRounded(json, normal.y);
|
|
||||||
writeRounded(json, normal.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeColorArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("color");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(3);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int colorSize = size * FI_COLOR, i, j;
|
|
||||||
for (i = 0; i < colorSize; i += 3) {
|
|
||||||
for (j = 0; j < 3; j++) {
|
|
||||||
writeRounded(json, color[i]);
|
|
||||||
writeRounded(json, color[i + 1]);
|
|
||||||
writeRounded(json, color[i + 2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeUvArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("uv");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(2);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int uvSize = size * FI_UV;
|
|
||||||
for (int i = 0; i < uvSize; i++) {
|
|
||||||
writeRounded(json, uv[i]);
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAoArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("ao");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(1);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int aoSize = size * FI_AO;
|
|
||||||
for (int i = 0; i < aoSize; i++) {
|
|
||||||
writeRounded(json, ao[i]);
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeBlocklightArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("blocklight");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(1);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int blSize = size * FI_BLOCKLIGHT;
|
|
||||||
for (int i = 0; i < blSize; i++) {
|
|
||||||
json.value(blocklight[i]);
|
|
||||||
json.value(blocklight[i]);
|
|
||||||
json.value(blocklight[i]);
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeSunlightArray(JsonWriter json) throws IOException {
|
|
||||||
json.name("sunlight");
|
|
||||||
json.beginObject();
|
|
||||||
|
|
||||||
json.name("type").value("Float32Array");
|
|
||||||
json.name("itemSize").value(1);
|
|
||||||
json.name("normalized").value(false);
|
|
||||||
|
|
||||||
json.name("array").beginArray();
|
|
||||||
int blSize = size * FI_SUNLIGHT;
|
|
||||||
for (int i = 0; i < blSize; i++) {
|
|
||||||
json.value(sunlight[i]);
|
|
||||||
json.value(sunlight[i]);
|
|
||||||
json.value(sunlight[i]);
|
|
||||||
}
|
|
||||||
json.endArray();
|
|
||||||
json.endObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeMaterialGroups(JsonWriter json) throws IOException {
|
|
||||||
json.name("groups").beginArray(); // groups
|
|
||||||
|
|
||||||
if (size > 0) {
|
|
||||||
|
|
||||||
int miSize = size * FI_MATERIAL_INDEX, lastMaterial = materialIndex[0], material = lastMaterial, groupStart = 0;
|
|
||||||
|
|
||||||
json.beginObject();
|
|
||||||
json.name("materialIndex").value(material);
|
|
||||||
json.name("start").value(0);
|
|
||||||
|
|
||||||
for (int i = 1; i < miSize; i++) {
|
|
||||||
material = materialIndex[i];
|
|
||||||
|
|
||||||
if (material != lastMaterial) {
|
|
||||||
json.name("count").value((i - groupStart) * 3L);
|
|
||||||
json.endObject();
|
|
||||||
|
|
||||||
groupStart = i;
|
|
||||||
|
|
||||||
json.beginObject();
|
|
||||||
json.name("materialIndex").value(material);
|
|
||||||
json.name("start").value(groupStart * 3L);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastMaterial = material;
|
|
||||||
}
|
|
||||||
|
|
||||||
json.name("count").value((miSize - groupStart) * 3L);
|
|
||||||
json.endObject();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
json.endArray(); // groups
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeRounded(JsonWriter json, double value) throws IOException {
|
|
||||||
// rounding and remove ".0" to save string space
|
|
||||||
double d = Math.round(value * 10000d) / 10000d;
|
|
||||||
if (d == (long) d) json.value((long) d);
|
|
||||||
else json.value(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sort() {
|
public void sort() {
|
||||||
if (size <= 1) return; // nothing to sort
|
if (size <= 1) return; // nothing to sort
|
||||||
|
|
||||||
@ -700,28 +473,7 @@ private void swap(int face1, int face2) {
|
|||||||
materialIndex[face2] = vi;
|
materialIndex[face2] = vi;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void calculateSurfaceNormal(
|
public static InstancePool<TileModel> instancePool() {
|
||||||
double p1x, double p1y, double p1z,
|
|
||||||
double p2x, double p2y, double p2z,
|
|
||||||
double p3x, double p3y, double p3z,
|
|
||||||
VectorM3f target
|
|
||||||
){
|
|
||||||
p2x -= p1x; p2y -= p1y; p2z -= p1z;
|
|
||||||
p3x -= p1x; p3y -= p1y; p3z -= p1z;
|
|
||||||
|
|
||||||
p1x = p2y * p3z - p2z * p3y;
|
|
||||||
p1y = p2z * p3x - p2x * p3z;
|
|
||||||
p1z = p2x * p3y - p2y * p3x;
|
|
||||||
|
|
||||||
double length = Math.sqrt(p1x * p1x + p1y * p1y + p1z * p1z);
|
|
||||||
p1x /= length;
|
|
||||||
p1y /= length;
|
|
||||||
p1z /= length;
|
|
||||||
|
|
||||||
target.set((float) p1x, (float) p1y, (float) p1z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InstancePool<HiresTileModel> instancePool() {
|
|
||||||
return INSTANCE_POOL;
|
return INSTANCE_POOL;
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@
|
|||||||
import com.flowpowered.math.vector.Vector3i;
|
import com.flowpowered.math.vector.Vector3i;
|
||||||
import de.bluecolored.bluemap.core.map.TextureGallery;
|
import de.bluecolored.bluemap.core.map.TextureGallery;
|
||||||
import de.bluecolored.bluemap.core.map.hires.BlockModelView;
|
import de.bluecolored.bluemap.core.map.hires.BlockModelView;
|
||||||
import de.bluecolored.bluemap.core.map.hires.HiresTileModel;
|
import de.bluecolored.bluemap.core.map.hires.TileModel;
|
||||||
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
|
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
|
||||||
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
|
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
|
||||||
import de.bluecolored.bluemap.core.resources.ResourcePath;
|
import de.bluecolored.bluemap.core.resources.ResourcePath;
|
||||||
@ -249,7 +249,7 @@ private boolean createElementFace(Direction faceDir, VectorM3f c0, VectorM3f c1,
|
|||||||
blockModel.initialize();
|
blockModel.initialize();
|
||||||
blockModel.add(2);
|
blockModel.add(2);
|
||||||
|
|
||||||
HiresTileModel tileModel = blockModel.getHiresTile();
|
TileModel tileModel = blockModel.getHiresTile();
|
||||||
int face1 = blockModel.getStart();
|
int face1 = blockModel.getStart();
|
||||||
int face2 = face1 + 1;
|
int face2 = face1 + 1;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
import com.flowpowered.math.vector.Vector4f;
|
import com.flowpowered.math.vector.Vector4f;
|
||||||
import de.bluecolored.bluemap.core.map.TextureGallery;
|
import de.bluecolored.bluemap.core.map.TextureGallery;
|
||||||
import de.bluecolored.bluemap.core.map.hires.BlockModelView;
|
import de.bluecolored.bluemap.core.map.hires.BlockModelView;
|
||||||
import de.bluecolored.bluemap.core.map.hires.HiresTileModel;
|
import de.bluecolored.bluemap.core.map.hires.TileModel;
|
||||||
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
|
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
|
||||||
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
|
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
|
||||||
import de.bluecolored.bluemap.core.resources.ResourcePath;
|
import de.bluecolored.bluemap.core.resources.ResourcePath;
|
||||||
@ -205,7 +205,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
|
|||||||
blockModel.initialize();
|
blockModel.initialize();
|
||||||
blockModel.add(2);
|
blockModel.add(2);
|
||||||
|
|
||||||
HiresTileModel tileModel = blockModel.getHiresTile();
|
TileModel tileModel = blockModel.getHiresTile();
|
||||||
int face1 = blockModel.getStart();
|
int face1 = blockModel.getStart();
|
||||||
int face2 = face1 + 1;
|
int face2 = face1 + 1;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.storage;
|
package de.bluecolored.bluemap.core.storage;
|
||||||
|
|
||||||
import de.bluecolored.bluemap.core.util.DelegateInputStream;
|
import de.bluecolored.bluemap.core.util.stream.DelegateInputStream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -72,14 +72,7 @@ public OutputStream writeMapTile(String mapId, int lod, Vector2i tile) throws IO
|
|||||||
Path file = getFilePath(mapId, lod, tile);
|
Path file = getFilePath(mapId, lod, tile);
|
||||||
|
|
||||||
OutputStream os = FileHelper.createFilepartOutputStream(file);
|
OutputStream os = FileHelper.createFilepartOutputStream(file);
|
||||||
try {
|
return new BufferedOutputStream(compression.compress(os));
|
||||||
os = new BufferedOutputStream(compression.compress(os));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
os.close();
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -240,7 +233,7 @@ public Path getFilePath(String mapId, int lod, Vector2i tile){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lod == 0) {
|
if (lod == 0) {
|
||||||
return p.resolve(fileName + ".json" + hiresCompression.getFileSuffix());
|
return p.resolve(fileName + ".prbm" + hiresCompression.getFileSuffix());
|
||||||
} else {
|
} else {
|
||||||
return p.resolve(fileName + ".png");
|
return p.resolve(fileName + ".png");
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
import de.bluecolored.bluemap.core.storage.Compression;
|
import de.bluecolored.bluemap.core.storage.Compression;
|
||||||
import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
|
import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
|
||||||
import de.bluecolored.bluemap.core.storage.sql.dialect.PostgresDialect;
|
import de.bluecolored.bluemap.core.storage.sql.dialect.PostgresDialect;
|
||||||
import de.bluecolored.bluemap.core.util.OnCloseOutputStream;
|
import de.bluecolored.bluemap.core.util.stream.OnCloseOutputStream;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
import de.bluecolored.bluemap.core.storage.*;
|
import de.bluecolored.bluemap.core.storage.*;
|
||||||
import de.bluecolored.bluemap.core.storage.sql.dialect.DialectType;
|
import de.bluecolored.bluemap.core.storage.sql.dialect.DialectType;
|
||||||
import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
|
import de.bluecolored.bluemap.core.storage.sql.dialect.Dialect;
|
||||||
import de.bluecolored.bluemap.core.util.OnCloseOutputStream;
|
import de.bluecolored.bluemap.core.util.stream.OnCloseOutputStream;
|
||||||
import org.apache.commons.dbcp2.*;
|
import org.apache.commons.dbcp2.*;
|
||||||
import org.apache.commons.pool2.ObjectPool;
|
import org.apache.commons.pool2.ObjectPool;
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.util;
|
package de.bluecolored.bluemap.core.util;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.core.util.stream.OnCloseOutputStream;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -112,6 +112,14 @@ public static Key parse(String formatted, String defaultNamespace) {
|
|||||||
return new Key(namespace, value);
|
return new Key(namespace, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Key minecraft(String value) {
|
||||||
|
return new Key(MINECRAFT_NAMESPACE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Key bluemap(String value) {
|
||||||
|
return new Key(BLUEMAP_NAMESPACE, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using our own function instead of {@link String#intern()} since the ConcurrentHashMap is much faster.
|
* Using our own function instead of {@link String#intern()} since the ConcurrentHashMap is much faster.
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,13 @@ public Registry() {
|
|||||||
this.entries = new ConcurrentHashMap<>();
|
this.entries = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public Registry(T... defaultEntires) {
|
||||||
|
this();
|
||||||
|
for (T entry : defaultEntires)
|
||||||
|
register(entry);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a new entry, only if there is no entry with the same key registered already.
|
* Registers a new entry, only if there is no entry with the same key registered already.
|
||||||
* Does nothing otherwise.
|
* Does nothing otherwise.
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package de.bluecolored.bluemap.core.util.stream;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class CountingOutputStream extends DelegateOutputStream {
|
||||||
|
|
||||||
|
private long count;
|
||||||
|
|
||||||
|
public CountingOutputStream(OutputStream out) {
|
||||||
|
this(out, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CountingOutputStream(OutputStream out, int initialCount) {
|
||||||
|
super(out);
|
||||||
|
this.count = initialCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
out.write(b);
|
||||||
|
count ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte @NotNull [] b) throws IOException {
|
||||||
|
out.write(b);
|
||||||
|
count += b.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte @NotNull [] b, int off, int len) throws IOException {
|
||||||
|
out.write(b, off, len);
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
count = 0;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package de.bluecolored.bluemap.core.util;
|
package de.bluecolored.bluemap.core.util.stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package de.bluecolored.bluemap.core.util;
|
package de.bluecolored.bluemap.core.util.stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
@ -22,7 +22,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.util;
|
package de.bluecolored.bluemap.core.util.stream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
@ -22,7 +22,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.util;
|
package de.bluecolored.bluemap.core.util.stream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
Loading…
Reference in New Issue
Block a user