GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2009-09-13 17:19:34

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

Gradient Wipe Transition

I can't rightly call this a transition in the Game Maker sense, not yet. This just demonstrates how one might construct a gradient wipe transition using a few blending tricks.

mBYNKWJ.jpg

The gradient image controls the sweep of the wipe from light to dark. This is a clock style wipe. Any gradient can be instantly turned into a transition. With a carefully constructed gradient you can even create brush strokes or handwriting effects. Several different gradients are demonstrated here.

mAVDeh9.gifMove the mouse vertically to perform the transition.
Move the mouse horizontally to control the contrast.
Press any key to select a random gradient.

Download gradient-transition03.gmk from Host-A

There is also no reason why a gradient can't change shape or be animated during the transition for far more elaborate effects. These dynamic effects are beyond the scope of this demonstration.


Abusing forum power since 1986.

Offline

#2 2009-09-13 20:19:41

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

Re: Gradient Wipe Transition

So simple it's complicated LOL.

Offline

#3 2009-09-14 04:38:11

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

Re: Gradient Wipe Transition

That's a good way to put it. This is my third pass at it and I think it's been distilled down to something fairly optimal. Earlier passes were a little more clear but much less simple.

When I began to review my notes from the original paper-only pass, it seemed quite complicated. Because I waited so long to try the idea, and because my notes were of exceptionally poor quality, I no longer understood what I had written. I could only remember being satisfied it would work.

yICwUsi.jpg
DO NOT ATTEMPT

So I abandoned the notes and from the keyboard reinvented it a little differently. Once I got it working, it had two branches, one for t < 0.5 and one for t >= 0.5. For the third pass I concentrated on trying simplify the effect. After some more random poking with different blending options I found a way to merge the two branches. That change made everything so much more beautiful.

I've polished a bit further and now have a version that works using the Game Maker transition engine. I've got one more trick up my sleeve and then I guess I'll make a GM extension. I've noodled a bit with the extension builder but this would be my first proper extension.


Abusing forum power since 1986.

Offline

#4 2009-09-14 16:10:10

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

Re: Gradient Wipe Transition

Here's the main code with some hopefully helpful comments. This script can be used with the Game Maker transition system. You just need to set up a few things first. You need a pair of globalvars, you need to prepare your gradient image to serve as its own alpha image, and you need to register the script with the transition engine.

//  draw_transition_gradient_wipe(surfaceA,surfaceB,width,height,fraction)
//      This is built to work with the Game Maker transition system.
//      It expects two globalvars to be set:
//      transition_contrast     number of contrast passes to perform
//      transition_image        a background image that is its own alpha,
//                              ie. background_set_alpha_from_background(bg,bg)
{   
    var work,sx,sy;
    //  Create work surface
    work = surface_create(argument2,argument3);
    if (work != -1)
    {
        //   Calculate the scaling of the transition image
        sx = argument2 / background_get_width(transition_image);
        sy = argument3 / background_get_height(transition_image);

        surface_set_target(work);
        
            //  SHIFT -  pushes the alpha gradient towards black or white
            //          depending on the given fraction 0.0 to 1.0;
            //          at 0.0 the gradient is fully pushed to black (fully transparent),
            //          at 1.0 the gradient is fully pushed to white (fully opaque)
            //
            //  1. Clear the work surface. If (t > 0.5) shift surface towards white;
            //      set alpha so that it ramps up from 0.0 to 1.0
            //      as t approaches 1.0 === (2*t-1) 
            //
            //  2. Add the alpha gradient, but if (t < 0.5) shift* it towards black;
            //      set alpha so that it ramps up from 0.0 to 1.0
            //      as t approaches 0.5 === (2*t)
            //      * scales towards black by necessity; shifting may look smoother
            argument4 *= 2;
            draw_clear_alpha(c_black,argument4-1);
            draw_set_blend_mode_ext(bm_one,bm_one);
            draw_background_ext(transition_image,0,0,sx,sy,0,c_white,argument4);
        
            
            //  CONTRAST - repeatedly squares self and doubles to increase contrast;
            //      values below 0.5 will be pushed towards 0.0,
            //      values above 0.5 will be pushed towards 1.0
            //      eg. 0.2*0.2 + 0.2*0.2 = 0.080
            //          0.4*0.4 + 0.4*0.4 = 0.320
            //          0.6*0.6 + 0.6*0.6 = 0.720
            //          0.8*0.8 + 0.8*0.8 = 1.128
            draw_set_blend_mode_ext(bm_dest_color,bm_src_color);
            repeat (transition_contrast) draw_surface(work,0,0);
    
            
            //  COMPOSITE - blend the two input images using the work surface alpha;
            //      1. Draw the B image using the alpha of the work surface
            //      2. Add the A image using the inverse alpha of the work surface
            draw_set_blend_mode_ext(bm_dest_alpha,bm_zero);
            draw_surface(argument1,0,0);
            draw_set_blend_mode_ext(bm_inv_dest_alpha,bm_one);
            draw_surface(argument0,0,0);
                
        surface_reset_target();

        //  All done, draw it and free the work surface.
        draw_set_blend_mode(bm_normal);
        draw_surface(work,0,0);  
        surface_free(work);
    }
}
{  
    //  Global vars required by custom transtion: draw_transition_gradient_wipe
    //      transition_image        background resource
    //      transition_contrast     wipe edge sharpness
    globalvar transition_image,transition_contrast;
}
{
    //  Prepare gradient
    background_set_alpha_from_background(backGradient,backGradient);
}
{
    //  Select transition
    transition_define(22,"draw_transition_gradient_wipe");
    transition_kind = 22;
    transition_steps = 60;
    transition_contrast = 5;
    transition_image = backGradient;

    room_goto(roomNext);
}

Abusing forum power since 1986.

Offline

#5 2009-09-15 04:20:52

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

Re: Gradient Wipe Transition

In part 2 of the "SHIFT" code, there is a note that the operation is actually scaling towards black, rather than shifting evenly. Apparently this causes the the transition to advance at an uneven rate. It might be possible to compensate for this by remapping t when it is less than 0.5, or maybe it can be overcome with some extra blending operations.

Also, I mentioned having a trick up my sleeve a couple posts back. The idea was based on the possibility that during a transition, the render target is set to a surface. If that were true it might be possible to eliminate the work surface which would be a big plus. I wasn't able to get it to work.


Abusing forum power since 1986.

Offline

#6 2009-09-15 04:37:47

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

Re: Gradient Wipe Transition

Here is some code showing a way to construct a shape-based wipe gradient. This is a heart wipe. It requires two images, one is the shape of a heart, white on black, and the other an image of the same size, white only. The shape image is used as an alpha channel for the white image.

kwhBH8a.pngZI6ZRM7.pngqEJjU2k.gif

//   shows how to create a gradient wipe using an image cutout
var i,c,a,r,s,o;
background_set_alpha_from_background(backWhite,backHeart);
draw_clear(c_black);
draw_set_blend_mode_ext(bm_src_alpha,bm_inv_src_alpha);
for(i=0;i<256;i+=1) 
{
    c = make_color_hsv(0,0,i);  // color
    a = i/256;                  // fraction of transition
    r = 0;                      // rotation in degrees
    s = 2.2-2.2*a;              // scaling factor
    o = 40*(1-a);               // y offset to maximize coverage

    d3d_transform_set_translation(-128,-128,0);     // set origin to center of image
    d3d_transform_add_scaling(s,s,s);               // scale it
    d3d_transform_add_rotation_z(r);                // rotate it
    d3d_transform_add_translation(128,128+o,0);     // move it into position
    draw_background_ext(backWhite,0,0,1,1,0,c,1);   // draw it
}
draw_set_blend_mode(bm_normal);

Abusing forum power since 1986.

Offline

#7 2009-09-17 22:53:09

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

Re: Gradient Wipe Transition

