Fixes to getFlatIcon and more. (#3353)

(Rebased and reopened #3347)

Attempted to fix pipe and door rendering
Fixed Table, carpet rendering
Ported full map-capture tool from bay, with python script to merge captured images.
This commit is contained in:
Karolis
2017-09-19 15:43:01 +03:00
committed by Erki
parent 82be2f30ad
commit 031b958039
15 changed files with 197 additions and 12 deletions

View File

@@ -33,6 +33,7 @@ Pipelines + Other Objects -> Pipe network
var/global/datum/pipe_icon_manager/icon_manager
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
gfi_layer_rotation = GFI_ROTATION_OVERDIR
/obj/machinery/atmospherics/New()
if(!icon_manager)

View File

@@ -166,6 +166,7 @@
alert_pressure = 55*ONE_ATMOSPHERE
level = 1
gfi_layer_rotation = GFI_ROTATION_DEFDIR
/obj/machinery/atmospherics/pipe/simple/New()
..()
@@ -432,6 +433,8 @@
level = 1
layer = 2.4 //under wires with their 2.44
gfi_layer_rotation = GFI_ROTATION_OVERDIR
/obj/machinery/atmospherics/pipe/manifold/New()
..()
alpha = 255
@@ -1310,6 +1313,7 @@
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
icon_state = "map_universal"
gfi_layer_rotation = GFI_ROTATION_OVERDIR
/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0)
if(!check_icon_cache())
@@ -1345,6 +1349,7 @@
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
icon_state = "map_universal"
gfi_layer_rotation = GFI_ROTATION_OVERDIR
/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
if(!check_icon_cache())

View File

@@ -394,3 +394,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
#define ITEMSIZE_NORMAL 3
#define ITEMSIZE_LARGE 4
#define ITEMSIZE_HUGE 5
// getFlatIcon function altering defines
#define GFI_ROTATION_DEFAULT 0 //Don't do anything special
#define GFI_ROTATION_DEFDIR 1 //Layers will have default direction of there object
#define GFI_ROTATION_OVERDIR 2 //Layers will have overidden direction

View File

@@ -743,8 +743,36 @@ as a single icon. Useful for when you want to manipulate an icon via the above a
if(I == copy) // 'I' is an /image based on the object being flattened.
curblend = BLEND_OVERLAY
add = icon(I:icon, I:icon_state, I:dir)
// This checks for a silent failure mode of the icon routine. If the requested dir
// doesn't exist in this icon state it returns a 32x32 icon with 0 alpha.
if (I:dir != SOUTH && add.Width() == 32 && add.Height() == 32)
// Check every pixel for blank (computationally expensive, but the process is limited
// by the amount of film on the station, only happens when we hit something that's
// turned, and bails at the very first pixel it sees.
var/blankpixel;
for(var/y;y<=32;y++)
for(var/x;x<32;x++)
blankpixel = isnull(add.GetPixel(x,y))
if(!blankpixel)
break
if(!blankpixel)
break
// If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0)
if (blankpixel)
// Pull the default direction.
add = icon(I:icon, I:icon_state)
else // 'I' is an appearance object.
if (istype(A,/atom))
var/atom/At = A
if (At.gfi_layer_rotation == GFI_ROTATION_DEFDIR)
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, TRUE)
else if (At.gfi_layer_rotation == GFI_ROTATION_OVERDIR)
var/image/Im = I
add = getFlatIcon(new/image(I), Im.dir, curicon, curstate, curblend, TRUE)
else
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, always_use_defdir)
else
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, always_use_defdir)
// Find the new dimensions of the flat icon to fit the added overlay
addX1 = min(flatX1, I:pixel_x+1)
@@ -758,8 +786,15 @@ as a single icon. Useful for when you want to manipulate an icon via the above a
flatX1=addX1;flatX2=addX2
flatY1=addY1;flatY2=addY2
var/iconmode
if(I in A.overlays)
iconmode = ICON_OVERLAY
else if(I in A.underlays)
iconmode = ICON_UNDERLAY
else
iconmode = blendMode2iconMode(curblend)
// Blend the overlay into the flattened icon
flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
flat.Blend(add, iconmode, I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
if(A.color)
flat.Blend(A.color, ICON_MULTIPLY)
@@ -862,7 +897,7 @@ proc/generate_image(var/tx as num, var/ty as num, var/tz as num, var/range as nu
if(!suppress_errors)
return
return generate_image_from_turfs(turfstocapture, range, cap_mode, user, lighting)
return generate_image_from_turfs(locate(tx, ty, tz), turfstocapture, range, cap_mode, user, lighting)
/proc/generate_image_from_turfs(turf/topleft, list/turf/turfstocapture, range as num, cap_mode = CAPTURE_MODE_PARTIAL, mob/living/user, lighting = TRUE)
var/tx = topleft.x

View File

@@ -27,6 +27,8 @@
//Detective Work, used for the duplicate data points kept in the scanners
var/list/original_atom
var/gfi_layer_rotation = GFI_ROTATION_DEFAULT
/atom/proc/reveal_blood()
return

View File

@@ -12,6 +12,7 @@
light_color = "#64C864"
light_power = 1
light_range = 2
gfi_layer_rotation = GFI_ROTATION_DEFDIR
var/light_power_on = 1
var/light_range_on = 2

View File

@@ -20,6 +20,7 @@
var/material/padding_material
var/base_icon = "bed"
var/can_dismantle = 1
gfi_layer_rotation = GFI_ROTATION_DEFDIR
/obj/structure/bed/Initialize(mapload, var/new_material, var/new_padding_material)
. = ..()

View File

@@ -145,7 +145,7 @@ var/list/admin_verbs_spawn = list(
/client/proc/spawn_chemdisp_cartridge
)
var/list/admin_verbs_server = list(
/datum/admins/proc/capture_map,
/datum/admins/proc/capture_map_part,
/client/proc/Set_Holiday,
/datum/admins/proc/startnow,
/datum/admins/proc/restart,
@@ -213,7 +213,8 @@ var/list/admin_verbs_debug = list(
/client/proc/cmd_display_del_log,
/client/proc/cmd_display_init_log,
/client/proc/cmd_ss_panic,
/client/proc/reset_openturf
/client/proc/reset_openturf,
/datum/admins/proc/capture_map
)
var/list/admin_verbs_paranoid_debug = list(

View File

@@ -1,4 +1,4 @@
/datum/admins/proc/capture_map(tx as null|num, ty as null|num, tz as null|num, range as null|num)
/datum/admins/proc/capture_map_part(tx as null|num, ty as null|num, tz as null|num, range as null|num)
set category = "Server"
set name = "Capture Map Part"
set desc = "Usage: Capture-Map-Part target_x_cord target_y_cord target_z_cord range (captures part of a map originating from bottom left corner)"
@@ -18,9 +18,64 @@
return
if(locate(tx,ty,tz))
var/cap = generate_image(tx ,ty ,tz ,range, CAPTURE_MODE_PARTIAL, null, 1, 1)
var/ligths = 0
if(alert("Do you want lighting to be included in capture?", "Map Capture", "No", "Yes") == "Yes")
ligths = 1
var/cap = generate_image(tx ,ty ,tz ,range, CAPTURE_MODE_PARTIAL, null, ligths, 1)
var/file_name = "map_capture_x[tx]_y[ty]_z[tz]_r[range].png"
usr << "Saved capture in cache as [file_name]."
usr << browse_rsc(cap, file_name)
else
usr << "Target coordinates are incorrect."
/datum/admins/proc/capture_map_capture_next(currentz, currentx, currenty, ligths)
if(locate(currentx, currenty, currentz))
var/cap = generate_image(currentx ,currenty ,currentz ,16, CAPTURE_MODE_PARTIAL, null, ligths, 1)
var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r16.png"
usr << "Saved capture in cache as [file_name]."
usr << browse_rsc(cap, file_name)
currentx = currentx + 16
spawn (6)
del(cap)
.(currentz, currentx, currenty, ligths)
else
currenty = currenty + 16
currentx = 1
if(locate(currentx, currenty, currentz))
var/cap = generate_image(currentx ,currenty ,currentz ,16, CAPTURE_MODE_PARTIAL, null, ligths, 1)
var/file_name = "map_capture_x[currentx]_y[currenty]_z[currentz]_r16.png"
usr << "Saved capture in cache as [file_name]."
usr << browse_rsc(cap, file_name)
currentx = currentx + 16
spawn (6)
del(cap)
.(currentz, currentx, currenty, ligths)
else
usr << "End of map, capture is done."
/datum/admins/proc/capture_map(tz as null|num)
set category = "Server"
set name = "Capture Map"
set desc = "Usage: Capture-Map target_z_cord (captures map)"
if(!check_rights(R_ADMIN|R_DEBUG|R_SERVER))
usr << "You are not allowed to use this command"
return
if(isnull(tz))
usr << "Map Part, map using camara like rendering."
usr << "Usage: Capture-Map target_z_cord"
usr << "Target Z coordinates define z level to capture."
return
if(!locate(1, 1, tz))
usr << "Target z-level is incorrect."
return
var/ligths = 0
if(alert("Do you want lighting to be included in capture?", "Map Capture", "No", "Yes") == "Yes")
ligths = 1
switch(alert("Are you sure? (This will cause masive lag!!!)", "Map Capture", "No", "Yes"))
if("Yes")
usr.client.holder.capture_map_capture_next(tz, 1, 1, ligths)

View File

@@ -236,3 +236,5 @@
var/list/progressbars
var/frozen = FALSE //related to wizard statues, if set to true, life won't process
gfi_layer_rotation = GFI_ROTATION_DEFDIR

3
tools/mapcapturemerge/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.png
*.pyc
captures/*.png

View File

@@ -0,0 +1,18 @@
# Map capture merge tool
---
This is script for merging captured map images using `Capture-Map` verb.
---
Map capture merge tool manual
======
1. Capture desired Z levels using in game verb `Capture-map`
2. Before closing game window, go to cache folder usually located under Documents/BYOND and copy all map capture images named like `map_capture_x1_y33_z1_r32.png` to folder under this tool called `captures`.
3. Install *Python* and *Pillow* library (If you don't have them).
4. Run `python merge.py` and wait for captured images to be merged.
5. After execution you will find all merged map images in this folder.
Notes:
* This tool been tested with Python 2.7.6 under Windows 10 Bash.
* This tool also been tested with Python 3.6.1 under Windows 10.

View File

View File

@@ -0,0 +1,15 @@
from PIL import Image
import re
reg_findnums = re.compile("[0-9]+")
class ImageFile:
def __init__(self, filename, path):
self.filename = path
nums = reg_findnums.findall(filename)
self.cords = (int(nums[0]), int(nums[1]), int(nums[2]))
self.range = int(nums[3])
def getImage(self):
im = Image.open(self.filename)
im.load()
return im

View File

@@ -0,0 +1,41 @@
from PIL import Image
import os, re, imageHelpers
def BYONDCordsToPixelCords(B, BMax):
y = (BMax[1] - B[1]) - 31
return (B[0] * 32 - 32, y * 32 - 32)
image_location = os.path.join(os.getcwd(), 'captures')
print("Map capture merger by Karolis")
capture_images = []
capture_re = re.compile("map_capture_x[0-9]+_y[0-9]+_z[0-9]+_r\d+\.png")
for image_file in os.listdir(image_location):
if os.path.isfile(os.path.join(image_location, image_file)) and capture_re.match(image_file):
#print(image_file)
capture_images.append(imageHelpers.ImageFile(image_file, os.path.join(image_location, image_file)))
max_x = 0
max_y = 0
z_levels = []
captures = {}
for capture in capture_images:
max_x = max(max_x, capture.cords[0] + capture.range)
max_y = max(max_y, capture.cords[1] + capture.range)
if not capture.cords[2] in z_levels:
z_levels.append(capture.cords[2])
captures[capture.cords[2]] = []
captures[capture.cords[2]].append(capture)
maxCords = (max_x, max_y)
for z in z_levels:
print("Merging map from " + str(z) + " z level.")
map = Image.new("RGBA", ((max_x - 1) * 32, (max_y - 1) * 32))
for capture in captures[z]:
part = capture.getImage()
map.paste(part, BYONDCordsToPixelCords(capture.cords, maxCords))
filename = "map_z" + str(z) + ".png"
print("Saving map as: " + filename)
map.save(filename)