Author Topic: FB Graphics #1.1: Basic Code Overview  (Read 8367 times)

0 Members and 1 Guest are viewing this topic.

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
FB Graphics #1.1: Basic Code Overview
« on: July 02, 2009 »
Introduction

This is the first in a series of tutorials that will cover the native graphic commands in FreeBasic. Rather than just pasting a bunch of subs and functions together we are going to take a more objected oriented approach and build a simple-to-use,  reusable and fast screen object similar to the graphic library TinyPTC. Since our screen object will be built using native FreeBasic commands it will provide a good framework to explore FreeBasic's graphic commands, and will also introduce key concepts in implementing object oriented programming within the context of a FreeBasic program.

Road Map

Each set of tutorials will be grouped according to a “version� number, with the major version introducing the working code (i.e., FB Graphics #1: Basic Screen Object Code) and the minor versions containing detailed discussions of the code (i.e., FB Graphics #1.1: Basic Code Overview). Following the version numbering while reading the tutorials will ensure that foundational concepts are fully understood before moving onto to more advanced topics.

These tutorials assume that you have the FreeBasic compiler up and running and that you understand how to edit and compile a program. The version 1.X tutorials will examine the code presented in the topic FB Graphics #1: Basic Screen Object Code.

Code Review

This tutorial will give a general overview of the code example, with subsequent 1.X tutorials examining the core ideas of the code in greater detail.

Comment Section

Code: [Select]
FB Graphics Series for DBFInteractive: http://www.dbfinteractive.com/
' Richard D. Clark
' 01: Basic Graphics Framework
' GPL 3.0
' This program is free software; you can redistribute it and/or modify it
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
' =======================================================================================================
' This is the first in a series of example programs in FB that illustrates the graphics engine in FB.
' This program builds a preliminary screen object that will be used as a base for the graphics series.
' The series will use only the built-in graphics and the standard FB libraries.
' =======================================================================================================

The first part of the code is a comment header that gives a description of the code and the license information. Since the compiler ignores any comments in the source, it is helpful to liberally comment your code so that you can understand what you were doing in the code when you come to it after a lengthy break. It is also good practice to specify the license of released code so that others can know to what extent they can use your code if they find it useful.

Include Section

Code: [Select]
Include the FB graphics library.
#Include "fbgfx.bi"
'Include the CRT for memory functions.
#Include "crt.bi"

The next section is the include section. The program is using two of the standard libraries, the FreeBasic graphics library and the C runtime library. The #Include directive doesn't have to be put at the top of the program. It does need to be called before the first instance of calling a function in an included file though, otherwise a compiler error will be generated. As we will see when we progress in the tutorials, an #Include file may include other files and we'll use this idea to create a version of the screen object that we can include in other programs.

An #Include file may be actual FreeBasic code or simply a set of data and function declarations. In the case of the standard libraries above, the include files are function, symbol and type definitions for the actual code that has been converted into libraries that are linked with the compiled program.

The fbgfx.bi file contains the data declarations that are used in the graphics engine in FreeBasic. The crt.bi file contains data and function declarations that are used in the C runtime library (CRT). We are including it here since we will be using the memory functions contained within the CRT. The CRT has a number of useful functions that have been optimized for speed and size and we will be using a few of these in our screen object as we expand the functionality of the object.

When the compiler sees the #Include directive, it stops compiling the current program and reads in the code of the specified include file. That code is then inserted at the point of the #Include directive and compiling continues. If the included file has one or more #Include directives, these will also be read and then compiled. The following code block lists an example from the CRT file.

Code: [Select]
#ifndef __CRT_BI__
#define __CRT_BI__

#ifdef __FB_WIN32__
# inclib "msvcrt"
#endif

#include once "crt/string.bi"
#include once "crt/math.bi"
#include once "crt/time.bi"
#include once "crt/wchar.bi"
#include once "crt/ctype.bi"
#include once "crt/stdlib.bi"
#include once "crt/stdio.bi"
#include once "crt/fcntl.bi"
#include once "crt/errno.bi"

#if defined(__FB_WIN32__) or defined(__FB_DOS__)
# include once "crt/dir.bi"
#endif

#endif ' __CRT_BI__

The #Include Once directive can be used to ensure that a file is only included once in the compiling process.

Using Command

Code: [Select]
'Set the default namespace.
Using FB

FreeBasic supports the use of namespaces. Namespaces are sections of code between the commands Namespace {i]name[/i] and End Namespace. Namespaces help prevent symbol name collisions between different libraries. For example, suppose you have created a Point object, but want to use a library that also has a point object. Compiling under these circumstances will generate a duplicate definition error by the compiler. To avoid that situation, a namespace can be used to isolate the library Point definition so that it does not collide with your user created Point object.

To use a function or variable within a namespace there are two options. You can preface the function or variable with the name of the namespace, i.e. FB.GFX_NULL, or you can use the Using name command to indicate that you want to use the library commands without the namespace prefix. Since there are a number of useful data definitions in the fbgfx.bi file that we can use in our screen object, we will just set the using namespace to fb so that we can directly access the data.

Enum

Code: [Select]
'Boolean enumeration.
Enum sbool
FALSE = 0
TRUE = Not FALSE
End Enum

Here we are creating an enumeration that we will use as a boolean value in the object. An enumeration is a set of identifiers that are usually grouped according to some common theme such as days of the week or values of a set of cards. They can also be used to create new data types, as is the case here. You can either set the value of an enumeration explicitly or let the compiler set the values for you. If not explicitly set, the value of the first enumeration identifier is 0 and following identifiers are incremented by 1. You can also let the compiler set a part of the values, and you can explicitly set the other values. For example, suppose you want the first enumeration identifier to have the value of 1, so you would set it equal to 1 in the code. The compiler will then assign 2 to the next identifier, and increment each identifier by 1.

Enumerations also add to the readability of your code. Ace is much more understandable than 1, and True is more understandable than -1. The numbers could mean anything, but it is quite apparent that Ace refers to a card and True to a boolean value.

The Type Definiton

Code: [Select]
'Create the screen object definition.
Type screenobject
Private:
_width As Integer       'The screen width.
_height As Integer      'The screen height.
_buffer As UInteger Ptr 'The screen update buffer.
_initok As sbool        'Flag indicates screen set successfully. True, set ok, False error.
Public:
Declare Constructor (ByVal scrwidth As Integer, ByVal scrheight As Integer) 'Sets up a graphics screen.
Declare Destructor  'Cleans up created objects.
Declare Property GetStatus () As sbool 'Returns command status.
Declare Property GetWidth () As Integer  'Returns the screen width.
Declare Property GetHeight () As Integer 'Returns the screen height.
Declare Sub DrawToBuffer (ByRef x As Integer, ByRef y As Integer, ByRef clr As UInteger) 'Sets the x and y location of buffer to color.
Declare Sub CopyBuffer ()'Copies buffer to screen.
Declare Sub ClearBuffer ()'Clears buffer. Fills to 0.
End Type

Here is where we get to the meat of the program, our screen object definition. As you can see it resembles a standard Type definition, but has some added features that will enable us to take an object oriented approach to creating our object. The next tutorial will cover the concepts of OOP in detail so just a quick overview will be given here.

The first thing you will notice is that the type is made up of two sections: a Private section and a Public section. The private section is accessible only from the within the type. This comprises our object's working data and is hidden from the outside world, a concept known as information hiding. Information hiding prevents warranted changes to the working data, making the object behave in a consistent and reliable manner.

The public section is the object's interface, the functions that are accessible from outside the type definition. The interface allows us to control access to the objects data section ensuring that the data going into the object and the data leaving the object (these are called messages in OOP) is consistent and correct. The interface also provides a means for the object to do something, such as updating the screen when needed.

Combining both the data, and the functions that operate on the data, into a single object is called encapsulation and is one of the fundamental concepts of objected oriented programming. There are also two other  concepts, polymorphism and inheritance that are key to OOP programming.

Polymorphism is the ability of an object to do different things depending on how certain functions are defined. For example an animal object may be able to Bark or Meow depending on how the Speak function is defined. In FreeBasic polymorphism is accomplished through the use of function pointers, a topic that will be covered at a later date.

Inheritance is the ability of an object to take on the characteristics of an ancestor object. That is, you can create a base object, and then create child objects from the base object that will automatically contain all the data and function definitions of the parent. FreeBasic doesn't support inheritance and is the only OOP feature not implemented.

Member Definitions

Code: [Select]
'Screen object constructor.
'This sets up both the screen and the associated screen buffer.
Constructor screenobject (ByVal scrwidth As Integer, ByVal scrheight As Integer)
'Set the default status. An error will change to False.
this._initok = TRUE
'Check the parameters to make sure that they are in bounds.
If (scrwidth > 0) And (scrheight > 0) Then
'Try and set the screen.
ScreenRes scrwidth, scrheight, 32
'Check to see if the screen was created successfully.
If ScreenPtr Then
'Set the screen width and height.
this._width = scrwidth
this._height = scrheight
'Create the update buffer.
this._buffer = Callocate (scrwidth * scrheight, SizeOf(UInteger))
'Make sure that the buffer was created.
If this._buffer = 0 Then
'Set status to False, error.
this._initok = FALSE
EndIf
Else
'Set status to False, error.
this._initok = FALSE
EndIf
Else
'Set status to False, error.
this._initok = FALSE
EndIf
End Constructor

'Screen object destructor.
'This will destroy any created objects like the update buffer.
Destructor screenobject
'Destroy the update buffer if initialized.
If this._buffer Then DeAllocate this._buffer
End Destructor

The major part of the program code is the member definitions, which will be covered in detail in the next tutorial. However, the code block has two important members, the constructor and destructor that warrant a brief mention.

The constructor is called when the object is created. We'll see the actual creation process in a moment. A constructor can take zero or more parameters; the screen object takes two parameters, the width and height (in pixels) of the desired screen. As you can see from the code snippet, the constructor attempts to set the screen to the desired resolution and then checks to see if the action was successful. If successful, an update buffer is created using the FreeBasic function Callocate. If any error occurs in the process, the private data variable initok is set to False to indicate that the process failed. This is important since the main code will need to know that the screen was created successfully before executing any code.

The destructor is called when the object is destroyed and is used to clean up any created data structures. The screen object uses the destructor to free the update buffer allocated in the constructor. It is important to clean up any created references when the object is no longer needed to maintain program integrity.

Main Program Code

Code: [Select]
' =======================================================================================================
' Main Program Code
' =======================================================================================================
'Init the random number generator.
Randomize Timer
'Create the screen object which will initialize and create the graphics screen.
Dim As screenobject aScreen = screenobject(640, 480)

'Make sure the screen intilizled properly.
If aScreen.GetStatus = FALSE Then
End
EndIf

'Draw a 100 screens
For i As Integer = 1 To 100
'Draw some random points to the screen.
For x As Integer = 0 To aScreen.GetWidth - 1
For y As Integer = 0 To aScreen.GetHeight - 1
aScreen.DrawToBuffer x, y, RGB (Rnd * 255, Rnd * 255, Rnd * 255)
Next
Next
'Copy the buffer to the screen.
ascreen.CopyBuffer
Next

'Clear the buffer.
ascreen.ClearBuffer
'Copy the buffer to the screen, should be black.
ascreen.CopyBuffer

'Wait for the user to end.
Print "Press any key"
Sleep

The rest of the program is the main program code. The object member functions will be discussed in detail in the next tutorial, so just the general program flow is described here.

The first main statement initializes the random number generation with the Randomize statement. The following Dim statement creates the actual screen object. The portion of the code after the equals sign screenobject(640, 480) is the constructor which attempts to set a 640x480 graphic screen. The GetStatus property of the object is then called after the object initialization to make sure that the screen was created successfully. If the screen creation process fails, the program cannot proceed.

A nested loop follows the creation of the screen object, where a 100 randomly generated screen are created. The inner loops iterates through the screen dimensions setting each location in the update buffer to a random color. The CopyBuffer function updates the visible screen with the buffer contents. After the loop finishes, the buffer is cleared with the ClearBuffer member function and then the buffer is copied and displayed again just to illustrate the clearing process.

While the main code doesn't seem to be very useful, it exercises all of the object data and function members to ensure everything is working correctly. What is not shown here, and should be a part of any test, is to pass the object bad data, in this case a screen resolution that FreeBasic can not implement, to make sure that the error trapping works as expected.

Summary

Even though the example code is relatively short, you can see that there is a lot going on, and so far we have only scratched the surface. This tutorial has just been a brief overview of the code which will be expanded on in upcoming tutorials. By the time we are finished exploring the various aspects of the existing code base, we will be in a good position to expand the functionality of our screen object and dig into more advanced topics.

Offline Clyde

  • A Little Fuzzy Wuzzy
  • DBF Aficionado
  • ******
  • Posts: 7271
  • Karma: 71
    • View Profile
Re: FB Graphics #1.1: Basic Code Overview
« Reply #1 on: July 02, 2009 »
Wonderfull mate :)
Still Putting The IT Into Gravy
If Only I Knew Then What I Know Now.

