mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-06 07:22:15 +00:00
More tweaks (#2889)
changes: Clipboard overlays are now a little gentler on SSoverlays. Ported potential performance improvements for getFlatIcon and listclearnulls from /tg/. Icon smoothing now clears the base icon by default; SMOOTH_NO_CLEAR_ICON disables this behavior. Potential SSoverlays performance improvement from /tg/. Speculative fix for #2826.
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
#define SMOOTH_DIAGONAL 4 //if atom should smooth diagonally, this should be present in 'smooth' var
|
||||
#define SMOOTH_BORDER 8 //atom will smooth with the borders of the map
|
||||
#define SMOOTH_QUEUED 16 //atom is currently queued to smooth.
|
||||
#define SMOOTH_CLEAR_ICON 32 // clear the atom's icon_state on smooth. SMOOTH_DIAGONAL implies this.
|
||||
#define SMOOTH_NO_CLEAR_ICON 32 // don't clear the atom's icon_state on smooth.
|
||||
|
||||
#define NULLTURF_BORDER 123456789
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
if(New)
|
||||
A.add_overlay(New)
|
||||
|
||||
if (A.icon_state && (A.smooth & SMOOTH_CLEAR_ICON))
|
||||
if (A.icon_state && !(A.smooth & SMOOTH_NO_CLEAR_ICON))
|
||||
A.icon_state = null
|
||||
|
||||
/proc/find_type_in_direction(atom/source, direction)
|
||||
|
||||
@@ -633,174 +633,149 @@ Get flat icon by DarkCampainger. As it says on the tin, will return an icon with
|
||||
as a single icon. Useful for when you want to manipulate an icon via the above as overlays are not normally included.
|
||||
*/
|
||||
|
||||
proc // Creates a single icon from a given /atom or /image. Only the first argument is required.
|
||||
getFlatIcon(image/A, defdir=2, deficon=null, defstate="", defblend=BLEND_DEFAULT, always_use_defdir = 0)
|
||||
// We start with a blank canvas, otherwise some icon procs crash silently
|
||||
var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon
|
||||
if(!A)
|
||||
return flat
|
||||
if(A.alpha <= 0)
|
||||
return flat
|
||||
var/noIcon = FALSE
|
||||
/proc/getFlatIcon(image/A, defdir=2, deficon=null, defstate="", defblend=BLEND_DEFAULT, always_use_defdir = 0)
|
||||
// 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
|
||||
|
||||
var/curicon
|
||||
if(A.icon)
|
||||
curicon = A.icon
|
||||
var/curicon
|
||||
if(A.icon)
|
||||
curicon = A.icon
|
||||
else
|
||||
curicon = deficon
|
||||
|
||||
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))
|
||||
curstate = ""
|
||||
else
|
||||
curicon = deficon
|
||||
|
||||
if(!curicon)
|
||||
noIcon = TRUE // Do not render this object.
|
||||
|
||||
var/curstate
|
||||
if(A.icon_state)
|
||||
curstate = A.icon_state
|
||||
else
|
||||
curstate = defstate
|
||||
var/curdir
|
||||
if(A.dir != 2 && !always_use_defdir)
|
||||
curdir = A.dir
|
||||
else
|
||||
curdir = defdir
|
||||
|
||||
if(!noIcon && !(curstate in icon_states(curicon)))
|
||||
if("" in icon_states(curicon))
|
||||
curstate = ""
|
||||
else
|
||||
noIcon = TRUE // Do not render this object.
|
||||
var/curblend
|
||||
if(A.blend_mode == BLEND_DEFAULT)
|
||||
curblend = defblend
|
||||
else
|
||||
curblend = A.blend_mode
|
||||
|
||||
var/curdir
|
||||
if(A.dir != 2 && !always_use_defdir)
|
||||
curdir = A.dir
|
||||
else
|
||||
curdir = defdir
|
||||
// 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
|
||||
// Add the atom's icon itself, without pixel_x/y offsets.
|
||||
if(!noIcon)
|
||||
copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir)
|
||||
copy.color = A.color
|
||||
copy.alpha = A.alpha
|
||||
copy.blend_mode = curblend
|
||||
layers[copy] = A.layer
|
||||
|
||||
var/curblend
|
||||
if(A.blend_mode == BLEND_DEFAULT)
|
||||
curblend = defblend
|
||||
else
|
||||
curblend = A.blend_mode
|
||||
// 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]
|
||||
if(!current)
|
||||
curIndex++ //Try the next layer
|
||||
continue
|
||||
currentLayer = current:layer
|
||||
if(currentLayer<0) // Special case for FLY_LAYER
|
||||
if(currentLayer <= -1000) return flat
|
||||
if(pSet == 0) // Underlay
|
||||
currentLayer = A.layer+currentLayer/1000
|
||||
else // Overlay
|
||||
currentLayer = A.layer+(1000+currentLayer)/1000
|
||||
|
||||
// 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
|
||||
// Add the atom's icon itself, without pixel_x/y offsets.
|
||||
if(!noIcon)
|
||||
copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir)
|
||||
copy.color = A.color
|
||||
copy.alpha = A.alpha
|
||||
copy.blend_mode = curblend
|
||||
layers[copy] = A.layer
|
||||
// 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
|
||||
break
|
||||
if(cmpIndex>layers.len) // Reached end of list without inserting
|
||||
layers[current]=currentLayer // Place at end
|
||||
|
||||
// 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]
|
||||
if(current)
|
||||
currentLayer = current:layer
|
||||
if(currentLayer<0) // Special case for FLY_LAYER
|
||||
if(currentLayer <= -1000) return flat
|
||||
if(pSet == 0) // Underlay
|
||||
currentLayer = A.layer+currentLayer/1000
|
||||
else // Overlay
|
||||
currentLayer = A.layer+(1000+currentLayer)/1000
|
||||
curIndex++
|
||||
|
||||
// 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
|
||||
break
|
||||
if(cmpIndex>layers.len) // Reached end of list without inserting
|
||||
layers[current]=currentLayer // Place at end
|
||||
|
||||
curIndex++
|
||||
else if(pSet == 0) // Switch to overlays
|
||||
if(curIndex>process.len)
|
||||
if(pSet == 0) // Switch to overlays
|
||||
curIndex = 1
|
||||
pSet = 1
|
||||
process = A.overlays
|
||||
else // All done
|
||||
break
|
||||
|
||||
var/icon/add // Icon of overlay being added
|
||||
var/icon/add // Icon of overlay being added
|
||||
|
||||
// Current dimensions of flattened icon
|
||||
var/{flatX1=1;flatX2=flat.Width();flatY1=1;flatY2=flat.Height()}
|
||||
// Dimensions of overlay being added
|
||||
var/{addX1;addX2;addY1;addY2}
|
||||
// Current dimensions of flattened icon
|
||||
var/{flatX1=1;flatX2=flat.Width();flatY1=1;flatY2=flat.Height()}
|
||||
// Dimensions of overlay being added
|
||||
var/{addX1;addX2;addY1;addY2}
|
||||
|
||||
for(var/I in layers)
|
||||
for(var/I in layers)
|
||||
|
||||
if(I:alpha == 0)
|
||||
continue
|
||||
if(I:alpha == 0)
|
||||
continue
|
||||
|
||||
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,/obj/machinery/atmospherics) && I in A.underlays)
|
||||
var/image/Im = I
|
||||
add = getFlatIcon(new/image(I), Im.dir, curicon, curstate, curblend, 1)
|
||||
else
|
||||
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, always_use_defdir)
|
||||
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)
|
||||
else // 'I' is an appearance object.
|
||||
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend)
|
||||
|
||||
// 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())
|
||||
// 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())
|
||||
|
||||
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
|
||||
// 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
|
||||
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, iconmode, I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
|
||||
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
|
||||
// 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
|
||||
|
||||
if(A.color)
|
||||
flat.Blend(A.color, ICON_MULTIPLY)
|
||||
if(A.alpha < 255)
|
||||
flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY)
|
||||
// Blend the overlay into the flattened icon
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
|
||||
|
||||
return icon(flat, "", SOUTH)
|
||||
if(A.color)
|
||||
flat.Blend(A.color, ICON_MULTIPLY)
|
||||
if(A.alpha < 255)
|
||||
flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY)
|
||||
|
||||
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.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer) continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
return icon(flat, "", SOUTH)
|
||||
|
||||
/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.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer) continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
|
||||
/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay.
|
||||
var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays.
|
||||
|
||||
@@ -110,11 +110,12 @@ proc/clearlist(var/list/L)
|
||||
L.Cut()
|
||||
|
||||
//Removes any null entries from the list
|
||||
proc/listclearnulls(list/list)
|
||||
if(istype(list))
|
||||
while(null in list)
|
||||
list -= null
|
||||
return
|
||||
//Returns TRUE if the list had nulls, FALSE otherwise
|
||||
/proc/listclearnulls(list/L)
|
||||
var/start_len = L.len
|
||||
var/list/N = new(start_len)
|
||||
L -= N
|
||||
return L.len < start_len
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
|
||||
Reference in New Issue
Block a user