GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2008-02-18 13:09:02

Alexander_Q
Member
Registered: 2008-02-14
Posts: 9

sprite_export_all(dir)

I made the following just now to export all sprite resources to .bmp files (subimages included in strip form).

Suggested usage: I use this server-side - the client requests a particular sprite, and the server finds it in his directory and uploads. Could be altered to export a sprite of a particular name.

Expand/*
**  Usage:
**      sprite_export_all(dir);
**
**  Arguments:
**      dir           Directory to export sprites to.
**
**  Notes:
**      Exports all sprite resources as .bmp strips to "dir"
**
**  GMLscripts.com
*/
{
    var dir,num,surfid,sprnumb;

    dir=argument0;
    num=sprite_create_from_screen(0,0,1,1,0,0,0,0,0,0);
    sprite_delete(num);
    for (i=0;i<=num;i+=1){    
        drawx=0
        if (sprite_exists(i)){
            sprnumb=sprite_get_number(i);
            surfid=surface_create(sprite_get_width(i)*sprnumb,sprite_get_height(i));
            surface_set_target(surfid);
            draw_clear(c_green);
            for (j=0;j<sprnumb;j+=1){
                draw_sprite(i,j,sprite_get_xoffset(i)+drawx,sprite_get_yoffset(i))
                drawx+=sprite_get_width(i);
            }
            surface_save(surfid, dir+sprite_get_name(i)+".bmp");
            surface_free(surfid);      
        }
    }
}

Last edited by Alexander_Q (2008-02-20 10:16:39)

Offline

#2 2008-02-18 13:21:23

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: sprite_export_all(dir)

This is an interesting idea for a script. I see one or two problems though.

First, you are creating surfaces, but you aren't freeing them when you are done.

Second, you are drawing the sprites against white, changing the transparency color. If a sprite has white in it, that part will become transparent too. I'd suggest replacing:

Expanddraw_clear(c_white);

... with:

Expanddraw_clear_alpha(c_black,1);
draw_set_blend_mode_ext(bm_inv_dest_color,bm_one);

But that's not without its own problems. (see my next post below)


Abusing forum power since 1986.

Offline

#3 2008-02-18 13:34:33

Alexander_Q
Member
Registered: 2008-02-14
Posts: 9

Re: sprite_export_all(dir)

Both good points Xot. I did have surface_free in there originally, but the way I use the script is inside a project which runs and closes immediately just for the sake of exporting its resources. I've added it back in just in case people want to use it in a different way.

The blend mode code however has had some strange effects at my end - it has placed a thick black outline around each sprite and placed it on a dark green background - such a thing could actually come in handy at some point, but for now it is not the intention of the script.

Any idea what went wrong? I don't fully understand the blend mode code.

Last edited by Alexander_Q (2008-02-18 13:34:47)

Offline

#4 2008-02-18 13:39:45

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: sprite_export_all(dir)

When sprites are initially loaded, as a Game Maker game starts, they are given an alpha mask and the sprite edges go through a process that duplicates the sprite edge colors into the transparent area which creates a colored outline around the sprite. If it didn't do this, and your transparency color was white, your sprites would have a white fringe exposed by subpixel sampling / antialiasing. This operation introduces a colored fringe around your sprite that is impossible to remove but normally isn't visible because of the alpha mask. There is no known way to export sprites that have transparent pixels exactly as they appear in the editor. The only way to work around it is to also export the alpha masks along with the sprites, and then reapply them to the sprites when they are reloaded.


Abusing forum power since 1986.

Offline

#5 2008-02-19 04:29:37

Alexander_Q
Member
Registered: 2008-02-14
Posts: 9

Re: sprite_export_all(dir)