Challenge Trophies Won:

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
Re: FB Graphics #1.1: Basic Code Overview
« Reply #2 on: July 02, 2009 »
Thanks man.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17378
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: FB Graphics #1.1: Basic Code Overview
« Reply #3 on: July 02, 2009 »
I am looking forward to the weekend so much so that I can start coding the display tutorial function of the new portal..... Yes it's coming.

It will be about two or three weeks before the portal is ready to go but I am really looking forward to it, your tutorials are giving me extra motivation to get the portal finished.

Thanks mate.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline rdc

  • Pentium
  • *****
  • Posts: 1495
  • Karma: 140
  • Yes, it is me.
    • View Profile
    • Clark Productions
Re: FB Graphics #1.1: Basic Code Overview
« Reply #4 on: July 02, 2009 »
Heh. Thanks man. Looking forward to seeing your webilistic magic. :)

I am working on the next installment. I am going to try and have a tut every few days, time permitting.

Offline neriakX

  • Atari ST
  • ***
  • Posts: 115
  • Karma: 29
  • CodeNoob
    • View Profile
Problem solved!
« Reply #5 on: September 22, 2011 »
Thanks for this great tutorial! However I  get compile errors when I select 'Make':

Code: [Select]
Build error(s)
E:\_Tools\FreeBASIC-0.23.0-win32\fbc -s console "FBGraphics 01.bas"
FBGraphics 01.o:fake:(.text+0x140): undefined reference to `_ZN12SCREENOBJECT16GETSTATUS__get__Ev@4'
FBGraphics 01.o:fake:(.text+0x162): undefined reference to `_ZN12SCREENOBJECT15GETWIDTH__get__Ev@4'
FBGraphics 01.o:fake:(.text+0x17b): undefined reference to `_ZN12SCREENOBJECT16GETHEIGHT__get__Ev@4'
FBGraphics 01.o:fake:(.text+0x1fc): undefined reference to `_ZN12SCREENOBJECT12DRAWTOBUFFERERiRiRj@16'
FBGraphics 01.o:fake:(.text+0x223): undefined reference to `_ZN12SCREENOBJECT10COPYBUFFEREv@4'
FBGraphics 01.o:fake:(.text+0x239): undefined reference to `_ZN12SCREENOBJECT11CLEARBUFFEREv@4'
FBGraphics 01.o:fake:(.text+0x242): undefined reference to `_ZN12SCREENOBJECT10COPYBUFFEREv@4'

I'm running Freebasic 0.23 on a Windows 7 x64 Machine. Maybe it's a Windows 7 problem?

Edit: It has to be something wrong with the object. they get created but don't seem to know their methods (subs)
Is there a problem with the Compile options? Windows Console -> fbc -s console

Edit 2: Cool, the source code from http://www.dbfinteractive.com/forum/index.php?topic=4215.0 works perfectly!
So, my problem is solved for now! :) Yay! :updance:

Edit 3: I think I found the 'bug' causing my problems. The only difference between the two source codes is the word 'this'. For eg. the Constructor screenobject code here has
Code: [Select]
this._width = scrwidthand
Code: [Select]
this._buffer = 0 etc.
That's not the case in the source code of thread http://www.dbfinteractive.com/forum/index.php?topic=4215.0

edit 4: HAHAHA! Feeling so dumb! Now I know why the upper code doesn't work ... It's incomplete!. It wasn't supposed to get executed at this stage (the screenobj propertys and subs are missing).
Sorry for bothering you guys ... mea culpa :-/  :whack:
« Last Edit: September 22, 2011 by dizphunkt »
cheers,
neriakX

Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17378
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: FB Graphics #1.1: Basic Code Overview
« Reply #6 on: September 22, 2011 »
It's really cool that you posted this all because you may help someone else with the same starting problems :)

Have some good Karma.  :goodpost:
Shockwave ^ Codigos
Challenge Trophies Won: