Simple FRAME Type

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Simple FRAME Type

Post by MrSwiss »

Hi all,

the fascinating thing about Type-Definition is, the difficulty to decide how many variables
are really needed (and other stuff as Sub's/Function's), in order to be most efficient.

With efficient I mean: minimum usage, of memory and maximum of flexibility (at the same
time), as well as optimized code, etc.

Many people use (IMHO) more variables in Type's, as absolutely mandated by functionality.
Frame_FrameWork.bas, is a try to demonstrate above:

Code: Select all

' Frame_FrameWork.bas -- 2017-03-12/13, MrSwiss
'
' NOTE:
' this FrameWork is optimized for: FBC 64bit
' taking into conideration the fact that, up to 4 param's are
' handed over inside CPU registers (not on the stack) that be-
' ing a reason, to use 2 Sub's, besides flexibility ...
'
' positioning/sizing is independent of drawing (incl. options)

' --- start type's definition's ---
Type V2L    ' 2 vectors of Long, a 'helper' type
    As Long x1, y1, x2, y2
End Type

Type _Frame ' minimalistic Frame Type
    As V2L      coord   ' position & size only
    Declare Sub _fset(ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0)
    Declare Sub _draw(ByVal As ULong = &hFF00FF00, ByVal As Boolean = FALSE, ByVal As Short = 0, ByVal As Boolean = TRUE)
End Type

Sub _Frame._fset  ( ByVal _x1 As Long = 0, _    ' Vect. 1 x (-axis)
                    ByVal _y1 As Long = 0, _    ' Vect. 1 y
                    ByVal _x2 As Long = 0, _    ' Vect. 2 x
                    ByVal _y2 As Long = 0 )     ' Vect. 2 y
    With coord
        .x1 = _x1 : .y1 = _y1       ' init 1st vector
        .x2 = _x2 : .y2 = _y2       ' init 2nd v...
    End With
End Sub

Sub _Frame._draw  ( ByVal clr As ULong = &hFF00FF00, _  ' color: default, green
                    ByVal sty As Boolean = FALSE, _     ' style: SINGLE/double Frame (default: single)
                    ByVal dst As Short = 0, _           ' distance: between frames (only if style = TRUE, needed)
                    ByVal vis As Boolean = TRUE )       ' visible: default, yes
    If Not vis Then Exit Sub        ' if not visible --> quit

    If sty AndAlso CBool(dst) Then  ' if TRUE AndAlso dst <> 0 then: double frame
                                    '    or single frame, double line thickness
        Dim As V2L frame_2          ' generate second frame
        With coord
            frame_2.x1 = .x1 + dst : frame_2.y1 = .y1 + dst
            frame_2.x2 = .x2 - dst : frame_2.y2 = .y2 - dst
            Line (.x1, .y1)-(.x2, .y2), clr, B  ' draw original frame
        End With
        With frame_2
            Line (.x1, .y1)-(.x2, .y2), clr, B  ' draw second frame
        End With
    Else                            ' else: single frame
        With coord
            Line (.x1, .y1)-(.x2, .y2), clr, B  ' draw original frame only
        End With
    EndIf
End Sub
' --- end of type's definition's ---

' example usage of above only ...
' screen definitions
Const           wid = 800, hei = 600, hwid = wid \ 2, hhei = hei \ 2, c_d = 32
' color definitions
Const As ULong  White = &hFFFFFFFF, yellow = &hFFFFFF00, red = &hFFFF0000, _
                pink = &hFFFF00FF, blue = &hFF0000FF, green = &hFF00FF00

' ===== MAIN =====
ScreenRes(wid, hei, c_d, 2) ' double buffered screen

Dim As _Frame   frame(2)    ' here we're using three different frame's
Dim As UByte    cnt = 0     ' just to demonstrate: not *always and only integer*!
' init frames
For i As UInteger = 0 To 2  ' for all upwards loops (fastest counter)
    Select Case As Const i
        Case 0 : frame(i)._fset(20, 20, wid-21, hei-21) ' original frame size/position
        Case 1 : frame(i)._fset(50, 50, wid-51, hei-51)
        Case 2 : frame(i)._fset(75, 75, wid-76, hei-76) ' used three times later ...
    End Select
Next


