### Author Topic: Help: how to get a non rectangular region of a surface?  (Read 3149 times)

#### froggy77

• Full Member
• Posts: 150
##### Help: how to get a non rectangular region of a surface?
« on: July 10, 2016, 06:49:16 pm »
Hello,

Is it possible to get the opposite region of several regions in a surface?
In this example, there are several yellow rectangles and I would like to get the black part.

« Last Edit: July 10, 2016, 06:52:01 pm by froggy77 »

#### Satoh

• Newbie
• Posts: 47
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #1 on: July 10, 2016, 07:27:17 pm »
technically those are still rectangles. You could get them in the same way you would get the yellow parts, but just imagining where the connecting lines would be between them.
Draw the biggest black rectangle you can find in the non-yellow space, and where there's an oddly shaped corner, fill it in with another separate rectangle.

Also, if you're trying to paint in the empty space, you can draw on the surface before you draw whatever goes in the yellow, and draw the yellow spaces afterward, and whatever's in the yellow should be drawn over whatever you filled the surface with before...

At least that's how I understand surfaces. (Similar with on_pre_draw and on_post_draw for sprites)

Like this:

EDIT:
If you're doing a 'lighting' script, where yellow spaces would be lights you want to 'cut out' of the blackness, I might have to rethink how to do that.. its something I've been wanting to try too.
Still, if you could define your yellow blocks before they're drawn... there should be a way to replace the black area with a transparent space... by specifying an shape made of some color like 0xFFFFFF00, which is pure white, but with 0 alpha opacity...

Maybe that helps maybe not. Get back to us if you come up with something that does, I'd like to see it.
« Last Edit: July 10, 2016, 07:32:41 pm by Satoh »
Patience is difficult and rarely thanked, but always appreciated, and sorely missed when absent.

#### froggy77

• Full Member
• Posts: 150
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #2 on: July 10, 2016, 09:29:29 pm »
Quote
technically those are still rectangles. You could get them in the same way you would get the yellow parts, but just imagining where the connecting lines would be between them.
Draw the biggest black rectangle you can find in the non-yellow space, and where there's an oddly shaped corner, fill it in with another separate rectangle.
==> I had the same idea but for now , I have a little trouble to think the script in its entirety.

Quote
Also, if you're trying to paint in the empty space, you can draw on the surface before you draw whatever goes in the yellow, and draw the yellow spaces afterward, and whatever's in the yellow should be drawn over whatever you filled the surface with before...
==> My first idea is to use dynamic tiles for lights in the editor and then add black rectangles by a script. If I work with the black parts from the editor , I move mistakenly tiles ; Moreover, the mapping is more difficult and less flexible. I move anything !

Quote
If you're doing a 'lighting' script, where yellow spaces would be lights you want to 'cut out' of the blackness, I might have to rethink how to do that.. its something I've been wanting to try too.
==> Yes I'm trying to make a lighting script for example to light/extinguish a candle on a table.

Quote
Still, if you could define your yellow blocks before they're drawn... there should be a way to replace the black area with a transparent space... by specifying an shape made of some color like 0xFFFFFF00, which is pure white, but with 0 alpha opacity...
==> It is a very good idea if it is possible with the engine. I'm going to test this.

Quote
Maybe that helps maybe not. Get back to us if you come up with something that does, I'd like to see it.
Thank you for taking the time to answer me. Ok

#### Satoh

• Newbie
• Posts: 47
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #3 on: July 10, 2016, 10:39:05 pm »
In hindsight, it seems not to be possible to replace a fully opaque pixel with a transparent one...
I'm assuming this is a consequence of SDL_BLENDMODE_BLEND in the source. This is an occasion where SDL_BLENDMODE_NONE would allow for more freedome, as you could use it to cut a section of the surface out and replace it completely (no blending) with the new section you drew...

if I understood the whole C++/lua interface thing I'd try my hand at making an unofficial branch with the feature, but alas, I don't get the C++ end at all. It'll be up to Christopho to add the lua function, whenever or if ever he does that.

A different option is required until then... I tried making a big lua table of filled and empty 'darkness' tiles and looping through them each frame, drawing them into the surface... which... kind of worked... but not well... and also caused a lot of lag... I'm still hopeful there is a method that will work... but I get the feeling it'll require some heady math.

If I could figure out how to graph 'everything but these 5 rectangles' as a limit... that might work... but would be speed dependant...
I'll let you know if I come up with any more ideas you can try.
Patience is difficult and rarely thanked, but always appreciated, and sorely missed when absent.

#### Christopho

• Hero Member
• Posts: 1182
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #4 on: July 11, 2016, 06:20:23 pm »

#### froggy77

• Full Member
• Posts: 150
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #5 on: July 28, 2016, 02:38:34 am »
Thanks Christopho, but I continue with my first idea. Obviously, I will also use your new feature.
I manage to get this table that will fill the empty areas. For now, it's just a LUA function that I must adapt to Solarus .

LUA FUNCTION:

