HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Images in JASS

09-21-2009, 07:23 PM#1
Deaod
Images

This is a little compilation of all i got to know about images over the last few days. This is not intended as a final documentation of images. If you have verifyable knowledge to add, please do so.

Collapse Declaration of the type:
type image extends handle

Collapse Image API:
native CreateImage takes string file, real sizeX, real sizeY, real sizeZ, real posX, real posY, real posZ, real originX, real originY, real originZ, integer imageType returns image
native DestroyImage takes image whichImage returns nothing
native ShowImage takes image whichImage, boolean flag returns nothing
native SetImageConstantHeight takes image whichImage, boolean flag, real height returns nothing
native SetImagePosition takes image whichImage, real x, real y, real z returns nothing
native SetImageColor takes image whichImage, integer red, integer green, integer blue, integer alpha returns nothing
native SetImageRender takes image whichImage, boolean flag returns nothing
native SetImageRenderAlways takes image whichImage, boolean flag returns nothing
native SetImageAboveWater takes image whichImage, boolean flag, boolean useWaterAlpha returns nothing
native SetImageType takes image whichImage, integer imageType returns nothing



Lets look at those functions in detail


General notes: Z things consistently dont work with one exception: SetImageConstantHeight, which in turn only works if the flag is true.
Once you store the invalid image (handle ID of -1) in a variable, that variable becomes read-only (unless you want to crash the game, that is).

Collapse JASS:
native CreateImage takes string file, real sizeX, real sizeY, real sizeZ, real posX, real posY, real posZ, real originX, real originY, real originZ, integer imageType returns image
Obviously the constructor for images.
string file: The path to the image. The image itself should have its border alpha-ed out completely. If an invalid path is specified CreateImage returns image(-1).
real sizeX, sizeY, sizeZ: The dimensions of the image. You can stretch images using these.
real posX, posY, posZ: Where to create the image. This is the bottom left corner of the image.
real originX, originY, originZ: Moves the origin (bottom left corner) of the image from posX/Y/Z in negative X/Y/Z-direction.
integer imageType: Working values range from 1 to 4 (4 and 1 included). Using 0 causes CreateImage to return image(-1). Every other value will simply cause WC3 to not display the image.
imageTypes also influence the order in which images are drawn above one another:
imageType 1 (labeled by Blizzard with "Selection") is drawn above all other imageTypes.
imageType 2 (labeled by Blizzard with "Indicator") is drawn above imageType 4, but below 1 and 3.
imageType 3 (labeled by Blizzard with "Occlusion Mask") is drawn above imageType 4 and 2 and below imageType 1.
imageType 4 (labeled by Blizzard with "Ubersplat") is drawn below every other type. Images of this type are additionally affected by time of day and the fog of war (only for tinting).
Multiple images with the same type are drawn in their order of creation, meaning that the image created first is drawn below the image created after.
This returns a new image, the first ID given being 0 and then counting upwards (0, 1, 2, 3, ...).


Collapse JASS:
native DestroyImage takes image whichImage returns nothing
Obviously the destructor for images.
image whichImage: Which image to destroy.
This function destroys the image specified and recycles the handle ID of that image instantly (no ref counting for images).
May crash the game if an invalid image is used (null, before the first image is created).


Collapse JASS:
native ShowImage takes image whichImage, boolean flag returns nothing
It shows/hides image whichImage, depending on boolean flag (true shows, false hides).
Seems like a redundant function in the light of SetImageRender(Always).


Collapse JASS:
native SetImageConstantHeight takes image whichImage, boolean flag, real height returns nothing
Untested, but if its decription can account for anthing, it locks the Z position to the given height, if the flag is true.
After a bit of testing i concluded that this is the only function thats able to modify an images Z offset.


Collapse JASS:
native SetImagePosition takes image whichImage, real x, real y, real z returns nothing
Sets the X/Y position of the provided image. Plain and simple. Havent found any quirks yet. This is the bottom left corner of the image, unless you used values form originX/Y/Z in the constructor other than 0, in which case the bottom left corner is moved further into negative X/Y/Z direction.


Collapse JASS:
native SetImageColor takes image whichImage, integer red, integer green, integer blue, integer alpha returns nothing
Works. Valid values for all channels range from 0 to 255. Values outside these bounds probably wont do much.


Collapse JASS:
native SetImageRender takes image whichImage, boolean flag returns nothing
Does not work. Use SetImageRenderAlways instead.


Collapse JASS:
native SetImageRenderAlways takes image whichImage, boolean flag returns nothing
Since SetImageRender is non-functional, this should be used to enable/disable rendering of the image.
I havent found the difference between this and ShowImage yet (this probably lessens the burden on the graphics engine of WC3).


Collapse JASS:
native SetImageAboveWater takes image whichImage, boolean flag, boolean useWaterAlpha returns nothing
Seems to work as described. Draws the specified image above the water if the flag is true. The second boolean (useWaterAlpha) doesnt seem to do much, but i havent tested every possible combination of this flag and imagetype.
Every imagetype other than 1 doesnt seem to appear above water.


Collapse JASS:
native SetImageType takes image whichImage, integer imageType returns nothing
Works as described. Changes the specified images type.


Blizzard internally uses images for the shadows of units, Selection Circles, and the preview version of selection circles. This list is non-exhaustive.
Images do get cleaned up properly through DestroyImage(). Setting local images to null is not necessary.

Images are so-called pseudo-handles, they have a separate handle stack for their own exclusive use. They can be handled asynchronously.

