You are not logged in.
Pages: 1
This function smooths/blends the colors held in a grid
I use a grid mapped to the screen and draw to the grid (setting the colors in the grid cells) then call this to smooth things out. Blending the colors together
I could not use a disk function here because the way colors are added and averaged.
//argument0 - grid with color values
var w,h;
w = ds_grid_width(argument0)
h = ds_grid_height(argument0)
var g; g = ds_grid_create(w,h)
var xx,yy;
yy = 0;
var av;
var ct;
repeat(h)
{
xx = 0;
repeat(w)
{
c1 = ds_grid_get(argument0,xx,yy);
c2 = ds_grid_get(argument0,xx-1,yy);
c3 = ds_grid_get(argument0,xx+1,yy);
c4 = ds_grid_get(argument0,xx,yy-1);
c5 = ds_grid_get(argument0,xx,yy+1);
c2 = merge_color(c1,c2,.5)
c3 = merge_color(c1,c3,.5)
c4 = merge_color(c1,c4,.5)
c5 = merge_color(c1,c5,.5)
c2 = merge_color(c2,c3,.5)
c3 = merge_color(c4,c5,.5)
c2 = merge_color(c2,c3,.5)
c1 = merge_color(c1,c2,.5)
ds_grid_set(g,xx,yy,c1);
xx+=1;
}
yy+=1;
}
ds_grid_copy(argument0,g);
ds_grid_destroy(g);
and this generates a smooth version for final display. As you usually have a small grid mapped to a large screen. It can be used to scale up an image held in a grid. it's faster than that grid manipulation function which I think I had posted here (cant find it)
gs is the grid size. In my application, the width and height (of grid) are the same, argument0 is the grid. I know it's a weird mix but I just though I'd share it as is. You can modify the code to generate a model of any size, via the xf yf values.
model = d3d_model_create();
var ct;
ct = 0;
xf = room_width/(gs-1);
yf = room_height/(gs-1);
//argument0 - grid
var w,h;
w = ds_grid_width(argument0)-1
h = ds_grid_height(argument0)-1
var g; g = ds_grid_create(w,h)
var xx,yy;
yy = 0;
var av;
d3d_model_primitive_begin(model,pr_trianglelist);
repeat(h)
{
xx = 0;
repeat(w)
{
c1 = ds_grid_get(argument0,xx,yy+1);
c2 = ds_grid_get(argument0,xx,yy);
c3 = ds_grid_get(argument0,xx+1,yy);
c4 = ds_grid_get(argument0,xx+1,yy+1);
x1 = xx*xf;
x2 = xx*xf;
x3 = (xx+1)*xf;
x4 = (xx+1)*xf;
y1 = (yy+1)*yf;
y2 = yy*yf;
y3 = yy*yf;
y4 = (yy+1)*yf;
d3d_model_vertex_color(model,x1,y1,0,c1,1)
d3d_model_vertex_color(model,x2,y2,0,c2,1)
d3d_model_vertex_color(model,x3,y3,0,c3,1)
d3d_model_vertex_color(model,x3,y3,0,c3,1)
d3d_model_vertex_color(model,x4,y4,0,c4,1)
d3d_model_vertex_color(model,x1,y1,0,c1,1)
xx+=1;
ct+=6;
if(ct>900)
{
d3d_model_primitive_end(model);
d3d_model_primitive_begin(model,pr_trianglelist);
ct = 0;
}
}
yy+=1;
}
d3d_model_primitive_end(model);
d3d_model_draw(model,0,0,0,-1)
if(is_string(argument1))
{
d3d_model_save(model,argument1)
}
d3d_model_destroy(model);
Last edited by icuurd12b42 (2009-12-16 06:42:47)
Offline
Here is the program that uses this method
http://www.yoyogames.com/games/107091-nebula-draw
I did move the first function and the rough draw code, which just draws the grid with rectangles, to a dll... But the model generation is pure gml (hold space)
Offline
I could not use a disk function here because the way colors are added and averaged.
Yes and no. You could use the disk function if you kept the color channels in separate grids but that might not be a speed improvement unless the radius of the smoothing area is larger than 2 or 3 pixels. It also wouldn't have the same weighting since in your script the center pixel appears to have much more influence on the blended color than the neighbor pixels.
Abusing forum power since 1986.
Offline
Yes, you can always change a few lines so the center pixel has less weight. I tried a half dozen variations. This one was best in the case of my little nebula drawing tool. As I needed the extra weight for the gradual changes (it's called every step) so that the whole getup would not fade out entirely.
Offline
I think a faster way, again only if you are willing to use separate grids for each channel, could be like this:
w = ds_grid_width(source);
h = ds_grid_height(source);
destination = ds_grid_create(w, h);
ds_grid_copy(destination, source);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, -1, 0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 1, 0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 0, -1);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 0, 1);
ds_grid_multiply_region(destination, 0, 0, w, h, 0.2);
You could easily give the center pixel extra weight with another ds_grid_multiply_region
call after the copy.
w = ds_grid_width(source);
h = ds_grid_height(source);
destination = ds_grid_create(w, h);
ds_grid_copy(destination, source);
ds_grid_multiply_region(destination, 0, 0, w, h, 12);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, -1, 0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 1, 0);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 0, -1);
ds_grid_add_grid_region(destination, source, 0, 0, w, h, 0, 1);
ds_grid_multiply_region(destination, 0, 0, w, h, 0.0625);
Abusing forum power since 1986.
Offline
Yep. Definitely you should also copy that suggestion in that grid smooth topic... Smart.
Offline
Also, I'm starting to wonder if I can do this with surfaces...
Instead of a 32x32 grid, have a 32x32 surface and draw onto another 32x32 surface at +1 -1... with alpha set properly. The final draw is that surface streched with interpolation ON....
Offline
Also, I'm starting to wonder if I can do this with surfaces...
Instead of a 32x32 grid, have a 32x32 surface and draw onto another 32x32 surface at +1 -1... with alpha set properly. The final draw is that surface streched with interpolation ON....
Yep. here it is. In my case, I had to use alpha .2 so it would balance (not fade out or fill the screen) because I call it all the time. And bm add so the pixel would keep the right color...
s2 and s(1) are the surfaces, say 32x32
s1 has the original image, draw onto with set pixel.
s2 is draws to with bm_add (on black), at offset
s2 is transfered back to s1
global.bleed 0-1 value defines how much the surface is tranfered back and in effect defined how much the color leaks on the canvas
s is drawn stretched with interpolation on the screen in the draw event
texture_set_interpolation(0)
surface_set_target(s2)
draw_set_blend_mode(bm_add)
draw_clear_alpha(c_black,1)
draw_surface_ext(s,0,0,1,1,0,c_white,.2);
v = 1;
draw_surface_ext(s,-v,0,1,1,0,c_white,.2);
draw_surface_ext(s,+v,0,1,1,0,c_white,.2);
draw_surface_ext(s,0,-v,1,1,0,c_white,.2);
draw_surface_ext(s,0,+v,1,1,0,c_white,.2);
draw_set_blend_mode(bm_add)
draw_set_color(c_black)
draw_rectangle(0,0,gs,gs,0)
draw_set_color(c_white)
draw_set_blend_mode(bm_normal)
surface_set_target(s)
draw_surface_ext(s2,0,0,1,1,0,c_white,global.bleed);
draw_set_blend_mode(bm_add)
draw_set_color(c_black)
draw_rectangle(0,0,gs,gs,0)
draw_set_color(c_white)
draw_set_blend_mode(bm_normal)
surface_reset_target();
Offline
Good call on the additive blending, that's the key to these multipass blur effects, especially when surfaces are involved.
Something you should experiment with is using blend mode _ext(bm_one,bm_one)
instead of bm_add
. Although they generally look identical, they are not exactly the same (at least on my hardware). I think they treat the alpha channel a little differently, although I haven't spent any time determining exactly how they differ. The difference between them is profound in my effects engine. Since _ext(bm_one,bm_one)
seems a little more predictable I tend to avoid bm_add
now.
Abusing forum power since 1986.
Offline
I believe bm_add
is functionally equivalent to _ext(bm_src_alpha,bm_one)
.
Offline
Hmmmm, I think you are right. I just tried _ext(bm_src_alpha,bm_one)
where I was having a problem with bm_add
and the result looked identical.
Abusing forum power since 1986.
Offline
Pages: 1