Merge remote-tracking branch 'upstream/master' into configurable-north
16
.gitignore
vendored
@@ -1,5 +1,8 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
build
|
MANIFEST
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
Minecraft_Overviewer.egg-info
|
||||||
terrain.png
|
terrain.png
|
||||||
cachedir*
|
cachedir*
|
||||||
|
|
||||||
@@ -14,10 +17,13 @@ ImPlatform.h
|
|||||||
Imaging.h
|
Imaging.h
|
||||||
|
|
||||||
# various forms of compiled c_overviewer extensions
|
# various forms of compiled c_overviewer extensions
|
||||||
c_overviewer.so
|
overviewer_core/c_overviewer.so
|
||||||
c_overviewer.pyd
|
overviewer_core/c_overviewer.pyd
|
||||||
c_overviewer_d.pyd
|
overviewer_core/c_overviewer_d.pyd
|
||||||
c_overviewer.dylib
|
overviewer_core/c_overviewer.dylib
|
||||||
|
|
||||||
|
# generated version file
|
||||||
|
overviewer_core/overviewer_version.py
|
||||||
|
|
||||||
# Mac OS X noise
|
# Mac OS X noise
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ Contributors
|
|||||||
|
|
||||||
This file contains a list of every person who has contributed code to
|
This file contains a list of every person who has contributed code to
|
||||||
Overviewer. It was created from the git commit log, and should include
|
Overviewer. It was created from the git commit log, and should include
|
||||||
everyone, but we may have missed a few.
|
everyone, but we may have missed a few and it is manually updated
|
||||||
|
now. If you feel like you've been left out, feel free to tell us!
|
||||||
|
|
||||||
Not currently included (but hopefully soon) are countless testers and bug
|
Not currently included (but hopefully soon) are countless testers and bug
|
||||||
reporters that helped fixed the many bugs that have popped up in the course of
|
reporters that helped fixed the many bugs that have popped up in the course of
|
||||||
@@ -40,14 +41,18 @@ feature.
|
|||||||
|
|
||||||
* arrai <array.of.intellect@gmail.com>
|
* arrai <array.of.intellect@gmail.com>
|
||||||
* Kyle Brantley <kyle@averageurl.com>
|
* Kyle Brantley <kyle@averageurl.com>
|
||||||
|
* but2002 <barryt_9@hotmail.com>
|
||||||
|
* Eric Carr <eric@carr.no>
|
||||||
* cbarber <CraigBarber@taryx.com>
|
* cbarber <CraigBarber@taryx.com>
|
||||||
* Alex Cline <cline@vivisimo.com>
|
* Alex Cline <cline@vivisimo.com>
|
||||||
|
* Andrew Clunis <andrew@orospakr.ca>
|
||||||
* CounterPillow <spam@tes-cheese.ch>
|
* CounterPillow <spam@tes-cheese.ch>
|
||||||
* Stephen Fluin <stephen@mistuph.com>
|
* Stephen Fluin <stephen@mistuph.com>
|
||||||
* Benjamin Herr <ben@0x539.de>
|
* Benjamin Herr <ben@0x539.de>
|
||||||
* Ryan Hitchman <hitchmanr@gmail.com>
|
* Ryan Hitchman <hitchmanr@gmail.com>
|
||||||
* Jenny <jennytoo@gmail.com>
|
* Jenny <jennytoo@gmail.com>
|
||||||
* Michael Jensen <emjay1988@gmail.com>
|
* Michael Jensen <emjay1988@gmail.com>
|
||||||
|
* Maciej Małecki <maciej.malecki@hotmail.com>
|
||||||
* Ryan McCue <ryanmccue@cubegames.net>
|
* Ryan McCue <ryanmccue@cubegames.net>
|
||||||
* Morlok8k <otis.spankmeyer@gmail.com>
|
* Morlok8k <otis.spankmeyer@gmail.com>
|
||||||
* Gregory Short <gshort2@gmail.com>
|
* Gregory Short <gshort2@gmail.com>
|
||||||
|
|||||||
9
MANIFEST.in
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
include COPYING.txt
|
||||||
|
include README.rst
|
||||||
|
include CONTRIBUTORS.rst
|
||||||
|
include overviewer.py
|
||||||
|
include sample.settings.py
|
||||||
|
recursive-include contrib/ *.py
|
||||||
|
recursive-include overviewer_core/ *.py
|
||||||
|
recursive-include overviewer_core/src/ *.c *.h
|
||||||
|
recursive-include overviewer_core/data/ *
|
||||||
@@ -22,14 +22,13 @@ if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
from configParser import ConfigOptionParser
|
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import util
|
|
||||||
import platform
|
import platform
|
||||||
|
from overviewer_core import util
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s")
|
logging.basicConfig(level=logging.INFO,format="%(asctime)s [%(levelname)s] %(message)s")
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ this_dir = util.get_program_path()
|
|||||||
|
|
||||||
# make sure the c_overviewer extension is available
|
# make sure the c_overviewer extension is available
|
||||||
try:
|
try:
|
||||||
import c_overviewer
|
from overviewer_core import c_overviewer
|
||||||
except ImportError:
|
except ImportError:
|
||||||
## if this is a frozen windows package, the following error messages about
|
## if this is a frozen windows package, the following error messages about
|
||||||
## building the c_overviewer extension are not appropriate
|
## building the c_overviewer extension are not appropriate
|
||||||
@@ -49,7 +48,7 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
## try to find the build extension
|
## try to find the build extension
|
||||||
ext = os.path.join(this_dir, "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
ext = os.path.join(this_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so"))
|
||||||
if os.path.exists(ext):
|
if os.path.exists(ext):
|
||||||
print "Something has gone wrong importing the c_overviewer extension. Please"
|
print "Something has gone wrong importing the c_overviewer extension. Please"
|
||||||
print "make sure it is up-to-date (clean and rebuild)"
|
print "make sure it is up-to-date (clean and rebuild)"
|
||||||
@@ -57,14 +56,17 @@ except ImportError:
|
|||||||
|
|
||||||
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
print "You need to compile the c_overviewer module to run Minecraft Overviewer."
|
||||||
print "Run `python setup.py build`, or see the README for details."
|
print "Run `python setup.py build`, or see the README for details."
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
if hasattr(sys, "frozen"):
|
if hasattr(sys, "frozen"):
|
||||||
pass # we don't bother with a compat test since it should always be in sync
|
pass # we don't bother with a compat test since it should always be in sync
|
||||||
elif "extension_version" in dir(c_overviewer):
|
elif "extension_version" in dir(c_overviewer):
|
||||||
# check to make sure the binary matches the headers
|
# check to make sure the binary matches the headers
|
||||||
if os.path.exists(os.path.join(this_dir, "src", "overviewer.h")):
|
if os.path.exists(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")):
|
||||||
with open(os.path.join(this_dir, "src", "overviewer.h")) as f:
|
with open(os.path.join(this_dir, "overviewer_core", "src", "overviewer.h")) as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines)
|
||||||
if lines:
|
if lines:
|
||||||
@@ -76,12 +78,10 @@ else:
|
|||||||
print "Please rebuild your c_overviewer module. It is out of date!"
|
print "Please rebuild your c_overviewer module. It is out of date!"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
from overviewer_core.configParser import ConfigOptionParser
|
||||||
|
from overviewer_core import optimizeimages, world, quadtree
|
||||||
|
from overviewer_core import googlemap, rendernode
|
||||||
|
|
||||||
import optimizeimages
|
|
||||||
import world
|
|
||||||
import quadtree
|
|
||||||
import googlemap
|
|
||||||
import rendernode
|
|
||||||
|
|
||||||
helptext = """
|
helptext = """
|
||||||
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>
|
%prog [OPTIONS] <World # / Name / Path to World> <tiles dest dir>
|
||||||
@@ -126,14 +126,14 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
if options.version:
|
if options.version:
|
||||||
print "Minecraft-Overviewer"
|
|
||||||
print "Git version: %s" % util.findGitVersion()
|
|
||||||
try:
|
try:
|
||||||
import overviewer_version
|
import overviewer_core.overviewer_version as overviewer_version
|
||||||
if hasattr(sys, "frozen"):
|
print "Minecraft-Overviewer %s" % overviewer_version.VERSION
|
||||||
print "py2exe version build on %s" % overviewer_version.BUILD_DATE
|
print "Git commit: %s" % overviewer_version.HASH
|
||||||
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
|
print "built on %s" % overviewer_version.BUILD_DATE
|
||||||
|
print "Build machine: %s %s" % (overviewer_version.BUILD_PLATFORM, overviewer_version.BUILD_OS)
|
||||||
except:
|
except:
|
||||||
|
print "version info not found"
|
||||||
pass
|
pass
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
@@ -178,6 +178,11 @@ def main():
|
|||||||
parser.print_help()
|
parser.print_help()
|
||||||
logging.error("Invalid world number")
|
logging.error("Invalid world number")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# final sanity check for worlddir
|
||||||
|
if not os.path.exists(os.path.join(worlddir, 'level.dat')):
|
||||||
|
logging.error("Invalid world path -- does not contain level.dat")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
if options.delete:
|
if options.delete:
|
||||||
|
|||||||
0
overviewer_core/__init__.py
Normal file
@@ -127,10 +127,10 @@ def get_tileentity_data(level):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
# This set holds blocks ids that can be seen through, for occlusion calculations
|
# This set holds blocks ids that can be seen through, for occlusion calculations
|
||||||
transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 30, 31, 32, 37, 38,
|
transparent_blocks = set([ 0, 6, 8, 9, 18, 20, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||||
39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64, 65, 66, 67,
|
34, 37, 38, 39, 40, 44, 50, 51, 52, 53, 55, 59, 63, 64,
|
||||||
68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79, 81, 83, 85,
|
65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 78, 79,
|
||||||
90, 92, 93, 94, 96])
|
81, 83, 85, 90, 92, 93, 94, 96])
|
||||||
|
|
||||||
# This set holds block ids that are solid blocks
|
# This set holds block ids that are solid blocks
|
||||||
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
solid_blocks = set([1, 2, 3, 4, 5, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||||
@@ -334,67 +334,6 @@ class ChunkRenderer(object):
|
|||||||
return self._up_left_skylight
|
return self._up_left_skylight
|
||||||
up_left_skylight = property(_load_up_left_skylight)
|
up_left_skylight = property(_load_up_left_skylight)
|
||||||
|
|
||||||
def generate_pseudo_ancildata(self,x,y,z,blockid, north_position = 0 ):
|
|
||||||
""" Generates a pseudo ancillary data for blocks that depend of
|
|
||||||
what are surrounded and don't have ancillary data
|
|
||||||
|
|
||||||
This uses a binary number of 4 digits to encode the info.
|
|
||||||
The encode is:
|
|
||||||
|
|
||||||
Bit: 1 2 3 4
|
|
||||||
Side: x y -x -y
|
|
||||||
Values: bit = 0 -> The corresponding side block has different blockid
|
|
||||||
bit = 1 -> The corresponding side block has same blockid
|
|
||||||
Example: if the bit1 is 1 that means that there is a block with
|
|
||||||
blockid in the side of the +x direction.
|
|
||||||
|
|
||||||
You can rotate the pseudo data multiplying by 2 and
|
|
||||||
if it is > 15 subtracting 15 and adding 1. (moving bits
|
|
||||||
in the left direction is like rotate 90 degree in anticlockwise
|
|
||||||
direction). In this way can be used for maps with other
|
|
||||||
north orientation.
|
|
||||||
|
|
||||||
North position can have the values 0, 1, 2, 3, corresponding to
|
|
||||||
north in bottom-left, bottom-right, top-right and top-left of
|
|
||||||
the screen.
|
|
||||||
|
|
||||||
The rotation feature is not used anywhere yet.
|
|
||||||
"""
|
|
||||||
|
|
||||||
blocks = self.blocks
|
|
||||||
up_left_blocks = self.up_left_blocks
|
|
||||||
up_right_blocks = self.up_right_blocks
|
|
||||||
left_blocks = self.left_blocks
|
|
||||||
right_blocks = self.right_blocks
|
|
||||||
|
|
||||||
pseudo_data = 0
|
|
||||||
|
|
||||||
# first check if we are in the border of a chunk, next check for chunks adjacent to this
|
|
||||||
# and finally check for a block with same blockid. I we aren't in the border of a chunk,
|
|
||||||
# check for the block having the sme blockid.
|
|
||||||
|
|
||||||
if (up_right_blocks is not None and up_right_blocks[0,y,z] == blockid) if x == 15 else blocks[x+1,y,z] == blockid:
|
|
||||||
pseudo_data = pseudo_data | 0b1000
|
|
||||||
|
|
||||||
if (right_blocks is not None and right_blocks[x,0,z] == blockid) if y == 15 else blocks[x,y + 1,z] == blockid:
|
|
||||||
pseudo_data = pseudo_data | 0b0100
|
|
||||||
|
|
||||||
if (left_blocks is not None and left_blocks[15,y,z] == blockid) if x == 0 else blocks[x - 1,y,z] == blockid:
|
|
||||||
pseudo_data = pseudo_data | 0b0010
|
|
||||||
|
|
||||||
if (up_left_blocks is not None and up_left_blocks[x,15,z] == blockid) if y == 0 else blocks[x,y - 1,z] == blockid:
|
|
||||||
pseudo_data = pseudo_data | 0b0001
|
|
||||||
|
|
||||||
# rotate the bits for other north orientations
|
|
||||||
while north_position > 0:
|
|
||||||
pseudo_data *= 2
|
|
||||||
if pseudo_data > 15:
|
|
||||||
pseudo_data -= 16
|
|
||||||
pseudo_data +=1
|
|
||||||
north_position -= 1
|
|
||||||
|
|
||||||
return pseudo_data
|
|
||||||
|
|
||||||
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False):
|
def chunk_render(self, img=None, xoff=0, yoff=0, cave=False):
|
||||||
"""Renders a chunk with the given parameters, and returns the image.
|
"""Renders a chunk with the given parameters, and returns the image.
|
||||||
If img is given, the chunk is rendered to that image object. Otherwise,
|
If img is given, the chunk is rendered to that image object. Otherwise,
|
||||||
|
Before Width: | Height: | Size: 563 B After Width: | Height: | Size: 563 B |
|
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 401 B |
|
Before Width: | Height: | Size: 672 B After Width: | Height: | Size: 672 B |
|
Before Width: | Height: | Size: 374 B After Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -100,3 +100,34 @@ body {
|
|||||||
background-color: #fff; /* fallback */
|
background-color: #fff; /* fallback */
|
||||||
background-color: rgba(255,255,255,0.8);
|
background-color: rgba(255,255,255,0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#searchControl {
|
||||||
|
padding: 5px;
|
||||||
|
height: 20px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchControl > input {
|
||||||
|
border: 2px solid #000;
|
||||||
|
font-size: 12pt;
|
||||||
|
width: 20em;
|
||||||
|
background-colour: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#searchDropDown {
|
||||||
|
border: 1px solid #000;
|
||||||
|
width: 17em;
|
||||||
|
font-size: 14pt;
|
||||||
|
background-color: #fff;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.searchResultItem {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.searchResultItem img {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
@@ -96,6 +96,25 @@ var overviewer = {
|
|||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Quote an arbitrary string for use in a regex matcher.
|
||||||
|
* WTB parametized regexes, JavaScript...
|
||||||
|
*
|
||||||
|
* From http://kevin.vanzonneveld.net
|
||||||
|
* original by: booeyOH
|
||||||
|
* improved by: Ates Goral (http://magnetiq.com)
|
||||||
|
* improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
||||||
|
* bugfixed by: Onno Marsman
|
||||||
|
* example 1: preg_quote("$40");
|
||||||
|
* returns 1: '\$40'
|
||||||
|
* example 2: preg_quote("*RRRING* Hello?");
|
||||||
|
* returns 2: '\*RRRING\* Hello\?'
|
||||||
|
* example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
|
||||||
|
* returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:'
|
||||||
|
*/
|
||||||
|
"pregQuote": function(str) {
|
||||||
|
return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Setup the varous mapTypes before we actually create the map. This used
|
* Setup the varous mapTypes before we actually create the map. This used
|
||||||
* to be a bunch of crap down at the bottom of functions.js
|
* to be a bunch of crap down at the bottom of functions.js
|
||||||
@@ -146,6 +165,9 @@ var overviewer = {
|
|||||||
var zoom = overviewerConfig.map.defaultZoom;
|
var zoom = overviewerConfig.map.defaultZoom;
|
||||||
var mapcenter;
|
var mapcenter;
|
||||||
var queryParams = overviewer.util.parseQueryString();
|
var queryParams = overviewer.util.parseQueryString();
|
||||||
|
if (queryParams.debug) {
|
||||||
|
overviewerConfig.map.debug=true;
|
||||||
|
}
|
||||||
if (queryParams.lat) {
|
if (queryParams.lat) {
|
||||||
lat = parseFloat(queryParams.lat);
|
lat = parseFloat(queryParams.lat);
|
||||||
}
|
}
|
||||||
@@ -291,6 +313,9 @@ var overviewer = {
|
|||||||
'title': jQuery.trim(item.msg),
|
'title': jQuery.trim(item.msg),
|
||||||
'icon': overviewerConfig.CONST.image.queryMarker
|
'icon': overviewerConfig.CONST.image.queryMarker
|
||||||
});
|
});
|
||||||
|
google.maps.event.addListener(marker, 'click', function(){ marker.setVisible(false); });
|
||||||
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,6 +342,7 @@ var overviewer = {
|
|||||||
'icon': iconURL,
|
'icon': iconURL,
|
||||||
'visible': false
|
'visible': false
|
||||||
});
|
});
|
||||||
|
item.marker = marker;
|
||||||
overviewer.util.debug(label);
|
overviewer.util.debug(label);
|
||||||
overviewer.collections.markers[label].push(marker);
|
overviewer.collections.markers[label].push(marker);
|
||||||
if (item.type == 'sign') {
|
if (item.type == 'sign') {
|
||||||
@@ -339,6 +365,7 @@ var overviewer = {
|
|||||||
'icon': iconURL,
|
'icon': iconURL,
|
||||||
'visible': false
|
'visible': false
|
||||||
});
|
});
|
||||||
|
item.marker = marker;
|
||||||
if (overviewer.collections.markers['__others__']) {
|
if (overviewer.collections.markers['__others__']) {
|
||||||
overviewer.collections.markers['__others__'].push(marker);
|
overviewer.collections.markers['__others__'].push(marker);
|
||||||
} else {
|
} else {
|
||||||
@@ -370,59 +397,76 @@ var overviewer = {
|
|||||||
point.x, point.y, point.z));
|
point.x, point.y, point.z));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (region.label) {
|
||||||
|
var name = region.label;
|
||||||
|
} else {
|
||||||
|
var name = "rawr";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(region.opacity) {
|
||||||
|
var strokeOpacity = region.opacity;
|
||||||
|
var fillOpacity = region.opacity * 0.25;
|
||||||
|
} else {
|
||||||
|
var strokeOpacity = region.strokeOpacity;
|
||||||
|
var fillOpacity = region.fillOpacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shapeOptions = {
|
||||||
|
'name': name,
|
||||||
|
'geodesic': false,
|
||||||
|
'map': null,
|
||||||
|
'strokeColor': region.color,
|
||||||
|
'strokeOpacity': strokeOpacity,
|
||||||
|
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
|
||||||
|
'zIndex': j
|
||||||
|
};
|
||||||
|
if (region.closed) {
|
||||||
|
shapeOptions["fillColor"] = region.color;
|
||||||
|
shapeOptions["fillOpacity"] = fillOpacity;
|
||||||
|
shapeOptions["paths"] = converted;
|
||||||
|
} else {
|
||||||
|
shapeOptions["path"] = converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matched = false;
|
||||||
|
|
||||||
for (k in overviewerConfig.objectGroups.regions) {
|
for (k in overviewerConfig.objectGroups.regions) {
|
||||||
var regionGroup = overviewerConfig.objectGroups.regions[k];
|
var regionGroup = overviewerConfig.objectGroups.regions[k];
|
||||||
var clickable = regionGroup.clickable;
|
var clickable = regionGroup.clickable;
|
||||||
var label = regionGroup.label;
|
var label = regionGroup.label;
|
||||||
|
|
||||||
if(region.label) {
|
if (!regionGroup.match(region))
|
||||||
var name = region.label
|
continue;
|
||||||
} else {
|
matched = true;
|
||||||
var name = 'rawr';
|
|
||||||
|
if (!region.label) {
|
||||||
clickable = false; // if it doesn't have a name, we dont have to show it.
|
clickable = false; // if it doesn't have a name, we dont have to show it.
|
||||||
}
|
}
|
||||||
|
|
||||||
if(region.opacity) {
|
if (region.closed) {
|
||||||
var strokeOpacity = region.opacity;
|
var shape = new google.maps.Polygon(shapeOptions);
|
||||||
var fillOpacity = region.opacity * 0.25;
|
|
||||||
} else {
|
} else {
|
||||||
var strokeOpacity = region.strokeOpacity;
|
var shape = new google.maps.Polyline(shapeOptions);
|
||||||
var fillOpacity = region.fillOpacity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region.closed) {
|
|
||||||
var shape = new google.maps.Polygon({
|
|
||||||
'name': name,
|
|
||||||
'clickable': clickable,
|
|
||||||
'geodesic': false,
|
|
||||||
'map': null,
|
|
||||||
'strokeColor': region.color,
|
|
||||||
'strokeOpacity': strokeOpacity,
|
|
||||||
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
|
|
||||||
'fillColor': region.color,
|
|
||||||
'fillOpacity': fillOpacity,
|
|
||||||
'zIndex': j,
|
|
||||||
'paths': converted
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var shape = new google.maps.Polyline({
|
|
||||||
'name': name,
|
|
||||||
'clickable': clickable,
|
|
||||||
'geodesic': false,
|
|
||||||
'map': null,
|
|
||||||
'strokeColor': region.color,
|
|
||||||
'strokeOpacity': strokeOpacity,
|
|
||||||
'strokeWeight': overviewerConfig.CONST.regionStrokeWeight,
|
|
||||||
'zIndex': j,
|
|
||||||
'path': converted
|
|
||||||
});
|
|
||||||
}
|
|
||||||
overviewer.collections.regions[label].push(shape);
|
overviewer.collections.regions[label].push(shape);
|
||||||
|
|
||||||
if (clickable) {
|
if (clickable) {
|
||||||
overviewer.util.createRegionInfoWindow(shape);
|
overviewer.util.createRegionInfoWindow(shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we haven't matched anything, go ahead and add it
|
||||||
|
if (!matched) {
|
||||||
|
if (region.closed) {
|
||||||
|
var shape = new google.maps.Polygon(shapeOptions);
|
||||||
|
} else {
|
||||||
|
var shape = new google.maps.Polyline(shapeOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
shape.setMap(overviewer.map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -490,7 +534,7 @@ var overviewer = {
|
|||||||
// the width and height of all the highest-zoom tiles combined,
|
// the width and height of all the highest-zoom tiles combined,
|
||||||
// inverted
|
// inverted
|
||||||
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
||||||
Math.pow(2, overviewerConfig.map.maxZoom));
|
Math.pow(2, overviewerConfig.map.zoomLevels));
|
||||||
|
|
||||||
if(overviewerConfig.map.north_direction == 'upper-right'){
|
if(overviewerConfig.map.north_direction == 'upper-right'){
|
||||||
x = -x-1;
|
x = -x-1;
|
||||||
@@ -511,13 +555,13 @@ var overviewer = {
|
|||||||
|
|
||||||
// point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2)
|
// point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2)
|
||||||
// so the Y coordinate is at 0.5, and the X is at 0.5 -
|
// so the Y coordinate is at 0.5, and the X is at 0.5 -
|
||||||
// ((tileSize / 2) / (tileSize * 2^maxZoom))
|
// ((tileSize / 2) / (tileSize * 2^zoomLevels))
|
||||||
// or equivalently, 0.5 - (1 / 2^(maxZoom + 1))
|
// or equivalently, 0.5 - (1 / 2^(zoomLevels + 1))
|
||||||
lat = 0.5;
|
var lng = 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.zoomLevels + 1));
|
||||||
lng = 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1));
|
var lat = 0.5;
|
||||||
|
|
||||||
// the following metrics mimic those in ChunkRenderer.chunk_render
|
// the following metrics mimic those in
|
||||||
// in "chunk.py" or, equivalently, chunk_render in src/iterate.c
|
// chunk_render in src/iterate.c
|
||||||
|
|
||||||
// each block on X axis adds 12px to x and subtracts 6px from y
|
// each block on X axis adds 12px to x and subtracts 6px from y
|
||||||
lng += 12 * x * perPixel;
|
lng += 12 * x * perPixel;
|
||||||
@@ -555,14 +599,13 @@ var overviewer = {
|
|||||||
// the width and height of all the highest-zoom tiles combined,
|
// the width and height of all the highest-zoom tiles combined,
|
||||||
// inverted
|
// inverted
|
||||||
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
var perPixel = 1.0 / (overviewerConfig.CONST.tileSize *
|
||||||
Math.pow(2, overviewerConfig.map.maxZoom));
|
Math.pow(2, overviewerConfig.map.zoomLevels));
|
||||||
|
|
||||||
// Revert base positioning
|
// Revert base positioning
|
||||||
// See equivalent code in fromWorldToLatLng()
|
// See equivalent code in fromWorldToLatLng()
|
||||||
|
lng -= 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.zoomLevels + 1));
|
||||||
lat -= 0.5;
|
lat -= 0.5;
|
||||||
|
|
||||||
lng -= 0.5 - (1.0 / Math.pow(2, overviewerConfig.map.maxZoom + 1));
|
|
||||||
|
|
||||||
// I'll admit, I plugged this into Wolfram Alpha:
|
// I'll admit, I plugged this into Wolfram Alpha:
|
||||||
// a = (x * 12 * r) + (z * 12 * r), b = (z * 6 * r) - (x * 6 * r)
|
// a = (x * 12 * r) + (z * 12 * r), b = (z * 6 * r) - (x * 6 * r)
|
||||||
// And I don't know the math behind solving for for X and Z given
|
// And I don't know the math behind solving for for X and Z given
|
||||||
@@ -622,7 +665,10 @@ var overviewer = {
|
|||||||
var coordsDiv = document.createElement('DIV');
|
var coordsDiv = document.createElement('DIV');
|
||||||
coordsDiv.id = 'coordsDiv';
|
coordsDiv.id = 'coordsDiv';
|
||||||
coordsDiv.innerHTML = '';
|
coordsDiv.innerHTML = '';
|
||||||
overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(coordsDiv);
|
if (overviewerConfig.map.controls.coordsBox) {
|
||||||
|
overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(coordsDiv);
|
||||||
|
}
|
||||||
|
|
||||||
// Update coords on mousemove
|
// Update coords on mousemove
|
||||||
google.maps.event.addListener(overviewer.map, 'mousemove', function (event) {
|
google.maps.event.addListener(overviewer.map, 'mousemove', function (event) {
|
||||||
var worldcoords = overviewer.util.fromLatLngToWorld(event.latLng.lat(), event.latLng.lng());
|
var worldcoords = overviewer.util.fromLatLngToWorld(event.latLng.lat(), event.latLng.lng());
|
||||||
@@ -689,7 +735,7 @@ var overviewer = {
|
|||||||
overviewer.util.createDropDown('Regions', items);
|
overviewer.util.createDropDown('Regions', items);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overviewer.collections.overlays.length > 0) {
|
if (overviewerConfig.map.controls.overlays && overviewer.collections.overlays.length > 0) {
|
||||||
// overlay maps control
|
// overlay maps control
|
||||||
var items = [];
|
var items = [];
|
||||||
for (i in overviewer.collections.overlays) {
|
for (i in overviewer.collections.overlays) {
|
||||||
@@ -717,6 +763,9 @@ var overviewer = {
|
|||||||
}
|
}
|
||||||
overviewer.util.createDropDown('Overlays', items);
|
overviewer.util.createDropDown('Overlays', items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call out to create search box, as it's pretty complicated
|
||||||
|
overviewer.util.createSearchBox();
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Reusable method for creating drop-down menus
|
* Reusable method for creating drop-down menus
|
||||||
@@ -785,6 +834,63 @@ var overviewer = {
|
|||||||
itemDiv.appendChild(textNode);
|
itemDiv.appendChild(textNode);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Create search box and dropdown in the top right google maps area.
|
||||||
|
*/
|
||||||
|
'createSearchBox': function() {
|
||||||
|
var searchControl = document.createElement("div");
|
||||||
|
searchControl.id = "searchControl";
|
||||||
|
|
||||||
|
var searchInput = document.createElement("input");
|
||||||
|
searchInput.type = "text";
|
||||||
|
|
||||||
|
searchControl.appendChild(searchInput);
|
||||||
|
|
||||||
|
var searchDropDown = document.createElement("div");
|
||||||
|
searchDropDown.id = "searchDropDown";
|
||||||
|
searchControl.appendChild(searchDropDown);
|
||||||
|
|
||||||
|
$(searchInput).keyup(function(e) {
|
||||||
|
var newline_stripper = new RegExp("[\\r\\n]", "g")
|
||||||
|
if(searchInput.value.length !== 0) {
|
||||||
|
$(searchDropDown).fadeIn();
|
||||||
|
|
||||||
|
$(searchDropDown).empty();
|
||||||
|
|
||||||
|
overviewer.collections.markerDatas.forEach(function(marker_list) {
|
||||||
|
marker_list.forEach(function(sign) {
|
||||||
|
var regex = new RegExp(overviewer.util.pregQuote(searchInput.value), "mi");
|
||||||
|
if(sign.msg.match(regex)) {
|
||||||
|
if(sign.marker !== undefined && sign.marker.getVisible()) {
|
||||||
|
var t = document.createElement("div");
|
||||||
|
t.className = "searchResultItem";
|
||||||
|
var i = document.createElement("img");
|
||||||
|
i.src = sign.marker.getIcon();
|
||||||
|
t.appendChild(i);
|
||||||
|
var s = document.createElement("span");
|
||||||
|
|
||||||
|
$(s).text(sign.msg.replace(newline_stripper, ""));
|
||||||
|
t.appendChild(s);
|
||||||
|
searchDropDown.appendChild(t);
|
||||||
|
$(t).click(function(e) {
|
||||||
|
$(searchDropDown).fadeOut();
|
||||||
|
overviewer.map.setZoom(7);
|
||||||
|
overviewer.map.setCenter(sign.marker.getPosition());
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$(searchDropDown).fadeOut();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (overviewerConfig.map.controls.searchBox) {
|
||||||
|
overviewer.map.controls[google.maps.ControlPosition.TOP_RIGHT].push(searchControl);
|
||||||
|
}
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Create the pop-up infobox for when you click on a region, this can't
|
* Create the pop-up infobox for when you click on a region, this can't
|
||||||
* be done in-line because of stupid Javascript scoping problems with
|
* be done in-line because of stupid Javascript scoping problems with
|
||||||
@@ -50,9 +50,18 @@ var overviewerConfig = {
|
|||||||
*/
|
*/
|
||||||
'mapType': true,
|
'mapType': true,
|
||||||
/**
|
/**
|
||||||
* The small box at the bottom that displays the link to the current map view.
|
* The coordsBox control is the box showing the XYZ coordinates
|
||||||
|
* under the cursor.
|
||||||
*/
|
*/
|
||||||
'link': true
|
'coordsBox': true,
|
||||||
|
/**
|
||||||
|
* The overlays control is the drop-down box for selecting overlays.
|
||||||
|
*/
|
||||||
|
'overlays': true,
|
||||||
|
/**
|
||||||
|
* The searchBox control is the search box for markers.
|
||||||
|
*/
|
||||||
|
'searchBox': true
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* The zoom level when the page is loaded without a specific zoom setting
|
* The zoom level when the page is loaded without a specific zoom setting
|
||||||
@@ -66,6 +75,12 @@ var overviewerConfig = {
|
|||||||
* This controls how close you can zoom in.
|
* This controls how close you can zoom in.
|
||||||
*/
|
*/
|
||||||
'maxZoom': {maxzoom},
|
'maxZoom': {maxzoom},
|
||||||
|
/**
|
||||||
|
* This tells us how many total zoom levels Overviewer rendered.
|
||||||
|
* DO NOT change this, even if you change minZoom and maxZoom, because
|
||||||
|
* it's used for marker position calculations and map resizing.
|
||||||
|
*/
|
||||||
|
'zoomLevels': {zoomlevels},
|
||||||
/**
|
/**
|
||||||
* Center on this point, in world coordinates. Should be an array, ex:
|
* Center on this point, in world coordinates. Should be an array, ex:
|
||||||
* [0,0,0]
|
* [0,0,0]
|
||||||
|
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 708 B After Width: | Height: | Size: 708 B |
|
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 253 B |
@@ -24,6 +24,7 @@ import json
|
|||||||
|
|
||||||
import util
|
import util
|
||||||
from c_overviewer import get_render_mode_inheritance
|
from c_overviewer import get_render_mode_inheritance
|
||||||
|
import overviewer_version
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module has routines related to generating a Google Maps-based
|
This module has routines related to generating a Google Maps-based
|
||||||
@@ -52,10 +53,15 @@ def mirror_dir(src, dst, entities=None):
|
|||||||
elif os.path.isfile(os.path.join(src,entry)):
|
elif os.path.isfile(os.path.join(src,entry)):
|
||||||
try:
|
try:
|
||||||
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
|
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
|
||||||
except IOError:
|
except IOError as outer:
|
||||||
# maybe permission problems?
|
try:
|
||||||
os.chmod(os.path.join(src, entry), stat.S_IRUSR)
|
# maybe permission problems?
|
||||||
os.chmod(os.path.join(dst, entry), stat.S_IWUSR)
|
src_stat = os.stat(os.path.join(src, entry))
|
||||||
|
os.chmod(os.path.join(src, entry), src_stat.st_mode | stat.S_IRUSR)
|
||||||
|
dst_stat = os.stat(os.path.join(dst, entry))
|
||||||
|
os.chmod(os.path.join(dst, entry), dst_stat.st_mode | stat.S_IWUSR)
|
||||||
|
except OSError: # we don't care if this fails
|
||||||
|
pass
|
||||||
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
|
shutil.copy(os.path.join(src, entry), os.path.join(dst, entry))
|
||||||
# if this stills throws an error, let it propagate up
|
# if this stills throws an error, let it propagate up
|
||||||
|
|
||||||
@@ -99,7 +105,11 @@ class MapGen(object):
|
|||||||
blank.save(os.path.join(tileDir, "blank."+quadtree.imgformat))
|
blank.save(os.path.join(tileDir, "blank."+quadtree.imgformat))
|
||||||
|
|
||||||
# copy web assets into destdir:
|
# copy web assets into destdir:
|
||||||
mirror_dir(os.path.join(util.get_program_path(), "web_assets"), self.destdir)
|
global_assets = os.path.join(util.get_program_path(), "overviewer_core", "data", "web_assets")
|
||||||
|
if not os.path.isdir(global_assets):
|
||||||
|
global_assets = os.path.join(util.get_program_path(), "web_assets")
|
||||||
|
mirror_dir(global_assets, self.destdir)
|
||||||
|
|
||||||
# do the same with the local copy, if we have it
|
# do the same with the local copy, if we have it
|
||||||
if self.web_assets_path:
|
if self.web_assets_path:
|
||||||
mirror_dir(self.web_assets_path, self.destdir)
|
mirror_dir(self.web_assets_path, self.destdir)
|
||||||
@@ -110,6 +120,8 @@ class MapGen(object):
|
|||||||
"{minzoom}", str(0))
|
"{minzoom}", str(0))
|
||||||
config = config.replace(
|
config = config.replace(
|
||||||
"{maxzoom}", str(zoomlevel))
|
"{maxzoom}", str(zoomlevel))
|
||||||
|
config = config.replace(
|
||||||
|
"{zoomlevels}", str(zoomlevel))
|
||||||
config = config.replace(
|
config = config.replace(
|
||||||
"{north_direction}", self.north_direction)
|
"{north_direction}", self.north_direction)
|
||||||
|
|
||||||
@@ -134,9 +146,9 @@ class MapGen(object):
|
|||||||
indexpath = os.path.join(self.destdir, "index.html")
|
indexpath = os.path.join(self.destdir, "index.html")
|
||||||
|
|
||||||
index = open(indexpath, 'r').read()
|
index = open(indexpath, 'r').read()
|
||||||
index = index.replace(
|
index = index.replace("{time}", str(strftime("%a, %d %b %Y %H:%M:%S %Z", localtime())))
|
||||||
"{time}", str(strftime("%a, %d %b %Y %H:%M:%S %Z", localtime())))
|
versionstr = "%s (%s)" % (overviewer_version.VERSION, overviewer_version.HASH[:7])
|
||||||
index = index.replace("{version}", util.findGitVersion())
|
index = index.replace("{version}", versionstr)
|
||||||
|
|
||||||
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
|
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
|
||||||
output.write(index)
|
output.write(index)
|
||||||
@@ -121,7 +121,7 @@ class QuadtreeGen(object):
|
|||||||
indexfile = os.path.join(self.destdir, "overviewerConfig.js")
|
indexfile = os.path.join(self.destdir, "overviewerConfig.js")
|
||||||
if not os.path.exists(indexfile):
|
if not os.path.exists(indexfile):
|
||||||
return -1
|
return -1
|
||||||
matcher = re.compile(r"maxZoom.*:\s*(\d+)")
|
matcher = re.compile(r"zoomLevels(?:\'|\")\s*:\s*(\d+)")
|
||||||
p = -1
|
p = -1
|
||||||
for line in open(indexfile, "r"):
|
for line in open(indexfile, "r"):
|
||||||
res = matcher.search(line)
|
res = matcher.search(line)
|
||||||
@@ -427,21 +427,21 @@ class QuadtreeGen(object):
|
|||||||
needs_rerender = False
|
needs_rerender = False
|
||||||
get_region_mtime = world.get_region_mtime
|
get_region_mtime = world.get_region_mtime
|
||||||
for col, row, chunkx, chunky, regionfile in chunks:
|
for col, row, chunkx, chunky, regionfile in chunks:
|
||||||
|
region, regionMtime = get_region_mtime(regionfile)
|
||||||
|
|
||||||
|
# don't even check if it's not in the regionlist
|
||||||
|
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
|
||||||
|
continue
|
||||||
|
|
||||||
# bail early if forcerender is set
|
# bail early if forcerender is set
|
||||||
if self.forcerender:
|
if self.forcerender:
|
||||||
needs_rerender = True
|
needs_rerender = True
|
||||||
break
|
break
|
||||||
|
|
||||||
# check region file mtime first.
|
# check region file mtime first.
|
||||||
region,regionMtime = get_region_mtime(regionfile)
|
|
||||||
if regionMtime <= tile_mtime:
|
if regionMtime <= tile_mtime:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# don't even check if it's not in the regionlist
|
|
||||||
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# checking chunk mtime
|
# checking chunk mtime
|
||||||
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
||||||
needs_rerender = True
|
needs_rerender = True
|
||||||
@@ -133,8 +133,8 @@ class RenderNode(object):
|
|||||||
else:
|
else:
|
||||||
if not complete % 1000 == 0:
|
if not complete % 1000 == 0:
|
||||||
return
|
return
|
||||||
logging.info("{0}/{1} tiles complete on level {2}/{3}".format(
|
logging.info("{0}/{1} ({4}%) tiles complete on level {2}/{3}".format(
|
||||||
complete, total, level, self.max_p))
|
complete, total, level, self.max_p, '%.1f' % ( (100.0 * complete) / total) ))
|
||||||
|
|
||||||
def go(self, procs):
|
def go(self, procs):
|
||||||
"""Renders all tiles"""
|
"""Renders all tiles"""
|
||||||
@@ -33,13 +33,13 @@ PyObject *init_chunk_render(PyObject *self, PyObject *args) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
textures = PyImport_ImportModule("textures");
|
textures = PyImport_ImportModule("overviewer_core.textures");
|
||||||
/* ensure none of these pointers are NULL */
|
/* ensure none of these pointers are NULL */
|
||||||
if ((!textures)) {
|
if ((!textures)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk_mod = PyImport_ImportModule("chunk");
|
chunk_mod = PyImport_ImportModule("overviewer_core.chunk");
|
||||||
/* ensure none of these pointers are NULL */
|
/* ensure none of these pointers are NULL */
|
||||||
if ((!chunk_mod)) {
|
if ((!chunk_mod)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -174,12 +174,18 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) {
|
|||||||
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f);
|
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
} else if (state->block == 20) { /* glass */
|
||||||
|
/* an aditional bit for top is added to the 4 bits of check_adjacent_blocks */
|
||||||
|
if ((z != 127) && (getArrayByte3D(state->blocks, x, y, z+1) == 20)) {
|
||||||
|
data = 0;
|
||||||
|
} else {
|
||||||
|
data = 16;
|
||||||
|
}
|
||||||
|
data = (check_adjacent_blocks(state, x, y, z, state->block) ^ 0x0f) | data;
|
||||||
|
return data;
|
||||||
} else if (state->block == 85) { /* fences */
|
} else if (state->block == 85) { /* fences */
|
||||||
return check_adjacent_blocks(state, x, y, z, state->block);
|
return check_adjacent_blocks(state, x, y, z, state->block);
|
||||||
|
|
||||||
|
|
||||||
} else if (state->block == 55) { /* redstone */
|
} else if (state->block == 55) { /* redstone */
|
||||||
/* three addiotional bit are added, one for on/off state, and
|
/* three addiotional bit are added, one for on/off state, and
|
||||||
* another two for going-up redstone wire in the same block
|
* another two for going-up redstone wire in the same block
|
||||||
@@ -354,6 +360,10 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
up_right_blocks_py = PyObject_GetAttrString(state.self, "up_right_blocks");
|
up_right_blocks_py = PyObject_GetAttrString(state.self, "up_right_blocks");
|
||||||
state.up_right_blocks = up_right_blocks_py;
|
state.up_right_blocks = up_right_blocks_py;
|
||||||
|
|
||||||
|
/* set up the random number generator again for each chunk
|
||||||
|
so tallgrass is in the same place, no matter what mode is used */
|
||||||
|
srand(1);
|
||||||
|
|
||||||
for (state.x = 15; state.x > -1; state.x--) {
|
for (state.x = 15; state.x > -1; state.x--) {
|
||||||
for (state.y = 0; state.y < 16; state.y++) {
|
for (state.y = 0; state.y < 16; state.y++) {
|
||||||
PyObject *blockid = NULL;
|
PyObject *blockid = NULL;
|
||||||
@@ -366,7 +376,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
for (state.z = 0; state.z < 128; state.z++) {
|
for (state.z = 0; state.z < 128; state.z++) {
|
||||||
state.imgy -= 12;
|
state.imgy -= 12;
|
||||||
|
|
||||||
/* get blockid */
|
/* get blockid */
|
||||||
state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z);
|
state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z);
|
||||||
if (state.block == 0) {
|
if (state.block == 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -402,7 +412,10 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
PyObject *tmp;
|
PyObject *tmp;
|
||||||
|
|
||||||
unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z);
|
unsigned char ancilData = getArrayByte3D(state.blockdata_expanded, state.x, state.y, state.z);
|
||||||
if ((state.block == 85) || (state.block == 9) || (state.block == 55) || (state.block == 54) || (state.block == 2) || (state.block == 90)) {
|
if ((state.block == 2) || (state.block == 9) ||
|
||||||
|
(state.block == 20) || (state.block == 54) ||
|
||||||
|
(state.block == 55) || (state.block == 85) ||
|
||||||
|
(state.block == 90)) {
|
||||||
ancilData = generate_pseudo_data(&state, ancilData);
|
ancilData = generate_pseudo_data(&state, ancilData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,14 +434,29 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
if (t != NULL && t != Py_None)
|
if (t != NULL && t != Py_None)
|
||||||
{
|
{
|
||||||
PyObject *src, *mask, *mask_light;
|
PyObject *src, *mask, *mask_light;
|
||||||
|
int randx = 0, randy = 0;
|
||||||
src = PyTuple_GetItem(t, 0);
|
src = PyTuple_GetItem(t, 0);
|
||||||
mask = PyTuple_GetItem(t, 1);
|
mask = PyTuple_GetItem(t, 1);
|
||||||
mask_light = PyTuple_GetItem(t, 2);
|
mask_light = PyTuple_GetItem(t, 2);
|
||||||
|
|
||||||
if (mask == Py_None)
|
if (mask == Py_None)
|
||||||
mask = src;
|
mask = src;
|
||||||
|
|
||||||
|
if (state.block == 31) {
|
||||||
|
/* add a random offset to the postion of the tall grass to make it more wild */
|
||||||
|
randx = rand() % 6 + 1 - 3;
|
||||||
|
randy = rand() % 6 + 1 - 3;
|
||||||
|
state.imgx += randx;
|
||||||
|
state.imgy += randy;
|
||||||
|
}
|
||||||
|
|
||||||
rendermode->draw(rm_data, &state, src, mask, mask_light);
|
rendermode->draw(rm_data, &state, src, mask, mask_light);
|
||||||
|
|
||||||
|
if (state.block == 31) {
|
||||||
|
/* undo the random offsets */
|
||||||
|
state.imgx -= randx;
|
||||||
|
state.imgy -= randy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,6 @@ rendermode_normal_occluded(void *data, RenderState *state) {
|
|||||||
static void
|
static void
|
||||||
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
RenderModeNormal *self = (RenderModeNormal *)data;
|
RenderModeNormal *self = (RenderModeNormal *)data;
|
||||||
int randx = 0,randy = 0;
|
|
||||||
unsigned char data_byte;
|
unsigned char data_byte;
|
||||||
|
|
||||||
/* first, check to see if we should use biome-compatible src, mask */
|
/* first, check to see if we should use biome-compatible src, mask */
|
||||||
@@ -133,11 +132,6 @@ rendermode_normal_draw(void *data, RenderState *state, PyObject *src, PyObject *
|
|||||||
if (state->block == 18) {
|
if (state->block == 18) {
|
||||||
src = mask = self->leaf_texture;
|
src = mask = self->leaf_texture;
|
||||||
} else if (state->block == 31) {
|
} else if (state->block == 31) {
|
||||||
/* add a random offset to the postion of the tall grass to make it more wild */
|
|
||||||
randx = rand() % 6 + 1 - 3;
|
|
||||||
randy = rand() % 6 + 1 - 3;
|
|
||||||
state->imgx = state->imgx + randx;
|
|
||||||
state->imgy = state->imgy + randy;
|
|
||||||
data_byte = getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z);
|
data_byte = getArrayByte3D(state->blockdata_expanded, state->x, state->y, state->z);
|
||||||
if (data_byte == 1) {
|
if (data_byte == 1) {
|
||||||
src = mask = self->tall_grass_texture;
|
src = mask = self->tall_grass_texture;
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import imp
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -27,13 +28,13 @@ import util
|
|||||||
import composite
|
import composite
|
||||||
|
|
||||||
_find_file_local_path = None
|
_find_file_local_path = None
|
||||||
def _find_file(filename, mode="rb"):
|
def _find_file(filename, mode="rb", verbose=False):
|
||||||
"""Searches for the given file and returns an open handle to it.
|
"""Searches for the given file and returns an open handle to it.
|
||||||
This searches the following locations in this order:
|
This searches the following locations in this order:
|
||||||
|
|
||||||
* the textures_path given in the config file (if present)
|
* the textures_path given in the config file (if present)
|
||||||
* The program dir (same dir as this file)
|
* The program dir (same dir as overviewer.py)
|
||||||
* The program dir / textures
|
* The overviewer_core textures dir
|
||||||
* On Darwin, in /Applications/Minecraft
|
* On Darwin, in /Applications/Minecraft
|
||||||
* Inside minecraft.jar, which is looked for at these locations
|
* Inside minecraft.jar, which is looked for at these locations
|
||||||
|
|
||||||
@@ -46,20 +47,29 @@ def _find_file(filename, mode="rb"):
|
|||||||
if _find_file_local_path:
|
if _find_file_local_path:
|
||||||
path = os.path.join(_find_file_local_path, filename)
|
path = os.path.join(_find_file_local_path, filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
if verbose: print "Found %s in '%s'" % (filename, path)
|
||||||
return open(path, mode)
|
return open(path, mode)
|
||||||
|
|
||||||
programdir = util.get_program_path()
|
programdir = util.get_program_path()
|
||||||
path = os.path.join(programdir, filename)
|
path = os.path.join(programdir, filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
if verbose: print "Found %s in '%s'" % (filename, path)
|
||||||
return open(path, mode)
|
return open(path, mode)
|
||||||
|
|
||||||
path = os.path.join(programdir, "textures", filename)
|
path = os.path.join(programdir, "overviewer_core", "data", "textures", filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return open(path, mode)
|
return open(path, mode)
|
||||||
|
elif hasattr(sys, "frozen") or imp.is_frozen("__main__"):
|
||||||
|
# windows special case, when the package dir doesn't exist
|
||||||
|
path = os.path.join(programdir, "textures", filename)
|
||||||
|
if os.path.exists(path):
|
||||||
|
if verbose: print "Found %s in '%s'" % (filename, path)
|
||||||
|
return open(path, mode)
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
path = os.path.join("/Applications/Minecraft", filename)
|
path = os.path.join("/Applications/Minecraft", filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
if verbose: print "Found %s in '%s'" % (filename, path)
|
||||||
return open(path, mode)
|
return open(path, mode)
|
||||||
|
|
||||||
# Find minecraft.jar.
|
# Find minecraft.jar.
|
||||||
@@ -79,6 +89,7 @@ def _find_file(filename, mode="rb"):
|
|||||||
if os.path.exists(jarpath):
|
if os.path.exists(jarpath):
|
||||||
try:
|
try:
|
||||||
jar = zipfile.ZipFile(jarpath)
|
jar = zipfile.ZipFile(jarpath)
|
||||||
|
if verbose: print "Found %s in '%s'" % (filename, jarpath)
|
||||||
return jar.open(filename)
|
return jar.open(filename)
|
||||||
except (KeyError, IOError):
|
except (KeyError, IOError):
|
||||||
pass
|
pass
|
||||||
@@ -151,13 +162,13 @@ def transform_image_side(img, blockID=None):
|
|||||||
# (don't just crop img, since we want the size of
|
# (don't just crop img, since we want the size of
|
||||||
# img to be unchanged
|
# img to be unchanged
|
||||||
mask = img.crop((0,8,16,16))
|
mask = img.crop((0,8,16,16))
|
||||||
n = Image.new(img.mode, img.size, (38,92,255,0))
|
n = Image.new(img.mode, img.size, bgcolor)
|
||||||
composite.alpha_over(n, mask,(0,0,16,8), mask)
|
composite.alpha_over(n, mask,(0,0,16,8), mask)
|
||||||
img = n
|
img = n
|
||||||
if blockID in (78,): # snow
|
if blockID in (78,): # snow
|
||||||
# make the top three quarters transparent
|
# make the top three quarters transparent
|
||||||
mask = img.crop((0,12,16,16))
|
mask = img.crop((0,12,16,16))
|
||||||
n = Image.new(img.mode, img.size, (38,92,255,0))
|
n = Image.new(img.mode, img.size, bgcolor)
|
||||||
composite.alpha_over(n, mask,(0,12,16,16), mask)
|
composite.alpha_over(n, mask,(0,12,16,16), mask)
|
||||||
img = n
|
img = n
|
||||||
|
|
||||||
@@ -235,7 +246,7 @@ def _build_block(top, side, blockID=None):
|
|||||||
top and side should be 16x16 image objects. Returns a 24x24 image
|
top and side should be 16x16 image objects. Returns a 24x24 image
|
||||||
|
|
||||||
"""
|
"""
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
original_texture = top.copy()
|
original_texture = top.copy()
|
||||||
top = transform_image(top, blockID)
|
top = transform_image(top, blockID)
|
||||||
@@ -315,36 +326,36 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
|
|||||||
|
|
||||||
A non transparent block uses top, side 3 and side 4.
|
A non transparent block uses top, side 3 and side 4.
|
||||||
|
|
||||||
If top is a tuple then first member is the top image and the second
|
If top is a tuple then first item is the top image and the second
|
||||||
member is an increment (integer) from 0 to 12. This increment will
|
item is an increment (integer) from 0 to 16 (pixels in the
|
||||||
used to crop the side images to look like a block and to paste all
|
original minecraft texture). This increment will be used to crop the
|
||||||
the images increment pixels lower. Using increment = 6 will create
|
side images and to paste the top image increment pixels lower, so if
|
||||||
a half-block.
|
you use an increment of 8, it willll draw a half-block.
|
||||||
|
|
||||||
NOTE: this method uses the top of the texture image (as done in
|
NOTE: this method uses the bottom of the texture image (as done in
|
||||||
minecraft with beds)
|
minecraft with beds and cackes)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
increment = 0
|
increment = 0
|
||||||
if isinstance(top, tuple):
|
if isinstance(top, tuple):
|
||||||
increment = top[1]
|
increment = int(round((top[1] / 16.)*12.)) # range increment in the block height in pixels (half texture size)
|
||||||
crop_height = int(increment * 16./12.)
|
crop_height = increment
|
||||||
top = top[0]
|
top = top[0]
|
||||||
if side1 != None:
|
if side1 != None:
|
||||||
side1 = side1.copy()
|
side1 = side1.copy()
|
||||||
ImageDraw.Draw(side1).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(side1).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
if side2 != None:
|
if side2 != None:
|
||||||
side2 = side2.copy()
|
side2 = side2.copy()
|
||||||
ImageDraw.Draw(side2).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(side2).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
if side3 != None:
|
if side3 != None:
|
||||||
side3 = side3.copy()
|
side3 = side3.copy()
|
||||||
ImageDraw.Draw(side3).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(side3).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
if side4 != None:
|
if side4 != None:
|
||||||
side4 = side4.copy()
|
side4 = side4.copy()
|
||||||
ImageDraw.Draw(side4).rectangle((0, 16 - crop_height,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(side4).rectangle((0, 0,16,crop_height),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
# first back sides
|
# first back sides
|
||||||
if side1 != None :
|
if side1 != None :
|
||||||
@@ -356,7 +367,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
|
|||||||
side1 = ImageEnhance.Brightness(side1).enhance(0.9)
|
side1 = ImageEnhance.Brightness(side1).enhance(0.9)
|
||||||
side1.putalpha(sidealpha)
|
side1.putalpha(sidealpha)
|
||||||
|
|
||||||
composite.alpha_over(img, side1, (0,0 + increment), side1)
|
composite.alpha_over(img, side1, (0,0), side1)
|
||||||
|
|
||||||
|
|
||||||
if side2 != None :
|
if side2 != None :
|
||||||
@@ -367,11 +378,11 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
|
|||||||
side2 = ImageEnhance.Brightness(side2).enhance(0.8)
|
side2 = ImageEnhance.Brightness(side2).enhance(0.8)
|
||||||
side2.putalpha(sidealpha2)
|
side2.putalpha(sidealpha2)
|
||||||
|
|
||||||
composite.alpha_over(img, side2, (12,0 + increment), side2)
|
composite.alpha_over(img, side2, (12,0), side2)
|
||||||
|
|
||||||
if bottom != None :
|
if bottom != None :
|
||||||
bottom = transform_image(bottom, blockID)
|
bottom = transform_image(bottom, blockID)
|
||||||
composite.alpha_over(img, bottom, (0,12), top)
|
composite.alpha_over(img, bottom, (0,12), bottom)
|
||||||
|
|
||||||
# front sides
|
# front sides
|
||||||
if side3 != None :
|
if side3 != None :
|
||||||
@@ -382,7 +393,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
|
|||||||
side3 = ImageEnhance.Brightness(side3).enhance(0.9)
|
side3 = ImageEnhance.Brightness(side3).enhance(0.9)
|
||||||
side3.putalpha(sidealpha)
|
side3.putalpha(sidealpha)
|
||||||
|
|
||||||
composite.alpha_over(img, side3, (0,6 + increment), side3)
|
composite.alpha_over(img, side3, (0,6), side3)
|
||||||
|
|
||||||
if side4 != None :
|
if side4 != None :
|
||||||
side4 = transform_image_side(side4, blockID)
|
side4 = transform_image_side(side4, blockID)
|
||||||
@@ -393,7 +404,7 @@ def _build_full_block(top, side1, side2, side3, side4, bottom=None, blockID=None
|
|||||||
side4 = ImageEnhance.Brightness(side4).enhance(0.8)
|
side4 = ImageEnhance.Brightness(side4).enhance(0.8)
|
||||||
side4.putalpha(sidealpha)
|
side4.putalpha(sidealpha)
|
||||||
|
|
||||||
composite.alpha_over(img, side4, (12,6 + increment), side4)
|
composite.alpha_over(img, side4, (12,6), side4)
|
||||||
|
|
||||||
if top != None :
|
if top != None :
|
||||||
top = transform_image(top, blockID)
|
top = transform_image(top, blockID)
|
||||||
@@ -414,7 +425,7 @@ def _build_blockimages():
|
|||||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||||
topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
|
topids = [ -1, 1, 0, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
|
||||||
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
34, -1, 52, 48, 49,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1,
|
34, -1, 52, 48, -1,160,144, -1,176, 74, -1, -1, -1, -1, 11, -1,
|
||||||
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
||||||
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4,
|
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 9, 4,
|
||||||
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
@@ -431,7 +442,7 @@ def _build_blockimages():
|
|||||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||||
sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
|
sideids = [ -1, 1, 3, 2, 16, 4, -1, 17,205,205,237,237, 18, 19, 32, 33,
|
||||||
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
# 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
34, -1, 52, 48, 49,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1,
|
34, -1, 52, 48, -1,160,144, -1,192, 74, -1, -1,- 1, -1, 11, -1,
|
||||||
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
# 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
||||||
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35,
|
55, -1, -1, -1, -1, 13, 12, 29, 28, 23, 22, -1, -1, 7, 8, 35,
|
||||||
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
# 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
@@ -502,12 +513,11 @@ def generate_texture_tuple(img, blockid):
|
|||||||
|
|
||||||
def generate_special_texture(blockID, data, north_direction):
|
def generate_special_texture(blockID, data, north_direction):
|
||||||
"""Generates a special texture, such as a correctly facing minecraft track"""
|
"""Generates a special texture, such as a correctly facing minecraft track"""
|
||||||
#print "%s has ancillary data: %X" %(blockID, data)
|
|
||||||
# TODO ladders, stairs, levers, buttons, and signs
|
|
||||||
# all need to behandled here (and in chunkpy)
|
|
||||||
|
|
||||||
data = convert_data(blockID, data, north_direction)
|
data = convert_data(blockID, data, north_direction)
|
||||||
|
|
||||||
|
# blocks need to be handled here (and in chunk.py)
|
||||||
|
|
||||||
if blockID == 2: # grass
|
if blockID == 2: # grass
|
||||||
# data & 0x10 means SNOW sides
|
# data & 0x10 means SNOW sides
|
||||||
side_img = terrain_images[3]
|
side_img = terrain_images[3]
|
||||||
@@ -544,33 +554,39 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 9: # spring water, flowing water and waterfall water
|
if blockID == 9 or blockID == 20: # spring water, flowing water and waterfall water, AND glass
|
||||||
|
# water and glass share the way to be rendered
|
||||||
watertexture = _load_image("water.png")
|
if blockID == 9:
|
||||||
|
texture = _load_image("water.png")
|
||||||
|
else:
|
||||||
|
texture = terrain_images[49]
|
||||||
|
|
||||||
if (data & 0b10000) == 16:
|
if (data & 0b10000) == 16:
|
||||||
top = watertexture
|
top = texture
|
||||||
|
|
||||||
else: top = None
|
else: top = None
|
||||||
|
|
||||||
if (data & 0b0001) == 1:
|
if (data & 0b0001) == 1:
|
||||||
side1 = watertexture # top left
|
side1 = texture # top left
|
||||||
else: side1 = None
|
else: side1 = None
|
||||||
|
|
||||||
if (data & 0b1000) == 8:
|
if (data & 0b1000) == 8:
|
||||||
side2 = watertexture # top right
|
side2 = texture # top right
|
||||||
else: side2 = None
|
else: side2 = None
|
||||||
|
|
||||||
if (data & 0b0010) == 2:
|
if (data & 0b0010) == 2:
|
||||||
side3 = watertexture # bottom left
|
side3 = texture # bottom left
|
||||||
else: side3 = None
|
else: side3 = None
|
||||||
|
|
||||||
if (data & 0b0100) == 4:
|
if (data & 0b0100) == 4:
|
||||||
side4 = watertexture # bottom right
|
side4 = texture # bottom right
|
||||||
else: side4 = None
|
else: side4 = None
|
||||||
|
|
||||||
img = _build_full_block(top,None,None,side3,side4)
|
# if nothing shown do not draw at all
|
||||||
|
if top == side3 == side4 == None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
img = _build_full_block(top,None,None,side3,side4)
|
||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
@@ -596,7 +612,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
|
|
||||||
if blockID == 26: # bed
|
if blockID == 26: # bed
|
||||||
increment = 5
|
increment = 8
|
||||||
left_face = None
|
left_face = None
|
||||||
right_face = None
|
right_face = None
|
||||||
if data & 0x8 == 0x8: # head of the bed
|
if data & 0x8 == 0x8: # head of the bed
|
||||||
@@ -640,6 +656,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 31: # tall grass
|
if blockID == 31: # tall grass
|
||||||
if data == 0: # dead shrub
|
if data == 0: # dead shrub
|
||||||
texture = terrain_images[55]
|
texture = terrain_images[55]
|
||||||
@@ -652,8 +669,134 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
img = _build_block(texture, texture, blockID)
|
img = _build_block(texture, texture, blockID)
|
||||||
return generate_texture_tuple(img,31)
|
return generate_texture_tuple(img,31)
|
||||||
|
|
||||||
|
|
||||||
|
if blockID in (29,33): # sticky and normal body piston.
|
||||||
|
if blockID == 29: # sticky
|
||||||
|
piston_t = terrain_images[106].copy()
|
||||||
|
else: # normal
|
||||||
|
piston_t = terrain_images[107].copy()
|
||||||
|
|
||||||
|
# other textures
|
||||||
|
side_t = terrain_images[108].copy()
|
||||||
|
back_t = terrain_images[109].copy()
|
||||||
|
interior_t = terrain_images[110].copy()
|
||||||
|
|
||||||
|
if data & 0x08 == 0x08: # pushed out, non full blocks, tricky stuff
|
||||||
|
# remove piston texture from piston body
|
||||||
|
ImageDraw.Draw(side_t).rectangle((0, 0,16,3),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
|
if data & 0x07 == 0x0: # down
|
||||||
|
side_t = side_t.rotate(180)
|
||||||
|
img = _build_full_block(back_t ,None ,None ,side_t, side_t)
|
||||||
|
|
||||||
|
elif data & 0x07 == 0x1: # up
|
||||||
|
img = _build_full_block((interior_t, 4) ,None ,None ,side_t, side_t)
|
||||||
|
|
||||||
|
elif data & 0x07 == 0x2: # east
|
||||||
|
img = _build_full_block(side_t , None, None ,side_t.rotate(90), back_t)
|
||||||
|
|
||||||
|
elif data & 0x07 == 0x3: # west
|
||||||
|
img = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), None)
|
||||||
|
temp = transform_image_side(interior_t, blockID)
|
||||||
|
temp = temp.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
composite.alpha_over(img, temp, (9,5), temp)
|
||||||
|
|
||||||
|
elif data & 0x07 == 0x4: # north
|
||||||
|
img = _build_full_block(side_t.rotate(90) ,None ,None , None, side_t.rotate(270))
|
||||||
|
temp = transform_image_side(interior_t, blockID)
|
||||||
|
composite.alpha_over(img, temp, (3,5), temp)
|
||||||
|
|
||||||
|
elif data & 0x07 == 0x5: # south
|
||||||
|
img = _build_full_block(side_t.rotate(270) ,None , None ,back_t, side_t.rotate(90))
|
||||||
|
|
||||||
|
else: # pushed in, normal full blocks, easy stuff
|
||||||
|
if data & 0x07 == 0x0: # down
|
||||||
|
side_t = side_t.rotate(180)
|
||||||
|
img = _build_full_block(back_t ,None ,None ,side_t, side_t)
|
||||||
|
elif data & 0x07 == 0x1: # up
|
||||||
|
img = _build_full_block(piston_t ,None ,None ,side_t, side_t)
|
||||||
|
elif data & 0x07 == 0x2: # east
|
||||||
|
img = _build_full_block(side_t ,None ,None ,side_t.rotate(90), back_t)
|
||||||
|
elif data & 0x07 == 0x3: # west
|
||||||
|
img = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), piston_t)
|
||||||
|
elif data & 0x07 == 0x4: # north
|
||||||
|
img = _build_full_block(side_t.rotate(90) ,None ,None ,piston_t, side_t.rotate(270))
|
||||||
|
elif data & 0x07 == 0x5: # south
|
||||||
|
img = _build_full_block(side_t.rotate(270) ,None ,None ,back_t, side_t.rotate(90))
|
||||||
|
|
||||||
|
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
|
if blockID == 34: # piston extension (sticky and normal)
|
||||||
|
if (data & 0x8) == 0x8: # sticky
|
||||||
|
piston_t = terrain_images[106].copy()
|
||||||
|
else: # normal
|
||||||
|
piston_t = terrain_images[107].copy()
|
||||||
|
|
||||||
|
# other textures
|
||||||
|
side_t = terrain_images[108].copy()
|
||||||
|
back_t = terrain_images[107].copy()
|
||||||
|
# crop piston body
|
||||||
|
ImageDraw.Draw(side_t).rectangle((0, 4,16,16),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
|
# generate the horizontal piston extension stick
|
||||||
|
h_stick = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
temp = transform_image_side(side_t, blockID)
|
||||||
|
composite.alpha_over(h_stick, temp, (1,7), temp)
|
||||||
|
temp = transform_image(side_t.rotate(90))
|
||||||
|
composite.alpha_over(h_stick, temp, (1,1), temp)
|
||||||
|
# Darken it
|
||||||
|
sidealpha = h_stick.split()[3]
|
||||||
|
h_stick = ImageEnhance.Brightness(h_stick).enhance(0.85)
|
||||||
|
h_stick.putalpha(sidealpha)
|
||||||
|
|
||||||
|
# generate the vertical piston extension stick
|
||||||
|
v_stick = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
temp = transform_image_side(side_t.rotate(90), blockID)
|
||||||
|
composite.alpha_over(v_stick, temp, (12,6), temp)
|
||||||
|
temp = temp.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
composite.alpha_over(v_stick, temp, (1,6), temp)
|
||||||
|
# Darken it
|
||||||
|
sidealpha = v_stick.split()[3]
|
||||||
|
v_stick = ImageEnhance.Brightness(v_stick).enhance(0.85)
|
||||||
|
v_stick.putalpha(sidealpha)
|
||||||
|
|
||||||
|
# Piston orientation is stored in the 3 first bits
|
||||||
|
if data & 0x07 == 0x0: # down
|
||||||
|
side_t = side_t.rotate(180)
|
||||||
|
img = _build_full_block((back_t, 12) ,None ,None ,side_t, side_t)
|
||||||
|
composite.alpha_over(img, v_stick, (0,-3), v_stick)
|
||||||
|
elif data & 0x07 == 0x1: # up
|
||||||
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
img2 = _build_full_block(piston_t ,None ,None ,side_t, side_t)
|
||||||
|
composite.alpha_over(img, v_stick, (0,4), v_stick)
|
||||||
|
composite.alpha_over(img, img2, (0,0), img2)
|
||||||
|
elif data & 0x07 == 0x2: # east
|
||||||
|
img = _build_full_block(side_t ,None ,None ,side_t.rotate(90), None)
|
||||||
|
temp = transform_image_side(back_t, blockID).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
composite.alpha_over(img, temp, (2,2), temp)
|
||||||
|
composite.alpha_over(img, h_stick, (6,3), h_stick)
|
||||||
|
elif data & 0x07 == 0x3: # west
|
||||||
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
img2 = _build_full_block(side_t.rotate(180) ,None ,None ,side_t.rotate(270), piston_t)
|
||||||
|
composite.alpha_over(img, h_stick, (0,0), h_stick)
|
||||||
|
composite.alpha_over(img, img2, (0,0), img2)
|
||||||
|
elif data & 0x07 == 0x4: # north
|
||||||
|
img = _build_full_block(side_t.rotate(90) ,None ,None , piston_t, side_t.rotate(270))
|
||||||
|
composite.alpha_over(img, h_stick.transpose(Image.FLIP_LEFT_RIGHT), (0,0), h_stick.transpose(Image.FLIP_LEFT_RIGHT))
|
||||||
|
elif data & 0x07 == 0x5: # south
|
||||||
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
img2 = _build_full_block(side_t.rotate(270) ,None ,None ,None, side_t.rotate(90))
|
||||||
|
temp = transform_image_side(back_t, blockID)
|
||||||
|
composite.alpha_over(img2, temp, (10,2), temp)
|
||||||
|
composite.alpha_over(img, img2, (0,0), img2)
|
||||||
|
composite.alpha_over(img, h_stick.transpose(Image.FLIP_LEFT_RIGHT), (-3,2), h_stick.transpose(Image.FLIP_LEFT_RIGHT))
|
||||||
|
|
||||||
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID == 35: # wool
|
if blockID == 35: # wool
|
||||||
if data == 0: # white
|
if data == 0: # white
|
||||||
top = side = terrain_images[64]
|
top = side = terrain_images[64]
|
||||||
@@ -710,6 +853,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
|
|
||||||
if blockID in (50,75,76): # torch, off redstone torch, on redstone torch
|
if blockID in (50,75,76): # torch, off redstone torch, on redstone torch
|
||||||
|
|
||||||
# choose the proper texture
|
# choose the proper texture
|
||||||
if blockID == 50: # torch
|
if blockID == 50: # torch
|
||||||
small = terrain_images[80]
|
small = terrain_images[80]
|
||||||
@@ -720,7 +864,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
# compose a torch bigger than the normal
|
# compose a torch bigger than the normal
|
||||||
# (better for doing transformations)
|
# (better for doing transformations)
|
||||||
torch = Image.new("RGBA", (16,16), (38,92,255,0))
|
torch = Image.new("RGBA", (16,16), bgcolor)
|
||||||
composite.alpha_over(torch,small,(-4,-3))
|
composite.alpha_over(torch,small,(-4,-3))
|
||||||
composite.alpha_over(torch,small,(-5,-2))
|
composite.alpha_over(torch,small,(-5,-2))
|
||||||
composite.alpha_over(torch,small,(-3,-2))
|
composite.alpha_over(torch,small,(-3,-2))
|
||||||
@@ -746,17 +890,17 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
elif data == 5: # standing on the floor
|
elif data == 5: # standing on the floor
|
||||||
# compose a "3d torch".
|
# compose a "3d torch".
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
small_crop = small.crop((2,2,14,14))
|
small_crop = small.crop((2,2,14,14))
|
||||||
slice = small_crop.copy()
|
slice = small_crop.copy()
|
||||||
ImageDraw.Draw(slice).rectangle((6,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(slice).rectangle((6,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
ImageDraw.Draw(slice).rectangle((0,0,4,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(slice).rectangle((0,0,4,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
composite.alpha_over(img, slice, (6,4))
|
composite.alpha_over(img, slice, (7,5))
|
||||||
composite.alpha_over(img, small_crop, (5,5))
|
composite.alpha_over(img, small_crop, (6,6))
|
||||||
composite.alpha_over(img, small_crop, (6,5))
|
composite.alpha_over(img, small_crop, (7,6))
|
||||||
composite.alpha_over(img, slice, (6,6))
|
composite.alpha_over(img, slice, (7,7))
|
||||||
|
|
||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
@@ -766,7 +910,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
side1 = transform_image_side(firetexture)
|
side1 = transform_image_side(firetexture)
|
||||||
side2 = transform_image_side(firetexture).transpose(Image.FLIP_LEFT_RIGHT)
|
side2 = transform_image_side(firetexture).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
composite.alpha_over(img, side1, (12,0), side1)
|
composite.alpha_over(img, side1, (12,0), side1)
|
||||||
composite.alpha_over(img, side2, (0,0), side2)
|
composite.alpha_over(img, side2, (0,0), side2)
|
||||||
@@ -813,14 +957,14 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
composite.alpha_over(img, tmp2, (0,6))
|
composite.alpha_over(img, tmp2, (0,6))
|
||||||
|
|
||||||
elif data == 1: # ascending north
|
elif data == 1: # ascending north
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back
|
img = Image.new("RGBA", (24,24), bgcolor) # first paste the texture in the back
|
||||||
tmp1 = transform_image(half_block_r)
|
tmp1 = transform_image(half_block_r)
|
||||||
composite.alpha_over(img, tmp1, (0,6))
|
composite.alpha_over(img, tmp1, (0,6))
|
||||||
tmp2 = _build_full_block(half_block_l, None, None, texture, side)
|
tmp2 = _build_full_block(half_block_l, None, None, texture, side)
|
||||||
composite.alpha_over(img, tmp2)
|
composite.alpha_over(img, tmp2)
|
||||||
|
|
||||||
elif data == 2: # ascending west
|
elif data == 2: # ascending west
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0)) # first paste the texture in the back
|
img = Image.new("RGBA", (24,24), bgcolor) # first paste the texture in the back
|
||||||
tmp1 = transform_image(half_block_u)
|
tmp1 = transform_image(half_block_u)
|
||||||
composite.alpha_over(img, tmp1, (0,6))
|
composite.alpha_over(img, tmp1, (0,6))
|
||||||
tmp2 = _build_full_block(half_block_d, None, None, side, texture)
|
tmp2 = _build_full_block(half_block_d, None, None, side, texture)
|
||||||
@@ -937,7 +1081,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
bottom = redstone_wire_t.copy().rotate(90)
|
bottom = redstone_wire_t.copy().rotate(90)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
bottom = Image.new("RGBA", (16,16), (38,92,255,0))
|
bottom = Image.new("RGBA", (16,16), bgcolor)
|
||||||
if (data & 0b0001) == 1:
|
if (data & 0b0001) == 1:
|
||||||
composite.alpha_over(bottom,branch_top_left)
|
composite.alpha_over(bottom,branch_top_left)
|
||||||
|
|
||||||
@@ -981,7 +1125,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
crop2 = transform_image_side(raw_crop, blockID)
|
crop2 = transform_image_side(raw_crop, blockID)
|
||||||
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
|
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
composite.alpha_over(img, crop1, (0,12), crop1)
|
composite.alpha_over(img, crop1, (0,12), crop1)
|
||||||
composite.alpha_over(img, crop2, (6,3), crop2)
|
composite.alpha_over(img, crop2, (6,3), crop2)
|
||||||
composite.alpha_over(img, crop3, (6,3), crop3)
|
composite.alpha_over(img, crop3, (6,3), crop3)
|
||||||
@@ -1014,6 +1158,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
|
|
||||||
if blockID == 63: # singposts
|
if blockID == 63: # singposts
|
||||||
|
|
||||||
texture = terrain_images[4].copy()
|
texture = terrain_images[4].copy()
|
||||||
# cut the planks to the size of a signpost
|
# cut the planks to the size of a signpost
|
||||||
ImageDraw.Draw(texture).rectangle((0,12,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(texture).rectangle((0,12,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
@@ -1031,7 +1176,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
texture_stick = texture_stick.resize((12,12), Image.ANTIALIAS)
|
texture_stick = texture_stick.resize((12,12), Image.ANTIALIAS)
|
||||||
ImageDraw.Draw(texture_stick).rectangle((2,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(texture_stick).rectangle((2,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
# W N ~90 E S ~270
|
# W N ~90 E S ~270
|
||||||
angles = (330.,345.,0.,15.,30.,55.,95.,120.,150.,165.,180.,195.,210.,230.,265.,310.)
|
angles = (330.,345.,0.,15.,30.,55.,95.,120.,150.,165.,180.,195.,210.,230.,265.,310.)
|
||||||
@@ -1069,8 +1214,8 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
swung=False
|
swung=False
|
||||||
|
|
||||||
# mask out the high bits to figure out the orientation
|
# mask out the high bits to figure out the orientation
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
if (data & 0x03) == 0:
|
if (data & 0x03) == 0: # northeast corner
|
||||||
if not swung:
|
if not swung:
|
||||||
tex = transform_image_side(raw_door)
|
tex = transform_image_side(raw_door)
|
||||||
composite.alpha_over(img, tex, (0,6), tex)
|
composite.alpha_over(img, tex, (0,6), tex)
|
||||||
@@ -1080,7 +1225,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
|
tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
composite.alpha_over(img, tex, (0,0), tex)
|
composite.alpha_over(img, tex, (0,0), tex)
|
||||||
|
|
||||||
if (data & 0x03) == 1:
|
if (data & 0x03) == 1: # southeast corner
|
||||||
if not swung:
|
if not swung:
|
||||||
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
|
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
composite.alpha_over(img, tex, (0,0), tex)
|
composite.alpha_over(img, tex, (0,0), tex)
|
||||||
@@ -1088,7 +1233,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
tex = transform_image_side(raw_door)
|
tex = transform_image_side(raw_door)
|
||||||
composite.alpha_over(img, tex, (12,0), tex)
|
composite.alpha_over(img, tex, (12,0), tex)
|
||||||
|
|
||||||
if (data & 0x03) == 2:
|
if (data & 0x03) == 2: # southwest corner
|
||||||
if not swung:
|
if not swung:
|
||||||
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
|
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
|
||||||
composite.alpha_over(img, tex, (12,0), tex)
|
composite.alpha_over(img, tex, (12,0), tex)
|
||||||
@@ -1096,7 +1241,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
|
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
composite.alpha_over(img, tex, (12,6), tex)
|
composite.alpha_over(img, tex, (12,6), tex)
|
||||||
|
|
||||||
if (data & 0x03) == 3:
|
if (data & 0x03) == 3: # northwest corner
|
||||||
if not swung:
|
if not swung:
|
||||||
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
|
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
composite.alpha_over(img, tex, (12,6), tex)
|
composite.alpha_over(img, tex, (12,6), tex)
|
||||||
@@ -1108,7 +1253,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
|
|
||||||
if blockID == 65: # ladder
|
if blockID == 65: # ladder
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
raw_texture = terrain_images[83]
|
raw_texture = terrain_images[83]
|
||||||
#print "ladder is facing: %d" % data
|
#print "ladder is facing: %d" % data
|
||||||
if data == 5:
|
if data == 5:
|
||||||
@@ -1133,7 +1278,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
|
|
||||||
if blockID in (27, 28, 66): # minetrack:
|
if blockID in (27, 28, 66): # minetrack:
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
if blockID == 27: # powered rail
|
if blockID == 27: # powered rail
|
||||||
if data & 0x8 == 0: # unpowered
|
if data & 0x8 == 0: # unpowered
|
||||||
@@ -1216,7 +1361,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
texture.putpixel((x,y),(0,0,0,255))
|
texture.putpixel((x,y),(0,0,0,255))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
incrementx = 0
|
incrementx = 0
|
||||||
if data == 2: # east
|
if data == 2: # east
|
||||||
@@ -1250,7 +1395,6 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
ImageDraw.Draw(fence_top).rectangle((0,0,15,5),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(fence_top).rectangle((0,0,15,5),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
ImageDraw.Draw(fence_top).rectangle((0,10,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(fence_top).rectangle((0,10,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
ImageDraw.Draw(fence_side).rectangle((0,0,15,0),outline=(0,0,0,0),fill=(0,0,0,0))
|
|
||||||
ImageDraw.Draw(fence_side).rectangle((0,0,5,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(fence_side).rectangle((0,0,5,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
ImageDraw.Draw(fence_side).rectangle((10,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(fence_side).rectangle((10,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
@@ -1270,10 +1414,10 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
fence_other_side.putalpha(othersidealpha)
|
fence_other_side.putalpha(othersidealpha)
|
||||||
|
|
||||||
# Compose the fence big stick
|
# Compose the fence big stick
|
||||||
fence_big = Image.new("RGBA", (24,24), (38,92,255,0))
|
fence_big = Image.new("RGBA", (24,24), bgcolor)
|
||||||
composite.alpha_over(fence_big,fence_side, (5,4),fence_side)
|
composite.alpha_over(fence_big,fence_side, (5,4),fence_side)
|
||||||
composite.alpha_over(fence_big,fence_other_side, (7,4),fence_other_side)
|
composite.alpha_over(fence_big,fence_other_side, (7,4),fence_other_side)
|
||||||
composite.alpha_over(fence_big,fence_top, (0,1),fence_top)
|
composite.alpha_over(fence_big,fence_top, (0,0),fence_top)
|
||||||
|
|
||||||
# Now render the small sticks.
|
# Now render the small sticks.
|
||||||
# Create needed images
|
# Create needed images
|
||||||
@@ -1301,7 +1445,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
fence_small_side.putalpha(sidealpha)
|
fence_small_side.putalpha(sidealpha)
|
||||||
|
|
||||||
# Create img to compose the fence
|
# Create img to compose the fence
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
# Position of fence small sticks in img.
|
# Position of fence small sticks in img.
|
||||||
# These postitions are strange because the small sticks of the
|
# These postitions are strange because the small sticks of the
|
||||||
@@ -1351,7 +1495,7 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
|
|
||||||
if blockID == 90: # portal
|
if blockID == 90: # portal
|
||||||
portaltexture = _load_image("portal.png")
|
portaltexture = _load_image("portal.png")
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
side = transform_image_side(portaltexture)
|
side = transform_image_side(portaltexture)
|
||||||
otherside = side.transpose(Image.FLIP_TOP_BOTTOM)
|
otherside = side.transpose(Image.FLIP_TOP_BOTTOM)
|
||||||
@@ -1380,23 +1524,21 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
otherside = ImageEnhance.Brightness(otherside).enhance(0.8)
|
otherside = ImageEnhance.Brightness(otherside).enhance(0.8)
|
||||||
otherside.putalpha(othersidealpha)
|
otherside.putalpha(othersidealpha)
|
||||||
|
|
||||||
img = Image.new("RGBA", (24,24), (38,92,255,0))
|
img = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
composite.alpha_over(img, side, (1,12), side)
|
composite.alpha_over(img, side, (1,6), side)
|
||||||
composite.alpha_over(img, otherside, (11,13), otherside) # workaround, fixes a hole
|
composite.alpha_over(img, otherside, (11,7), otherside) # workaround, fixes a hole
|
||||||
composite.alpha_over(img, otherside, (12,12), otherside)
|
composite.alpha_over(img, otherside, (12,6), otherside)
|
||||||
composite.alpha_over(img, top, (0,6), top)
|
composite.alpha_over(img, top, (0,6), top)
|
||||||
|
|
||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
if blockID in (93, 94): # redstone repeaters, ON and OFF
|
if blockID in (93, 94): # redstone repeaters (diodes), ON and OFF
|
||||||
# NOTE: this function uses the redstone torches generated above,
|
# generate the diode
|
||||||
# this must run after the function of the torches.
|
|
||||||
|
|
||||||
top = terrain_images[131] if blockID == 93 else terrain_images[147]
|
top = terrain_images[131] if blockID == 93 else terrain_images[147]
|
||||||
side = terrain_images[5]
|
side = terrain_images[5]
|
||||||
increment = 9
|
increment = 13
|
||||||
|
|
||||||
if (data & 0x3) == 0: # pointing east
|
if (data & 0x3) == 0: # pointing east
|
||||||
pass
|
pass
|
||||||
@@ -1411,12 +1553,22 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
top = top.rotate(90)
|
top = top.rotate(90)
|
||||||
|
|
||||||
img = _build_full_block( (top, increment), None, None, side, side)
|
img = _build_full_block( (top, increment), None, None, side, side)
|
||||||
|
|
||||||
|
# compose a "3d" redstone torch
|
||||||
|
t = terrain_images[115].copy() if blockID == 93 else terrain_images[99].copy()
|
||||||
|
torch = Image.new("RGBA", (24,24), bgcolor)
|
||||||
|
|
||||||
|
t_crop = t.crop((2,2,14,14))
|
||||||
|
slice = t_crop.copy()
|
||||||
|
ImageDraw.Draw(slice).rectangle((6,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
ImageDraw.Draw(slice).rectangle((0,0,4,12),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
|
composite.alpha_over(torch, slice, (6,4))
|
||||||
|
composite.alpha_over(torch, t_crop, (5,5))
|
||||||
|
composite.alpha_over(torch, t_crop, (6,5))
|
||||||
|
composite.alpha_over(torch, slice, (6,6))
|
||||||
|
|
||||||
# paste redstone torches everywhere!
|
# paste redstone torches everywhere!
|
||||||
t = specialblockmap[(75,5)] if blockID == 93 else specialblockmap[(76,5)]
|
|
||||||
torch = t[0].copy() # textures are stored as tuples (RGB,A)
|
|
||||||
torch.putalpha(t[1])
|
|
||||||
|
|
||||||
# the torch is too tall for the repeater, crop the bottom.
|
# the torch is too tall for the repeater, crop the bottom.
|
||||||
ImageDraw.Draw(torch).rectangle((0,16,24,24),outline=(0,0,0,0),fill=(0,0,0,0))
|
ImageDraw.Draw(torch).rectangle((0,16,24,24),outline=(0,0,0,0),fill=(0,0,0,0))
|
||||||
|
|
||||||
@@ -1521,10 +1673,11 @@ def generate_special_texture(blockID, data, north_direction):
|
|||||||
img = _build_full_block(None, None, None, texture, None)
|
img = _build_full_block(None, None, None, texture, None)
|
||||||
|
|
||||||
elif data & 0x4 == 0: # closed trapdoor
|
elif data & 0x4 == 0: # closed trapdoor
|
||||||
img = _build_full_block((texture, 9), None, None, texture, texture)
|
img = _build_full_block((texture, 12), None, None, texture, texture)
|
||||||
|
|
||||||
return generate_texture_tuple(img, blockID)
|
return generate_texture_tuple(img, blockID)
|
||||||
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def convert_data(blockID, data, north_direction):
|
def convert_data(blockID, data, north_direction):
|
||||||
@@ -1830,9 +1983,10 @@ def getBiomeData(worlddir, chunkX, chunkY):
|
|||||||
# (when adding new blocks here and in generate_special_textures,
|
# (when adding new blocks here and in generate_special_textures,
|
||||||
# please, if possible, keep the ascending order of blockid value)
|
# please, if possible, keep the ascending order of blockid value)
|
||||||
|
|
||||||
special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 31, 35, 43, 44,
|
special_blocks = set([ 2, 6, 9, 17, 18, 20, 26, 23, 27, 28, 29, 31, 33,
|
||||||
50, 51, 53, 54, 55, 58, 59, 61, 62, 63, 64, 65, 66,
|
34, 35, 43, 44, 50, 51, 53, 54, 55, 58, 59, 61, 62,
|
||||||
67, 68, 71, 75, 76, 85, 86, 90, 91, 92, 93, 94, 96])
|
63, 64, 65, 66, 67, 68, 71, 75, 76, 85, 86, 90, 91,
|
||||||
|
92, 93, 94, 96])
|
||||||
|
|
||||||
# this is a map of special blockIDs to a list of all
|
# this is a map of special blockIDs to a list of all
|
||||||
# possible values for ancillary data that it might have.
|
# possible values for ancillary data that it might have.
|
||||||
@@ -1842,10 +1996,14 @@ special_map = {}
|
|||||||
special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings)
|
special_map[6] = range(16) # saplings: usual, spruce, birch and future ones (rendered as usual saplings)
|
||||||
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data
|
special_map[9] = range(32) # water: spring,flowing, waterfall, and others (unknown) ancildata values, uses pseudo data
|
||||||
special_map[17] = range(3) # wood: normal, birch and pine
|
special_map[17] = range(3) # wood: normal, birch and pine
|
||||||
|
special_map[20] = range(32) # glass, used to only render the exterior surface, uses pseudo data
|
||||||
special_map[26] = range(12) # bed, orientation
|
special_map[26] = range(12) # bed, orientation
|
||||||
special_map[23] = range(6) # dispensers, orientation
|
special_map[23] = range(6) # dispensers, orientation
|
||||||
special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered
|
special_map[27] = range(14) # powered rail, orientation/slope and powered/unpowered
|
||||||
special_map[28] = range(6) # detector rail, orientation/slope
|
special_map[28] = range(6) # detector rail, orientation/slope
|
||||||
|
special_map[29] = (0,1,2,3,4,5,8,9,10,11,12,13) # sticky piston body, orientation, pushed in/out
|
||||||
|
special_map[33] = (0,1,2,3,4,5,8,9,10,11,12,13) # normal piston body, orientation, pushed in/out
|
||||||
|
special_map[34] = (0,1,2,3,4,5,8,9,10,11,12,13) # normal and sticky piston extension, orientation, sticky/normal
|
||||||
special_map[35] = range(16) # wool, colored and white
|
special_map[35] = range(16) # wool, colored and white
|
||||||
special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab
|
special_map[43] = range(4) # stone, sandstone, wooden and cobblestone double-slab
|
||||||
special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab
|
special_map[44] = range(4) # stone, sandstone, wooden and cobblestone slab
|
||||||
@@ -1854,7 +2012,7 @@ special_map[51] = range(16) # fire, position in the block (not implemented)
|
|||||||
special_map[53] = range(4) # wooden stairs, orientation
|
special_map[53] = range(4) # wooden stairs, orientation
|
||||||
special_map[54] = range(12) # chests, orientation and type (single or double), uses pseudo data
|
special_map[54] = range(12) # chests, orientation and type (single or double), uses pseudo data
|
||||||
special_map[55] = range(128) # redstone wire, all the possible combinations, uses pseudo data
|
special_map[55] = range(128) # redstone wire, all the possible combinations, uses pseudo data
|
||||||
special_map[58] = (0,) # crafting table
|
special_map[58] = (0,) # crafting table, it has 2 different sides
|
||||||
special_map[59] = range(8) # crops, grow from 0 to 7
|
special_map[59] = range(8) # crops, grow from 0 to 7
|
||||||
special_map[61] = range(6) # furnace, orientation
|
special_map[61] = range(6) # furnace, orientation
|
||||||
special_map[62] = range(6) # burning furnace, orientation
|
special_map[62] = range(6) # burning furnace, orientation
|
||||||
@@ -1871,9 +2029,9 @@ special_map[85] = range(17) # fences, all the possible combination, uses pseudo
|
|||||||
special_map[86] = range(5) # pumpkin, orientation
|
special_map[86] = range(5) # pumpkin, orientation
|
||||||
special_map[90] = (1,2,4,8) # portal, in 2 orientations, 4 cases, uses pseudo data
|
special_map[90] = (1,2,4,8) # portal, in 2 orientations, 4 cases, uses pseudo data
|
||||||
special_map[91] = range(5) # jack-o-lantern, orientation
|
special_map[91] = range(5) # jack-o-lantern, orientation
|
||||||
special_map[92] = range(6) # cake!
|
special_map[92] = range(6) # cake, eaten amount, (not implemented)
|
||||||
special_map[93] = range(16) # OFF redstone repeater, orientation and delay (delay not implemented)
|
special_map[93] = range(16) # OFF redstone repeater, orientation and delay
|
||||||
special_map[94] = range(16) # ON redstone repeater, orientation and delay (delay not implemented)
|
special_map[94] = range(16) # ON redstone repeater, orientation and delay
|
||||||
special_map[96] = range(8) # trapdoor, open, closed, orientation
|
special_map[96] = range(8) # trapdoor, open, closed, orientation
|
||||||
|
|
||||||
# grass and leaves are graysacle in terrain.png
|
# grass and leaves are graysacle in terrain.png
|
||||||
@@ -1888,6 +2046,7 @@ special_map[18] = range(16) # leaves, birch, normal or pine leaves (not implemen
|
|||||||
special_map[31] = range(3) # tall grass, dead shrub, fern and tall grass itself
|
special_map[31] = range(3) # tall grass, dead shrub, fern and tall grass itself
|
||||||
|
|
||||||
# placeholders that are generated in generate()
|
# placeholders that are generated in generate()
|
||||||
|
bgcolor = None
|
||||||
terrain_images = None
|
terrain_images = None
|
||||||
blockmap = None
|
blockmap = None
|
||||||
biome_grass_texture = None
|
biome_grass_texture = None
|
||||||
@@ -1896,11 +2055,15 @@ biome_tall_fern_texture = None
|
|||||||
biome_leaf_texture = None
|
biome_leaf_texture = None
|
||||||
specialblockmap = None
|
specialblockmap = None
|
||||||
|
|
||||||
def generate(north_direction, path=None):
|
def generate(path=None,texture_size=24,bgc = (26,26,26,0),north_direction='lower-left'):
|
||||||
global _north
|
global _north
|
||||||
_north = north_direction
|
_north = north_direction
|
||||||
global _find_file_local_path
|
global _find_file_local_path
|
||||||
|
global bgcolor
|
||||||
|
bgcolor = bgc
|
||||||
|
global _find_file_local_path, texture_dimensions
|
||||||
_find_file_local_path = path
|
_find_file_local_path = path
|
||||||
|
texture_dimensions = (texture_size, texture_size)
|
||||||
|
|
||||||
# This maps terainids to 16x16 images
|
# This maps terainids to 16x16 images
|
||||||
global terrain_images
|
global terrain_images
|
||||||
@@ -1924,3 +2087,30 @@ def generate(north_direction, path=None):
|
|||||||
for blockID in special_blocks:
|
for blockID in special_blocks:
|
||||||
for data in special_map[blockID]:
|
for data in special_map[blockID]:
|
||||||
specialblockmap[(blockID, data)] = generate_special_texture(blockID, data, north_direction)
|
specialblockmap[(blockID, data)] = generate_special_texture(blockID, data, north_direction)
|
||||||
|
|
||||||
|
if texture_size != 24:
|
||||||
|
# rescale biome textures.
|
||||||
|
biome_grass_texture = biome_grass_texture.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
biome_leaf_texture = biome_leaf_texture.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
biome_tall_grass_texture = biome_tall_grass_texture.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
biome_tall_fern_texture = biome_tall_fern_texture.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
|
||||||
|
# rescale the normal block images
|
||||||
|
for i in range(len(blockmap)):
|
||||||
|
if blockmap[i] != None:
|
||||||
|
block = blockmap[i]
|
||||||
|
alpha = block[1]
|
||||||
|
block = block[0]
|
||||||
|
block.putalpha(alpha)
|
||||||
|
scaled_block = block.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
blockmap[i] = generate_texture_tuple(scaled_block, i)
|
||||||
|
|
||||||
|
# rescale the special block images
|
||||||
|
for blockid, data in iter(specialblockmap):
|
||||||
|
block = specialblockmap[(blockid,data)]
|
||||||
|
if block != None:
|
||||||
|
alpha = block[1]
|
||||||
|
block = block[0]
|
||||||
|
block.putalpha(alpha)
|
||||||
|
scaled_block = block.resize(texture_dimensions, Image.ANTIALIAS)
|
||||||
|
specialblockmap[(blockid,data)] = generate_texture_tuple(scaled_block, blockid)
|
||||||
@@ -21,19 +21,22 @@ import imp
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
def get_program_path():
|
def get_program_path():
|
||||||
if hasattr(sys, "frozen") or imp.is_frozen("__main__"):
|
if hasattr(sys, "frozen") or imp.is_frozen("__main__"):
|
||||||
return os.path.dirname(sys.executable)
|
return os.path.dirname(sys.executable)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return os.path.dirname(__file__)
|
# normally, we're in ./overviewer_core/util.py
|
||||||
|
# we want ./
|
||||||
|
return os.path.dirname(os.path.dirname(__file__))
|
||||||
except NameError:
|
except NameError:
|
||||||
return os.path.dirname(sys.argv[0])
|
return os.path.dirname(sys.argv[0])
|
||||||
|
|
||||||
|
|
||||||
|
# does not require git, very likely to work everywhere
|
||||||
def findGitVersion():
|
def findGitHash():
|
||||||
this_dir = get_program_path()
|
this_dir = get_program_path()
|
||||||
if os.path.exists(os.path.join(this_dir,".git")):
|
if os.path.exists(os.path.join(this_dir,".git")):
|
||||||
with open(os.path.join(this_dir,".git","HEAD")) as f:
|
with open(os.path.join(this_dir,".git","HEAD")) as f:
|
||||||
@@ -46,6 +49,24 @@ def findGitVersion():
|
|||||||
else:
|
else:
|
||||||
return data
|
return data
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
|
import overviewer_version
|
||||||
|
return overviewer_version.HASH
|
||||||
|
except:
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
def findGitVersion():
|
||||||
|
try:
|
||||||
|
p = Popen(['git', 'describe', '--tags'], stdout=PIPE, stderr=PIPE)
|
||||||
|
p.stderr.close()
|
||||||
|
line = p.stdout.readlines()[0]
|
||||||
|
if line.startswith('release-'):
|
||||||
|
line = line.split('-', 1)[1]
|
||||||
|
# turn 0.1.2-50-somehash into 0.1.2-50
|
||||||
|
# and 0.1.3 into 0.1.3
|
||||||
|
line = '-'.join(line.split('-', 2)[:2])
|
||||||
|
return line.strip()
|
||||||
|
except:
|
||||||
try:
|
try:
|
||||||
import overviewer_version
|
import overviewer_version
|
||||||
return overviewer_version.VERSION
|
return overviewer_version.VERSION
|
||||||
@@ -196,12 +196,17 @@ class World(object):
|
|||||||
in the chunk coordinate system, and figures out the row and column
|
in the chunk coordinate system, and figures out the row and column
|
||||||
in the image each one should be. Returns (col, row)."""
|
in the image each one should be. Returns (col, row)."""
|
||||||
|
|
||||||
|
# columns are determined by the sum of the chunk coords, rows are the
|
||||||
|
# difference
|
||||||
# change this function, and you MUST change unconvert_coords
|
# change this function, and you MUST change unconvert_coords
|
||||||
return (chunkx + chunky, chunky - chunkx)
|
return (chunkx + chunky, chunky - chunkx)
|
||||||
|
|
||||||
def unconvert_coords(self, col, row):
|
def unconvert_coords(self, col, row):
|
||||||
"""Undoes what convert_coords does. Returns (chunkx, chunky)."""
|
"""Undoes what convert_coords does. Returns (chunkx, chunky)."""
|
||||||
return ((col - row) / 2, (row + col) / 2)
|
|
||||||
|
# col + row = chunky + chunky => (col + row)/2 = chunky
|
||||||
|
# col - row = chunkx + chunkx => (col - row)/2 = chunkx
|
||||||
|
return ((col - row) / 2, (col + row) / 2)
|
||||||
|
|
||||||
def findTrueSpawn(self):
|
def findTrueSpawn(self):
|
||||||
"""Adds the true spawn location to self.POI. The spawn Y coordinate
|
"""Adds the true spawn location to self.POI. The spawn Y coordinate
|
||||||
@@ -229,25 +234,27 @@ class World(object):
|
|||||||
chunkX = spawnX/16
|
chunkX = spawnX/16
|
||||||
chunkY = spawnZ/16
|
chunkY = spawnZ/16
|
||||||
|
|
||||||
## The filename of this chunk
|
try:
|
||||||
chunkFile = self.get_region_path(chunkX, chunkY)
|
## The filename of this chunk
|
||||||
|
chunkFile = self.get_region_path(chunkX, chunkY)
|
||||||
if chunkFile is not None:
|
if chunkFile is not None:
|
||||||
data = nbt.load_from_region(chunkFile, chunkX, chunkY, self.north_direction)[1]
|
data = nbt.load_from_region(chunkFile, chunkX, chunkY, self.north_direction)[1]
|
||||||
if data is not None:
|
if data is not None:
|
||||||
level = data['Level']
|
level = data['Level']
|
||||||
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||||
|
|
||||||
## The block for spawn *within* the chunk
|
## The block for spawn *within* the chunk
|
||||||
inChunkX = spawnX - (chunkX*16)
|
inChunkX = spawnX - (chunkX*16)
|
||||||
inChunkZ = spawnZ - (chunkY*16)
|
inChunkZ = spawnZ - (chunkY*16)
|
||||||
|
|
||||||
## find the first air block
|
## find the first air block
|
||||||
while (blockArray[inChunkX, inChunkZ, spawnY] != 0):
|
while (blockArray[inChunkX, inChunkZ, spawnY] != 0):
|
||||||
spawnY += 1
|
spawnY += 1
|
||||||
if spawnY == 128:
|
if spawnY == 128:
|
||||||
break
|
break
|
||||||
|
except ChunkCorrupt:
|
||||||
|
#ignore corrupt spawn, and continue
|
||||||
|
pass
|
||||||
self.POI.append( dict(x=disp_spawnX, y=spawnY, z=disp_spawnZ,
|
self.POI.append( dict(x=disp_spawnX, y=spawnY, z=disp_spawnZ,
|
||||||
msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
|
msg="Spawn", type="spawn", chunk=(chunkX, chunkY)))
|
||||||
self.spawn = (disp_spawnX, spawnY, disp_spawnZ)
|
self.spawn = (disp_spawnX, spawnY, disp_spawnZ)
|
||||||
@@ -314,7 +321,6 @@ class World(object):
|
|||||||
world.
|
world.
|
||||||
|
|
||||||
Returns (regionx, regiony, filename)"""
|
Returns (regionx, regiony, filename)"""
|
||||||
|
|
||||||
join = os.path.join
|
join = os.path.join
|
||||||
if regionlist is not None:
|
if regionlist is not None:
|
||||||
for path in regionlist:
|
for path in regionlist:
|
||||||
196
setup.py
Normal file → Executable file
@@ -1,26 +1,61 @@
|
|||||||
from distutils.core import setup, Extension
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from distutils.core import setup
|
||||||
|
from distutils.extension import Extension
|
||||||
from distutils.command.build import build
|
from distutils.command.build import build
|
||||||
from distutils.command.clean import clean
|
from distutils.command.clean import clean
|
||||||
from distutils.command.build_ext import build_ext
|
from distutils.command.build_ext import build_ext
|
||||||
|
from distutils.command.sdist import sdist
|
||||||
|
from distutils.cmd import Command
|
||||||
from distutils.dir_util import remove_tree
|
from distutils.dir_util import remove_tree
|
||||||
from distutils.sysconfig import get_python_inc
|
from distutils.sysconfig import get_python_inc
|
||||||
from distutils import log
|
from distutils import log
|
||||||
import os, os.path
|
import sys, os, os.path
|
||||||
import glob
|
import glob
|
||||||
import platform
|
import platform
|
||||||
import time
|
import time
|
||||||
|
import overviewer_core.util as util
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import py2exe
|
import py2exe
|
||||||
except ImportError:
|
except ImportError:
|
||||||
py2exe = None
|
py2exe = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import py2app
|
||||||
|
from setuptools.extension import Extension
|
||||||
|
except ImportError:
|
||||||
|
py2app = None
|
||||||
|
|
||||||
# now, setup the keyword arguments for setup
|
# now, setup the keyword arguments for setup
|
||||||
# (because we don't know until runtime if py2exe is available)
|
# (because we don't know until runtime if py2exe/py2app is available)
|
||||||
setup_kwargs = {}
|
setup_kwargs = {}
|
||||||
setup_kwargs['options'] = {}
|
|
||||||
setup_kwargs['ext_modules'] = []
|
setup_kwargs['ext_modules'] = []
|
||||||
setup_kwargs['cmdclass'] = {}
|
setup_kwargs['cmdclass'] = {}
|
||||||
|
setup_kwargs['options'] = {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# metadata
|
||||||
|
#
|
||||||
|
|
||||||
|
# Utility function to read the README file.
|
||||||
|
# Used for the long_description. It's nice, because now 1) we have a top level
|
||||||
|
# README file and 2) it's easier to type in the README file than to put a raw
|
||||||
|
# string in below ...
|
||||||
|
def read(fname):
|
||||||
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
setup_kwargs['name'] = 'Minecraft-Overviewer'
|
||||||
|
setup_kwargs['version'] = util.findGitVersion()
|
||||||
|
setup_kwargs['description'] = 'Generates large resolution images of a Minecraft map.'
|
||||||
|
setup_kwargs['url'] = 'http://overviewer.org/'
|
||||||
|
setup_kwargs['author'] = 'Andrew Brown'
|
||||||
|
setup_kwargs['author_email'] = 'brownan@gmail.com'
|
||||||
|
setup_kwargs['license'] = 'GNU General Public License v3'
|
||||||
|
setup_kwargs['long_description'] = read('README.rst')
|
||||||
|
|
||||||
|
# top-level files that should be included as documentation
|
||||||
|
doc_files = ['COPYING.txt', 'README.rst', 'CONTRIBUTORS.rst', 'sample.settings.py']
|
||||||
|
|
||||||
# helper to create a 'data_files'-type sequence recursively for a given dir
|
# helper to create a 'data_files'-type sequence recursively for a given dir
|
||||||
def recursive_data_files(src, dest=None):
|
def recursive_data_files(src, dest=None):
|
||||||
@@ -40,15 +75,26 @@ def recursive_data_files(src, dest=None):
|
|||||||
ret.append((current_dest, current_sources))
|
ret.append((current_dest, current_sources))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
# helper to create a 'package_data'-type sequence recursively for a given dir
|
||||||
|
def recursive_package_data(src, package_dir='overviewer_core'):
|
||||||
|
full_src = os.path.join(package_dir, src)
|
||||||
|
ret = []
|
||||||
|
for dirpath, dirnames, filenames in os.walk(full_src, topdown=False):
|
||||||
|
current_path = os.path.relpath(dirpath, package_dir)
|
||||||
|
for filename in filenames:
|
||||||
|
ret.append(os.path.join(current_path, filename))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
#
|
#
|
||||||
# py2exe options
|
# py2exe options
|
||||||
#
|
#
|
||||||
|
|
||||||
if py2exe is not None:
|
if py2exe is not None:
|
||||||
setup_kwargs['console'] = ['overviewer.py']
|
setup_kwargs['console'] = ['overviewer.py']
|
||||||
setup_kwargs['data_files'] = [('textures', ['textures/lava.png', 'textures/water.png', 'textures/fire.png', 'textures/portal.png']),
|
setup_kwargs['data_files'] = [('', doc_files)]
|
||||||
('', ['COPYING.txt', 'README.rst'])]
|
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/textures', 'textures')
|
||||||
setup_kwargs['data_files'] += recursive_data_files('web_assets')
|
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets')
|
||||||
setup_kwargs['zipfile'] = None
|
setup_kwargs['zipfile'] = None
|
||||||
if platform.system() == 'Windows' and '64bit' in platform.architecture():
|
if platform.system() == 'Windows' and '64bit' in platform.architecture():
|
||||||
b = 3
|
b = 3
|
||||||
@@ -56,6 +102,27 @@ if py2exe is not None:
|
|||||||
b = 1
|
b = 1
|
||||||
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter'}
|
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter'}
|
||||||
|
|
||||||
|
#
|
||||||
|
# py2app options
|
||||||
|
#
|
||||||
|
|
||||||
|
if py2app is not None:
|
||||||
|
setup_kwargs['app'] = ['overviewer.py']
|
||||||
|
setup_kwargs['options']['py2app'] = {'argv_emulation' : False}
|
||||||
|
setup_kwargs['setup_requires'] = ['py2app']
|
||||||
|
|
||||||
|
#
|
||||||
|
# script, package, and data
|
||||||
|
#
|
||||||
|
|
||||||
|
setup_kwargs['packages'] = ['overviewer_core']
|
||||||
|
setup_kwargs['scripts'] = ['overviewer.py']
|
||||||
|
setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets')}
|
||||||
|
|
||||||
|
if py2exe is None:
|
||||||
|
setup_kwargs['data_files'] = [('share/doc/minecraft-overviewer', doc_files)]
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# c_overviewer extension
|
# c_overviewer extension
|
||||||
#
|
#
|
||||||
@@ -79,20 +146,23 @@ except:
|
|||||||
# used to figure out what files to compile
|
# used to figure out what files to compile
|
||||||
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave']
|
render_modes = ['normal', 'overlay', 'lighting', 'night', 'spawn', 'cave']
|
||||||
|
|
||||||
c_overviewer_files = ['src/main.c', 'src/composite.c', 'src/iterate.c', 'src/endian.c', 'src/rendermodes.c']
|
c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c']
|
||||||
c_overviewer_files += map(lambda mode: 'src/rendermode-%s.c' % (mode,), render_modes)
|
c_overviewer_files += map(lambda mode: 'rendermode-%s.c' % (mode,), render_modes)
|
||||||
c_overviewer_files += ['src/Draw.c']
|
c_overviewer_files += ['Draw.c']
|
||||||
c_overviewer_includes = ['src/overviewer.h', 'src/rendermodes.h']
|
c_overviewer_includes = ['overviewer.h', 'rendermodes.h']
|
||||||
|
|
||||||
|
c_overviewer_files = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_files)
|
||||||
|
c_overviewer_includes = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_includes)
|
||||||
|
|
||||||
|
setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
|
||||||
|
|
||||||
setup_kwargs['ext_modules'].append(Extension('c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[]))
|
|
||||||
|
|
||||||
# tell build_ext to build the extension in-place
|
# tell build_ext to build the extension in-place
|
||||||
# (NOT in build/)
|
# (NOT in build/)
|
||||||
setup_kwargs['options']['build_ext'] = {'inplace' : 1}
|
setup_kwargs['options']['build_ext'] = {'inplace' : 1}
|
||||||
# tell the build command to only run build_ext
|
|
||||||
build.sub_commands = [('build_ext', None)]
|
|
||||||
|
|
||||||
# custom clean command to remove in-place extension
|
# custom clean command to remove in-place extension
|
||||||
|
# and the version file
|
||||||
class CustomClean(clean):
|
class CustomClean(clean):
|
||||||
def run(self):
|
def run(self):
|
||||||
# do the normal cleanup
|
# do the normal cleanup
|
||||||
@@ -101,7 +171,7 @@ class CustomClean(clean):
|
|||||||
# try to remove '_composite.{so,pyd,...}' extension,
|
# try to remove '_composite.{so,pyd,...}' extension,
|
||||||
# regardless of the current system's extension name convention
|
# regardless of the current system's extension name convention
|
||||||
build_ext = self.get_finalized_command('build_ext')
|
build_ext = self.get_finalized_command('build_ext')
|
||||||
pretty_fname = build_ext.get_ext_filename('c_overviewer')
|
pretty_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
|
||||||
fname = pretty_fname
|
fname = pretty_fname
|
||||||
if os.path.exists(fname):
|
if os.path.exists(fname):
|
||||||
try:
|
try:
|
||||||
@@ -114,8 +184,55 @@ class CustomClean(clean):
|
|||||||
else:
|
else:
|
||||||
log.debug("'%s' does not exist -- can't clean it",
|
log.debug("'%s' does not exist -- can't clean it",
|
||||||
pretty_fname)
|
pretty_fname)
|
||||||
|
|
||||||
|
versionpath = os.path.join("overviewer_core", "overviewer_version.py")
|
||||||
|
if os.path.exists(versionpath):
|
||||||
|
try:
|
||||||
|
if not self.dry_run:
|
||||||
|
os.remove(versionpath)
|
||||||
|
log.info("removing '%s'", versionpath)
|
||||||
|
except OSError:
|
||||||
|
log.warn("'%s' could not be cleaned -- permission denied", versionpath)
|
||||||
|
else:
|
||||||
|
log.debug("'%s' does not exist -- can't clean it", versionpath)
|
||||||
|
|
||||||
class CustomBuild(build_ext):
|
# now try to purge all *.pyc files
|
||||||
|
for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")):
|
||||||
|
for f in files:
|
||||||
|
if f.endswith(".pyc"):
|
||||||
|
if self.dry_run:
|
||||||
|
log.warn("Would remove %s", os.path.join(root,f))
|
||||||
|
else:
|
||||||
|
os.remove(os.path.join(root, f))
|
||||||
|
|
||||||
|
def generate_version_py():
|
||||||
|
try:
|
||||||
|
outstr = ""
|
||||||
|
outstr += "VERSION=%r\n" % util.findGitVersion()
|
||||||
|
outstr += "HASH=%r\n" % util.findGitHash()
|
||||||
|
outstr += "BUILD_DATE=%r\n" % time.asctime()
|
||||||
|
outstr += "BUILD_PLATFORM=%r\n" % platform.processor()
|
||||||
|
outstr += "BUILD_OS=%r\n" % platform.platform()
|
||||||
|
f = open("overviewer_core/overviewer_version.py", "w")
|
||||||
|
f.write(outstr)
|
||||||
|
f.close()
|
||||||
|
except:
|
||||||
|
print "WARNING: failed to build overviewer_version file"
|
||||||
|
|
||||||
|
class CustomSDist(sdist):
|
||||||
|
def run(self):
|
||||||
|
# generate the version file
|
||||||
|
generate_version_py()
|
||||||
|
sdist.run(self)
|
||||||
|
|
||||||
|
class CustomBuild(build):
|
||||||
|
def run(self):
|
||||||
|
# generate the version file
|
||||||
|
generate_version_py()
|
||||||
|
build.run(self)
|
||||||
|
print "\nBuild Complete"
|
||||||
|
|
||||||
|
class CustomBuildExt(build_ext):
|
||||||
def build_extensions(self):
|
def build_extensions(self):
|
||||||
c = self.compiler.compiler_type
|
c = self.compiler.compiler_type
|
||||||
if c == "msvc":
|
if c == "msvc":
|
||||||
@@ -123,32 +240,39 @@ class CustomBuild(build_ext):
|
|||||||
for e in self.extensions:
|
for e in self.extensions:
|
||||||
e.extra_link_args.append("/MANIFEST")
|
e.extra_link_args.append("/MANIFEST")
|
||||||
|
|
||||||
|
# build in place, and in the build/ tree
|
||||||
|
self.inplace = False
|
||||||
|
build_ext.build_extensions(self)
|
||||||
|
self.inplace = True
|
||||||
build_ext.build_extensions(self)
|
build_ext.build_extensions(self)
|
||||||
|
|
||||||
|
class CheckTerrain(Command):
|
||||||
|
user_options=[]
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
def run(self):
|
||||||
|
from overviewer_core.textures import _find_file
|
||||||
|
import hashlib
|
||||||
|
import zipfile
|
||||||
|
print "checking..."
|
||||||
|
try:
|
||||||
|
f = _find_file("terrain.png", verbose=True)
|
||||||
|
except IOError:
|
||||||
|
log.error("Could not find the file terrain.png")
|
||||||
|
return
|
||||||
|
|
||||||
if py2exe is not None:
|
h = hashlib.sha1()
|
||||||
# define a subclass of py2exe to build our version file on the fly
|
h.update(f.read())
|
||||||
class CustomPy2exe(py2exe.build_exe.py2exe):
|
log.info("Hash of terrain.png file is: %s", h.hexdigest())
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
import util
|
|
||||||
f = open("overviewer_version.py", "w")
|
|
||||||
f.write("VERSION=%r\n" % util.findGitVersion())
|
|
||||||
f.write("BUILD_DATE=%r\n" % time.asctime())
|
|
||||||
f.write("BUILD_PLATFORM=%r\n" % platform.processor())
|
|
||||||
f.write("BUILD_OS=%r\n" % platform.platform())
|
|
||||||
f.close()
|
|
||||||
setup_kwargs['data_files'].append(('.', ['overviewer_version.py']))
|
|
||||||
except:
|
|
||||||
print "WARNING: failed to build overview_version file"
|
|
||||||
py2exe.build_exe.py2exe.run(self)
|
|
||||||
setup_kwargs['cmdclass']['py2exe'] = CustomPy2exe
|
|
||||||
|
|
||||||
setup_kwargs['cmdclass']['clean'] = CustomClean
|
setup_kwargs['cmdclass']['clean'] = CustomClean
|
||||||
setup_kwargs['cmdclass']['build_ext'] = CustomBuild
|
setup_kwargs['cmdclass']['sdist'] = CustomSDist
|
||||||
|
setup_kwargs['cmdclass']['build'] = CustomBuild
|
||||||
|
setup_kwargs['cmdclass']['build_ext'] = CustomBuildExt
|
||||||
|
setup_kwargs['cmdclass']['check_terrain'] = CheckTerrain
|
||||||
###
|
###
|
||||||
|
|
||||||
setup(**setup_kwargs)
|
setup(**setup_kwargs)
|
||||||
|
|
||||||
|
|
||||||
print "\nBuild Complete"
|
|
||||||
|
|||||||