diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index e251b41..ae100b4 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -28,6 +28,7 @@ for many different parts of the code. * Aaron Griffith * Alex Headley * Alex Jurkiewicz + * Michael Writhe * Xon ------------------------ @@ -41,6 +42,7 @@ feature. * Kyle Brantley * cbarber * Alex Cline + * CounterPillow * Stephen Fluin * Benjamin Herr * Ryan Hitchman @@ -51,3 +53,4 @@ feature. * Gregory Short * Sam Steele * timwolla + * Jeffrey Warren diff --git a/overviewer_core/data/web_assets/index.html b/overviewer_core/data/web_assets/index.html index 3798f17..7fa8e31 100644 --- a/overviewer_core/data/web_assets/index.html +++ b/overviewer_core/data/web_assets/index.html @@ -1,15 +1,22 @@ + + + + + + +
diff --git a/overviewer_core/data/web_assets/overviewer.js b/overviewer_core/data/web_assets/overviewer.js index eea2f7d..4cbfc11 100644 --- a/overviewer_core/data/web_assets/overviewer.js +++ b/overviewer_core/data/web_assets/overviewer.js @@ -145,7 +145,7 @@ var overviewer = { var lng = defaultCenter.lng(); var zoom = overviewerConfig.map.defaultZoom; var mapcenter; - queryParams = overviewer.util.parseQueryString(); + var queryParams = overviewer.util.parseQueryString(); if (queryParams.lat) { lat = parseFloat(queryParams.lat); } @@ -225,13 +225,25 @@ var overviewer = { overviewer.collections.mapTypes[i].name, overviewer.collections.mapTypes[i]); } - + // Make the link again whenever the map changes google.maps.event.addListener(overviewer.map, 'maptypeid_changed', function() { $('#'+overviewerConfig.CONST.mapDivId).css( 'background-color', overviewer.util.getMapTypeBackgroundColor( overviewer.map.getMapTypeId())); }); + + // Add live hash update listener + google.maps.event.addListener(overviewer.map, 'dragend', function() { + overviewer.util.updateHash(); + }); + google.maps.event.addListener(overviewer.map, 'zoom_changed', function() { + overviewer.util.updateHash(); + }); + // Jump to the hash if given + overviewer.util.initHash(); + + // We can now set the map to use the 'coordinate' map type overviewer.map.setMapTypeId(overviewer.util.getDefaultMapTypeId()); }, @@ -457,29 +469,6 @@ var overviewer = { } return results; }, - /** - * Set the link (at the bottom of the screen) to the current view. - * TODO: make this preserve the mapTypeId as well - */ - 'setViewUrl': function() { - var displayZoom = overviewer.map.getZoom(); - if (displayZoom == overviewerConfig.map.maxZoom) { - displayZoom = 'max'; - } else { - displayZoom -= overviewerConfig.map.maxZoom; - } - var point; - var point = overviewer.util.fromLatLngToWorld( - overviewer.map.getCenter().lat(), overviewer.map.getCenter().lng()); - var viewUrl = location.href.substring(0, location.href.lastIndexOf( - location.search)) - + '?x=' + Math.floor(point.x) - + '&y=' + Math.floor(point.y) - + '&z=' + Math.floor(point.z) - + '&zoom=' + displayZoom; - document.getElementById('link').innerHTML = viewUrl; - - }, 'getDefaultMapTypeId': function() { return overviewer.collections.mapTypeIds[0]; }, @@ -579,21 +568,6 @@ var overviewer = { * like the compass, current view link, etc. */ 'createMapControls': function() { - // viewstate link (little link to where you're looking at the map, - // normally bottom left) - var viewStateDiv = document.createElement('DIV'); - viewStateDiv.id='link'; - // add it to the map, bottom left. - if (overviewerConfig.map.controls.link) { - google.maps.event.addListener(overviewer.map, 'zoom_changed', function() { - overviewer.util.setViewUrl(); - }); - google.maps.event.addListener(overviewer.map, 'center_changed', function() { - overviewer.util.setViewUrl(); - }); - overviewer.map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(viewStateDiv); - } - // compass rose, in the top right corner var compassDiv = document.createElement('DIV'); compassDiv.style.padding = '5px'; @@ -775,9 +749,11 @@ var overviewer = { overviewer.collections.infoWindow.close(); } // Replace our Info Window's content and position + var point = overviewer.util.fromLatLngToWorld(event.latLng.lat(),event.latLng.lng()); var contentString = 'Region: ' + shape.name + '
' + - 'Clicked Location:
' + event.latLng.lat() + ', ' + - event.latLng.lng() + '
'; + 'Clicked Location:
' + Math.round(point.x,1) + ', ' + point.y + + ', ' + Math.round(point.z,1) + + '
'; infowindow.setContent(contentString); infowindow.setPosition(event.latLng); infowindow.open(overviewer.map); @@ -802,7 +778,58 @@ var overviewer = { infowindow.open(overviewer.map, marker); overviewer.collections.infoWindow = infowindow; }); - } + }, + 'initHash': function() { + if(window.location.hash.split("/").length > 1) { + overviewer.util.goToHash(); + + // Add a marker indicating the user-supplied position + var coordinates = overviewer.util.fromLatLngToWorld(overviewer.map.getCenter().lat(), overviewer.map.getCenter().lng()); + overviewer.collections.markerDatas.push([{ + 'msg': 'Coordinates ' + Math.floor(coordinates.x) + ', ' + Math.floor(coordinates.y) + ', ' + Math.floor(coordinates.z), + 'x': coordinates.x, + 'y': coordinates.y, + 'z': coordinates.z, + 'type': 'querypos'}]); + } + }, + 'setHash': function(x, y, z, zoom) { + window.location.replace("#/" + Math.floor(x) + "/" + Math.floor(y) + "/" + Math.floor(z) + "/" + zoom); + }, + 'updateHash': function() { + var coordinates = overviewer.util.fromLatLngToWorld(overviewer.map.getCenter().lat(), overviewer.map.getCenter().lng()); + var zoom = overviewer.map.getZoom(); + if (zoom == overviewerConfig.map.maxZoom) { + zoom = 'max'; + } else if (zoom == overviewerConfig.map.minZoom) { + zoom = 'min'; + } else { + // default to (map-update friendly) negative zooms + zoom -= overviewerConfig.map.maxZoom; + } + overviewer.util.setHash(coordinates.x, coordinates.y, coordinates.z, zoom); + }, + 'goToHash': function() { + var coords = window.location.hash.split("/"); + var latlngcoords = overviewer.util.fromWorldToLatLng(parseInt(coords[1]), parseInt(coords[2]), parseInt(coords[3])); + var zoom = coords[4]; + if (zoom == 'max') { + zoom = overviewerConfig.map.maxZoom; + } else if (zoom == 'min') { + zoom = overviewerConfig.map.minZoom; + } else { + zoom = parseInt(zoom); + if (zoom < 0 && zoom + overviewerConfig.map.maxZoom >= 0) { + // if zoom is negative, treat it as a "zoom out from max" + zoom += overviewerConfig.map.maxZoom; + } else { + // fall back to default zoom + zoom = overviewerConfig.map.defaultZoom; + } + } + overviewer.map.setCenter(latlngcoords); + overviewer.map.setZoom(zoom); + }, }, /** * The various classes needed in this file. @@ -835,6 +862,7 @@ var overviewer = { overviewerConfig.map.center[0], overviewerConfig.map.center[1], overviewerConfig.map.center[2])); + overviewer.util.updateHash(); }); }, /** diff --git a/overviewer_core/googlemap.py b/overviewer_core/googlemap.py index af56fbe..331a4ea 100644 --- a/overviewer_core/googlemap.py +++ b/overviewer_core/googlemap.py @@ -128,6 +128,7 @@ class MapGen(object): index = open(indexpath, 'r').read() index = index.replace( "{time}", str(strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()))) + index = index.replace("{version}", util.findGitVersion()) with open(os.path.join(self.destdir, "index.html"), 'w') as output: output.write(index) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index f971ac0..5d8e583 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -364,6 +364,12 @@ chunk_render(PyObject *self, PyObject *args) { for (state.z = 0; state.z < 128; state.z++) { state.imgy -= 12; + + /* get blockid */ + state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z); + if (state.block == 0) { + continue; + } /* make sure we're rendering inside the image boundaries */ if ((state.imgx >= imgsize0 + 24) || (state.imgx <= -24)) { @@ -373,11 +379,6 @@ chunk_render(PyObject *self, PyObject *args) { continue; } - /* get blockid */ - state.block = getArrayByte3D(blocks_py, state.x, state.y, state.z); - if (state.block == 0) { - continue; - } /* decref'd on replacement *and* at the end of the z for block */ if (blockid) { diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index b5fb86a..b740420 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -19,7 +19,7 @@ import os.path import zipfile from cStringIO import StringIO import math - +from random import randint import numpy from PIL import Image, ImageEnhance, ImageOps, ImageDraw @@ -189,7 +189,47 @@ def transform_image_slope(img, blockID=None): newimg = img.transform((24,24), Image.AFFINE, transform) return newimg + + +def transform_image_angle(img, angle, blockID=None): + """Takes an image an shears it in arbitrary angle with the axis of + rotation being vertical. + WARNING! Don't use angle = pi/2 (or multiplies), it will return + a blank image (or maybe garbage). + + NOTE: angle is in the image not in game, so for the left side of a + block angle = 30 degree. + """ + + # Take the same size as trasform_image_side + img = img.resize((12,12), Image.ANTIALIAS) + + # some values + cos_angle = math.cos(angle) + sin_angle = math.sin(angle) + + # function_x and function_y are used to keep the result image in the + # same position, and constant_x and constant_y are the coordinates + # for the center for angle = 0. + constant_x = 6. + constant_y = 6. + function_x = 6.*(1-cos_angle) + function_y = -6*sin_angle + big_term = ( (sin_angle * (function_x + constant_x)) - cos_angle* (function_y + constant_y))/cos_angle + + # The numpy array is not really used, but is helpful to + # see the matrix used for the transformation. + transform = numpy.array([[1./cos_angle, 0, -(function_x + constant_x)/cos_angle], + [-sin_angle/(cos_angle), 1., big_term ], + [0, 0, 1.]]) + + transform = tuple(transform[0]) + tuple(transform[1]) + + newimg = img.transform((24,24), Image.AFFINE, transform) + + return newimg + def _build_block(top, side, blockID=None): """From a top texture and a side texture, build a block image. @@ -982,6 +1022,49 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 63: # singposts + + texture = terrain_images[4].copy() + # 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)) + + # If the signpost is looking directly to the image, draw some + # random dots, they will look as text. + if data in (0,1,2,3,4,5,15): + for i in range(15): + x = randint(4,11) + y = randint(3,7) + texture.putpixel((x,y),(0,0,0,255)) + + # Minecraft uses wood texture for the signpost stick + texture_stick = terrain_images[20] + 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)) + + img = Image.new("RGBA", (24,24), (38,92,255,0)) + + # W N ~90 E S ~270 + angles = (330.,345.,0.,15.,30.,55.,95.,120.,150.,165.,180.,195.,210.,230.,265.,310.) + angle = math.radians(angles[data]) + post = transform_image_angle(texture, angle) + + # choose the position of the "3D effect" + incrementx = 0 + if data in (1,6,7,8,9,14): + incrementx = -1 + elif data in (3,4,5,11,12,13): + incrementx = +1 + + composite.alpha_over(img, texture_stick,(11, 8),texture_stick) + # post2 is a brighter signpost pasted with a small sift, + # gives to the signpost some 3D effect. + post2 = ImageEnhance.Brightness(post).enhance(1.2) + composite.alpha_over(img, post2,(incrementx, -3),post2) + composite.alpha_over(img, post, (0,-2), post) + + return (img.convert("RGB"), img.split()[3]) + + if blockID in (64,71): #wooden door, or iron door if data & 0x8 == 0x8: # top of the door raw_door = terrain_images[81 if blockID == 64 else 82] @@ -1140,6 +1223,42 @@ def generate_special_texture(blockID, data): return (img.convert("RGB"), img.split()[3]) + if blockID == 68: # wall sign + texture = terrain_images[4].copy() + # 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)) + + # draw some random black dots, they will look as text + """ don't draw text at the moment, they are used in blank for decoration + + if data in (3,4): + for i in range(15): + x = randint(4,11) + y = randint(3,7) + texture.putpixel((x,y),(0,0,0,255)) + """ + + img = Image.new("RGBA", (24,24), (38,92,255,0)) + + incrementx = 0 + if data == 2: # east + incrementx = +1 + sign = _build_full_block(None, None, None, None, texture) + elif data == 3: # west + incrementx = -1 + sign = _build_full_block(None, texture, None, None, None) + elif data == 4: # north + incrementx = +1 + sign = _build_full_block(None, None, texture, None, None) + elif data == 5: # south + incrementx = -1 + sign = _build_full_block(None, None, None, texture, None) + + sign2 = ImageEnhance.Brightness(sign).enhance(1.2) + composite.alpha_over(img, sign2,(incrementx, 2),sign2) + composite.alpha_over(img, sign, (0,3), sign) + + return (img.convert("RGB"), img.split()[3]) if blockID == 85: # fences # create needed images for Big stick fence @@ -1360,15 +1479,15 @@ def generate_special_texture(blockID, data): static_torch = (5,-1) elif (data & 0xC) == 4: # two ticks delay - moving_torch = (2,0) + moving_torch = (0,2) static_torch = (5,-1) elif (data & 0xC) == 8: # three ticks delay - moving_torch = (3,0) + moving_torch = (-1,2) static_torch = (5,-1) elif (data & 0xC) == 12: # four ticks delay - moving_torch = (4,-1) + moving_torch = (-2,3) static_torch = (5,-1) elif (data & 0x3) == 2: # pointing west @@ -1492,8 +1611,8 @@ def getBiomeData(worlddir, chunkX, chunkY): # please, if possible, keep the ascending order of blockid value) special_blocks = set([ 2, 6, 9, 17, 18, 26, 23, 27, 28, 35, 43, 44, 50, - 51, 53, 54, 55, 58, 59, 61, 62, 64, 65, 66, 67, 71, - 75, 76, 85, 86, 90, 91, 92, 93, 94]) + 51, 53, 54, 55, 58, 59, 61, 62, 63, 64, 65, 66, 67, + 68, 71, 75, 76, 85, 86, 90, 91, 92, 93, 94]) # this is a map of special blockIDs to a list of all # possible values for ancillary data that it might have. @@ -1519,10 +1638,12 @@ special_map[58] = (0,) # crafting table special_map[59] = range(8) # crops, grow from 0 to 7 special_map[61] = range(6) # furnace, orientation special_map[62] = range(6) # burning furnace, orientation +special_map[63] = range(16) # signpost, orientation special_map[64] = range(16) # wooden door, open/close and orientation special_map[65] = (2,3,4,5) # ladder, orientation special_map[66] = range(10) # minecrart tracks, orientation, slope special_map[67] = range(4) # cobblestone stairs, orientation +special_map[68] = (2,3,4,5) # wall sing, orientation special_map[71] = range(16) # iron door, open/close and orientation special_map[75] = (1,2,3,4,5) # off redstone torch, orientation special_map[76] = (1,2,3,4,5) # on redstone torch, orientation