Code: (LUA) [Select]
`-- TEST -- WIP ---- Function to initialize a table which will contain values (x, y , width, height) in order to draw the opposite rectangles to 'tbl' to fill a surface.-- 'tbl' is not the new table, but the table which contains values.local function init_opposite_table(tbl)    -- Length of the original table    local length = #tbl        -- Clone this table in a temporary table    local t_temp = {}    k, v = next(tbl, nil)    while k do        t_temp[k] = v        k, v = next(tbl,k)    end        -- Then, add x and y of opposite corners in this new table    for i = 1, length do        local l = #t_temp + 1        t_temp[l] = {}        t_temp[l][1] = t_temp[i][1] + t_temp[i][3]        t_temp[l][2] = t_temp[i][2] + t_temp[i][4]    end        -- Function to initialize a simple table (for example for t_x and t_y)    -- 'tbl' is not the new table, but the table which contains values.    -- TODO: replace 320 and 240 by sol.video.get_window_size() in Solarus    local function init_simple_table(tbl, key, min, max)            -- Create a temporary table        local t = {}        -- Insert minimun and maximum values        if min ~= nil then            t[#t + 1] = min          else              t[#t + 1] = 0        end        if max ~= nil then            t[#t + 1] = max        else            if key == 1 then                max = 320            elseif key == 2 then                max =    240            end            t[#t + 1] = max        end        -- Add entries in the table        for k in pairs(tbl) do            t[#t + 1] = tbl[k][key]        end        -- Create another temporary table        -- and delete duplicate entries        local t_no_dup = {};          for _, v in pairs(t) do            t_no_dup[v] = v        end        -- Clear the first temporary table        local t = {}        -- Sort        for k in pairs(t_no_dup) do            t[#t + 1] = k        end        table.sort(t)        -- Return the result        return t    end        -- Initialize a table for x and a table for y    local t_x = init_simple_table(t_temp, 1)    local t_y = init_simple_table(t_temp, 2)        -- Max values for x and y    local vx_max = math.max(unpack(t_x))    local vy_max = math.max(unpack(t_y))        -- Create a temporary table    -- Merge rectangles that are on the same line (the width is changed) when possible.    local t_temp = {}    for ky, vy in pairs(t_y) do        if vy < vy_max then            local x            local y            local width            local height = t_y[ky + 1] - vy            for kx, vx in pairs(t_x) do                if vx < vx_max then                    for i = 1, length do                        if x == nil then                            x = vx                            y = vy                        end                        if vx == tbl[i][1] and vy >= tbl[i][2] and vy < (tbl[i][2] + tbl[i][4])  then                            width = vx - x                            if width > 0 then                                local l = #t_temp + 1                                t_temp[l] = {x, y , width, height, ky}                            end                                                        x = (tbl[i][1] + tbl[i][3])                        end                    end                else                    width = vx - x                    local l = #t_temp + 1                    t_temp[l] = {x, y , width, height, ky}                end            end        end    end        -- Create a table from the previous temporary table    -- Merge the rectangles which have the same x and the same width (the height is changed) when possible    local opp_tbl = {}    local max_n = #t_temp    local count = 0    for j in pairs(t_temp) do        local height = t_temp[j][4]        local ky = t_temp[j][5]        local var = 1        if     t_temp[j][5] ~= nil then            for n = j, max_n do                if t_temp[j][1] == t_temp[n][1] and t_temp[j][3] == t_temp[n][3] and ky ~= t_temp[n][5] then                    if (ky + var) == t_temp[n][5] then                        t_temp[n][5] = nil                        var = var + 1                        height = height + t_temp[n][4]                     end                end            end            t_temp[j][5] = nil            count = count + 1            opp_tbl[count] = t_temp[j]            opp_tbl[count][4] = height        end    end    return opp_tblend-- Original tablelocal t_lights = {{108, 46, 34, 19}, {19, 212, 85, 28}, {174, 4, 86, 54}, {44, 32, 53, 166}}-- Initialize the opposite tablelocal t_nolight = init_opposite_table(t_lights)`

PRINT:

Code: (LUA) [Select]
`-- Print tables to test the resultsprint("-------- t_lights --------")print("x", "y","w","h")print("---------------------------")t = t_lightsfor k in pairs(t) do    print(t[k][1], t[k][2], t[k][3], t[k][4])endprint("-------------")print("rectangles " .. #t_lights)print("-------------")print("-------- t_nolight --------")print("x", "y","w","h")print("---------------------------")t = t_nolightfor k in pairs(t) do    print(t[k][1], t[k][2], t[k][3], t[k][4])endprint("-------------")print("rectangles " .. #t_nolight)print("-------------")print("TOTAL " .. #t_lights + #t_nolight)print("---------------------------")`

RESULTS:

-------- t_lights --------
x    y    w    h
---------------------------
108    46    34    19
19    212    85    28
174    4    86    54
44    32    53    166
-------------
rectangles 4
-------------
-------- t_nolight --------
x    y    w    h
---------------------------
0    0    320    4
0    4    174    28
260    4    60    54
0    32    44    166
97    32    77    14
97    46    11    19
142    46    32    12
142    58    178    7
97    65    223    133
0    198    320    14
0    212    19    28
104    212    216    28
-------------
rectangles 12
-------------
TOTAL 16
---------------------------

Here the result in picture:
• yellow rectangles = table named "t_lights" (4 rectangles)
• black rectangles = table named "t_nolight" (12 rectangles)

Here the result if I had not optimized the function. There would be too many rectangles...

« Last Edit: July 28, 2016, 02:43:43 am by froggy77 »

#### froggy77

• Full Member
• Posts: 150
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #6 on: November 14, 2016, 08:03:46 pm »
Work still in progress with a few headache especially after a few months without making.

#### MetalZelda

• Hero Member
• Posts: 551
##### Re: Help: how to get a non rectangular region of a surface?
« Reply #7 on: November 15, 2016, 10:37:35 pm »
It should be easier with surface blending now, you just need a bitmap and 2 surfaces: one modulate (for the darkness, tone, whatever), and one "blend" (where you draw the light effect)