I changed the script at my end to include a call to an external batch file converter. Now, the script outputs bmp strips and then converts them to .png at maximum compression (lossless so far with 256 colour format, haven't tried it with others). This script addition relies on an external .exe file. Should I include it, or perhaps just put the addition in the header as a usage example?

Offline

#6 2008-02-19 07:14:05

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: sprite_export_all(dir)

I think anything calling an external program is probably outside the scope of GMLscripts.com, unless if it was part of the OS.

Oh, and to answer your question about the blend mode: it is designed to draw the sprite without transparency.

Blend mode primer: All pixels have RGBA components (red, green, blue, alpha). When blending, they are thought of as running from zero to one rather than 0 to 255. In this example, draw_set_blend_mode_ext(bm_inv_dest_color,bm_one) says:

(1) multiply the source by the inverse of the destination color (the destination is black in this case (each color component is zero), which means the inverse is white (each color component is one))
(2) multiply the destination color by one (in other words, keep the same)
(3) add them together.

This procedure of multiplying the components of the source and destination pixels by selected factors (bm_inv_dest_color & bm_one, in this case), and then adding them together is how all blend modes work.

Expand{Rs,Gs,Bs,As} = Color & Alpha components of the Source
{Rd,Gd,Bd,Ad} = Color & Alpha components of the Destination

(bm_inv_dest_color, bm_one)
R' = Rs * (1.0 - Rd) + Rd * 1.0
G' = Gs * (1.0 - Gd) + Gd * 1.0
B' = Bs * (1.0 - Bd) + Bd * 1.0
A' = As * (1.0 - Ad) + Ad * 1.0


//  Example 1
//      Source      = orange (alpha = 1)
//      Destination = black (alpha = 1)
//      Factor1     = bm_inv_dest_color
//      Factor2     = bm_one

// Result = SRC * F1          + DST * F2
R' = 1.0  = 1.0 * (1.0 - 0.0) + 0.0 * 1.0
G' = 0.5  = 0.5 * (1.0 - 0.0) + 0.0 * 1.0
B' = 0.0  = 0.0 * (1.0 - 0.0) + 0.0 * 1.0
A' = 1.0  = 1.0 * (1.0 - 1.0) + 1.0 * 1.0


//  Example 2
//      Source      = blue-gray (alpha = 0)
//      Destination = black (alpha = 1)
//      Factor1     = bm_inv_dest_color
//      Factor2     = bm_one

// Result = SRC * F1          + DST * F2
R' = 0.3  = 0.3 * (1.0 - 0.0) + 0.0 * 1.0
G' = 0.6  = 0.6 * (1.0 - 0.0) + 0.0 * 1.0
B' = 1.0  = 1.0 * (1.0 - 0.0) + 0.0 * 1.0
A' = 1.0  = 0.0 * (1.0 - 0.0) + 1.0 * 1.0

Abusing forum power since 1986.

Offline

#7 2008-02-20 10:19:02

Alexander_Q
Member
Registered: 2008-02-14
Posts: 9

Re: sprite_export_all(dir)

I've had to make a change to this script. A line was changed to "draw_sprite(i,j,sprite_get_xoffset(i)+drawx,sprite_get_yoffset(i))" to account for sprites whose origin was not "0,0". Now regardless of origin or number of frames, the correct image/strip will be output.

I think it's better to just guess a draw_clear colour than to use blending if it's going to create an unintended black line around the image. What do you think?

Offline

#8 2008-02-20 14:04:11

xot
Administrator
Registered: 2007-08-18
Posts: 1,240

Re: sprite_export_all(dir)

I believe you'll get slight fringing no matter what color you use for the background. It may be less pronounced if you can provide the exact transparency color, use that as your background, and draw the sprite normally on top of it. But I don't believe there is any way to eliminate fringing completely. Even worse, your sprites will degenerate a little more each successive time you export them. There is no real way around it except to always keep your sprites external and load them from the disk at run time. If you do that, you don't need to exporting the resources from inside the game, you can simply copy the files. I know that's not what you are trying to achieve. Similarly, you could keep your sprites non-transparent in the editor and create transparent versions of them at run time. I think that might prevent the edge processing step from damaging the originals, but I've never tried it. Working that way is a bit unintuitive and doubles your texture memory footprint.

I've given a lot of though to exporting sprites exactly as they appear in the editor, and I've concluded (with others) that it is essentially impossible. As a compromise, I wracked my brains to find ways to absolutely determine the transparency color automatically, but every method I think of fails in certain special cases. For instance, you can attempt to determine the exact color simply by looking at the color in the bottom-left corner of the sprite. However, if any of the pixels immediately surrounding it are not transparent, the color in the corner won't be accurate. Or you could go so far as to scan the alpha channel for a 3x3 area that is totally black (100% transparent) and then check the center pixel in the corresponding area of the color channels of the sprite. That should certainly be the correct color, but there may not be such a 3x3 area in the alpha mask in every case, and such a scan would be very slow. And as I said, knowing the exact color won't really solve the fringing issue. The sprites are permanently damaged as soon as the game loads.

The final method involves hacking the EXE, as it's running, finding the sprite data, and exporting it from there ... which is madness.

Exporting both the alpha channel and the color channels may be the best compromise. If you do that, then the sprites should look the same at run time. They won't look exactly the same as they do in the editor, but they won't look any worse than the originals look at run time.


Abusing forum power since 1986.

Offline

#9 2008-02-20 17:04:21

Alexander_Q
Member
Registered: 2008-02-14
Posts: 9

Re: sprite_export_all(dir)

... I can't believe I didn't think of that - I'll just make all my sprites non-transparent. You see, it is a kind of "resource center" that exports all of the sprites - they don't need to actually be used in game, and in the client program their transparency is already taken care of. This will just export them exactly how they were imported, which I trust to be correct.

This doesn't help people using more complex graphics or sprites in different situations, but it's solved for me.

Offline

Board footer

Powered by FluxBB