Do  ' MAIN-LOOP
    Cls
    Select Case As Const cnt
        Case 0  ' double frame red, filled with blue
            frame(0)._draw(red, TRUE, 6)    
            Paint (21, 21), blue, red       ' fill double-frame, inside original 
        Case 1  ' double frame -green- default color, double filled (frame and inside)
            frame(1)._draw(, TRUE, -10)     ' dst can be + (inside), - (outside)
            Paint (49, 49), green, green    ' frame fill: outside of original frame
            Paint (51, 51), pink, green     ' fill inside frame too ...
        Case 2  ' single frame yellow filled with red
            frame(2)._draw(yellow) : Paint (76, 76), red, yellow
        Case 3  ' Single frame, thick line (double thickness), aka: double frame, no space
                ' inbetween the two frames
            frame(2)._draw(blue, TRUE, 1)   ' only with +/- 1 setting of dst
        Case 4  ' just to showcase "invisible frame" pink
            frame(2)._draw(pink, 1,, FALSE) ' will never be shown!
            Draw String (hwid - 64, hhei - 10), "invisible frame!", white
            Draw String (hwid - 80, hhei +  2), "frame is set to PINK", white
    End Select
    Flip                                ' show it (screencopy)
    cnt += 1 : If cnt > 4 Then cnt = 0  ' increment counter : conditional counter reset
    If Len(InKey()) Then Exit Do        ' user action quit's (key press/mouse click [X])
    Sleep(750)
Loop
' ===== END-MAIN ===== ' ----- EOF -----
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Simple FRAME Type

Post by sancho2 »

Is there an argument against making _FSet a constructor?

Code: Select all

...
Type _Frame ' minimalistic Frame Type
    As V2L      coord   ' position & size only
    Declare Constructor (ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0)
    Declare Sub _draw(ByVal As ULong = &hFF00FF00, ByVal As Boolean = FALSE, ByVal As Short = 0, ByVal As Boolean = TRUE)
End Type

Constructor _Frame( ByVal _x1 As Long = 0, _    ' Vect. 1 x (-axis)
                    ByVal _y1 As Long = 0, _    ' Vect. 1 y
                    ByVal _x2 As Long = 0, _    ' Vect. 2 x
                    ByVal _y2 As Long = 0 )     ' Vect. 2 y
    With coord
        .x1 = _x1 : .y1 = _y1       ' init 1st vector
        .x2 = _x2 : .y2 = _y2       ' init 2nd v...
    End With
End Constructor
...
' init frames
For i As UInteger = 0 To 2  ' for all upwards loops (fastest counter)
    Select Case As Const i
    	Case 0 : frame(i)= _frame(20, 20, wid-21, hei-21) ' original frame size/position
    	Case 1 : frame(i)= _frame(50, 50, wid-51, hei-51)
    	Case 2 : frame(i)= _frame(75, 75, wid-76, hei-76) ' used three times later ...
    End Select
Next
...
In fact isn't FSet superfluous, since the coords can be set individually, or even as a group?:

Code: Select all

'' init frames
'For i As UInteger = 0 To 2  ' for all upwards loops (fastest counter)
'    Select Case As Const i
'        Case 0 : frame(i)._fset(20, 20, wid-21, hei-21) ' original frame size/position
'        Case 1 : frame(i)._fset(50, 50, wid-51, hei-51)
'        Case 2 : frame(i)._fset(75, 75, wid-76, hei-76) ' used three times later ...
'    End Select
'Next
frame(0).coord = Type(20, 20, wid-21, hei-21)
frame(1).coord = Type(50, 50, wid-51, hei-51)
frame(2).coord = Type(75, 75, wid-76, hei-76)
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple FRAME Type

Post by MrSwiss »

sancho2 wrote:Is there an argument against making _FSet a constructor?
Yes, there is: it says simple = no OOP = no Constructor!
And, it's more versatile than a Constructor, it can be used in MAIN code also.
E.g. to re-initialize the frame at program's run-time.
sancho2 wrote:In fact isn't FSet superfluous, since the coords can be set individually, or even as a group?
No, see above explanation. How you are going about initializing it, is up to you.
But, I could easily thwart your direct attempt, by forcing you, to use it:

Code: Select all

Type _Frame ' minimalistic Frame Type
  Private:
    As V2L      coord   ' position & size only (protected from direct modification, now!)
  Public:
    Declare Sub _fset(ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0, ByVal As Long = 0)
    Declare Sub _draw(ByVal As ULong = &hFF00FF00, ByVal As Boolean = FALSE, ByVal As Short = 0, ByVal As Boolean = TRUE)