Units create at least one image, which is their shadow.
You can access the shadow of a unit directly after its creation, using some script like this:
Collapse JASS:
function CreateUnitWithShadow takes player owner, integer uid, real x, real y, real facing, string shadowfile returns unit
    local image i=CreateImage(shadowfile, 64, 64, 0, 0,0,0,64,64,0, 3) // creates a dummy image
    local unit u
    if GetHandleId(i)==-1 then // if the new shadow is invalid, abort, it can screw up the game
        debug call BJDebugMsg("CreateUnitWithShadow: Invalid path for new shadow!") // it could also be caused by an imageType of 0, but thats a less common cause
        return null // since the image is invalid, we dont need to destroy it
    endif
    call DestroyImage(i) // destroy the dummy.
    set u=CreateUnit(owner, uid, x,y,facing) // create the unit. this also creates a new image which functions as the shadow of the unit. The shadow will use the ID of the dummy image.
    call DestroyImage(i) // destroy the shadow of the unit
    call CreateImage(shadowfile, 64, 64, 0, 0,0,0,64,64,0, 3) // this creates the new shadow for the unit, note that i dont need to overwrite "i" as the id this image will get is predictable
    call SetImageRenderAlways(i, true) // display the shadow
    // no need to null "i", as images dont use ref-counting
    return u // return the unit
endfunction
Note that this is only for demonstration purposes. You can create a whole system for handling dynamic shadows of units with this at its core.

It could look like this
Collapse JASS:
library GatherShadows requires AutoIndex, ImageUtils
    
    globals
        private constant    string              DUMMY_IMAGE_FILE        = "ReplaceableTextures\\CommandButtons\\BTNPeasant.blp"
    endglobals
    
    globals
        private image TempImg=null
    endglobals
    
    struct UnitShadow
        image img
        private unit u
        
        private static method createFilter takes unit u returns boolean
            return TempImg!=null // if it equals null, CreateUnit was not used.
        endmethod
        
        private method onCreate takes nothing returns nothing
            set img=TempImg
            set TempImg=null
        endmethod
        
        private method onDestroy takes nothing returns nothing
            set img=null
        endmethod
        
        implement AutoCreate
        implement AutoDestroy
    endstruct
    
    private function CreateUnitHook takes player p, integer uid, real x, real y, real ang returns nothing
        set TempImg=CreateImage(DUMMY_IMAGE_FILE, 0,0,0,0,0,0,0,0,0,1)
        call DestroyImage(TempImg)
    endfunction
    
    hook CreateUnit CreateUnitHook
    
endlibrary

Credits for AutoIndex go to grim001.



I attached a map demonstrating ordering of images, the fact that theyre not ref-counted and the first ID is null. The map also demonstrates the possible bug with destroying images.

Credits for the imported images go to Pitzermike, who packed those images with his TextSplat system.

EDIT 1: Updated most (all?) untested or not thoroughly tested functions and added a clarification to SetImagePosition.
EDIT 2: Added a link to Pitzermikes TextSplat system.
EDIT 3: Added another general note to inform about the newfound bug when writing image variables currently containing the invalid image.
EDIT 4: Added a proof-of-concept script that automatically gathers the handle id of the shadows of units entering the game.
Attached Files
File type: w3mImageTesting.w3m (13.6 KB)
File type: w3mAutoShadow_Test.w3m (54.1 KB)
09-22-2009, 03:24 AM#2
fX_
informative
09-22-2009, 03:37 AM#3
midiway
that explains everything
09-22-2009, 04:04 AM#4
Rising_Dusk
You should test all of those "untested"s and submit it as a tutorial.
09-22-2009, 04:49 AM#5
TheKid
And be a little more descriptive on certain things where you've just said "Works.". For example, recall the SetImagePosition function. Earlier you stated that when you create an image, you must specify the coordinates of the bottom-left corner of the image. Does the same thing apply to SetImagePosition?

Quote:
Originally Posted by Deaod
Where to create the image. This is the bottom left corner of the image.
If it is a general rule for images that their coordinates refer to the bottom-left of the image, then it would be best stated above rather than specifically in the constructor notes.
09-22-2009, 06:24 AM#6
Deaod
Updated first post after more testing of previously untested functions.

Also addressed the problem you brought up, TheKid.
09-24-2009, 09:40 PM#7
Rising_Dusk
I like this a lot. Update the first post credits (Where you talk about Pitzey's TextSplat library) by linking to the TextSplat library and I will approve this.
09-25-2009, 11:44 AM#8
Deaod
Done.
09-25-2009, 12:42 PM#9
Rising_Dusk
Approved.
09-25-2009, 04:40 PM#10
Ignifex
I've been playing around with images a bit to create a menu. My experience is that changing an image's Z coordinate with SetImageConstantHeight will work, but once I place a unit on the map, it is placed back to the terrain's Z (ie. no effect of the call).
Can anyone confirm this? If there is a workaround, I would be interested, as I am now dedicating a small corner of my map to the menu.
09-26-2009, 09:34 AM#11
Silvenon
Before, only dimensions which were powers of two were allowed, otherwise they wouldn't show. But now they seem to allow other dimensions too (I've been testing a lot).
10-21-2009, 12:52 PM#12
Tot
I've here'd that all images, if you want them to show up properly have to fullfill a special criteria (something with 255 or 0 alpha somewhere) otherwise they're screwed up.

Is this true?
10-21-2009, 01:46 PM#13
Rising_Dusk
You should test it with his demo map, because that'd be real easy.
10-21-2009, 02:45 PM#14
Tot
Tried and remembered the solution

It's easy:
all Images have to have a border with alpha==0 around, otherwise the border will get screwed up

try to display the footman ('hfoo') -icon with and without this border and you'll see...

(I hate my english)
10-24-2009, 10:38 AM#15
Silvenon
Yeah, that's called a transparent border... I thought everyone already knew that after PitzerMike's tutorial.