Here's some revised code. It's not as pretty but it works correctly. Transition is now smooth as moonbeams. I wish it was a little simpler.

            //  SHIFT -  pushes the alpha gradient towards black or white
            //          depending on the given fraction 0.0 to 1.0;
            //          at 0.0 the gradient is fully pushed to black (fully transparent),
            //          at 1.0 the gradient is fully pushed to white (fully opaque)
            //
            //  if (t < 0.5)
            //      1. Clear the work surface to opaque
            //      2. Invert gradient
            //      3. Add alpha so that it ramps up from 0.0 to 1.0 as t approaches 0.5
            //      4. Invert gradient
            //
            //  If (t >= 0.5) 
            //      1. Clear the work surface, set alpha so that it ramps from 0.0 to 1.0, as t approaches 1.0
            //      2. Add gradient

            if (argument4 < 0.5) {

                var a; a = 1-2*argument4;
                draw_clear_alpha(c_white,1);
                draw_set_blend_mode_ext(bm_zero,bm_inv_src_color);
                draw_background_ext(transition_image,0,0,sx,sy,0,c_white,1);
                
                draw_set_blend_mode_ext(bm_one,bm_one);
                draw_primitive_begin(pr_trianglestrip);
                draw_vertex_color(0,0,c_white,a);
                draw_vertex_color(argument2,0,c_white,a);
                draw_vertex_color(0,argument3,c_white,a);
                draw_vertex_color(argument2,argument3,c_white,a);
                draw_primitive_end();
                                
                draw_set_blend_mode_ext(bm_inv_dest_color,bm_zero);
                draw_primitive_begin(pr_trianglestrip);
                draw_vertex_color(0,0,c_white,1);
                draw_vertex_color(argument2,0,c_white,1);
                draw_vertex_color(0,argument3,c_white,1);
                draw_vertex_color(argument2,argument3,c_white,1);
                draw_primitive_end();

            }else{

                draw_clear_alpha(c_black,2*argument4-1);
                draw_set_blend_mode_ext(bm_one,bm_one);
                draw_background_ext(transition_image,0,0,sx,sy,0,c_white,1);

            }

Abusing forum power since 1986.

Offline

#8 2009-09-18 11:11:47

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

Re: Gradient Wipe Transition

These blending tricks have got my mind going. I think it might be possible to (1) alter the phase of the gradient and (2) create band-pass filters. The combination might allow inexpensive color cycling effects. This probably wouldn't be much different than some of the work brac37 has done with his real-time HSV manipulation blending filters. I haven't studied his code but I have a rough idea of how the algorithm would need to work.

Working on this has made something else very clear. Every version of the Game Maker transition engine is seriously bugged. CPU core is spiked at 100% for the duration of any transition. There is no good reason for this, something has clearly been written incorrectly. I don't know about GM8 but I have every reason to believe the problem persists. I don't have it installed anymore and I don't want to monkey with my clock in any event so I can't test. I wish I had noticed this sooner. I'm afraid Mark will ignore the problem at this late stage in GM8's development.


Abusing forum power since 1986.

Offline

#9 2009-09-18 14:55:07

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

Re: Gradient Wipe Transition

It's because there is no sleep() or iohandle() in the transition code. You can probably add those in when you make your own transitions. I'm sure there is a lot of data being sent to the video card so the takes a lot of processing power. It's probably because at this point this is done via directx, as opposed to just drawing on an old regular DC like a regular application does, it takes more from the PC than simple graphics to acces the video via directx...

Anyway, I have written my own transition system to support 3d transitions.
http://host-a.net/icuurd12b42/CameraFramework.zip

Hit space and compare with GM's

It's not the best method, various hacks in place (including a dll to prevent some of the creen freaking out which only works half the time) which would likelly not be compatible with many games but it's something to look at.

All those hacks are to do with grabing the 3d screen. At the time I was too stupid to realise you SHOULD ALWAYS call d3d_start in your camera draw event so it draws in 3d the very first time to room starts. Instead I used an alarm to bypass the first draw... Anyway...

Offline

#10 2009-09-18 15:36:19

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

Re: Gradient Wipe Transition

I'm sure there is a lot of data being sent to the video card so the takes a lot of processing power.

