Efficient Drawing

New to FreeBASIC? Post your questions here.
Post Reply
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Efficient Drawing

Post by nimdays »

I need your opinion about this.
The last rect is the the top most rect.

Code: Select all

type scr
    as integer w,h
    as uinteger ptr p
end type

type rect
    as integer x,y,w,h
    as ulong c
end type

sub init_rect(r as rect ptr,x as integer,y as integer,_
              w as integer,h as integer,c as ulong)
    r->x = x
    r->y = y
    r->w = w
    r->h = h
    r->c = c
end sub

sub clear_scr(s as SCR ptr,c as ulong)
    for i as integer = 0 to s->w * s->h -1
        s->p[i] = c
    next i
end sub

sub draw_rect(s as SCR ptr,r as rect ptr)
    dim as integer xx = r->x,yy = r->y,w = r->w,h = r->h
    
    dim as uinteger ptr p = @s->p[yy*s->w +xx]
    for y as integer = 0 to h  -1
        for x as integer = 0 to w  -1
            if p[x] shr 24 = 0 then
               p[x] = r->c
            end if
        next x
        p += s->w
    next y
    
end sub

sub draw_rect1(s as SCR ptr,r as rect ptr)
    dim as integer xx = r->x,yy = r->y,w = r->w,h = r->h
    
    dim as uinteger ptr p = @s->p[yy*s->w +xx]
    for y as integer = 0 to h  -1
        for x as integer = 0 to w  -1
            p[x] = r->c
        next x
        p += s->w
    next y
    
end sub

dim as scr sc
sc.w = 800
sc.h = 600
screenres sc.w,sc.h,32
sc.p = screenptr()

dim as rect r(40)

for i as integer = 1 to 40
    init_rect(@r(i-1),i*10,i*10,300,180,rnd*&hff0000ff)
next i

clear_scr(@sc,&h0000007f)

dim as double t = timer()

screenlock()
for i as integer = 0 to 39
    draw_rect1(@sc,@r(i))
next i
screenunlock()

print using "##.####";timer()-t

sleep 100

t = timer()

screenlock()
for i as integer = 39 to 0 step -1
    draw_rect(@sc,@r(i))
next i
screenunlock()

print using "##.####";timer()-t

sleep

Do you think this is enough?
Last edited by nimdays on Jan 03, 2018 4:53, edited 2 times in total.
paul doe
Moderator
Posts: 1732
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Effecient Drawing

Post by paul doe »

nimdays wrote:Do you think this is enough?
Um, I don't know. Enough for what? Btw, the code crashes on 64-bit; if you're accessing the pixel buffer directly, you should use ulongs (32-bit unsigned in both 32 and 64-bit) instead of uintegers, which are platform dependent (they are either 32 or 64 bits, depending on what compiler you use).
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Re: Effecient Drawing

Post by nimdays »

paul doe wrote:
nimdays wrote:Do you think this is enough?
Um, I don't know. Enough for what? Btw, the code crashes on 64-bit; if you're accessing the pixel buffer directly, you should use ulongs (32-bit unsigned in both 32 and 64-bit) instead of uintegers, which are platform dependent (they are either 32 or 64 bits, depending on what compiler you use).
Thanks, I'll fix that.

This is about overlapped rectangles.
The first is traditional way from the first rect and so on, And the second from the last rect first by checking the alpha channel of the destination.

Code: Select all

if p[x] shr 24 = 0 then
      p[x] = r->c
end if
By the way, I found this from pixman region source.
Maybe this is the most efficient ?

Code: Select all

 *  -----------				    -----------
 *  |         |				    |         |		    band 0
 *  |         |  --------		    -----------  --------
 *  |         |  |      |  in y-x banded    |         |  |      |   band 1
 *  |         |  |      |  form is	    |         |  |      |
 *  -----------  |      |		    -----------  --------
 *               |      |				 |      |   band 2
 *               --------				 --------
paul doe
Moderator
Posts: 1732
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Effecient Drawing

Post by paul doe »

nimdays wrote:This is about overlapped rectangles.
The first is traditional way from the first rect and so on, And the second from the last rect first by checking the alpha channel of the destination.
Oh yeah, I see it now. Yes, it's an efficient approach. I use a very similar one here: viewtopic.php?f=15&t=26105. The only thing that you have to be careful, it's in using the pitch of a buffer, not its width. You can get the pitch of the screen via screenInfo() call, and of a buffer by casting a pixel buffer to a fb.image ptr:

Code: Select all

screenInfo( , , , , sc.pitch ) '' <-- gets the pitch of the screen
cast( fb.image ptr, buffer )->pitch '' <-- gets the pitch of a pixel buffer
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Re: Effecient Drawing

Post by nimdays »

paul doe wrote: Oh yeah, I see it now. Yes, it's an efficient approach. I use a very similar one here: viewtopic.php?f=15&t=26105. The only thing that you have to be careful, it's in using the pitch of a buffer, not its width. You can get the pitch of the screen via screenInfo() call, and of a buffer by casting a pixel buffer to a fb.image ptr:

Code: Select all

