mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Merge pull request #4602 from VOREStation/upstream-merge-5765
[MIRROR] Speeds up getFlatIcon
This commit is contained in:
@@ -627,22 +627,44 @@ proc/ColorTone(rgb, tone)
|
||||
if(gray <= tone_gray) return BlendRGB("#000000", tone, gray/(tone_gray || 1))
|
||||
else return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1))
|
||||
|
||||
|
||||
/*
|
||||
Get flat icon by DarkCampainger. As it says on the tin, will return an icon with all the overlays
|
||||
as a single icon. Useful for when you want to manipulate an icon via the above as overlays are not normally included.
|
||||
The _flatIcons list is a cache for generated icon files.
|
||||
*/
|
||||
|
||||
// Ported from /tg/station
|
||||
// Creates a single icon from a given /atom or /image. Only the first argument is required.
|
||||
/proc/getFlatIcon(image/A, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE)
|
||||
// We start with a blank canvas, otherwise some icon procs crash silently
|
||||
var/icon/flat = icon('icons/effects/effects.dmi', "nothing") // Final flattened icon
|
||||
if(!A)
|
||||
return flat
|
||||
if(A.alpha <= 0)
|
||||
return flat
|
||||
var/noIcon = FALSE
|
||||
//Define... defines.
|
||||
var/static/icon/flat_template = icon('icons/effects/effects.dmi', "nothing")
|
||||
|
||||
#define BLANK icon(flat_template)
|
||||
#define SET_SELF(SETVAR) do { \
|
||||
var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null); \
|
||||
if(A.alpha<255) { \
|
||||
SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);\
|
||||
} \
|
||||
if(A.color) { \
|
||||
if(islist(A.color)){ \
|
||||
SELF_ICON.MapColors(arglist(A.color))} \
|
||||
else{ \
|
||||
SELF_ICON.Blend(A.color,ICON_MULTIPLY)} \
|
||||
} \
|
||||
##SETVAR=SELF_ICON;\
|
||||
} while (0)
|
||||
#define INDEX_X_LOW 1
|
||||
#define INDEX_X_HIGH 2
|
||||
#define INDEX_Y_LOW 3
|
||||
#define INDEX_Y_HIGH 4
|
||||
|
||||
#define flatX1 flat_size[INDEX_X_LOW]
|
||||
#define flatX2 flat_size[INDEX_X_HIGH]
|
||||
#define flatY1 flat_size[INDEX_Y_LOW]
|
||||
#define flatY2 flat_size[INDEX_Y_HIGH]
|
||||
#define addX1 add_size[INDEX_X_LOW]
|
||||
#define addX2 add_size[INDEX_X_HIGH]
|
||||
#define addY1 add_size[INDEX_Y_LOW]
|
||||
#define addY2 add_size[INDEX_Y_HIGH]
|
||||
|
||||
if(!A || A.alpha <= 0)
|
||||
return BLANK
|
||||
|
||||
var/noIcon = FALSE
|
||||
if(start)
|
||||
if(!defdir)
|
||||
defdir = A.dir
|
||||
@@ -653,23 +675,13 @@ The _flatIcons list is a cache for generated icon files.
|
||||
if(!defblend)
|
||||
defblend = A.blend_mode
|
||||
|
||||
var/curicon
|
||||
if(A.icon)
|
||||
curicon = A.icon
|
||||
else
|
||||
curicon = deficon
|
||||
var/curicon = A.icon || deficon
|
||||
var/curstate = A.icon_state || defstate
|
||||
|
||||
if(!curicon)
|
||||
noIcon = TRUE // Do not render this object.
|
||||
|
||||
var/curstate
|
||||
if(A.icon_state)
|
||||
curstate = A.icon_state
|
||||
else
|
||||
curstate = defstate
|
||||
|
||||
if(!noIcon && !(curstate in icon_states(curicon)))
|
||||
if("" in icon_states(curicon))
|
||||
if(!((noIcon = (!curicon))))
|
||||
var/curstates = icon_states(curicon)
|
||||
if(!(curstate in curstates))
|
||||
if("" in curstates)
|
||||
curstate = ""
|
||||
else
|
||||
noIcon = TRUE // Do not render this object.
|
||||
@@ -683,36 +695,28 @@ The _flatIcons list is a cache for generated icon files.
|
||||
else
|
||||
curdir = A.dir
|
||||
|
||||
//Let's check if the icon actually contains any diagonals, just skip if it's south to save (lot of) time
|
||||
if(curdir != SOUTH)
|
||||
var/icon/test_icon
|
||||
var/directionals_exist = FALSE
|
||||
var/list/dirs_to_check = cardinal - SOUTH
|
||||
outer:
|
||||
for(var/possible_dir in dirs_to_check)
|
||||
test_icon = icon(curicon,curstate,possible_dir,frame=1)
|
||||
for(var/x in 1 to world.icon_size)
|
||||
for(var/y in 1 to world.icon_size)
|
||||
if(!isnull(test_icon.GetPixel(x,y)))
|
||||
directionals_exist = TRUE
|
||||
break outer
|
||||
if(!directionals_exist)
|
||||
//Try to remove/optimize this section ASAP, CPU hog.
|
||||
//Determines if there's directionals.
|
||||
if(!noIcon && curdir != SOUTH)
|
||||
var/exist = FALSE
|
||||
var/static/list/checkdirs = list(NORTH, EAST, WEST)
|
||||
for(var/i in checkdirs) //Not using GLOB for a reason.
|
||||
if(length(icon_states(icon(curicon, curstate, i))))
|
||||
exist = TRUE
|
||||
break
|
||||
if(!exist)
|
||||
base_icon_dir = SOUTH
|
||||
//
|
||||
|
||||
if(!base_icon_dir)
|
||||
base_icon_dir = curdir
|
||||
|
||||
var/curblend
|
||||
if(A.blend_mode == BLEND_DEFAULT)
|
||||
curblend = defblend
|
||||
else
|
||||
curblend = A.blend_mode
|
||||
ASSERT(!BLEND_DEFAULT) //I might just be stupid but lets make sure this define is 0.
|
||||
|
||||
// Before processing overlays, make sure any pending overlays are applied
|
||||
if (isloc(A))
|
||||
var/atom/aAtom = A
|
||||
if(aAtom.flags & OVERLAY_QUEUED)
|
||||
COMPILE_OVERLAYS(aAtom)
|
||||
var/curblend = A.blend_mode || defblend
|
||||
|
||||
if(A.overlays.len || A.underlays.len)
|
||||
var/icon/flat = BLANK
|
||||
// Layers will be a sorted list of icons/overlays, based on the order in which they are displayed
|
||||
var/list/layers = list()
|
||||
var/image/copy
|
||||
@@ -725,64 +729,35 @@ The _flatIcons list is a cache for generated icon files.
|
||||
layers[copy] = A.layer
|
||||
|
||||
// Loop through the underlays, then overlays, sorting them into the layers list
|
||||
var/list/process = A.underlays // Current list being processed
|
||||
var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays
|
||||
var/curIndex=1 // index of 'current' in list being processed
|
||||
var/current // Current overlay being sorted
|
||||
var/currentLayer // Calculated layer that overlay appears on (special case for FLOAT_LAYER)
|
||||
var/compare // The overlay 'add' is being compared against
|
||||
var/cmpIndex // The index in the layers list of 'compare'
|
||||
while(TRUE)
|
||||
if(curIndex<=process.len)
|
||||
current = process[curIndex]
|
||||
for(var/process_set in 0 to 1)
|
||||
var/list/process = process_set? A.overlays : A.underlays
|
||||
for(var/i in 1 to process.len)
|
||||
var/image/current = process[i]
|
||||
if(!current)
|
||||
curIndex++ //Try the next layer
|
||||
continue
|
||||
var/image/I = current
|
||||
if(I.plane != FLOAT_PLANE && I.plane != A.plane)
|
||||
curIndex++
|
||||
if(current.plane != FLOAT_PLANE && current.plane != A.plane)
|
||||
continue
|
||||
currentLayer = I.layer
|
||||
if(currentLayer<0) // Special case for FLOAT_LAYER
|
||||
if(currentLayer <= -1000)
|
||||
var/current_layer = current.layer
|
||||
if(current_layer < 0)
|
||||
if(current_layer <= -1000)
|
||||
return flat
|
||||
if(pSet == 0) // Underlay
|
||||
currentLayer = A.layer+currentLayer/1000
|
||||
else // Overlay
|
||||
currentLayer = A.layer+(1000+currentLayer)/1000
|
||||
current_layer = process_set + A.layer + current_layer / 1000
|
||||
|
||||
// Sort add into layers list
|
||||
for(cmpIndex=1,cmpIndex<=layers.len,cmpIndex++)
|
||||
compare = layers[cmpIndex]
|
||||
if(currentLayer < layers[compare]) // Associated value is the calculated layer
|
||||
layers.Insert(cmpIndex,current)
|
||||
layers[current] = currentLayer
|
||||
for(var/p in 1 to layers.len)
|
||||
var/image/cmp = layers[p]
|
||||
if(current_layer < layers[cmp])
|
||||
layers.Insert(p, current)
|
||||
break
|
||||
if(cmpIndex>layers.len) // Reached end of list without inserting
|
||||
layers[current]=currentLayer // Place at end
|
||||
layers[current] = current_layer
|
||||
|
||||
curIndex++
|
||||
|
||||
if(curIndex>process.len)
|
||||
if(pSet == 0) // Switch to overlays
|
||||
curIndex = 1
|
||||
pSet = 1
|
||||
process = A.overlays
|
||||
else // All done
|
||||
break
|
||||
//sortTim(layers, /proc/cmp_image_layer_asc)
|
||||
|
||||
var/icon/add // Icon of overlay being added
|
||||
|
||||
// Current dimensions of flattened icon
|
||||
var/flatX1=1
|
||||
var/flatX2=flat.Width()
|
||||
var/flatY1=1
|
||||
var/flatY2=flat.Height()
|
||||
var/list/flat_size = list(1, flat.Width(), 1, flat.Height())
|
||||
// Dimensions of overlay being added
|
||||
var/addX1
|
||||
var/addX2
|
||||
var/addY1
|
||||
var/addY2
|
||||
var/list/add_size[4]
|
||||
|
||||
for(var/V in layers)
|
||||
var/image/I = V
|
||||
@@ -793,25 +768,36 @@ The _flatIcons list is a cache for generated icon files.
|
||||
curblend = BLEND_OVERLAY
|
||||
add = icon(I.icon, I.icon_state, base_icon_dir)
|
||||
else // 'I' is an appearance object.
|
||||
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, FALSE, no_anim)
|
||||
|
||||
add = getFlatIcon(image(I), curdir, curicon, curstate, curblend, FALSE, no_anim)
|
||||
if(!add)
|
||||
continue
|
||||
// Find the new dimensions of the flat icon to fit the added overlay
|
||||
addX1 = min(flatX1, I.pixel_x+1)
|
||||
addX2 = max(flatX2, I.pixel_x+add.Width())
|
||||
addY1 = min(flatY1, I.pixel_y+1)
|
||||
addY2 = max(flatY2, I.pixel_y+add.Height())
|
||||
add_size = list(
|
||||
min(flatX1, I.pixel_x+1),
|
||||
max(flatX2, I.pixel_x+add.Width()),
|
||||
min(flatY1, I.pixel_y+1),
|
||||
max(flatY2, I.pixel_y+add.Height())
|
||||
)
|
||||
|
||||
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
|
||||
if(flat_size ~! add_size)
|
||||
// Resize the flattened icon so the new icon fits
|
||||
flat.Crop(addX1-flatX1+1, addY1-flatY1+1, addX2-flatX1+1, addY2-flatY1+1)
|
||||
flatX1=addX1;flatX2=addX2
|
||||
flatY1=addY1;flatY2=addY2
|
||||
flat.Crop(
|
||||
addX1 - flatX1 + 1,
|
||||
addY1 - flatY1 + 1,
|
||||
addX2 - flatX1 + 1,
|
||||
addY2 - flatY1 + 1
|
||||
)
|
||||
flat_size = add_size.Copy()
|
||||
|
||||
// Blend the overlay into the flattened icon
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1)
|
||||
|
||||
if(A.color)
|
||||
if(islist(A.color))
|
||||
flat.MapColors(arglist(A.color))
|
||||
else
|
||||
flat.Blend(A.color, ICON_MULTIPLY)
|
||||
|
||||
if(A.alpha < 255)
|
||||
flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY)
|
||||
|
||||
@@ -819,12 +805,30 @@ The _flatIcons list is a cache for generated icon files.
|
||||
//Clean up repeated frames
|
||||
var/icon/cleaned = new /icon()
|
||||
cleaned.Insert(flat, "", SOUTH, 1, 0)
|
||||
return cleaned
|
||||
. = cleaned
|
||||
else
|
||||
return icon(flat, "", SOUTH)
|
||||
. = icon(flat, "", SOUTH)
|
||||
else //There's no overlays.
|
||||
if(!noIcon)
|
||||
SET_SELF(.)
|
||||
|
||||
//Clear defines
|
||||
#undef flatX1
|
||||
#undef flatX2
|
||||
#undef flatY1
|
||||
#undef flatY2
|
||||
#undef addX1
|
||||
#undef addX2
|
||||
#undef addY1
|
||||
#undef addY2
|
||||
|
||||
#undef INDEX_X_LOW
|
||||
#undef INDEX_X_HIGH
|
||||
#undef INDEX_Y_LOW
|
||||
#undef INDEX_Y_HIGH
|
||||
|
||||
#undef BLANK
|
||||
#undef SET_SELF
|
||||
|
||||
/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
|
||||
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
|
||||
|
||||
Reference in New Issue
Block a user