I'm not sure what you mean by that. Every transition is made of simple Direct3D primitives using prerendered surfaces for textures (incidentally, you can modify these directly during a transition for additional effects). I should think I'd be able to do dozens of transitions before it would ever impact the CPU.

Putting sleep() in the transition does help a little, which means Mark must be using a really naive wait loop:

do { /* nothing */ } until (timeNow > timeDone);

Hey wait a minute. You are doing the same thing! You've got these things drawing dozens, maybe hundreds of times during a single frame. You need sleep, my friend.

I must say you really went to town with those transitions. That must have been fun/tedious. There are some cool ones in there.

This is certainly a tricky problem for 3D. You are definitely on the right track. I think it may still be possible to do this without any glitching or a DLL and be able to use the existing Game Maker transition engine, if desired. It all hinges on when exactly GM sets the render target for the room being entered. The right combination of controllers, flags, events, screen captures, and toggling of automatic drawing might get you there.

Last edited by xot (2009-09-20 18:20:10)


Abusing forum power since 1986.

Offline

#11 2009-09-18 18:00:48

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

Re: Gradient Wipe Transition

I'm prety sure I meant that even though it uses dirext x and surfaces, I suspect using DirectX is more costly, CPU wize, than using a regular windows device context. Faster as a bigger pipe is used but that means more CPU is used to do the transfer. Though one would think using surfaces means all actions occure in the video card, I don't think so.


I know I need to sleep. Going to bed right now LOL...r

    io_handle();

That is called at least. I thought I was doing the sleep thing wacko ; sleep (time before drawing-current time after drawing so that 1 refresh matches the room speed) thing in the loop. I guess I must have been satisfied with the the way my system worked... that is the faster you PC the more frames you would get in the transition and the smotther it would be as each frame/transition step could possibly be very minute. When I did this, it was on a slower PC... On this one, I don;t even need the dll anymore. I remember just getting a few frames for the primitive based transitions, so the sleep may have been considered useless.

I don't think it's possible to use transitions in 3d. because that is surface based. 3d nukes the surface and the surface nukes the z buffer/ But, again, that was before I started to call d3d_start in the camear draw... I could try again.

So instead, the transitions are sprite based, using GM save screen and load sprite which is rather fast. save screen works in 3d so that was the obvious method. Also, the advantage is that this works on PCs that dont support surfaces. if any of them still exist out there.

Yes, It was a lot of fun making them. I spent like 3-4 days on them.

Offline

#12 2009-09-18 18:47:56

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

Re: Gradient Wipe Transition

If GM sets the render target between the Create event and the Draw event, it should be possible to render your room, save a screenshot, load it, and supply it when the Draw event hits. If GM sets the render target before the Create event, then it's not possible unless you can somehow detect and re-set the render target manually.


Abusing forum power since 1986.

Offline

#13 2009-09-18 22:01:41

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

Re: Gradient Wipe Transition

Actually having now fully documented the event order. I now see how I can take the snapshots in that temp object I add to the room (first draw, first room, secon draw is next room). it's in charge of getting the first and next room image. I think I can simplify some stuff and possibly even make it compatible with gm's transition system if I wanted. Though the 3d transition would still have to be sprite based...

Hmm. Next on the plate I guess.

Offline

#14 2009-09-20 18:21:10

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

Re: Gradient Wipe Transition

As expected GM8RC1 has the same CPU hogging transition problem. I've submitted it as a bug to the tracker. I'm expecting, "not going to change it for this version" response, which would be a shame. I think this a legitimate problem after seeing someone at GMC post about it interfering with music playback.


Abusing forum power since 1986.

Offline

#15 2009-09-20 21:19:53

icuurd12b42
Member
Registered: 2008-12-11
Posts: 303

Re: Gradient Wipe Transition

Adding a sleep and io_handle in his caller code should not be that hard... But yeah, that's what I suspect will happen.

Offline

#16 2013-05-02 17:40:56

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

Re: Gradient Wipe Transition

My original project file / revisions work correctly?

I would need to see your project to help find the problem. Feel free to send a private message to me if you don't wish to post your project publicly.

Welcome to the forums.


Abusing forum power since 1986.

Offline

Board footer

Powered by FluxBB