screenInfo( , , , , sc.pitch ) '' <-- gets the pitch of the screen
cast( fb.image ptr, buffer )->pitch '' <-- gets the pitch of a pixel buffer
Thanks, I'm reading it now.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Efficient Drawing

Post by MrSwiss »

This is now *portable*: compile's/run's with both compilers (32/64):

Code: Select all

type scr
    as integer   w, h
    as ulong ptr p
    Declare Sub _clear(As ULong)    ' NO variable-names required!
end Type

sub scr._clear(c as ulong)  ' embedded has always the type's info!
    With This   ' scr type (direct, NO ptr's needed!)
        for i as UInteger = 0 to .w * .h - 1
            .p[i] = c
        next
    End With
end Sub
' end scr

type rect
    as integer  x, y, w, h
    as ulong    c
    Declare Sub init(As integer, as integer, as integer, as integer, as ULong)
end type

sub rect.init(x as integer, y as integer, _
              w as integer, h as integer, _
              c as ulong)
    With This   ' rect type (direct, NO ptr's needed!)
        .x = x : .y = y : .w = w : .h = h : .c = c
    End With
end Sub
' end rect


' type independent sub
sub draw_rect(s as SCR ptr, r as rect ptr)
    dim as integer  xx = r->x, yy = r->y, iw = r->w - 1, ih = r->h - 1
    Dim As ULong    cc = r->c
    dim as ulong ptr p = @s->p[yy * s->w + xx]

    for j as UInteger = 0 to ih
        for i As UInteger = 0 to iw
            p[i] = cc
        Next
        p += s->w
    Next
End Sub


' screen and (type) sc init
dim as scr sc
With sc
    .w = 800 : .h = 600 ' type (width/height only)
ScreenRes(.w, .h, 32)   ' screen (using type)
    .p = screenptr()    ' type (screen access)
End With

' rectangle init
dim as rect r(39)   ' = 40 elements!
for i as UInteger = 0 to 39
    r(i).init(i*10, i*10, 300, 180, Rnd*&hff0000ff) ' type embedded Sub (see below)
next i

' main start
Dim As Double   t1 = 0.0, t2 = 0.0, ts
sc._clear(&hFF00007F)  ' type embedded Sub (call as 'dim(ed)', NOT as 'written'!)

ScreenLock()
ts = Timer              ' timing 1 start
For i as UInteger = 0 to 39
    draw_rect(@sc, @r(i))
Next
t1 = Timer - ts         ' timing 1 end
screenunlock()
print using "##.####"; t1

Sleep(2500, 1)          ' wait 2.5 Sec.
sc._clear(&hFF7F0000)   ' type embedded Sub (call as 'dim(ed)', NOT as 'written'!)

screenlock()
ts = timer()            ' timing 2 start
For i as integer = 39 to 0 step -1  ' the only one 'integer', because: 'down counting-loop'
    draw_rect(@sc, @r(i))
next i
t2 = Timer - ts         ' timing 2 end
screenunlock()
print using "##.####"; t2

Sleep
' main end --- EOF ---
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Re: Efficient Drawing

Post by nimdays »

MrSwiss wrote:This is now *portable*: compile's/run's with both compilers (32/64):

Code: Select all

type scr
    as integer   w, h
    as ulong ptr p
    Declare Sub _clear(As ULong)    ' NO variable-names required!
end Type

sub scr._clear(c as ulong)  ' embedded has always the type's info!
    With This   ' scr type (direct, NO ptr's needed!)
        for i as UInteger = 0 to .w * .h - 1
            .p[i] = c
        next
    End With
end Sub
' end scr

type rect
    as integer  x, y, w, h
    as ulong    c
    Declare Sub init(As integer, as integer, as integer, as integer, as ULong)
end type

sub rect.init(x as integer, y as integer, _
              w as integer, h as integer, _
              c as ulong)
    With This   ' rect type (direct, NO ptr's needed!)
        .x = x : .y = y : .w = w : .h = h : .c = c
    End With
end Sub
' end rect


' type independent sub
sub draw_rect(s as SCR ptr, r as rect ptr)
    dim as integer  xx = r->x, yy = r->y, iw = r->w - 1, ih = r->h - 1
    Dim As ULong    cc = r->c
    dim as ulong ptr p = @s->p[yy * s->w + xx]

    for j as UInteger = 0 to ih
        for i As UInteger = 0 to iw
            p[i] = cc
        Next
        p += s->w
    Next
End Sub


' screen and (type) sc init
dim as scr sc
With sc
    .w = 800 : .h = 600 ' type (width/height only)
ScreenRes(.w, .h, 32)   ' screen (using type)
    .p = screenptr()    ' type (screen access)
End With

' rectangle init
dim as rect r(39)   ' = 40 elements!
for i as UInteger = 0 to 39
    r(i).init(i*10, i*10, 300, 180, Rnd*&hff0000ff) ' type embedded Sub (see below)
next i

' main start
Dim As Double   t1 = 0.0, t2 = 0.0, ts
sc._clear(&hFF00007F)  ' type embedded Sub (call as 'dim(ed)', NOT as 'written'!)