End Type
With a single frame (see below), there isn't any initializing outside of main-loop
needed.
I personally prefer it, to let the machine do the work (as much as possible).

If you look at the example code carefully, you'll realize that a single FRAME could
be used (instead of the array), to achieve exactly the same functionality.
The array is in fact the overkill, if there is such a thing.
The array is only really needed, if there is more than one frame needed (at the
same time, on screen).

Proof of above (just recoded MAIN):

Code: Select all

' ===== MAIN =====
ScreenRes(wid, hei, c_d, 2) ' double buffered screen

Dim As _Frame   frame       ' here we're using one frame only!
Dim As UByte    cnt = 0     ' just to demonstrate: not *always and only integer*!

Do  ' MAIN-LOOP
    Cls
    Select Case As Const cnt
        Case 0  ' double frame red, filled with blue
            frame._fset(20, 20, wid-21, hei-21)
            frame._draw(red, TRUE, 6)    
            Paint (21, 21), blue, red       ' fill double-frame, inside original 
        Case 1  ' double frame -green- default color, double filled (frame and inside)
            frame._fset(50, 50, wid-51, hei-51)
            frame._draw(, TRUE, -10)     ' dst can be + (inside), - (outside)
            Paint (49, 49), green, green    ' frame fill: outside of original frame
            Paint (51, 51), pink, green     ' fill inside frame too ...
        Case 2  ' single frame yellow filled with red
            frame._fset(75, 75, wid-76, hei-76) ' used three times
            frame._draw(yellow) : Paint (76, 76), red, yellow
        Case 3  ' Single frame, thick line (double thickness), aka: double frame, no space
                ' inbetween the two frames
            frame._draw(blue, TRUE, 1)   ' only with +/- 1 setting of dst
        Case 4  ' just to showcase "invisible frame" pink
            frame._draw(pink, 1,, FALSE) ' will never be shown!
            Draw String (hwid - 64, hhei - 10), "invisible frame!", white
            Draw String (hwid - 80, hhei +  2), "frame is set to PINK", white
    End Select
    Flip                                ' show it (screencopy)
    cnt += 1 : If cnt > 4 Then cnt = 0  ' increment counter : conditional counter reset
    If Len(InKey()) Then Exit Do        ' user action quit's (key press/mouse click [X])
    Sleep(750)
Loop
' ===== END-MAIN ===== ' ----- EOF -----
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Simple FRAME Type

Post by sancho2 »

According to a response to my question "when does a Type become a class?"
Every UDT becomes a class if you add:
member method (sub/function)
or / and destructor/constructor
or / and operator

So _FSet and _Draw already make the _Frame type OOP.

The constructor can be called like any other method, just like _FSet.

Code: Select all

frame(2).Construcotr(12, 12, 24, 24)
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple FRAME Type

Post by MrSwiss »

It simply looks like we're using different definition-criteria, to define OOP.

Joshy's definition (D.J.Peters), is simply for *class* (not implying OO).
The better definition, because it is OO related, as defined by marcov.
(from the very same page, you are pointing to):
marcov wrote:In the OO sense, a type is really an object (and then its type is a class) when it

- has instantiation (you can create multiple ones without getting in the way)
- has identity, one instantiation is clearly different from another.
- has polymorphism (you can work with a general kind of something even while they are actually more specialized forms). This can be obtained with inheritance (statically typed polymorphism), or by other ways.

The first two are simple, but the third goes beyond simply adding methods/functions to a struct/record.
The polymorphism mechanisms are, by my book:
  • Constructor(s)
    Destructor
    Operator(s) --> aka: Method(s)
    Type Extends Object <--- here, OO really starts ...
Without any of those no OOP (fully dynamic class). Just a complex Type (call it a static class, if you like).
Just having a Sub/Function, makes not yet for OOP. Polymorphism is still missing (see above).
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: Simple FRAME Type

Post by marcov »

MrSwiss wrote:Type Extends Object <--- here, OO really starts ...
Inheritance is just one way of achieving polymorphism. There are more ways (like dynamic dispatch, e.g. the COM IDispatch interface) and mix forms. It is not even that uncommon, since most Apple systems (objective C, swift) implement it.
Post Reply