ScreenLock()
ts = Timer              ' timing 1 start
For i as UInteger = 0 to 39
    draw_rect(@sc, @r(i))
Next
t1 = Timer - ts         ' timing 1 end
screenunlock()
print using "##.####"; t1

Sleep(2500, 1)          ' wait 2.5 Sec.
sc._clear(&hFF7F0000)   ' type embedded Sub (call as 'dim(ed)', NOT as 'written'!)

screenlock()
ts = timer()            ' timing 2 start
For i as integer = 39 to 0 step -1  ' the only one 'integer', because: 'down counting-loop'
    draw_rect(@sc, @r(i))
next i
t2 = Timer - ts         ' timing 2 end
screenunlock()
print using "##.####"; t2

Sleep
' main end --- EOF ---
Thanks, I missed a lot.

By the way, You missed the alpha checker.
Nevermind, I'll add that later.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Efficient Drawing

Post by MrSwiss »

nimdays wrote:By the way, You missed the alpha checker.
Nope, not missed, it didn't work, that's the reason, I've kicked it out ...

Btw: if you want to use transparency, you'll have to set ScreenRes(), accordingly:

Code: Select all

ScreenRes(w, h, 32,, 64)    ' aka: GFX_ALPHA_PRIMITIVES = &h40, see: fbgfx.bi
P.S. it doesn't make sense, to quote entire posts ... (you could easily remove the
whole code section).
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Re: Efficient Drawing

Post by nimdays »

MrSwiss wrote:Btw: if you want to use transparency, you'll have to set ScreenRes(), accordingly:

Code: Select all

ScreenRes(w, h, 32,, 64)    ' aka: GFX_ALPHA_PRIMITIVES = &h40, see: fbgfx.bi
This is not about transparency, The second method will avoid drawing the area of the previous rectangles.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Efficient Drawing

Post by MrSwiss »

nimdays wrote:This is not about transparency, The second method will avoid drawing the area of ...
OK, got it ... below a little test, proof of concept code:

Code: Select all

' Alpha_To_ReColor.bas -- 2018-01-07, MrSwiss
'
' compile: -s gui
'
Declare Sub DrawScreen(ByVal As ULong Ptr, ByRef As Const ULong, ByRef As Const UByte)

Const As UShort sw = 600, sh = 600, cd = 32, pg = 2 ' screen definitions
' ===== START-MAIN =====
ScreenRes(sw, sh, cd, pg)
ScreenSet(1, 0)     ' double buffer setup
Width 600\8, 600\16 ' 16 x 8 Font size
Color(&h00000000, &h00FFFFFF) : Cls ' black on white (Alpha = &h00)
' local variables ... colors, counter, sleep-time, sqare-size
Dim As ULong    c1 = &hFFFF7F00, c2 = &h63636363, c3 = &hFF00FF00, c4 = &h000000FF, _
                c5 = &h63FFFFFF, c6 = &h0000FFFF, c7 = &h00000000, cnt = 0, sTime = 2500, sq = 59
' draw a checkered board 8 x 8 (60 x 60 pixels, border 60)
For j As UInteger = 0 To 7
    Var v = 60 + j * 60         ' calc. vertical pos.
    For i As UInteger = 0 To 7
        Var h = 60 + i * 60     ' calc. horizontal pos.
        Line (v, h)-Step(sq, sq), c2, B
        If cnt Mod 2 Then Paint (v + 1, h + 1), c1, c2 Else Paint (v + 1, h + 1), c3, c2
        cnt += 1
    Next
    cnt += 1
Next : Flip : Sleep(sTime, 1)
' start modifying color with Alpha's value ...
Dim As ULong Ptr    ps = ScreenPtr          ' get low level access
DrawScreen(ps, c4, 0)    : Sleep(sTime, 1)  ' re-color background (Alpha = 0)
DrawScreen(ps, c5, &h63) : Sleep(sTime, 1)  ' re-color grid (Alpha = 63)
DrawScreen(ps, c6, 0)    : Sleep(sTime, 1)  ' re-color background (Alpha = 0)
DrawScreen(ps, c7, &h63)                    ' re-color grid (Alpha = 63)
Locate 2, 2 : Print " press a key to QUIT ... ";' show quit msg
Flip : Sleep                                ' Wait for user action before quitting
' ===== END-MAIN =====
Sub DrawScreen( _
    ByVal sptr As ULong Ptr, _  ' a copy (of the original)
    ByRef clr  As Const ULong, _' direct (read only)
    ByRef chk  As Const UByte _ ' direct (read only)
    )
    For x As UInteger = 0 To (sw * sh - 1)  ' const's are: global!
        If sptr[x] Shr 24 = chk Then sptr[x] = clr
    Next : Flip     ' <-- this is for double buffered screen
End Sub
' ----- EOF -----
nimdays
Posts: 236
Joined: May 29, 2014 22:01
Location: West Java, Indonesia

Re: Efficient Drawing

Post by nimdays »

Thanks again MrSwiss, That's some nice boards.
Post Reply