Search for notes by fellow students, in your own course and all over the country.

Browse our notes for titles which look like what you need, you can preview any of the notes via a sample of the contents. After you're happy these are the notes you're after simply pop them into your shopping cart.

My Basket

ICT(COMPUTER HARDWARE AND RESOURCES)£11.25

Title: A Beginners Guide(purebasic programming )
Description: A beginners guide to learn basic programming

Document Preview

Extracts from the notes are below, to see the PDF you'll receive please use the links above


or
df 4
te ic v
d a as
Up r e b
Pu

Purebasic
A Beginner’s Guide To Computer Programming

Gary Willoughby

Purebasic
A Beginners Guide To Computer Programming

Gary Willoughby

PureBasic - A Beginner’s Guide To Computer Programming
by Gary Willoughby
Copyright © 2006 Gary Willoughby
This book and all included source materials such as diagrams, photos and PureBasic source code is
distributed under the Creative Commons Attribution Non-Commercial Share Alike License
...
org/about/licenses/
PureBasic is a registered trademark of Fantaisie Software
...

Fantaisie Software
10, rue de Lausanne
67640 Fegersheim
France
www
...
com
Published 2006, by Aardvark Global Publishing
...
The author or
publisher shall not be liable if incidental or consequential damages occur in connection with, or arising
from, the furnishings, performance, or use of the programs, associated instructions, and/or claims of
productivity gains
...
For up to date news and information regarding PureBasic
please refer to www
...
com
...
Rather than list the names and entities that own
the trademarks or insert a trademark symbol with each mention of the trademarked name, the
publisher states that it is using the names for editorial purposes only and to the benefit of the
trademark owner, with no intention of infringing on that trademark
...


Acknowledgments
Thanks to Fred and the Purebasic team for the Purebasic language, keep up the good work, it rocks!
Thanks to Paul Dixon for clarifying some of the details regarding binary encoding of floating point
numbers
...


“With great power there must also come great responsibility!”
--Ben Parker (Spiderman’s Uncle)

Code examples contained in this book can be downloaded freely from

www
...
co
...
ix
I
...
1

1
...
3
The History Of PureBasic
...
5
A First Look At The IDE
...
7
The Debugger
...
8
Introducing The PureBasic Help File
...
Data Types
...
10
Numbers
...
12
Variables And Constants
...
Operators
...
18
Operator Precedence
...
34
4
...
37
Boolean Logic
...
38
The ‘Select’ Statement
...
43
5
...
49
Structures
...
52
Linked Lists
...
67
6
...
71
Why Use Procedures Or Subroutines?
...
71
Procedure Basics
...
76
The ‘Global’ Keyword
...
79
The ‘Shared’ Keyword
...
82
Passing Variables To Procedures
...
86
Passing Linked Lists To Procedures
...
91

7
...
93
Using The PureBasic Helpfile
...
95
Examples Of Common Commands
...
104
Read The Helpfile
...
Good Programming Style
...
111
The Value Of Comments
...
113
Golden Rules For Writing Easily Readable Code
...
117
II Graphical User Interfaces
...
Creating User Interfaces
...
131
Creating Native User Interfaces
...
139
Adding Gadgets
...
148
Menu Keyboard Shortcuts
...
156
A First Look At The New Visual Designer
...
165
10
...
167
2D Drawing Commands
...
179
Introducing Screens
...
192
11
...
203
An Overview Of The OGRE Engine
...
206
A Simple First Person Camera
...
221
What’s Next?
...
Sound
...
227
Module Files
...
233
CD Audio
...
243
13
...
245
Compiler Directives And Functions
...
252
Parsing Command Line Parameters
...
262
Pointers
...
279
Dynamic Link Libraries
...
293
V

Appendices
...
Useful Internet Links
...
Helpful Charts
...
Glossary
...
332

ix

Preface
About this Book
This book provides a quick introduction to the PureBasic programming language
...
This book has been written, with the complete novice
in mind
...
With PureBasic becoming more and more widely used, many people are starting
out and finding they need the occasional push in the right direction or need an explanation of a certain
feature or oddity
...


This Book’s Scope
Although this book covers the essentials of the PureBasic language, I’ve kept this book’s scope quite
narrow to make sure it’s not information overload for new users
...

For example I won’t talk much about how easy it is to use DirectX or OpenGL directly in PureBasic,
otherwise this book would be triple in size and although topics such as pointers, threads and the
Win32 API is talked about later in this book, don’t expect too many fancy examples as I’ve only given
an overview to such advanced topics
...
Clean, uncluttered syntax, small compiled executable files and a fantastically active community of
programmers
...


x

Preface

Despite this books limited scope, I think you will find this a great first book on PureBasic which will
also give you a solid grounding on programming in general if you were to migrate to other languages
...
By the time you’ve
finished this book, you will have learned not only the essentials of the language itself, but also how to
apply that knowledge to day-to-day tasks
...


This Book’s Structure
Much of this book is designed to introduce you to PureBasic as quickly as possible and is organized by
presenting the major language features a section at a time
...
For example, when we
get to graphical user interfaces and graphics, I’ll assume you now understand procedures and
structures
...
Most of the examples given are not really very useful as
standalone programs but are there to demonstrate and explain the current topic
...
An overview
on how to run a PureBasic program from the IDE and what the debugger is for
...
Usage guidelines are given for all the built-in data types as well as
information on memory usage and where applicable, numerical limits
...
A full explanation is given for all operators along with diagrams and
examples
...

Chapter 4, Conditional Statements And Loops
In this chapter I explain how PureBasic handles boolean values, the ‘If’ and ‘Select’ statements are
introduced and loops are explained and demonstrated
...

Chapter 5, Other Data Structures
This chapter reveals how to create and use other methods for storing and organizing data, such as user
defined structures, arrays and linked lists
...


Preface

xi

Chapter 6, Procedures And Subroutines
Procedures and Subroutines are an essential part of programming in any language as they can be used
to execute sections of code (along with variable parameters in the case of procedures) from any part of
the running program
...

Chapter 7, Using Built-In Commands
This chapter demonstrates some of the most widely used built-in commands
...
An explanation is given on Handles and IDs, both of which
are simple to understand but sometimes easily confused
...
When programming in any language, errors are always
a problem, be it a simple typo or a bug in the language itself
...

Part II: Graphical User Interfaces
Nearly every program nowadays has a user interface of some description and here I will show you how
to create one
...

Chapter 9, Creating User Interfaces
Here I show you how you can built your own user interfaces
...

Events are also described and examples are given on how to react when an event is detected within
your interface
...

Part III: Graphics And Sound
Graphics and sound have an important role in nearly every computer system today
...

Chapter 10, 2D Graphics
This chapter introduces two dimensional graphics such as lines and shapes and how they are drawn
on the screen
...

Chapter 11, 3D Graphics
The three dimensional graphics in PureBasic are provided by the OGRE engine
...
The OGRE engine is still
undergoing development and is still being integrated fully into PureBasic, but some nice things are still
possible
...

Part IV: Advanced Topics
The last section deals with things which a novice would find very advanced
...
This section is to wet your appetite for knowledge to improve
your understanding of PureBasic and programming in general
...
Compiler directives are
explained and a how-to guide is written for DLL creation
...

Part V: Appendices
This is the final section of this book and it ends with appendices that direct the reader to useful pages
on the Internet, provides helpful charts and includes a comprehensive glossary of words and terms
...

All you will need to start programming today is a little bit of time and a copy of PureBasic, available
from www
...
com

I
The Core
Language
In this section, we will study the PureBasic language itself
...
By the time you finish reading this section and studying the examples, you’ll be ready to
write programs yourself
...
While I may skip certain things along the way, the basics you learn
here will stand you in very good stead for when the unknown pops up
...


1
3

Getting Started
This first chapter starts with a brief history of PureBasic and then takes a quick look at how to run
PureBasic programs
...
Along the
way we’ll study different ways you can compile from within PureBasic - just enough to get you started
...
It
looks a little daunting for new users but after an overview and a little tutorial, things will look less scary

The History Of PureBasic
PureBasic started life in 1995 as a command-set expansion for BlitzBasic after PureBasic’s author,
Frédéric Laboureur hit many limitations with BlitzBasic while programming an application called
‘TheBoss’, a powerful application launcher for the Commodore Amiga
...
Fred’s progress was quite slow to begin with as good
documentation was hard to find for assembly programming and of course online forums didn’t then
exist for BlitzBasic plug-in programming
...
He was also astonished with the incredible things that could be achieved with an old 68000
processor if everything was programmed correctly
...
They were very fast and sold at a relatively
cheap cost, even compared to the high-end 68060 processors
...
An opportunity had presented itself for the creation of a new language

4

Getting Started

which would be the logical replacement and enhancement of BlitzBasic, which also would have full
support for the 680x0 and PowerPC processors
...
The main differences between
PureBasic and ‘normal’ compilers then was the inclusion of a ‘virtual processor’ (which actually used
the 680x0 assembly mnemonics) right from the start to allow different kinds of assembly output (or
any language) possible without changing the compiler core
...
Fred fully dedicated all his time to program the
compiler and learned a great deal including the C language to be able eventually to produce a fully
portable compiler
...

While refining and bug testing, Fred also studied other programming languages to give him a firm
grounding in other areas and to give him the best foundation to make better, more informed decisions
about the internal design and how PureBasic should grow and expand in the future
...
Fred of course defended himself saying that it would be a piece of cake to port PureBasic to a
new system, but he had to prove it!

A Brief Overview of The Assembly Language
Assembly language or simply Assembly, is a human-readable notation for the machine language that a
specific computer architecture uses
...

Programming in machine code, by supplying the computer with the numbers of the operations it must
perform can be quite a burden, because for every operation the corresponding number must be looked up or
remembered
...
Each number was represented by an alphabetic
code
...
Assembly is compiled using an Assembler
...

Even the internal storage method of numbers in memory was reversed! After three months in
development and after the founding of his new company, Fantaisie Software, a new website was

Getting Started

5

created and PureBasic for Windows was finally released
...

After many years of careful development, a team was formed around Fred to help him with the
development and testing of new releases
...

After the massive success of the Windows release the next logical step was to support more operating
systems
...
All versions supporting the native application
programming interfaces (APIs) of these particular operating systems, all using the native graphical
user interfaces to give them the correct look and feel of the system
...
The Windows, Linux and Mac OS versions are
still being tirelessly developed and supported today!
Version 4 is the latest incarnation of PureBasic which has nearly all been rewritten from scratch
...
PureBasic v4 also brought
huge language improvements, nearly all of which are covered in this book
...
Here is a list of some of PureBasic’s development goals and policies
...

All Programs compiled using PureBasic can be sold commercially free of any further cost or royalties
...

All compiled programs should not rely on any runtimes and be completely ‘stand-alone’ executables
...
Can you imagine Microsoft giving you free version upgrades of VB
...

PureBasic’s development philosophy is one of creating a programming environment that is both fun
and functional to use
...
With all past version upgrades there has been included bug fixes, new
commands plus brand new IDEs and a Visual Designer, the last two of which are covered in later areas
of this book
...


6

Getting Started

A First Look At The IDE
PureBasic’s Integrated Development Environment consists of a source code editor, a visual form
designer and a compiler
...
In the PureBasic community the source code editor is usually referred to as the ‘IDE’, while the
visual form designer is usually given the dubious name of the ‘VD’
...


Menu
Toolbar

Customizable
Pane

Editor
Pane

Error Log
Quick Help
The IDE as it appears on Microsoft Windows
...
1

The IDE (Fig
...
At the top is the menu bar giving access to
the menu commands, below that is a customizable toolbar which can be configured to hold many
different icons each triggering a pre-defined menu command
...
On the right of the editor pane is another user
customized pane which can contain a procedure viewer, a variable viewer, a file explorer, etc
...
Below the
panes there is the status bar which shows information on what row and column is being edited and
displays the quick help
...
Once code has been entered into the editor

Getting Started

7

pane and the ‘Compile/Run’ toolbar button has been pressed (Shortcut Key: F5) the code is then
passed to the compiler for the creation of an executable
...
Not only that but other editors require some
configuration to correctly pass the file to the PureBasic compiler which some users find a little too
complicated to begin with
...
This
can be a very handy reference when you are speed coding (maybe after too much coffee) and searching the
helpfile is too much hassle
...


How To Run PureBasic Programs
Right, let’s get started to learn how to run programs
...
pb’) that contain the actual PureBasic code
...
There are many ways of doing this such as:
In the IDE:
Press the ‘F5’ keyboard shortcut for ‘Compile/Run’
...

Select the menu command: ‘Compiler->Compile/Run’
...

Using the command line:
Enter the command: ‘PBCompiler filename’ where ‘filename’ is the name of the text file
...

The first three IDE methods mentioned above, achieve the same result and any one of these three can
be used while actually writing and testing the current program (it doesn’t matter which one)
...

When selected the text file is immediately compiled into a temporary executable file called
‘purebasic0
...
This is
handy when you need to see immediately how your program runs, without specifying a proper name
for the compiled executable
...
exe’, and so on
...
exe’ as the temporary name
...

The last IDE method, using the ‘Compiler->Create Executable
...
Once this menu command has been selected a dialog box appears asking you to specify
a name and location for your final executable program file
...
Other parameters can be
passed along with the filename to further customize the compilation
...

That is all there is to compile and run your first program
...
It
controls and keeps track of all variables and procedure parameters, etc
...
It
is a second pair of eyes on your code to highlight errors and to avoid potential program crashes such
as zero division, illegal array offset access and data overflow errors
...
The program execution can
be stopped and forwarded step by step to locate any faults or strange behavior
...

The Debugger can be toggled on and off at any time by pressing the ‘Enable Debugger’ toolbar button
or by selecting the menu command (Menu:Debugger->Enable Debugger)
...


A Note On Program Structure
The structure of a PureBasic program is quite easy to understand
...
It’s that easy
...
If the debugger spots a problem
the compilation is stopped and an error is raised
...
This is exactly how the compiler processes the text file
...
This all seems pretty straightforward but you may run into this at
sometime, especially when you start to use procedures (these will be explained fully in Chapter 6)
...


Introducing The PureBasic Helpfile
With every PureBasic installation, a complete helpfile is installed alongside
...
If they were, then it would be a very sizable
document and not very printer friendly
...
In fact, every time I personally create
a program using the PureBasic IDE, I like to keep the helpfile open at all times to quickly flick between
the two
...

IDE Integration
At anytime when you are using the IDE to create your program, you can press the ‘F1’ key on your
keyboard to trigger the launching of the PureBasic helpfile
...

This integration between the IDE and helpfile is invaluable once you start to gain speed while
programming
...
After the enter
key is pressed then we then end the program nicely
...
For example,
place your flashing cursor anywhere within the ‘OpenConsole()’ keyword and hit ‘F1’
...


2

10

Data Types
Now that the introductions are over let’s begin this chapter with more substance, namely Data Types
...
Data types are the
descriptions of the containers of this data
...

To enable you to get up and running as soon as possible, I have included many of examples and
everything is explained using plain speech
...
The basic idea of typing data is to give some useful meaning to what is ultimately just
binary digits
...
Data is held within the computers RAM until needed by the program
...


Numbers
The first data types to be introduced are the numbers types
...
Anything you use numbers for in
the real world, you can also use PureBasic’s numeric types to store that data
...
Integers are
numbers which don’t have a decimal point and can either be positive or negative
...
Here are a few examples of floating point numbers:
52
...
0005

1668468
...
000004

0
...
The numerical types are described
here in Fig
...


PureBasic’s Numeric Types
Type

Suffix

Memory Usage (RAM)

Numerical Limit

Byte


...
c

1 byte (8 bits)

0 to 255

Char (Unicode)


...
w

2 bytes (16 bits)

-32768 to 32767

Long


...
q

8 bytes (64 bits)

-9223372036854775808 to 9223372036854775807

Float


...
d

8 bytes (64 bits)

Unlimited*

* This will be explained fully in Chapter 13 (A Closer Look At Numeric Data Types)
...
2

Numerical Limits
In Fig
...
The amount of RAM allocated and the names of the numerical
types are more or less the same as the C language
...
For beginners, all you need to remember is the numerical limits of each type and
understand that this can’t be exceeded
...

If a numeric data type is exceeded numerically then that numeric value will wrap around the lower
numeric level
...


12

Data Types

Strings
The last standard PureBasic data type is a String
...

As their name suggests, Strings are just simply strings of characters
...
This way is to use double
quotation marks to encapsulate the String
...
This is recognized as a String rather than a
number because of the double quotation marks around it
...

Strings are probably the simplest data type to understand because they are so easy to use
...


PureBasic’s String Types
Type

Suffix

Memory Usage (RAM)

Character Limit

String


...
s{length}

4 bytes (32 bits)

User Defined*

Fixed Length String

${length}

4 bytes (32 bits)

User Defined*

* The ‘length’ parameter defines the string’s maximum length
...
3

Strings can be made up from any character in the ASCII character set, including the control characters
(See Appendix B (Helpful Charts) for a full listing of ASCII characters) except the null character as that
is used to signify the end of a String
...


Variables And Constants
To store and manipulate data in any program you need to use the correct data type for storage but you
also need a way to easily find that data in memory
...
Put simply, variables refer to data that can change its value, while constants refer to
data that will never ever change
...
Variable
names can be named anything you want, but many people like to keep them as descriptive as possible
to convey what the actual value is that the variable holds
...

Variables are essential for the organization and storage of your data
...
Open the PureBasic IDE and let’s create a variable of our own
...
You enter a variable name followed by a
type suffix to define what type of variable it is to be, followed by an operation you wish to perform on
it
...

In the following statement, we assign the value of ‘1’ to the name ‘NumberOfLinesOfCode’, using the
equals operator (=) and using a Byte as its data type
...
b = 1

Look at this statement a little more closely
...
No variable ever has spaces! If you need to separate the words in a variable to make it
more easy to read you can use underscores like this:
Number_Of_Lines_Of_Code
...
Variable names must not start
with a number and must not contain any operators (see Fig
...
Also
no special characters are allowed such as accented characters (ß, ä, ö, ü)
...
b’ added to the end of
the variable name is a suffix to tell the compiler that this variable is to be a Byte and as such will use
the associated amount of memory and impose the associated numerical limit
...
2
...
3
...
If a type suffix is not used like this:
NumberOfLinesOfCode = 1

The variable is declared as a Long as this is the default type of PureBasic
...
PureBasic does provide a way to change the default type by using the
‘Define’ keyword like this:
Define
...
The above two variables for instance are both declared as Bytes because of the ‘
...
If this keyword is not used in a PureBasic program then the
default type remains as a Long
...
w Day, Month, Year

This code switches the default type to a Word and declares three variables, ‘Day’, ‘Month’ and ‘Year’ as
Words but because these variables have no value assigned to them, they are given the value of zero (0)
...
b = 123
CharVariable
...
w = 4567
LongVariable
...
q = 9223372036854775807
FloatVariable
...
1415927
DoubleVariable
...
53456776674545
StringVariableOne
...
s{6} = "abcdef"
StringVariableFour${3} = "abc"

You will notice the last four variables are Strings but are all defined by slightly different suffixes
...
Each one
of these types can be defined by using two suffixes
...
s’ and ‘$’
...
Both can be used in the same program but the two suffixes
are not interchangeable
...
s = "Test String One"
StringVariable$ = "Test String Two"

Even though they have the same name, the different suffixes mean they are different variables all
together
...

StringVariable
...
s
Debug StringVariable$

In this example the ‘Debug’ keyword is used to echo the values of the two variables to the Debug
Output window
...
You will see
two lines appear in the Debug Output window showing the values of the two variables that we used
‘Debug’ with
...
When a final executable is made all the ‘Debug’ commands are removed from the final
program, leaving a small executable size
...
Any data type
can be used with this command, making it invaluable for quickly printing helpful numbers, memory
addresses, returned Strings and/or values of calculations
...


One more thing to note about variables is that they are not case sensitive
...
Look at this example:
TestVariable
...
As you can see, letter case means nothing to a variable as this example outputs the text
‘Test String Three’
...
For example, once a variable has been declared as a String then
from then on you can never store an integer or floating point number in that variable
...
s = "Test String One"
StringVariable = 100

This example will never compile and if you try to, you will get a polite message from the IDE telling
you that you cannot write a numeric value into a String variable
...
s = "Test String One"
StringVariable = "One Hundred"

Because the variable ‘StringVariable’ was originally declared as a String, only Strings can be given as
values to that variable from then on
...
So let’s recap on the main variable rules
...

2)
...

4)
...

6)
...


Variables must not contain spaces
...

Variable names must not contain any operators (See Fig
...

Variable names must not contain any special or accented characters (ß, ä, ö, ü)
...

Once a variable has been declared, its data type can never be changed during runtime
...


16

Data Types

Constants
Constants are similar to variables in that they provide an easy way to reference data and can be called
whatever you want, but that’s where the similarity ends
...
Look at this example:
#DAYS_IN_THE_YEAR = "365"

We know that the number of days in a standard year will never change so we can use a constant to
express this
...
The IDE will complain,
telling you that a constant with that name has already been declared and halt compilation
...
Look at this example:
#DAYS_IN_THE_YEAR = "365"
Debug "There are " + #DAYS_IN_THE_YEAR + " days in the year
...
"

because the constant is replaced by the value it was assigned, in this case ‘365’, and then compiled
...
All constants are declared using a prefix rather than a suffix
...

Enumerating Constants
If you need a block of constants all of which are assigned numeric values enumerated one after the
other, then you can use the ‘Enumeration’ keyword
...
If you want to start the enumeration at a number other than ‘0’, you can use an optional
numeric parameter with the ‘Enumeration’ keyword, like this:

Data Types

17

Enumeration 10
#TEN
#ELEVEN
#TWELVE
EndEnumeration
Debug #TEN
Debug #ELEVEN
Debug #TWELVE

Now you can see the constant ‘#TEN’ has the value of ‘10’ and the rest are incremented from then on
...
Look at this example:
Enumeration 10 Step 5
#TEN
#FIFTEEN
#TWENTY
EndEnumeration
Debug #TEN
Debug #FIFTEEN
Debug #TWENTY

Now the constants are incremented by ‘5’, starting at ‘10’
...
Just like this:
Enumeration 5
#FIVE
#ONE_HUNDRED = 100
#ONE_HUNDRED_AND_ONE
#ONE_HUNDRED_AND_TWO
EndEnumeration
Debug
Debug
Debug
Debug

#FIVE
#ONE_HUNDRED
#ONE_HUNDRED_AND_ONE
#ONE_HUNDRED_AND_TWO

Here you can see demonstrated, after the line: ‘#ONE_HUNDRED = 100’, all the constants are then
enumerated from ‘100’
...


3

18

Operators
Operators are used to assign values to variables and to manipulate the data that those variables
contain
...
There are also many diagrams showing how
the more advanced operators manipulate data at a binary level
...


An Introduction To Operators
Operators are a set of functions that can perform arithmetic operations on numerical data, boolean
operations on truth values and perform String operations for manipulating strings of text
...
For example, the equals operator (=) can be used to assign
a value to a variable as well as being used as an equality operator to test that two variables or values
are equal
...
First, it can be
used to assign a value to a variable like this:
LongVariable
...
l = 1
If LongVariable = 1
Debug "Yes, LongVariable does equal 1"
EndIf

This is the first time you have seen the ‘If’ keyword but don’t worry
...
In this case, if ‘LongVariable’

Operators

19

equals ‘1’ then echo some text to the Debug Output window
...
First, here is an example of number addition:
NumberOne
...
l = 25
NumberThree
...
Another way to show this might be:
NumberOne
...
l = 50
NumberOne + 25
Debug NumberOne

Once an initial value is assigned to ‘NumberOne’ we can use the plus operator to add another value to
it, so now the number echoed to the Debug Output window is ‘75’
...
s = "Mary had a"
StringTwo
...
s = StringOne + StringTwo
Debug StringThree

The word concatenate basically means to chain or join together and that’s exactly what we are doing
with these two Strings
...
This is another way:
StringOne
...
s = "Mary had a"
StringOne + " little lamb"
Debug StringOne

20

Operators

This works kind of like the numeric shortcut but instead of adding the value numerically, the second
String is joined to the existing String variable
...
Unlike the addition operator, the minus operator cannot work with Strings
...
l = 50
NumberTwo
...
l = NumberOne - NumberTwo
Debug NumberThree

The text echoed to the Debug Window should be ‘25’ which is ‘NumberTwo’ subtracted from
‘NumberOne’
...
l = 50
NumberOne - 10
Debug NumberOne

Here ‘NumberOne’ is assigned the value of ‘50’ then ‘NumberOne’ is decremented by ‘10’ using the
minus operator
...

* (Multiplication)
The multiplication operator is used to multiply two values together and like the minus operator cannot
work with Strings
...
l = 5
NumberTwo
...
l = NumberOne * NumberTwo
Debug NumberThree

The debug output should be ‘125’ because in this example we’ve multiplied ‘NumberOne’ by
‘NumberTwo’ (5*25=125)
...

NumberOne
...
The new value of ‘NumberOne’ (150) is then echoed to the Debug Output
window
...

You’ve probably guessed how to use it from reading the other examples but here is an example showing
its use anyway:

Operators

21

NumberOne
...
l = 2
NumberThree
...
We then
divide ‘NumberOne’ (100) by ‘NumberTwo’ (2) and store the result (50) in ‘NumberThree’
...
As before a shortcut can be used to
divide a variable by a specified number:
NumberOne
...
Then we echo the result stored in ‘NumberOne’ (10) to the Debug Output window
...
If you are a
little unfamiliar with binary and how PureBasic stores numbers using binary you can refer to Chapter
13 (A Closer Look At Numeric Data Types) where a full explanation is given
...

The bitwise ‘&’ operator tests two values to see if they are both true on a bit by bit basis, if two bits are
compared and are both true (1) then the operator returns true (1) otherwise it returns false (0)
...
Here is a diagram to try to explain
a little better
...
4
In Fig
...
After the
calculation is complete, an end result of ‘69’ is achieved
...
If you look at the right most column (which is the
column associated with the value of ‘1’ in binary) both bits of the two numbers in this column are set
at ‘1’ so the value returned by the ‘&’ operator is ‘1’ (which in PureBasic is true)
...
Remember that when using the ‘&’ operator both bits have to be ‘1’ before the operator will
return ‘1’ otherwise it will return ‘0’
...
In this case the value returned by this calculation is ‘69’
...
4 into code:
NumberOne
...
b = 117
NumberThree
...
The value of
‘NumberThree’ is then echoed to the Debug Output window, which in this case should be ‘69’
...
b = 77
NumberOne & 117
Debug NumberOne

Here ‘NumberOne’ is assigned the value ‘77’ and then in the next line we ‘&’ the value ‘117’ to
‘NumberOne’
...

Fig
...


‘&’ (Bitwise AND) Bit Comparison
Left Hand Side

Right Hand Side

Result

0

0

0

0

1

0

1

0

0

1

1

1

Fig
...
This applies to all bits within the two numbers that are to be compared
...
6
In Fig
...
After the
calculation is complete, an end result of ‘118’ is achieved
...
If you look at the right most column (which is
the column associated with the value of ‘1’ in binary) both bits of the two numbers in this column are
set at ‘0’ so the value returned by the ‘|’ operator is ‘0’ (false)
...
If we look
at the fifth column from the right you will see that the first number has a bit which is set at ‘1’ and the
second number has a bit which is set at ‘0’
...
The ‘|’ operator will always
return true, unless both bits are ‘0’
...
6 starting from the right to the left and when
finished the resulting number is returned
...

Here is an example to translate Fig
...
b = 54
NumberTwo
...
b = NumberOne & NumberTwo
Debug NumberThree

In this small example two variables are assigned numbers that are to be evaluated using the ‘|’ operator
and the variable ‘NumberThree’ contains the result of this calculation
...
Just like the other
operators the bitwise ‘|’ operator can be used as a shortcut if you just need to ‘|’ a number to a single
variable:
NumberOne
...
This value is then echoed to the Debug Output window
...
7 shows the comparison made between two bits and the result given by the ‘|’ operator
...
7
! (Bitwise XOR)
The bitwise ‘!’ operator tests two values to see if one of them is true on a bit by bit basis, if the two bits
are compared and either one is true (1) then the operator returns true (1) otherwise it returns false (0)
...
Here is a diagram to try to
explain a little better:

The ‘!’ (Bitwise XOR) Operator
False

True

True

False

True

True

False

False

Binary Value of 38

0

0

1

0

0

1

1

0

Binary Value of 74

0

1

0

0

1

0

1

0

Result value of 108

0

1

1

0

1

1

0

0

!

8 bit number
(1 byte)

Fig
...
8 you can see the two numbers to be evaluated using the ‘!’ operator are ‘38 and ‘74’
...
To explain how this value is achieved you
need to look at each column of bits from the top down again
...
If we move one column along
to the left we can see that both bits of the two numbers are both ‘1’, so the ‘!’ operator still returns ‘0’

Operators

25

(false)
...
If both bits are set to ‘1’ or ‘0’ then the ‘!’ operator will return ‘0’ (false)
...
8 starting from the right to the left and when
finished the resulting number is returned
...

Here is an example to translate Fig
...
b = 38
NumberTwo
...
b = NumberOne ! NumberTwo
Debug NumberThree

In this small example two variables are assigned numbers that are to be evaluated using the ‘!’ operator
and the variable ‘NumberThree’ contains the result of this calculation
...

Just like the other operators the bitwise ‘!’ operator has a shortcut if you just need to ‘!’ a number to a
single variable:
NumberOne
...
This value is then echoed to the Debug Output window
...
9 shows the comparison made between two bits and the result given by the ‘!’ operator:

‘!’ (Bitwise XOR) Bit Comparison
Left Hand Side

Right Hand Side

Result

0

0

0

0

1

1

1

0

1

1

1

0

Fig
...

The bitwise ‘~’ operator is known as an Unary operator meaning that it uses one value or expression
to return a value
...
b = 43
NumberTwo
...
This value
(which should be ‘-44’) is then echoed to the Debug Output window
...
10
In Fig
...
To understand better how numbers are represented in binary within PureBasic, especially
negative (signed) numbers, see chapter 13 (A Closer Look At Numeric Data Types)
...
As their name suggests they shift all bits to the left or right depending on which operator is used
...
b = 50
NumberTwo
...
Then we create a variable called
‘NumberTwo’ and assign it the value of ‘NumberOne’ which has been bit shifted to the left by one
place
...
You
can understand the function of this operator more clearly looking at Fig
...

As you can see the resulting value simply has its binary digits (bits) shifted to the left from their
original position, in this case by one place
...


Operators

27

The ‘<<’ (Bit Shift Left) Operator
Binary Value of 50

0

0

1

1

0

0

1

0

Result value of 100

0

1

1

0

0

1

0

0

Bits shifted 1 place to the left

8 bit number
(1 byte)

Fig
...
Here is
some code demonstrating the use of the ‘>>’ operator:
NumberOne
...
b = NumberOne >> 1
Debug NumberTwo

In this example we assign ‘NumberOne’ the value of ‘50’
...
This resulting value (which should be ‘25’) is then echoed to the Debug Output window
...
12
As you can see the resulting value simply has its binary digits (bits) shifted to the right from their
original position, in this case by one place
...

If the number is a positive number, the left most bit (sometimes called the most significant bit) is set
to zero
...
If the source number is a negative
(signed) number then the left most bit will be one
...

The bits on the right will be shifted ‘off the end’ of the number (in this case a Byte) and will be lost
forever
...
If the value on the left hand
side of this operator is less than the value on the right hand side then this operator will return true (1)
otherwise it will return false (0)
...
l = 1
NumberTwo
...
If we change the value of ‘NumberOne’ to ‘3’, like this:
NumberOne
...
l = 2
If NumberOne < NumberTwo
Debug "1: NumberOne is less than NumberTwo"
Else
Debug "2: NumberTwo is less than NumberOne"
EndIf

We now see in the Debug Output window that the second debug statement has been executed because
now ‘NumberOne’ is no longer less than ‘NumberTwo’
...
If the value on the left hand
side of this operator is more than the value on the right hand side then this operator will return true
(1) otherwise it will return false (0)
...
l = 2
NumberTwo
...
If we change the value of ‘NumberOne’ to ‘0’, like this:

Operators

29

NumberOne
...
l = 1
If NumberOne > NumberTwo
Debug "1: NumberOne is more than NumberTwo"
Else
Debug "2: NumberTwo is more than NumberOne"
EndIf

We now see in the Debug Output window that the second debug statement has been executed because
now ‘NumberOne’ is no longer more than ‘NumberTwo’
...
If the value on the left hand
side of this operator is less than or equal to the value on the right hand side then this operator will
return true (1) otherwise it will return false (0)
...
l = 0
NumberTwo
...
If we change the value of ‘NumberOne’ to ‘1’ then
the ‘If’ statement will still return true (1) because ‘NumberOne’ is still less than or equal to
‘NumberTwo’
...
This is achieved easily by making sure the value
of ‘NumberOne’ is NOT less than or equal to the value of ‘NumberTwo’, like this:
NumberOne
...
l = 1
If NumberOne <= NumberTwo
Debug "1: NumberOne is less than or equal to NumberTwo"
Else
Debug "2: NumberOne is NOT less than or equal to NumberTwo"
EndIf

>= (More than or equal to)
The ‘>=’ operator is used in comparisons of two variables or expressions
...
Here is a code snippet demonstrating its usage:
NumberOne
...
l = 1
If NumberOne >= NumberTwo
Debug "1: NumberOne is more than or equal to NumberTwo"
Else
Debug "2: NumberOne is NOT more than or equal to NumberTwo"
EndIf

Here in the ‘If’ statement we test to see if ‘NumberOne’ is more than or equal to ‘NumberTwo’, which
of course it is, so the first debug statement is executed
...

To demonstrate the second debug statement being executed we have to make sure that the ‘If’
statement is given a false result from the ‘>=’ operator
...
l = 0
NumberTwo
...
If the value on the left
hand side of this operator is not equal to the value on the right hand side then this operator will return
true (1) otherwise it will return false (0)
...
l = 0
NumberTwo
...
If we change the value of ‘NumberOne’ to ‘1’, like this:
NumberOne
...
l = 1

Operators

31

If NumberOne <> NumberTwo
Debug "1: NumberOne does not equal NumberTwo"
Else
Debug "2: NumberOne does equal NumberTwo"
EndIf

We now see in the Debug Output window that the second debug statement has been executed because
‘NumberOne’ is now equal to ‘NumberTwo’ and the ‘<>’ operator returns false
...

The ‘And’ operator is used for checking two expressions to make sure both evaluate as true
...
s = "The quick brown fox"
NumberOne
...
Because both do so
the ‘And’ operator returns true and the first debug statement is executed
...
This operator is optimized in such a way that if the first of the expressions
return a false result then the ‘And’ operator immediately returns false and doesn’t bother to evaluate
the next expression
...

Not (Logical NOT)
The ‘Not’ operator is used to perform a logical negation on an expression or a boolean value
...
See this example:
One
...
l = 2
If Not One = 5
Debug "1: One = 5 is evaluated as true (1)"
Else
Debug "2: One = 5 is evaluated as false (0)"
EndIf

32

Operators

If Not Two = 2
Debug "1: Two = 2 is evaluated as true (1)"
Else
Debug "2: Two = 2 is evaluated as false (0)"
EndIf

We can see here that the first ‘If’ statement is testing to make sure that the Long variable, ‘One’ equals
‘5’ which it doesn’t and the expression returns false
...
Opposite values are shown in the second ‘If’
statement
...

Or (Logical OR)
The ‘Or’ operator is used for checking two expressions to make sure one or the other evaluate as true
...
s = "The quick brown fox"
NumberOne
...
You will notice that
the second expression in the ‘If’ statement actually returns false because ‘NumberOne’ does not equal
‘100’
...
The ‘Or’ operator will only return a false result if both expressions on the right
and left hand side return a false result themselves
...
This is handy when you want to write code that runs very
quickly
...
Look
at this piece of code:
StringOne
...
l = 105
If StringOne = "The quick brown fox" XOr NumberOne = 105
Debug "1: Only one expression is true (1)"
Else
Debug "2: The expressions are either both true (1) or both false (0)"
EndIf

Operators

33

The ‘If’ statement is testing both expressions using the ‘XOr’ operator to make sure only one
expression is evaluating as true
...
If this example was
changed to make sure only one expression returned a true value, then the ‘If’ would return true and
execute the first debug statement
...
Here is an example:
NumberOne
...
In which there are two ‘8’s in ‘20’, this
leaves ‘4’ as a remainder
...
We then
echo this value to the Debug Output window
...
They are used
to determine the execution order of nested expressions
...
In the case of nested brackets the inner-most set is
evaluated first, then the next set and so on until the final set is reached
...
l = 2 * 5 + 3
Debug NumberOne

Here the value of ‘NumberOne’ is ‘13’ because the order of evaluation is, ‘2 * 5’ then ‘+ 3’, if we add
brackets like this:
NumberOne
...


Operator Precedence
Operator precedence is a term that means the order in which operators are evaluated during compile
time
...
13 you can see the order in which operators are evaluated based on their
individual priority
...


34

Operators

Operator Precedence
Priority*

Operators

1

(

2

~

3

<<

>>

4

|

&

5

*

/

6

+

-

7

>

8

And

)

%

!

>=

<

<=

Or

Not

XOr

* The operators at the top of this list are evaluated first
...
13

In this example:
Debug 3 + 10 * 2

the multiplication operator is evaluated first before the addition operator because it has a greater
priority even though it appears after the addition operator in this expression
...

To customize the operator precedence, use brackets to encapsulate portions of code to make them
execute with a higher priority
...


Expression Notes
When PureBasic’s compiler evaluates an expression between Integers and Floats, it sometimes
changes the data type of the expression’s components to evaluate it properly
...
Fig
...


Operators

35

If you find that strange results are being returned from operators or expressions or that the number
returned is not of the expected type, it’s a good idea to re-check the expression to make sure the
compiler is not following these rules
...
l = b
...
l

‘b’ and ‘c’ both remain as a Long before and during evaluation, a Long is then returned and assigned to ‘a’
...
l = b
...
f

Because this expression contains a Float, ‘b’ is converted to
Float before the evaluation
...


a
...
l + c
...
The resulting Long returned by the addition operator is
then converted to a Float and assigned to ‘a’
...
l = b
...
f

‘b’ and ‘c’ both remain as a Float before and during evaluation
...


Fig
...
This can be used in two ways
...
The second way is when
the result of the operator is used in an expression to test whether the values of the expression on the LHS and the RHS are the same (if they are the
same the equals operator will return true, otherwise it will return false)
...
Gives a result of the value of the expression on the RHS added to the value of the expression on the LHS
...


-

Minus
...
When there is no expression on the LHS this
operator gives the negative value of the value of the expression on the RHS
...
(This operator cannot be used with strings)
...
Multiplies the value of the expression on the LHS by the value of the expression on the RHS
...
(This operator
cannot be used with strings)
...
Divides the value of the expression on the LHS by the value of the expression on the RHS
...
(This operator cannot be used
with strings)
...
You should be familiar with binary numbers when using this operator
...
Additionally, if the result of the operator is not used and there is a variable on
the LHS, then the result will be stored directly in that variable
...


|

Bitwise OR
...
The result of this operator will be the value of the expression on the
LHS OR’ed with the value of the expression on the RHS, bit for bit
...
(This operator cannot be used with strings)
...
You should be familiar with binary numbers when using this operator
...
Additionally, if the result of the operator is not used and there is a variable on
the LHS, then the result will be stored directly in that variable
...


~

Bitwise NOT
...
The result of this operator will be the NOT’ed value of the
expression on the RHS
...
e
...
(This operator cannot be used with strings)
...
This is used to compare the values of the expressions on the LHS and RHS
...


>

More than
...
If the value of the expression on the LHS is more than the
value of the expression on the RHS this operator will give a result of true, otherwise the result is false
...
This is used to compare the values of the expressions on the LHS and RHS
...


>=

More than or equal to
...
If the value of the expression on the LHS is more
than or equal to the value of the expression on the RHS this operator will give a result of true, otherwise the result is false
...
This is used to compare the values of the expressions on the LHS and RHS
...


And

Logical AND
...
If the value of the expressions on the LHS and the RHS are
both true then the result is true, otherwise the result is false
...
This is used to compare the values of the expressions on the LHS and RHS
...


Not

Logical NOT
...
In other words if an expression returns a true value, using the Not operator
can invert this value to a false
...


XOr

Logical XOR
...
If only one of the expressions on the LHS or the RHS is
evaluated as true then the result is true
...


<<

Arithmetic shift left
...
Additionally, when the result of this operator is not used and the LHS contains a variable, that variable will have its value shifted by the amount
on the RHS
...


>>

Arithmetic shift right
...
Additionally, when the result of this operator is not used and the LHS contains a variable, that variable will have its value shifted by the
amount on the RHS
...


%

Modulo
...


()

Brackets
...
Expressions in brackets are evaluated
first before any other part of the current expression
...


RHS = Right hand side

LHS = Left hand side

Fig
...
These are major parts of any program
and help define the program flow
...
I then move on to conditional statements such as ‘If’ and ‘Select’ which are used to tell
the program how to proceed when a particular condition is met
...
As always full
explanations are given along with many examples
...
George Boole was a mathematician and philosopher who invented
a form of algebra now called Boolean algebra
...
This form has grown to be the basis of all modern computer
arithmetic
...
These two values (or
states) are tested using logic operations to determine a result
...
The three
most basic logic operations were (and still are) AND, OR and NOT
...
(You can see these logical operators implemented in PureBasic
and read how to use them in Chapter 3)
...
2 and Fig
...
So in PureBasic to express a true or false value we use numbers
...
If you are using
these numeric values to represent true and false, then it would be a good idea to use PureBasic’s builtin constants instead, to make your program code easier to read and understand later on
...

Nearly all commands in PureBasic return a value
...
These values are returned to be
tested if needed and sometimes they are required to make sure certain actions take place
...
Here I’m testing to make sure my window has
been created
...
If, however, it
has not been created, then I end the program after informing the user something went wrong
...

This is a first glimpse of the value of having true and false tests
...


The ‘If’ Statement
An ‘If’ keyword is used to construct statements which effect the flow of the program
...
Sometimes when programs are running, you
may get unusual input or errors and is nice to be able to direct the flow of the program to handle such
things, if and when they occur
...
If it doesn’t receive this true value,
then it will execute another separate piece of code immediately after the ‘Else’ keyword further along
in the statement
...

a
...
It does, and returns a true value, so the
first line after the ‘If’ keyword is executed
...
To finished the ‘If’ statement off, you must use the ‘EndIf’
keyword, as this defines the end of the ‘If’ statement
...
While this is correct, ‘If’
statements are a special case regarding what they recognized as true
...

This is handy when using an ‘If’ statement to test if a variable, command or expression returns any value
other than ‘0’
...
This expression is being tested to see if it evaluates as true
...
The ‘Else’ keyword is also completely optional and
is only used here to present a complete example
...
l = 5
If a = 5
Debug "A true value was found"
EndIf

The only drawback with this smaller example is that it doesn’t provide any feedback when a false result
is encountered
...

Let’s look at a simple ‘If’ statement to test to see if a variable has a value
...
l = 5
If Beads
Debug "The variable has a value"
Else
Debug "The variable does not have a value"
EndIf

Here, after the ‘If’ keyword I have used just one variable as the expression to test
...
The value is not ‘0’, so it is considered true (See
the info box ‘Everything Is True?’) and the relevant piece of code is executed
...


40

Conditional Statements And Loops

Let’s take a look at a more complicated example of an expression inside an ‘If’ statement
...

Value1
...
l = 5
Value3
...
As you can see the expressions that can be tested can be quite complicated
and be very specific about what values you are testing for
...
The ‘ElseIf’ keyword,
as its name suggests, is a combination of ‘Else’ and ‘If’
...
However, unlike the
‘Else’ keyword, it will execute an alternative piece of code only if the ‘ElseIf’ conditional expression
evaluates as true
...
l = 10
If NumberOfBeads < 5
Debug "The variable
ElseIf NumberOfBeads
Debug "The variable
Else
Debug "The variable
EndIf

has a value below '5'"
> 5
has a value above '5'"
has a value of '5'"

Here we test the value of the ‘NumberOfBeads’ variable
...
Because this returns false the program then moves onto the ‘ElseIf’ part
...

The ‘ElseIf’ statement is a great way to extend an ‘If’ to check for multiple values and there is an
unlimited number of ‘ElseIf’ checks you can make within an ‘If’ statement
...
When a great deal of checks are needed sometimes a ‘Select’
statement is preferred
...
Because of this behavior some care is needed
when designing an ‘If’ statement
...


The ‘Select’ Statement
‘Select’ statements are a direct complement to ‘If’s
...
While ‘If’s are very powerful
in what they do, sometimes it’s better to use a ‘Select’ when things are starting to get complicated and
a great deal of conditions are needed to be tested for
...

Days
...
The ‘Case’ keywords that follow are branches that
could potentially be executed should the value of ‘Days’ be equal to the variable or expression following
that particular ‘Case’ statement
...

You will notice that in the last place where there would normally be a ‘Case’ statement, there is another
keyword named ‘Default’
...

Checking For Multiple Values
‘Select’ statements can check for lots of different values and can be neatly presented to produce clear
concise code
...
Here is an example:
Weight
...
Using the ‘To’ keyword to
specify a range or specify several numbers in one ‘Case’ statement using commas
...
In this example
I’ve used numbers but these can be replaced by expressions or variables for more precise handling of
the potential values that the selected variable or expression might have
...
Official PureBasic Home")
PrintN("2
...
PureArea
...
s = Input()
Select Destination
Case "1"
RunProgram("http://www
...
com")
Case "2"
RunProgram("http://forums
...
com")
Case "3"
RunProgram("http://www
...
net")
EndSelect
EndIf
End

In this example I’ve used a few new commands that you will not be familiar with but I think this simple
program neatly demonstrates one use of the ‘Select’ statement
...

The main thing to notice about this example is that the ‘Select’ statement is testing the ‘Destination’
variable
...
The ‘Case’ statements are then also defined using Strings to match correctly
the variable’s value
...

As a side note, you can also see in this last example that I’ve used an ‘If’ statement to test that
‘OpenConsole()’ returns true and correctly opens a console window
...
All programs that use graphical
user interfaces employ loops to manage the drawing of the interface and to continuously monitor for
input from the user
...
Loops are also a great way of processing large
amounts of data within arrays or linked lists by iterating through them, one element at a time
...
These loops, sometimes called ‘For/Next’ loops, are a great way of looping through
data when you need an incrementing variable available to be used as a counter or as an index for an
individual element of a looping array
...

For x
...
A user defined Long variable must be
entered immediately following this keyword, which in this example I’ve called ‘x’
...
After this variable assignment
the ‘To’ keyword is used to define a range, so I’ve entered ‘10’ as the upper limit that ‘x’ should reach
during our loop
...
We do this using the line ‘Next x’
...

The code between these two lines is repeated in a loop depending on how many steps there are
between the start and end value in the range specified
...

You will notice if you run the above example, the Debug Output window shows the different values that
‘x’ has during the loop
...

Here’s another example of using a loop to easily traverse an array
...
s(3)
Names(0)
Names(1)
Names(2)
Names(3)

=
=
=
=

"Gary"
"Sara"
"Stella"
"MiniMunch"

For x
...
As you can see from the last example, it just takes three lines of code to echo all of the
array’s element values to the Debug Output window, no matter what size the array
...

‘For’ loops can also be constructed using expressions too:
StartVar
...
l = 10
For x = StartVar - 4 To StopVar / 2
Debug x
Next x

and, of course, loops can be nested if you need to process multi-dimensional arrays:
Dim Numbers
...
The
unique configurability of ‘For’ loops make them powerful to use and extremely useful for looping code
a user defined amount of times
...
Here is
another example:
For x
...
This keyword can only be
used in a ‘For’ loop and this is the only place in the loop that it can be used
...
In this case I’ve used the number ‘2’, this increments the variable ‘x’ by ‘2’ on every
iteration
...

‘ForEach’ Loops
This type of loop is different from all the others in that it only works with linked lists
...
Here is a simple
example
...
s()
AddElement(Shopping())
Shopping() = "Bunch of bananas"
AddElement(Shopping())
Shopping() = "Tea bags"
AddElement(Shopping())
Shopping() = "Cheese"
ForEach Shopping()
Debug Shopping()
Next

In this example after the linked list is defined and a few elements added, I use a ‘ForEach’ loop to echo
the list’s contents to the Debug Output window
...

The loop starts with the ‘ForEach’ keyword followed by the linked list name
...
The code that sits between these two lines is the code that’s
repeated for the length of the linked list
...
A
‘ForEach’ loops works on all type of linked list, even structured linked lists
...

‘While’ Loops
This particular loop uses an expression to determine wether it should start and how long it should
continue
...
After each individual iteration through
the loop, the expression is tested again for a true value, if this expression still returns true, the loop
continues
...
Look at this example:
Monkeys
...
It starts with the ‘While’ keyword, then an expression is used to
control the loop, in this case I’ve used ‘Monkeys < 10’
...
The initial expression checks to see if the variable ‘Monkeys’ is below ‘10’, if it is the loop will
enter and start
...
If you
look at the output in the Debug Output window you will see that when ‘Monkeys’ equals ‘10’ the
expression returns false (because it is no longer less than ‘10’) and the loop ends
...
This can be demonstrated in this example:
Monkeys
...
‘Repeat’ loops begin with the
‘Repeat’ keyword and end in one of two ways
...
I’ll fully explain both ways, starting with
the ‘Until’ keyword
...
l = 0
Repeat
Debug Bananas
Bananas + 1
Until Bananas > 10

Opposite to ‘While’ loops, the controlling expression is at the end of the loop and this is evaluated to
see if it returns false
...
As you can see from
the above example, when ‘Bananas’ value is greater than ‘10’ the loop ends
...
This is demonstrated here:
Bananas
...
Once this expression is evaluated, ‘Bananas’ is greater
than ‘10’ so the expression returns true and the loop ends
...
To construct a continuous loop just use the ‘Forever’ keyword instead

Conditional Statements And Loops

47

of the ‘Until’ keyword and an expression, like this:
Counter
...
Use the ‘Kill Program’ menu command (Menu:Debugger->Kill Program) to exit this example
...
This can cause problems in your programs because these loops can stop everything else
from working until they exit
...

The PureBasic IDE makes this easy for you
...
This not only ends the loop but also quits the whole program straight
away
...
These two
keywords are ‘Break’ and ‘Continue’
...

If the ‘Break’ keyword is used anywhere within any type of loop then that loop is immediately exited
as soon as this keyword is encountered
...
Let’s
have a look at an example of the ‘Break’ keyword:
For x = 1 To 10
If x = 5
Break
EndIf
Debug x
Next x

Here in this ‘For’ loop I’ve prematurely broken out of the loop using the ‘Break’ keyword when ‘x’
equals ‘5’
...
Here is
an example of breaking out of nested loops using the optional level parameter of the ‘Break’ keyword:

48

Conditional Statements And Loops

For x
...

Next up is the ‘Continue’ keyword
...
This is more simple than it sounds:
For x
...
This
jumps out of the loop and continues from the top at the beginning of the sixth iteration where ‘x’ now
equals ‘6’
...

Loops can be used for a variety of things in computer programming, mainly to reduce tedious code and
to iterate quickly through vast amounts of data
...


5

49

Other Data
Structures
In this chapter I’ll explain how to create and use other methods for storing and organizing data, such
as user defined structures, arrays and linked lists
...
As always, full explanations and multiple examples are given
...
Using the ‘Structure’ keyword you are able to define your own structured type and
then assign that type to a variable
...
Confused? Then let’s look at an example of
a structure that contains several fields:
Structure PERSONALDETAILS
FirstName
...
s
Home
...
PERSONALDETAILS
Me\FirstName = "Gary"
Me\LastName = "Willoughby"
Me\Home = "A House"
Debug "First Name: " + Me\FirstName
Debug "Last Name: " + Me\LastName
Debug "Home: " + Me\Home

Here the structure ‘PERSONALDETAILS’ is created using the ‘Structure’ keyword
...

The ‘EndStructure’ keyword is used to define the end of the new structure
...
We assign this structured type in exactly the same way as we
assign any type to a variable, like this:
Me
...
To assign values to the individual
variables (sometimes called fields) within the new ‘Me’ structured variable, we use the ‘\’ character
...
PERSONALDETAILS
Father\FirstName = "Peter"
Debug Father\FirstName

Here in this little example, we create a new structured variable called ‘Father’ with a user defined
structured type of ‘PERSONALDETAILS’
...
We then echo this value to the Debug Output window
...
In applications they can help to
define anything from personal records to window coordinates, in games they can be used to help
define bullets, spaceships along with all associated values
...
In the ‘PERSONALDETAILS’ structure there are defined three field variables of
the String type, each having a size of 4 Bytes (see Fig
...

So the newly declared variable ‘Me’ takes up 12 Bytes (3 x 4 Bytes) in memory
...

Structure PERSONALDETAILS
FirstName
...
s
Home
...


The ‘SizeOf()’ Command
This command returns the size of any structure or defined variable in Bytes
...
This command is invaluable for Windows programming as some Win32 API
functions need the size of a particular structure or variable as a parameter
...


Other Data Structures

51

Inheriting Fields From Another Structure
Structures can also inherit fields from another structure by using the optional ‘Extends’ keyword
...
s
LastName
...
s
EndStructure
Structure FULLDETAILS Extends PERSONALDETAILS
Address
...
s
ZipCode
...
FULLDETAILS
User\FirstName = "John"
User\LastName = "Smith"
User\Home = "A House"
User\Address = "A Street"
User\Country = "UK"
User\ZipCode = "12345"
Debug
Debug
Debug
Debug
Debug
Debug

"Users
"Users
"Users
"Users
"Users
"Users

First Name: " + User\FirstName
Last Name: " + User\LastName
Home: " + User\Home
Address: " + User\Address
Country: " + User\Country
Zip Code: " + User\ZipCode

In this example the ‘FULLDETAILS’ structure is extending the ‘PERSONALDETAILS’ structure
during its creation, inheriting all the fields from the ‘PERSONALDETAILS’ structure
...
We assign this newly created structured type to the variable ‘User’,
then proceed to assign values to all its fields
...

Structure Unions
Structure unions are a way of conserving memory by forcing groups of variables within a structure to
share the same memory address
...
You may want to read Chapter 13 (Pointers) to understand
better how unions work
...
l
Two
...
l
EndStructureUnion
EndStructure

52

Other Data Structures

Debug SizeOf(UNIONSTRUCTURE)
UnionVariable
...

When we run this small program, the first debug statement echoes ‘4’ (Bytes) to the Debug Output
window
...

Further on in the program we assign the ‘UnionVariable’ the type of ‘UNIONSTRUCTURE’ and assign
the value of ‘123’ to ‘UnionVariable\One’, then it’s echoed
...

Structures can also contain what are known as Static Arrays but I’ll need to explain Arrays before we
can apply that knowledge to structures
...


Arrays
In PureBasic, An Array can hold a user defined amount of variables of the same data type
...
Arrays can also be defined to contain structured variables instead of the standard PureBasic
variable types
...

The ‘Dim’ Keyword
Arrays in PureBasic are created by using the ‘Dim’ keyword, like this example:
Dim LongArray
...
Then we give this new array a name, In this case, I’ve imaginatively
called it ‘LongArray’
...
Here I’ve used the ‘
...
After
the type is defined then we have to define how many indices this array is to hold
...
In the above example we’ve used a ‘2’ to define the last index, so this
actually gives our new array three indices, this is because array indices always start at zero
...


Other Data Structures

53

This simple array is sometimes referred to as a One Dimensional array because it requires only one
index to assign and return all values within it
...
l(2)
LongArray(0) = 10
LongArray(1) = 25
LongArray(2) = 30
Debug LongArray(0) + LongArray(1)
Debug LongArray(1) * LongArray(2)
Debug LongArray(2) - LongArray(0)

After the values are assigned, we then echoed some tests to the Debug Output window using the values
stored in the array indices
...
The results of ‘25 * 30’ and ‘30 - 10’ are then echoed too
...

LastIndex
...
l = 0
Dim StringArray
...
s’ suffix
attached to the array name while using the ‘Dim’ command)
...
Then we used the variable ‘FirstIndex’ to assign a String to the first
index of the array and in later assignments we use an expression using the addition operator
...
See Fig
...


One Dimension String Array
Index

Value

0

One is one and all alone

1

Two, two, the lily-white boys

2

Three, three, the rivals

Fig
...
Just to wet your appetite, here is an example of an array with a thousand indices
having each index assigned a value using a ‘For’ loop and then each index’s value is echoed to the
Debug Output window using a second ‘For’ loop
...
l(999)
For x = 0 To 999
TestArray(x) = x
Next x
For x = 0 To 999
Debug TestArray(x)
Next x

Run it and take a look at the Debug Output window
...

Multi-dimensional Arrays
The best way of describing multi-dimensional arrays are in terms of tables holding columns and rows
...
In the following example, we will create an array called ‘Animals’ which contains three indices,
each of which contain a further three indices
...
s(2, 2)
Animals(0, 0) = "Sheep"
Animals(0, 1) = "4 Legs"
Animals(0, 2) = "Baaa"
Animals(1, 0) = "Cat"
Animals(1, 1) = "4 Legs"
Animals(1, 2) = "Meow"
Animals(2, 0) = "Parrot"
Animals(2, 1) = "2 Legs"
Animals(2, 2) = "Screech"
Debug Animals(0, 0) + " has " + Animals(0, 1) + " And says " + Animals(0, 2)
Debug Animals(1, 0) + " has " + Animals(1, 1) + " And says " + Animals(1, 2)
Debug Animals(2, 0) + " has " + Animals(2, 1) + " And says " + Animals(2, 2)

After defining the array, we then assign values to its indices
...
Two
dimensional arrays can easily be understood by representing them in a two dimensional table
consisting of rows and columns
...
17 shows the ‘Animals’ array in a similar way that Fig
...
It shows the rows and columns that can be accessed using two indices required
by a two dimensional array
...
17
Using Fig
...
For example, if I want to echo the value of row index ‘1’ and column index ‘2’ to the Debug
Output window, we type:
Debug Animals(1, 2)

This should echo the text ‘Meow’
...
Fig
...
18, notice the modified first row
...
18
Another way to explain Multi-dimensional arrays are that they are arrays within arrays
...
The
number of arrays that are contained within each index of the first dimension is dependent on how the
array was first defined
...
s(5)
Animals
...
s(2,
Animals
...
s(2,

4)
5, 3)
5, 4, 5)
3, 6, 2, 3)

After two dimensions, things start to get a little hard on your head, but if you keep in mind, the array
within an array explanation, you should be able to work things out
...

Structured Type Arrays
Until now we have seen how to define different arrays using only the standard PureBasic types but we
can also ‘Dim’ an array using a structure
...
s
Weight
...
s
EndStructure
Dim FishInTank
...
"
FishInTank(0)\Color = "Red, White and Black"
FishInTank(1)\Kind = "Box Fish"
FishInTank(1)\Weight = "1 oz
...
"
FishInTank(2)\Color = "Green"
Debug FishInTank(0)\Kind+" "+FishInTank(0)\Weight+" "+FishInTank(0)\Color
Debug FishInTank(1)\Kind+" "+FishInTank(1)\Weight+" "+FishInTank(1)\Color
Debug FishInTank(2)\Kind+" "+FishInTank(2)\Weight+" "+FishInTank(2)\Color

Here after we define the ‘FISH’ structure we define the array using the ‘Dim’ keyword and use ‘FISH’
as the array’s type in exactly the same way as we used the ‘
...
I’ve
also used ‘2’ as the last index for this array
...
We just amalgamate the syntax of assignment to arrays and structures like this:
FishInTank(0)\Kind = "Clown Fish"

Other Data Structures

57

Let’s break this down into easily understandable chunks
...
Then comes the current index contained within brackets in this case, index ‘0’
...
We then use the ‘=’ operator to assign a String value to that field
...
To assign or retrieve any of
the other fields we just use their names:
Debug FishInTank(1)\Kind
Debug FishInTank(1)\Weight
Debug FishInTank(1)\Color

Here we echo all the different fields to the Debug Output window of index ‘1’
...
19 for a graphical representation of the ‘FishInTank’ array
...


Colour: Red, White and Black

1

Kind: Box Fish

Weight: 1 oz
...


Colour: Green

Fig
...
This gives you access to the unique fields of a structure within every index available inside
multi-dimensional arrays
...


58

Other Data Structures

Here is an example of how to define a two dimensional structured type array:
Structure FISH
Kind
...
s
Color
...
FISH(2, 2)

...

Instead refer to Fig
...


Two Dimension Structured Type Array
Index

0

1

2

0

Kind: Clown Fish
Kind: Box Fish
Weight: 4 oz
...

Colour: Red, White and Black Colour: Yellow

Kind: Sea Horse
Weight: 2 oz
...

Colour: Red

Kind: Angel Fish
Weight: 4 oz
...

Colour: Pink

2

Kind: Gold Fish
Weight: 2 oz
...

Colour: Black and White

Kind: Shark
Weight: 1 lb
...
20
To retrieve a value from this kind of array we need to supply two indices and a field name such as this:
Debug FishInTank(1, 1)\Kind

which would echo the text ‘Angel Fish’ to the Debug Output window
...

FishInTank(1, 1)\Color = “Dark Red”

This would change all fields of the ‘FISH’ structure located in the middle area in the array located at
indices ‘1, 1’
...
21
...


Other Data Structures

59

Two Dimension Structured Type Array (Modified)
Index

0

1

2

0

Kind: Box Fish
Kind: Clown Fish
Weight: 1 oz
...

Colour: Red, White and Black Colour: Yellow

1

Kind: Parrot Fish
Weight: 5 oz
...

Colour: Dark Red

Kind: Shrimp
Weight: 1 oz
...

Colour: Orange

Kind: Lion Fish
Weight: 8 oz
...

Colour: Grey

Kind: Sea Horse
Weight: 2 oz
...
21
You will probably only use one dimensional structured type arrays in your programs for now but to
know how multi-dimensional structured type arrays work will give you a good understanding of more
advanced code
...
The first way is to use the ‘Dim’ command again which redefines the array but in the process
destroys all previous data assigned to it
...
Here are examples showing both these behaviors
...
s(2)
Dogs(0) = "Jack Russell"
Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"
Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)
Dim Dogs
...
After the second definition, you will
notice that the ‘Debug’ commands return nothing from the newly defined array
...
This data destruction can have a good use though
...
When redefining arrays like this
you must always redefine them using the same type or an error will be raised
...
s(2)
Dogs(0) = "Jack Russell"
Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"
For x
...
s(4)
Dogs(3) = "Yorkshire Terrier"
Dogs(4) = "Greyhound"
For x
...
The extra two indices (‘3’ and ‘4’) are assigned data and then the whole array
has its data echoed to the Debug Output window
...
You must be aware though, if I used the ‘ReDim’ command to redefine an array with fewer indices
than it previously had then of course the data within the discarded indices are lost
...
This is standard behavior for a Basic command such as this
...
These
rules should be observed when using arrays in your programs
...
If an array is re-defined using the ‘Dim’ command, its previous data is lost
...
If an array is re-defined using the ‘ReDim’ command, its previous data is kept
...
Arrays can only be made up of one type of variable (a structured or a standard variable type)
...
Arrays can be Global, Protected, Static and Shared
...

5)
...

6)
...

7)
...

8)
...

9)
...


Other Data Structures

61

Static Arrays Within Structures
Static arrays within structures are a little bit different from the normal arrays that have been
previously described
...
These types of arrays also only exist within structures
...
Once a static array is defined its internal structure cannot be modified
...
Static arrays (like structures) cannot be redefined
...
They can only be made up of one type of variable (a structured or a standard variable type)
...
The size of an array is only limited by the current machine’s installed RAM
...
Static arrays can only have one dimension
...
They can be dynamically defined, using a variable or an expression to define dimension size
...
When defining dimension size, you define the amount of indices it is to contain, not the last index
...
Static arrays can only be accessed through the structure variable within which they are defined
...
s
Mother
...
s[2]
Surname
...
FAMILY
Family\Father = "Peter"
Family\Mother = "Sarah"
Family\Children[0] = "John"
Family\Children[1] = "Jane"
Family\Surname = "Smith"
Debug
Debug
Debug
Debug
Debug

"Family Members:"
Family\Father + " " + Family\Surname
Family\Mother + " " + Family\Surname
Family\Children[0] + " " + Family\Surname
Family\Children[1] + " " + Family\Surname

Here in this example, the ‘FAMILY’ structure has a field called ‘Children’ which is a static String array
...
This defines this static array will hold two indices
...
In our new static array we now have two indices, ‘0’ and ‘1’, further on in the example I assign
values to all the fields in the ‘Family’ structured variable, including the two indices in the ‘Children’
static array
...


62

Other Data Structures

Assigning data to a static String array (using square brackets):
Family\Children[0] = "John"

Assigning data to a standard Long array (using curved brackets):
LongArray(0) = 10

You will also notice that you do not need to use a keyword such as ‘Dim’ when you define a static array
...
Within the square brackets you
define how many indices you wish to give to this newly created static array
...
s
EmployeeClockNumber
...
s
EmployeeContactNumbers
...
EMPLOYEES(9)
Company(0)\EmployeeName = "Bruce Dickinson"
Company(0)\EmployeeClockNumber = 666
Company(0)\EmployeeAddress = "22 Acacia Avenue"
Company(0)\EmployeeContactNumbers[0] = 0776032666
Company(0)\EmployeeContactNumbers[1] = 0205467746
Company(1)\EmployeeName = "Adrian Smith"
Company(1)\EmployeeClockNumber = 1158

...
Inside the ‘EMPLOYEES’ structure I’ve
used a Long static array to store two contact phone numbers
...
’ and then onto ‘Company(1)\
...
I don’t actually
complete this example due to not wanting to waffle on, but you can see where I’m going with it and
how everything works
...
They are
however different to arrays in that they don’t use an index to assign and retrieve data
...
Linked lists are also totally dynamic, meaning that they can grow
or shrink depending on how much data you need them to hold
...

Linked lists are a great way of storing and organizing data of an unknown length and can be sorted in
several ways
...
Inside the built-in ‘Sort’ library there are also two
functions that are used purely for sorting linked lists, I shall mention these later
...

The ‘NewList’ Keyword
Linked Lists in PureBasic are created by using the ‘NewList’ keyword as in this example:
NewList Fruit
...
First we use the
‘NewList’ keyword to tell the compiler we are about to define a linked list
...
After a name has been given we then define its type,
which again in this case is the String type
...
You will
notice in this small example that there are no indices defined within the brackets
...
Let’s look at how we
add elements to our new list, here is a more complete example:
NewList Fruit
...
In the above example, I’ve added two new elements to the
‘Fruit()’ list
...
When you
add a new element using this function, not only does it automatically define a new element but it also
makes the linked list name point to that newly created, empty element
...
First the new element is created, then the linked list name again points to the newly created
empty element
...
When I’m using it here
it must not be confused with the computer science term ‘point’ or ‘pointers’
...
When I use it here, especially when I say the Linked List name points to the current element, I use
it in a descriptive sense and not literally pointing to the area in memory that this element uses
...


You would think that this is wrong because we are assigning the text ‘Apple’ to the same name as we
assigned the text ‘Banana’
...
We can also check how many elements are in our list at any time using
the built-in ‘CountList()’ function, like this:
Debug CountList(Fruit())

If we executed the above code then the number of elements contained within the ‘Fruit()’ list will be
echoed to the Debug Output window
...

Let’s add a few more elements to this list and then echo all of the element values to the Debug Output
window
...
s()
AddElement(Fruit())
Fruit() = "Banana"
AddElement(Fruit())
Fruit() = "Apple"
AddElement(Fruit())
Fruit() = "Pear"
AddElement(Fruit())
Fruit() = "Orange"
ForEach Fruit()
Debug Fruit()
Next

In this larger example, we create a new linked list called ‘Fruits()’ and within it we create four elements
and assign them individual values
...
The ‘ForEach’ keyword is used to define a loop
which is only used for linked lists
...
22 gives a brief overview of the linked list commands available in the built-in ‘Linked List’ library
...
The more advanced commands can be found in the PureBasic helpfile
...


ClearList(List())

Clears the list of all elements
...


DeleteElement(List())

Deletes the current element within the list

FirstElement(List())

Go to the first element in the list
...


LastElement(List())

Go to the last element in the list
...

(Element positions start at ‘0’)
...


PreviousElement(List())

Go to the previous element within the list
...


SelectElement(List(), Position)

Make the current element the one specified by the
‘Position’ parameter
...
22
Structured Linked Lists
Now that I have explained standard linked lists, let’s move onto structured linked lists
...
You can then effectively have a dynamically resizing linked list masquerading as a structured type
array that grows and shrinks depending on what information you have to store
...

Structure FISH
Kind
...
s
Color
...
FISH()

66

Other Data Structures

AddElement(FishInTank())
FishInTank()\Kind = "Clown Fish"
FishInTank()\Weight = "4 oz
...
"
FishInTank()\Color = "Yellow"
AddElement(FishInTank())
FishInTank()\Kind = "Sea Horse"
FishInTank()\Weight = "2 oz
...
The main difference here though is that array style indices are not
used
...
This command then moves the current position
of the list to this newly created element
...
"
FishInTank()\Color = "Red, White and Black"

Because the name ‘FishInTank()’ now points to your new element there is no need to use an index
...
At the end of the
example another ‘ForEach’ loop is used to quickly and efficiently echo the data to the Debug Output
window
...
For example, in
the past I’ve written a program to track household expenses, and used a structured linked list to hold
the details of these expenses
...

While writing this program I thought that I must make this program flexible to handle new expenses
when they occur and to be able to delete old ones, just in-case I buy a new car and/or pay off a loan,
etc
...
When I need to add an entry I use the ‘AddElement()’
function and when I need to delete an entry I use the ‘DeleteElement()’ function
...
I will give talk more extensively about GUIs in Chapter 9
...
This is because
arrays are continuous areas of memory which only use the standard amount of RAM per type for each
index
...
This is because linked lists are not in the same continuous piece of memory
and need to store information on where to find the other elements within RAM
...


Sorting Arrays And Linked Lists
Arrays and linked lists are great for storing all sorts of data and these data structures can easily be
traversed to quickly retrieve that data
...
Here are a few
examples of how to use the commands of the ‘Sort’ library (Helpfile:Reference Manual->General
Libraries->Sort) to sort arrays and linked lists
...
First of all you need an array pre-filled with values then
use the ‘SortArray()’ command to sort it
...
The second parameter is an option, to specify how
you would like the array to be sorted
...

‘1’ : Sort the array in descending order being case sensitive
...

‘3’ : Sort the array in descending order without being case sensitive (‘A’ is the same as ‘a’)
...
These last two parameters are used to specify an array position
range to perform the sort within
...
s(3)
Fruit(0) = "Banana"
Fruit(1) = "Apple"
Fruit(2) = "Pear"
Fruit(3) = "Orange"
SortArray(Fruit(), 0)

68

Other Data Structures

For x
...
Here is the syntax example:
SortStructuredArray(Array(), Options, Offset, Type [, Start, End])

The first parameter is the array name complete with brackets
...
The third parameter is an offset (a position within the
originating structure) of the field you would like to sort by
...
The ‘OffsetOf()’ command returns the number of Bytes that a particular variable field is
offset, from the beginning of a structure
...
You can use built-in constants for the forth parameter to describe what
type of variable you are sorting by, these are:
‘#PB_Sort_Byte’
‘#PB_Sort_Character’
‘#PB_Sort_Word’
‘#PB_Sort_Long’
‘#PB_Sort_Quad’
‘#PB_Sort_Float’
‘#PB_Sort_Double’
‘#PB_Sort_String’

: The field in the structure to sort by, is a Byte (
...
c)
: The field in the structure to sort by, is a Word (
...
l)
: The field in the structure to sort by, is a Quad (
...
f)
: The field in the structure to sort by, is a Double (
...
s or $)

The last two parameters in this command are optional and don’t need to be specified when using this
command
...
Using the
above information, we can sort a full structured array in ascending order and sorting by the ‘Range’
field, like this:
Structure WEAPON
Name
...
l
EndStructure
Dim Weapons
...
l = 0 To 2
Debug Weapons(x)\Name + " : " + Str(Weapons(x)\Range)
Next x

In this example, I’ve chosen the ‘Range’ field to sort the structured array by, so in the sort command
I’ve defined this using the offset ‘OffsetOf(WEAPON\Range)’ and telling the sort command it is a Long
type variable field by using the ‘#PB_Sort_Long’ constant
...
First of all you need a linked list pre-filled with
values then use the ‘SortList()’ command to sort it
...
The second is the sort options, these are
exactly the same as the ‘SortArray()’ command
...

Using the above information, we can sort a full linked list in ascending order and being case sensitive,
using the sort command like this:
NewList Fruit
...
Here is this command’s syntax example:
SortStructuredList(List(), Options, Offset, Type [, Start, End])

The first parameter is the linked list name complete with brackets
...
The third parameter is an offset (a position
within the originating structure) of the field you would like to sort by
...
The forth parameter defines what type of variable is found at the previously
passed offset
...
The last two
parameters are used to specify a linked list position range to perform the sort within
...
s
Weight
...
GIRL()
AddElement(Girls())
Girls()\Name = "Mia"
Girls()\Weight = "8
...

Sorting Made Easy
All the previous sorting examples can be used in the same way to sort all numeric fields as well as
Strings, it’s just a case of choosing the right sorting option when using the different sort commands
...
Try some examples yourself to practice sorting using these commands
...
Procedures are an essential part of any
programming language and provide a way of neatly structuring code and enabling code re-use
...
I will also mention subroutines in this chapter but these are not a
major feature in many programming languages
...


Why Use Procedures Or Subroutines?
In theory, I guess you never need to use procedures or subroutines
...
Procedures and subroutines provide ways of calling separate
pieces of code at any time during your main code
...
For example, you could call a procedure to play a sound or update a display or even call one
that contains a fully functional program
...
Well structured code is always better for reading later on, especially if you revisit
your code for tweaking, or you are working in a team and many people are likely to work on the same
file
...
Subroutines provide a way of
jumping to another piece of code further down in your source code and then returning to the point of
the jump after executing it
...
This jump destination in your code is specified using a subroutine label
...
After the destination label, you enter normal PureBasic code that you wish this subroutine to
execute
...
l = 10
Debug a
Gosub Calculation
Debug a
End
Calculation:
a = a * 5 + 5
Return

In this example, we give the variable ‘a’ the value of ‘10’ and echo it to the Debug Output window
...
You can tell it’s a label by the colon
after its name and you will probably notice that the IDE colors labels differently too
...
When returning to the main code, we return to the next line just after the
original ‘Gosub’ command
...
This value has now changed according to the calculation performed
in the subroutine
...
The ‘End’ keyword not only immediately
terminates a program when it’s executed but also defines the end point of a program during
compilation
...


Procedures and Subroutines

73

Jumping From A Subroutine
This is generally considered very bad coding practice but as I’m talking about subroutines, I may as
well follow the style of the rest of this book and describe them in their entirety, as well as mentioning
the correct syntax to be able to do it
...
This is achieved by using the ‘FakeReturn’ and ‘Goto’ keywords
...
l = 10
Debug a
Gosub Calculation
Debug a
End
RunAgain:
a
...

This example is pretty straightforward if you follow it carefully
...
We jump to another label (subroutine) called ‘RunAgain’ which references another almost
self-contained program complete with another ‘End’ keyword, which really is not ideal
...
I feel you can
structure code a lot better using procedures
...
PureBasic can be described as a ‘Procedural’ and ‘Structured’ programming language
...
They are quite literally the
structure in structured programming
...
In their most basic form they are just a holder for a piece of code
that can be called (run) at any time in your program, very similar to subroutines
...
Unlike
subroutines however, procedures can be given multiple starting parameters and they can even return
one value of any built-in type
...

Procedure NurseryRhyme()
Debug "Mary had a little lamb, its fleece was white as snow
...
"
EndProcedure
NurseryRhyme()

In order to use a procedure in your code you have to define it first
...
Code is then entered after this line which the
procedure is to contain
...

We can call this piece of code contained within this procedure at any time by just using its name, like
this:
NurseryRhyme()

Before we move on, I need to point out a few things in this example that need further explanation
...
These
are used to hold any parameters that need to be passed to the procedure
...
Also, when you call the
procedure, you always need to include the brackets as part of the procedure call, parameters or no
parameters
...

One more thing to point out is that the procedure name, e
...
‘NurseryRhyme()’ must not contain any
spaces and should adhere to the same naming guidelines as set out for variables
...
If you want to repeat this procedure code at any time in this small
example, just call it over and over again using its name
...
"
Debug "And everywhere that Mary went, that lamb was sure to go
...
l = 1 To 5
NurseryRhyme()
Next x

Procedures can be called from anywhere in programs, as in the above example, where I’ve called the
‘NurseryRhyme()’ procedure from a loop
...

Procedure NurseryRhyme2()
Debug "And everywhere that Mary went, that lamb was sure to go
...
"
NurseryRhyme2()
EndProcedure
NurseryRhyme1()

Here, you can see that ‘NurseryRhyme1()’ contains a call to ‘NurseryRhyme2()’
...
You will
notice that I’ve coded ‘NurseryRhyme2()’ first, above ‘NurseryRhyme1()’
...
Because
‘NurseryRhyme1()’ calls ‘NurseryRhyme2()’, the latter had to be defined first
...
It will raise
an error if it encounters a procedure call and no procedure has yet been defined
...

As with most things in life though there is an exception to this rule
...
The ‘Declare’ keyword doesn’t define a
procedure, it merely lets the compiler know what procedures it will be asked to call
...
Here’s an example:
Declare NurseryRhyme1()
Declare NurseryRhyme2()
NurseryRhyme1()
Procedure NurseryRhyme1()
Debug "Mary had a little lamb, its fleece was white as snow
...
"
EndProcedure

When using the ‘Declare’ keyword, you just define the first line of the procedure, identically as you
would when using the ‘Procedure’ keyword
...
Because this is purely a declaration and not a definition, you must also define the
procedure as normal somewhere else in your code
...

If you look at the above example, you can see I’ve used two declarations using the ‘Declare’ keyword
...
The actual procedure definitions are
at the end of the code
...
This term refers to what scope any given variable, array or linked list is available to be used
in
...

a
...
I’ve also
defined a procedure called ‘DisplayValue()’ and in this procedure I’ve written one line of code to echo
the value of ‘a’
...
Now, if you run this example you
would expect that the value of ‘a’ (which is ‘10’) to be echoed to the Debug Output window but this is
not the case
...
This is due to program scope
...
The first thing to
remember when using variables in PureBasic is that they are by default Local in scope
...
l = 10’ this variable is local to the
scope in which it is defined, in this case, local to the main source code
...

In the ‘DisplayValue()’ procedure we echo the value of ‘a’, but this variable ‘a’ is not the same as the
one outside the procedure
...
The one inside the
procedure is local to the procedure so neither variable is accessible to one another
...

As I said before, if the original variable was made to be a global variable, then all procedures can see
it and use it, let me demonstrate how this is done
...
l = 10
Procedure DisplayValue()
Debug a
EndProcedure
DisplayValue()

Here you will notice the only change I’ve made is that I’ve used the ‘Global’ keyword before the variable
definition
...
In the Debug Output window you will now see the correct value of ‘10’ echoed
...

Take a look at this:
Procedure DisplayValue()
a
...
If we want to see
and use the ‘a’ variable outside the defining procedure, we need to make it global
...
l = 10
EndProcedure
DisplayValue()
Debug a

Reading through these last few examples you may be thinking why not make all variables global? This
might make sense to some people but when programs reach a larger scale, things can get muddled and
confusing if all variables are global
...
Using different scopes within your program also enables you to use temporary variable names
within procedures for calculations or loops, safe in the knowledge that they won’t effect any variables
outside
...
Suspect values and variables can be narrowed down more quickly to a
particular scope if less global variables are used
...
Up until PureBasic v4, all arrays and linked lists were global by default
ensuring they all could always be manipulated by procedures
...
They
even use the same scope keywords
...


The ‘Global’ Keyword
Global Variables
I’ve already given an example of the ‘Global’ keyword while explaining program scope but here it is
again to make this list complete
...
l = 10
Procedure DisplayValue()
Debug a
EndProcedure
DisplayValue()

The ‘Global’ keyword is used before a variable definition to make that variable’s scope global
...
The syntax is very simple as you can see from the above example
...
l(1)
Procedure ChangeValues()
Numbers(0) = 3
Numbers(1) = 4
EndProcedure
ChangeValues()
Debug Numbers(0)
Debug Numbers(1)

In this example, similar to global variables, I’ve used the ‘Global’ keyword in front of the array
definition so I’m able to access it within the procedure
...


Procedures and Subroutines

79

Global Linked Lists
Global Newlist Numbers
...
Without the ‘Global’ keyword in front of the linked list, the
procedure would not be able to see or use it
...
This is very useful for defining temporary variable names
inside procedures or just to make sure procedure variables never interfere with any global variables in
the main code
...
l = 10
Procedure ChangeValue()
Protected a
...
If you run the above
example the result echoed to the Debug Output window will be ‘10’ because even though we call the
‘ChangeValue()’ procedure the protected variable doesn’t alter the global one
...


80

Procedures and Subroutines

Protected Arrays
Global Dim Numbers
...
l(1)
Numbers(0) = 3
Numbers(1) = 4
EndProcedure
ChangeValues()
Debug Numbers(0)
Debug Numbers(1)

In this example we use the ‘Protected’ keyword in exactly the same way as the protected variable
example
...
This keyword is great for protecting arrays within procedures so they never interfere
with the main code even if they have the same name as global arrays
...
l()
AddElement(Numbers())
Numbers() = 1
Procedure ChangeValue()
Protected Newlist Numbers
...
This keyword is great for protecting linked lists within procedures so they never interfere with the
main code even if they have the same name as global linked lists
...
This is when the ‘Shared’ keyword is used
...
l = 10
Procedure ChangeValue()
Shared a
a = 50
EndProcedure
ChangeValue()
Debug a

Here, even though ‘a’ is originally not defined as global, you can still access it from within a procedure
by using the ‘Shared’ keyword
...

Shared Arrays
Dim Numbers
...
When specifying what array you
want to share, you just need to specify the array name along with brackets on the end, like this:
‘Numbers()’, there’s no need for the type suffix, indices or dimensions to be specified
...
l()
Procedure ChangeValue()
Shared Numbers()
AddElement(Numbers())
Numbers() = 100
EndProcedure
ChangeValue()
SelectElement(Numbers(), 1)
Debug Numbers()

82

Procedures and Subroutines

In this example even though the ‘Numbers()’ linked list is not defined as global, I can still access it
from the ‘ChangeValue()’ procedure using the ‘Shared’ keyword, very similar to the shared array
example
...


The ‘Static’ Keyword
Static Variables
Every time a procedure exits, all variable values defined within it are lost
...
See this
example:
Procedure ChangeValue()
Static a
...
l = 1 To 5
ChangeValue()
Next x

Here in the ‘ChangeValue()’ procedure I’ve set the ‘a’ variable to be static by using the ‘Static’ keyword
...
I then
call this procedure five times using a standard ‘For’ loop
...
This is because the value of ‘a’ is remembered between procedure
calls
...

Procedure ChangeValue()
Static Dim Numbers
...
l = 1 To 5
ChangeValue()
Next x

In the above example, I’ve used the ‘Static’ keyword to preserve the array’s values between procedure
calls in exactly the same as static variables
...
This is because the static array’s values have all been preserved between the calls
...
l()
If CountList(Numbers()) = 0
AddElement(Numbers())
EndIf
SelectElement(Numbers(), 1)
Numbers() + 1
Debug Numbers()
EndProcedure
For x
...
If you look at the echoed values they are all different and incremented
by ‘1’
...
If the list has
no elements then I add one, otherwise I just change the value of the existing element within the static
linked list
...


Passing Variables To Procedures
As I mentioned before, one of the most useful abilities procedures possess is that they can accept initial
starting parameters
...

Parameters are used as a way of passing values from the main program into any procedure for
processing
...
This is how you define a procedure to accept parameters:
Procedure AddTogether(a
...
l)
Debug a + b
EndProcedure
AddTogether(10, 5)
AddTogether(7, 7)
AddTogether(50, 50)

All parameters that are to be passed to a procedure should be inside the brackets and if multiple
parameters are needed then they should be separated by commas
...
Here, I’ve defined two parameters, ‘a’
and ‘b’, both of which are Long type variables
...
The procedure then adds these variables together and displays the result in the Debug
Output window
...

Here’s another example using Strings:
Procedure JoinString(a
...
s)
Debug a + b
EndProcedure
JoinString("Mary had a little lamb, ", "its fleece was white as snow
...
")
JoinString("
...
I’ve basically modified the ‘AddTogether(a
...
l)’ procedure and replaced the Long type
parameters with String types and renamed it to ‘JoinString(a
...
s)’
...

Another point to remember regarding procedures is that their parameters don’t have to be all of the
same type, you can mix and match as much as you like
...
b, b
...
l, d
...
s)
Debug "Byte: " + Str(a)
Debug "Word: " + Str(b)
Debug "Long: " + Str(c)
Debug "Float: " + StrF(d)
Debug "String: " + e
EndProcedure
LotsOfTypes(104, 21674, 97987897, 3
...
The values that are passed in the
procedure call are assigned to the defined procedure parameters ‘a’, ‘b’, ‘c’, ‘d’ and ‘e’ respectively
...

You’ve also probably noticed I’ve used two built-in functions that you may not be familiar with
...


Procedures and Subroutines

85

Strictly Passing Values To Procedures
When calling a procedure you must make sure that any defined parameters are called using the correct types
or you will raise a syntax error when compiling
...
l, b
...
If String type variables are defined as parameters
then you must call the procedure using Strings as values for these parameters
...
I know this seems obvious but I think it’s worth pointing out
...
Not only
are they a great timesaver in respect of typing code but they allow programmers to extend the
functionality of PureBasic and then have freedom to use this functionality in any source code from
then on
...

Optional Variable Parameters
A new feature in PureBasic v4 was the inclusion of optional procedure parameters
...

Basically you can set an initial value for any parameter in case it isn’t used on the procedure call
...
l, b
...
l = 3)
Debug a
Debug b
Debug c
EndProcedure
DisplayParameters(1, 2)

If you look at the procedure definition in the above example you will see that the last parameter has
been defined differently to the others and has been given the initial value of ‘3’
...
When I call the procedure
in the above example using ‘DisplayParameters(1, 2)’, missing out the last parameter, then you can see
this default value recognized and used in the echoed output within the Debug Output window
...
You must understand however that
all optional parameters must always appear to the right of standard non-optional parameters
...


86

Procedures and Subroutines

Passing Arrays To Procedures
...
Their usage is simplicity itself and very easy to demonstrate
...
Here
is a simple one dimensional String array defined with four indices (remember that the indices start at
‘0’) I’ve called it ‘Countries’:
Dim Countries
...
s(1))
For x
...
For
starters, you define an array parameter within the same procedure brackets as any other standard
parameter
...

First a name is used to act as the array name within the procedure
...
These brackets usually contain a number
which expresses an array index
...
In the above example I’ve used a one dimensional array, so the
full array parameter looks like this:
MyArray
...

You will notice that I’ve used ‘MyArray’ as the array parameter name, this is not essential and you can
call your parameters whatever you like
...
e
...

Inside this procedure you are now able to use the ‘MyArray()’ as any other normal array, getting and
setting values to and from it using standard indices
...
You can however, be as
creative as you like, in finding ways to process arrays
...
No types, indices or dimensions are necessary when actually passing an array
in a procedure call
...

Passing Multi-dimensional arrays
You can also pass multi-dimensional arrays as parameters as demonstrated in this example:
Dim Countries
...
s(2))
For x
...
You will notice that in this array parameter definition
we use ‘2’ within the brackets to specify that the expected array will be a two dimensional array, like
this:
MyArray
...
You do it exactly as illustrated on
the previous page, you just need change the array parameter type to match the structure used in the
array definition
...
s
Population
...
COUNTRY(3)
Countries(0)\Name = "England"
Countries(0)\Population = "57,000,000"
Countries(1)\Name = "Northern Ireland"
Countries(1)\Population = "2,000,000"
Countries(2)\Name = "Scotland"
Countries(2)\Population = "5,200,000"
Countries(3)\Name = "Wales"
Countries(3)\Population = "3,100,000"
Procedure EchoArray(MyArray
...
l = 0 To 3
Debug MyArray(x)\Name + " - " + "Population: " + MyArray(x)\Population
Next x
EndProcedure
EchoArray(Countries())

Here I’ve used a structured array, defined using the ‘COUNTRY’ structure
...
You can see this parameter for yourself in the above procedure definition:
MyArray
...
If all of this is coded correctly as above, then a one dimensional, ‘COUNTRY’ structured
array will pass into this procedure just fine
...
This
is very similar to passing an array
...
l()
AddElement(Numbers())
Numbers() = 25
AddElement(Numbers())
Numbers() = 50
AddElement(Numbers())
Numbers() = 75
Procedure EchoList(MyList
...
After
adding three elements to this list, I’ve defined the ‘EchoList()’ procedure that this linked list will be
passed into
...
Linked lists don’t
use indices like arrays, so you don’t need to type a number inside the brackets
...
Like
this:
EchoList(Numbers())

Of course inside the ‘EchoList()’ procedure the ‘MyList()’ linked list now contains all of the
information that the passed linked list had and can be used in exactly the same as any other standard
linked list
...

Passing Structured linked lists
Structured linked lists can also be passed easily as procedure parameters
...

Structure FLAGS
Country
...
s
EndStructure
NewList Info
...
FLAGS())
ForEach MyList()
Debug MyList()\Country + "'s flag is the " + MyList()\Flag
Next
EndProcedure
EchoList(Info())

Notice from the above example, the linked list parameter looks like this:
MyList
...


Arrays And Linked Lists Are Passed By Reference
Unlike variables, arrays and linked lists are passed by reference
...
Instead an internal memory
pointer is passed to the procedure and this is used to manipulate the array or linked list
...
The only
thing you need to consider is that when you pass an array or linked list into a procedure, the parameter name
used will not be a separate local array or linked list
...

For example, if you pass an array called ‘Dogs()’ into a procedure as a parameter, this parameter could have
a different name and be called ‘Cats()’ for instance
...
When the procedure exits you will notice that the ‘Dogs()’ array has been modified in
the same way as the ‘Cats()’ array
...

This is only true for arrays and linked lists, variables on the other hand are passed by value, meaning that an
actual value is copied into the variable parameter
...


Procedures and Subroutines

91

Returning A Value From Procedures
Another great feature of procedures is that they can return a value
...
Returning a value from a procedure is a great way to be able to calculate or
manipulate data within a procedure and then return something useful
...
See
Fig
...
3 for a list of types that can be returned by procedures
...
First you need to define what type
is to be returned from the procedure, this is done by slightly extending the procedure definition
...
l AddTogether(a
...
l)
ProcedureReturn a + b
EndProcedure
Debug AddTogether(7, 5)

The above procedure definition has been given a new type suffix on the end of the ‘Procedure’ keyword
...
The above definition has been given
the ‘
...
To actually make the
procedure return a value we need to use the ‘ProcedureReturn’ keyword
...
In this case the resulting value evaluated from ‘a +
b’ is returned
...
In this
case I’ve used it as an expression for a ‘Debug’ statement
...

If we want a procedure to return a String we just switch the return type to ‘
...
As shown here:
Procedure
...
s, b
...
s’ keyword
...
In this new example, I pass two Strings into the procedure, which are then
concatenated and returned from the line ‘ProcedureReturn a + b’
...

Procedures that return values can be used anywhere where expressions are
...
l AddTogether(a
...
l)
ProcedureReturn a + b
EndProcedure
Debug AddTogether(AddTogether(2, 3), AddTogether(4, 1))

Here I’ve used the ‘AddTogether(a
...
l)’ procedure to return values added together from two separate
calls to the same procedure
...
Both of these procedure calls are being used as
parameters within another procedure call
...

Parameters Do Not Affect Return Types
One thing to remember when using procedure return types is that they don’t have to be the same as
defined parameter types
...
s DisplayValue(a
...
s)
ProcedureReturn Str(a) + b
EndProcedure
x = 5
While x >= 0
Debug DisplayValue(x, " green bottles hanging on the wall
...
l, b
...
s’ keyword
...

Return types are very strict though, just as much as variable types
...
You can see this
in action in the above example
...

Limitations Of Returning Results
While using procedures to return results there are however two limitations
...
Meaning that you cannot return two or more values in one procedure call
...
You can only
return built-in PureBasic types
...
See Chapter 13 (Pointers) for an explanation of this technique
...
These range from
String manipulation, to mathematics, to file handling and even graphics commands
...

In this chapter I will introduce and explain the most commonly used built-in commands that
PureBasic has to offer
...

This chapter starts with a description on how to read the command syntax in the PureBasic helpfile
and then moves on to the actual command descriptions and explanations
...


Using The PureBasic Helpfile
Here we will take a proper look at the PureBasic helpfile and I explain how the pages are organized,
how to read them and more importantly, how to use the built-in commands that are described there
...
The syntax portion at the top of each helpfile page is an example of how
the command is actually typed into the IDE and what parameters are expected to be passed to it
...
This is how to navigate to the correct
page: (Helpfile:Reference Manual->General Libraries->Image->SaveImage)
...

In the ‘SaveImage()’ syntax example it is shown that this command can accept four parameters and so
all four are within the brackets
...
This is to signify that these last two parameters are optional and don’t have to be
used when you need to call the ‘SaveImage()’ command
...
bmp")
SaveImage(1, "Image
...
jpg", #PB_ImagePlugin_JPEG, 10)

The first example will save an image called ‘Image
...
The
second example will save the image as JPEG format and use the standard compression value
...

Simple!

What Are Those Square Brackets Within The Syntax Examples?
The square brackets shown in syntax examples are never used when using these commands
...
Square
brackets are only ever used in actual code when you are using Static Arrays
...


The first thing you may realize while using built-in commands is that they look and act exactly like
normal procedure calls
...
The trick to using them correctly is that when you call a builtin command, you must pass it the correct parameters as defined in that command’s syntax example,
otherwise a syntax error will be triggered by the compiler
...


Using Built-in Commands

95

PB Numbers And OS Identifiers
When using built-in commands it is important to understand the role of PureBasic’s object numbering
system and that of operating system identifiers, as these are used directly when controlling what
happens in your program
...
For example, to identify parts of a graphical user interface or different images you
have to identify them by a number
...

The PureBasic helpfile is invaluable for the information it contains but it can get a little confusing
when first trying to understand PureBasic’s object numbering system and operating system
identifiers
...
Let me explain
exactly what they are so you can understand the helpfile better
...
A
PureBasic object, among others, can be a window, a gadget or even an image
...

Many PureBasic commands need either one or two PB numbers passed to them as parameters to
function correctly
...
If a command needs a PB number, these are usually shown as a constant, beginning with a
hash (#) and ending with the name of the library that the command resides in, e
...
‘#Image’ is used
for an image number, ‘#Window’ is used for a window number, etc
...

CreateImage(#Image, Width, Height)

As you can see this command expects a PB number to be passed to it as the first parameter, shown by
‘#Image’
...
In fact, any
integer can be used as a PB number for an object, as long as it is unique amongst others if many of the
same objects are used
...

The Same Kind Of Objects Can’t Share PB Numbers
PureBasic numbers provide a great way to refer to anything that PureBasic creates on an individual
basis
...
If you create
an image with a number of ‘1’ then later in your program you create another image with the number
of ‘1’, PureBasic automatically destroys the first and frees the memory it was using before creating the
second
...
This feature
is also very handy if you want to replace objects at any time
...
For example, you can create a window using
‘1’ as its PB number and then create a button gadget on it using ‘1’ as its PB number too
...

When using different commands to create objects, things can get confusing when trying to keep track
of all the numbers that must be used
...
These constants are usually defined in an enumeration block
to keep the numbers sequential
...
Throughout the program I can also use these constants
to refer to the images by name
...
This method of using constants for PureBasic’s numbers guarantees clearly
organized and readable code
...
This constant is:
#PB_Any

This constant can be used wherever a PB number is expected in an object creation command
...
So for example, the first time it
is used its value may be ‘1’, then the second time it is used its value may be ‘2’
...

The only thing to keep in mind while using ‘#PB_Any’ as a PB number, is that in order for you to refer
to this object later, you have to know what value ‘#PB_Any’ had during the object’s creation
...
Here is an example of using a
dynamic PB number in the ‘CreateImage’ command:
ImageDog
...
This works in exactly the same way
for all object creation commands
...
To view them in real working examples, see Chapter 9
...
These numbers are how the actual operating system keeps track of such things as
windows, fonts and images, etc
...
While
programming in PureBasic you will notice that some commands return OS identifiers while others
may need them as parameters
...
l = WindowID(#Window)
GadgetOSId
...
l = ImageID(#Image)

I’ve listed three here but there are a few more
...
ID()’ usually return
OS Identifiers
...
An OS identifier is used in this command instead of a PB number
for maximum compatibility, just in case the window has been created by the operating system’s native
API
...

Every operating system has a native application programming interface or API for short
...
OS identifiers are used to keep track of, and access all objects that the operating
system contains
...
For an operating system to track thousands of items, the numbers used
can be quite large, so don’t be surprised to see OS identifiers that are over eight digits in length
...
OS identifiers play
a major part when using the API of any operating system, especially the Windows API, which I cover
a little more in Chapter 13
...

These commands are usually found in most PureBasic programs and because of this, learning their
syntax and purpose is very advantageous
...
Here they are presented
below in alphabetical order, complete with their helpfile location and examples on usage
...
l = Asc(Character
...

In the standard ASCII character set, numbers from ‘0’ to ‘255’ are used to represent characters and
computer control codes
...

Text
...
l = 1 To Len(Text)
Debug Mid(Text, x, 1) + "
Next x

:

" + Str(Asc(Mid(Text, x, 1)))

The above example uses a ‘For’ loop and the built-in ‘Mid()’ command to break up the text contained
in the ‘Text’ variable into separate letters
...
These values along with the associated letters
are echoed to the Debug Output window
...
See Appendix B (Helpful Charts) for a full ASCII
chart, showing all characters and associated numbers from ‘0’ to ‘255’
...
s = Chr(ASCIIValue
...
The returned
string is the associated ASCII character of the value passed as a parameter
...


Using Built-in Commands

99

The parameter passed to this command: ‘ASCIIValue
...

Text
...
s + Chr(105) + Chr(115) + Chr(32)
Text
...
s + Chr(116) + Chr(101) + Chr(115) + Chr(116)
Debug Text

The above example constructs the String ‘This is a test’ by concatenating the results from multiple
‘Chr()’ commands
...
See Appendix B (Helpful Charts) for a full ASCII chart,
showing all characters and associated numbers from ‘0’ to ‘255’
...
The time is measured in milliseconds (which is a thousandth of a second)
...
"
Delay(5000)
Debug "This is executed 5 seconds later"

When the above example is run, the second ‘Debug’ statement is executed five seconds after the first
one because I’ve used the value of ‘5000’ milliseconds (5 seconds) in the ‘Delay()’ command
...
l = ElapsedMilliseconds()

This command returns the number of milliseconds that have elapsed since your computer was turned
on
...
"
StartTime
...
"

100

Using Built-in Commands

This command is great for performing any kind of timing operation in your program
...
Then when you want this timer to stop, you record the time again using
‘ElapsedMilliseconds()’
...
This is all demonstrated
in the above example
...
You have to remember that it’s recording the milliseconds elapsed from
system switch on
...

FindString()
(Helpfile:Reference Manual->General Libraries->String->FindString)
Syntax Example:
Position
...
s, StringToFind
...
l)

This command tries to find the ‘StringToFind’ parameter within the ‘String’ parameter, starting from
the position indicated by the ‘StartPosition’ parameter
...
These positions referred to are character counts from the beginning of
the ‘String
...

String
...
s = "fish"
FirstOccurrence
...
l = FindString(String, StringToFind, FirstOccurrence + 1)
Debug "Index of the first occurrence: " + Str(FirstOccurrence)
Debug "Index of the second occurrence: " + Str(SecondOccurrence)

This example shows how to find a String within another String
...
The second ‘FindString()’ command tries to find the same String
but from a position of ‘FirstOccurrence + 1’ to make sure we avoid the first occurrence being found
again
...

Both are then echoed to the Debug Output window
...
l = Len(String
...


Using Built-in Commands

101

Alphabet
...
l = Len(Alphabet)
Debug LengthOfString

This example is very simple because the ‘Len()’ command is very simple itself
...
This variable is then passed to the ‘Len()’ command which
returns ‘26’ (this is how many characters the ‘Alphabet’ variable contains)
...

MessageRequester()
(Helpfile:Reference Manual->General Libraries->Requester->MessageRequester)
Syntax Example:
Result
...
s, Text
...
It
can be used within any type of program, not just programs with a graphical user interface
...
The second parameter
is the actual message string displayed in the window itself
...
By using different flags for the last parameter, you can alter the style of the requester
window to include different buttons
...
To find out which one, you can test the return value, like this:
Title
...
s = "This is the default style message requester"
MessageRequester(Title, Message, #PB_MessageRequester_Ok)
Message
...
"
Result
...
s = "In this style you can choose 'Yes' or 'No' or 'Cancel'
...
l = MessageRequester(Title, Message, #PB_MessageRequester_YesNoCancel)
Select Result
Case #PB_MessageRequester_Yes
Debug "You pressed 'Yes'"
Case #PB_MessageRequester_No
Debug "You pressed 'No'"
Case #PB_MessageRequester_Cancel
Debug "You pressed 'Cancel'"
EndSelect

This example shows all the different ways that the ‘MessageRequester’ command can be used
...
Using
constants like this takes all the worry out of remembering numeric values
...

Mid()
(Helpfile:Reference Manual->General Libraries->String->Mid)
Syntax Example:
Result
...
s, StartPosition
...
l)

This command returns a cropped String which is extracted from another
...
The extracted String can then be taken from any position within the starting
String, defined by the ‘StartPosition’ parameter
...
Here’s an example:
StartingString
...
s = Mid(StartingString, 17, 4)
Debug ExtractedString

Here I extract the String ‘Dock’ by specifying the start position as ‘17’, then I extract ‘4’ characters
...

Random()
(Helpfile:Reference Manual->General Libraries->Misc->Random)
Syntax Example:
Result
...
l)

This command is simple to demonstrate because all it does is return a random integer between (and
including) ‘0’ and the value defined in the ‘Maximum’ parameter
...

Str(), StrF(), StrQ(), StrD()
(Helpfile:Reference Manual->General Libraries->String->Str)
Syntax Examples:
Result
...
s
Result
...
s
Result
...
s

=
=
=
=
=
=

Str(Value
...
w)
Str(Value
...
f [, DecimalPlaces
...
q)
StrD(Value
...
l])

These four commands are essentially the same
...

There are four different commands here to handle four different types of numeric values, ‘Str()’ to
handle Byte, Word and Long types, ‘StrF()’ to handle Floats, ‘StrQ()’ to handle Quads and ‘StrD()’ to
handle Doubles
...
In the case of ‘StrF()’ and ‘StrD()’ you will notice that there is also an optional parameter
called ‘DecimalPlaces’
...

Debug
Debug
Debug
Debug

"Long converted to a String: " + Str(2147483647)
"Float converted to a String: " +StrF(12
...
05643564333454646, 14)

The above example shows how to convert four different kinds of numeric values into Strings
...
One important thing to take note of is that if you omit the
‘DecimalPlaces’ parameter in the Float or Double type commands, then they will both default to six
decimal places and you may lose a lot of precision
...
l
Result
...
q
Result
...
s)
ValF(String
...
s)
ValD(String
...
The difference is that these commands take a String as a parameter and return a numeric
value depending on which flavor of ‘Val()’ is used
...
Here’s a simple example:
LongTypeVar
...
f = ValF("12
...
q = ValQ("9223372036854775807")
DoubleTypeVar
...
05643564333454646")
Debug
Debug
Debug
Debug

LongTypeVar
FloatTypeVar
QuadTypeVar
DoubleTypeVar

In this example I’ve used all four different types of the ‘Val()’ command to convert four Strings into
their respective numeric types
...
For
example, if you look at the ‘ValF("12
...


Handling Files
Using files is a natural way for any program to store and retrieve data
...
All the
file manipulation commands are stored in the same File library, located here in the PureBasic helpfile:
(Helpfile:Reference Manual->General Libraries->File)
Not all the file commands will explained fully within this section, but I will give you a good grounding
on reading and writing files so that the remainder of the commands will become easy to understand,
when you use them
...

#FILE_RHYME = 1
Dim Rhyme
...
"

Using Built-in Commands

105

If CreateFile(#FILE_RHYME, "Baa baa
...
l = 0 To 3
WriteStringN(#FILE_RHYME, Rhyme(x))
Next x
CloseFile(#FILE_RHYME)
EndIf

To begin with I’ve used the constant ‘#FILE_RHYME’ to be used as the PB number for our new file
object and I’ve defined a String array to hold my nursery rhyme
...
If I wanted to open and write to an existing
file, I could use the ‘OpenFile()’ command, but in the above example, I want to create and write to a
new file, so I use the ‘CreateFile()’ command instead
...

I’ve also used the ‘CreateFile()’ command within an ‘If’ statement to test that the command returns
true
...
It’s
always a good idea to test file creation, as things could go very wrong if you try to write to an invalid
file
...
This takes two
parameters, the first is the PB number associated with the file object I want to write to, the second is
the actual String I wish to write
...
The ‘WriteStringN()’ command used in this example
is an extended version of the ‘WriteString()’ command
...
This ‘N’ denotes that a 'new line' character is written after the String during the command’s
execution
...

Once I have written all Strings to the file and the loop exits, I close the file using the ‘CloseFile()’
command
...


Different Ways Of Creating Or Opening Files
When using PureBasic’s file commands to read or write to files, you must choose the right command
depending on how you wish to use that file
...

‘ReadFile()’ will open the defined file for reading and prevents any writing to it
...

‘CreateFile()’ creates an empty file for writing to
...

Each one works in exactly the same way and all share the same two parameters
...


106

Using Built-in Commands

This file containing the nursery rhyme should now be somewhere on your hard drive
...
txt’, then the newly created file will be in the same
directory as your source code file
...

If CreateFile(#FILE_RHYME, "C:\My Directory\Baa baa
...


When using this method though, you must always make sure that all directories specified in the path
do exist before you write the file, else the file creation will fail
...
This command not only closes the selected file but frees it up again to be opened by
another program if needed
...
PureBasic uses a buffer system to increase
performance of file access, so if you are open a file in another editor and some data you expected to be there
is missing you must check that you’ve closed the file properly using ‘CloseFile()’
...

The file buffers are completely transparent to the regular user, so you won’t have to worry about them too
much, you just need to close each file when you have finished with it to avoid any errors
...
Now that you understand how
the ‘WriteString()’ command works the others are simple to grasp
...
b)
WriteChar(#File, Value
...
w)
WriteLong(#File, Value
...
q)
WriteFloat(#File, Value
...
d)

These can be used to write any built-in type value to a file and all commands can be used as many times
as you like
...
To make things even more simple, these commands are all used in the same manner
as the ‘WriteString()’ command, the first parameter is the file object to write to and the second is the
actual value to write
...
PureBasic makes it extremely simple with
powerful file reading commands
...
txt’, and place them into a linked list called ‘FileContents’
...
You don’t have to
echo this data though, you can go on to manipulate the Strings in any way you see fit during your
program
...
s()
If ReadFile(#FILE_REPORT, "Report
...
Then I create a linked list called ‘FileContents’ to hold the Strings we’re going to read
...
I’ve used a linked list here because they are easy to use and can grow with new items, unlike
arrays who’s size is pre-defined
...
Like the ‘CreateFile()’ command, the first parameter is a PB
number that this newly opened file will be associated with, while the second is the name of the file to
be read
...
If it does then I can be sure this file has been opened correctly and I’m able to access it properly
...
I’ve used a ‘While’ loop here, so I don’t
have to type out repeated commands to read the Strings within
...
In the loop I check to see if this is returning false on each iteration, if it is I
know I’m not at the end the file and I can continue reading from it
...

While the file is open, I use the ‘ReadString()’ command to read one String at a time from it
...
Each time I read a String from
the file, I create a new element within the ‘FileContents’ linked list and assign the String to it
...


108

Using Built-in Commands

Once the loop is broken, I then correctly close the open file with the ‘CloseFile()’ command
...
A simple ‘ForEach’ loop is
then used to echo the read data to the Debug Output window
...
PureBasic
provides specific commands for each of the built-in types to read them correctly
...
This parameter is the PB number of the open file object to read from
...
Unlike ‘ReadString()’ they won’t keep
reading until another line is encountered
...
This would also move the file access pointer forward ‘4’ Bytes within the file, ready for
the next read command
...
This imaginary position is where you will
read from or write to in an open file
...
Once you start reading or
writing, the file access pointer starts moving
...
If you are reading from a file then
the access pointer will move after each read operation to the end of the last value read until the end of the file
is encountered, and the ‘Eof()’ command returns true
...
‘Loc()’ stands for ‘Location’
...

(Helpfile:Reference Manual->General Libraries->File->Loc)
Syntax Example:
Position
...
The position is returned as a Quad value to support large files
...

(Helpfile:Reference Manual->General Libraries->File->FileSeek)
Syntax Example:
FileSeek(#File, NewPosition
...
This allows you to read from any
position, within in any file at any time
...

Finding Out The Current File Size?
To find out the size of the currently used file, you use the ‘Lof()’ command
...

(Helpfile:Reference Manual->General Libraries->File->Lof)
Syntax Example:
Length
...
The
length is returned as a Quad type, to support large files
...
In the code below I’m reading a MP3 music file to
discover if it has an ID3(v1) tag embedded inside it
...

After reading the specifications of MP3 ID3 tags on the Internet, I discovered that the tag information
is always added to the end of a regular MP3 file and this tag is always ‘128’ Bytes long
...

Here’s the code:
#FILE_MP3 = 1
MP3File
...
mp3"

110

Using Built-in Commands

If ReadFile(#FILE_MP3, MP3File)
FileSeek(#FILE_MP3, Lof(#FILE_MP3) - 128)
For x
...
s + Chr(ReadByte(#FILE_MP3))
Next x
CloseFile(#FILE_MP3)
If Text = "TAG"
Debug "'" + MP3File + "' has an ID3v1 tag embedded within it
...
"
EndIf
EndIf

After opening the file using ‘ReadFile()’, I move the file access pointer to the correct place by finding
out the length of the file, then back tracking ‘128’ Bytes
...
So I use a loop to
perform a ‘ReadByte()’ operation three times and I pass each Byte to the ‘Chr()’ command to return a
character
...
Once the loop
has ended and the is file closed I check the value of ‘Text’
...


Read The Helpfile
This has been the warcry of many good programmers for years, especially on Internet forums
...
There really is no getting around the fact that people who read more about a
subject are usually better at understanding it
...

The best piece of advice I can give to you to start learning PureBasic is to read the PureBasic helpfile
from front to back and read every page about every command
...

Sometimes the only thing that distinguishes a good programmer from a truly great one is the amount
of reading and study of relevant information that has taken place
...


8

111

Good
Programming
Style
Until now I’ve concentrated on explaining core essentials of PureBasic programming
...
I think it’s now time that I mention something about the style
of how a program should be written
...
Learning to program can be great fun but that fun can soon erode away
when you are confronted with (and trying to understand) poorly written code, especially if you are the
author
...

In the following paragraphs I’m going to describe ways in which you can format your code for
maximum readability
...
Hopefully after reading further you will settle into your own style and stick to it
...
I’ve also included some guidance on how
to use the PureBasic debugger to track down where problems may be occurring in your code
...
One answer would be, if I
were to write this book without headings, subheadings, paragraphs or capitalization and flow the text
into one big block, would it be as easy to read as it is now?
Formatting code neatly has absolutely nothing to do with program compilation and it doesn’t alter the
function or execution of the compiled program either, it’s purely done to make code easily readable
...
Sometimes because you might not finish what you are doing in one day or
you might revise an old program to include new functionality
...
If you have ugly, unorganized code then I guarantee you will have
difficulty in reading it and carrying on with your project
...
A program that is perfectly clear to
understand today may not be clear tomorrow
...
If you are working on a
project within a team and amending other people’s code, as well as writing new stuff, it is essential that
the whole team uses the same formatting standard
...


The Value Of Comments
The very first thing to talk about when mentioning good programming style is the use of Comments
...
I thought, I would wait until this chapter
for a chance to describe them properly as I regard comments as one of the most important aspects of
writing good code
...
They are never compiled into the final executable or
have any other bearing on the program
...

Comments are a way to provide a more detailed explanation of what you are writing as well as provide
an overview on how different parts of your program are meant to work and how they interact with the
rest of the code
...

;This calculation is only accurate to six decimal places
...
f Pi()
ProcedureReturn 4 * (4 * ATan(1/5) - ATan(1/239))
EndProcedure
CircleDiameter
...
"

Here I’ve used comments within this example to describe the function of the ‘Pi()’ procedure and more
importantly explain its limitation of only being accurate to six decimal places
...
l AddTogether(a
...
l) ;Add two numbers and return the result
ProcedureReturn a + b
EndProcedure

You have to remember is the semi-colon at the beginning, this defines where the comment starts
...
If you want a comment to continue onto a new line then you have to start that new line with
another semi colon
...
Comments shouldn’t be too lengthy but long enough to explain what you
need to
...
In six month’s time when you revisit your
code, you will be glad comments are there to help you understand your work
...

2)
...

4)
...


Adding license or copyright information
...

Adding notices of where code could be improved
...

Clarifying procedure internals by drawing graphs or formulae using ASCII art
...
This entire book has been written in this style, which
I personally feel is an easy to read and learn format
...
Hopefully you will find
this style helpful and continue to use it
...
This notation is easy to understand, you capitalize the first letter of the name
and then capitalize any other words that follow
...
This capitalization format makes these words look as if they have humps
running along them, hence the name ‘CamelHump’ notation
...


114

Good Programming Style

Example:
NumberOfDays
...
s(11)
NewList Days
...
If I need to
distinguish separate words within them, I use underscores
...
This again is
the standard format of C and the Windows API
...
Notice, the following structure name is all uppercase
...
s
ServiceCode
...
Indents are very often used to give purely visual aids to reading
code
...

; 'Number' = Number to round up and return as a String
...

Procedure
...
f, DecimalPlaces
...
f
Protected T
...
f = 0
...
f = Pow(10, DecimalPlaces)
ProcedureReturn StrF(Int((Number + R) * T) / T, DecimalPlaces)
EndProcedure
Debug StrFRound(3
...
This clearly defines code between the
beginning and ending keywords of a code block such as a procedure or an ‘If’ statement
...
Indentation
is especially helpful in nested statements, like this:
For x = 0 To 2
For y = 0 To 2
z
...
Only one tab to the right is used per code block so the code contained within a
particular block isn’t too far away from the beginning and end keywords, which could also make code
harder to read
...

This is the beginning and end of an ‘If’ statement
...
This will become more useful the larger your programs get
...
This is
easily done using the colon (‘:’) character
...
Look at this:
Dim Birds
...
I feel sometimes it
can help, while it’s not over used
...
These files are standard PureBasic files but have either the ‘*
...
pbi’ extension
...
pbi’ files are PureBasic Include files
...
The ‘*
...

In these separate files I hold different parts of the main program and then include them all into the
main source code file by using the ‘IncludeFile’ or ‘XIncludeFile’ keyword
...
pbi’ where all my procedures will be defined
...
pbi"

This has the effect of taking all lines of code from the "Procedures
...
Wherever the ‘IncludeFile’ command appears, this is where
the code from the included file will be added into your main code
...

If you add an ‘IncludeFile’ line many times within your main code using the same file name, you will
get duplicate pieces of code inserted into your main code file
...
This is used in the same way as above:
XIncludeFile "Procedures
...
pbi’ file, only if this line has not been
used before
...
I prefer to use ‘XIncludeFile’ for everything, as it cuts down on errors
occurring
...
This closes everything correctly
within your program and frees any memory used by it
...
The syntax for use is simple, just use this keyword where you would like your
program to end
...

Without exit code:
End ; Immediately ends the program and frees all memory used by it
...


Golden Rules For Writing Easily Readable Code
Here is a list of golden rules I follow while writing a program
...
If you follow this list you too will write good, clean, understandable code
...


Good Programming Style

117

1)
...
clear, accurate, pronounceable, descriptive names
...
Group logically connected variables or data into arrays or structures
...
Procedures should perform one function and perform it well
...
Use indentation to show code structure
...
Use parentheses (brackets) in expressions to avoid any evaluation confusion
...
Use blank lines to separate different procedures and other blocks of code
...
Try not to use the ‘Goto’ or ‘Gosub’ keyword
...
Use comments to help people (or you) understand your code more clearly
...
Try not to document bad code with comments, re-write the code properly
...
When working in a team, agree a formatting style before starting, then stick to it
...
Even the
most experienced and dedicated programmer can make mistakes or forget to handle common ones or
maybe even overlook them altogether
...

Use An Error Handler Procedure
If your using PureBasic for large projects you might find that you’ll be making many tests to confirm
a true value
...
This value is nearly always an
integer and always above ‘0’ if things have gone right
...

While some people use ‘If’ statements to check things have gone right before proceeding, I find this
approach is only useful for small programs as it can lead to a lot of confusing nested ‘If’ statements
when used for larger ones
...
This not only makes your source code much more easy to read but you can pass user
defined messages to this procedure to inform users of where exactly in your program things have gone
wrong and with what command
...
txt")
Debug ReadString(#TEXTFILE)
CloseFile(#TEXTFILE)
Else
MessageRequester("Error", "Could not open the file: 'TextFile
...
")
EndIf

Here I test to make sure I can read the file ‘TextFile
...
While this
method is fine for small programs, I prefer this way for bigger projects:

118

Good Programming Style

#TEXTFILE = 1
Procedure HandleError(Result
...
s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
HandleError(ReadFile(#TEXTFILE,"TextFile
...
txt'
...
The first parameter called ‘Result’, is where the return value from a command
is passed
...
This is to make sure any return values are passed correctly
...
s’, is the String you wish to be displayed if the passed command returns ‘0’
...

When I pass this command to the ‘HandleError()’ procedure:
ReadFile(#TEXTFILE, "TextFile
...
txt’ does not exist on your hard drive or something else goes wrong, the ‘ReadFile()’
command will return ‘0’
...
Inside the procedure this parameter is tested to see if its value is equal to ‘0’, if it is then
the error message passed in the second parameter will be displayed using a message requester and the
program will end
...

If the command passed to the error handling procedure returns a value above ‘0’, then this command
is considered to have been successful and the error handling procedure takes no action
...
Using an error handling procedure really
becomes useful in larger programs, where many commands need to be tested one after another
...
Look at this example of testing multiple commands:
HandleError(InitEngine3D(), "InitEngine3D() failed to initialized!")
HandleError(InitSprite(), "InitSprite() failed to initialized!")
HandleError(InitKeyboard(), "InitKeyboard() failed to initialized!")
HandleError(OpenScreen(1024, 768, 32, "Game"), "A screen could not be opened!")

Can you image using ‘If’ statements to test all these commands? It would be a nested ‘If’ nightmare,
and this isn’t even a full program yet! Using error handling procedures makes your code look neater,
cleaner and more readable
...
The only problem with this approach is that ‘HandleError’ appears at the start of every line,
which some people find intrusive
...
This command enables explicit variable definition within the whole of your program
...
If
the ‘Define’ keyword has been used to define another default type then any un-typed variables will use
that instead
...
Let me show you how this command could prove
useful
...
l = 1024
Procedure CalculateYearlyAmount(Value
...
l = Value * 52
ProcedureReturn YearlyAmount
EndProcedure
Debug CalculateYearlyAmount(WeaklyAmount)

Now, this looks okay and if you quickly scan through this example you don’t see any problems
...
This is obviously not right as we
are supposed to be passing it the ‘WeeklyAmount’ variable which has a value of ‘1024’
...
Notice
that this variable is spelt incorrectly and so it’s treated as a new variable
...
Variables that haven’t had their type or value defined during creation are always assigned
the default type, and given a null value
...

Automatically defining variables that have been typed like this is considered by some programmers to
be careless and very error prone
...
If we used this command
in the above example we would get a few messages informing us that some variables need to be more
strictly defined
...
These are ‘Define’, ‘Global’, ‘Protected’, ‘Static’ and
‘Shared’, as explained in Chapters 2 and 6
...
This would be a bit strange as it

120

Good Programming Style

should already be done earlier in the program
...
Here’s what the above example would look like using
the ‘EnableExplicit’ command and all variables defined in a more explicit way
...
l = 1024
Procedure CalculateYearlyAmount(Value
...
l = Value * 52
ProcedureReturn YearlyAmount
EndProcedure
Debug CalculateYearlyAmount(WeeklyAmount)

Hopefully using this command should prevent many more variable based spelling mistakes because
every time a spelling mistake is encountered the compiler will treat it as a separate variable name and
you will be asked to clarify this variable’s scope and definition
...

At anytime if you want to revert to default PureBasic behavior, you can switch off the ‘EnableExplicit’
command’s influence by using the ‘DisableExplicit’ command
...
First it sets the default type for un-typed variables, as shown
in Chapter 2
...
s
MyString = "Hello"
Secondly, the ‘Define’ command can be used to define variables after an ‘EnableExplicit’ command has been
used
...
In this case, the ‘Define’ command may be used like this:
EnableExplicit
Define MyVar
...


Introducing The PureBasic Debugger
PureBasic provides a full featured debugger that helps find errors and bugs within your code
...
It also provides
advanced functions for assembly programmers to examine and modify CPU registers or view values
stored in associated memory addresses
...

If you run your program and the debugger encounters an error, the program will halt and the line
where the error occurred will be marked in the IDE (using red) and the error will be displayed in the
IDE Error Log and IDE status bar
...
To end the running program use the ‘Kill Program’ menu item
(Menu:Debugger->Kill Program) or its associated toolbar button
...

While writing a program in the IDE, the debugger is enabled by default
...
23
...
This
button is also a shortcut to the ‘Use Debugger’ menu item, (Menu:Debugger->Use Debugger) which is
also a toggle
...
->Compiler Options->Enable Debugger)
...
If one is used, the others mirror its status
...
These can
all be used to debug your program but some don’t have the same functionality
...
The PureBasic IDE running on some operating systems doesn’t
support this built-in version so a stand-alone debugger is also supplied with the installation
...
The third debugger runs in
a console only
...

The available debuggers can be selected as default in the IDE preferences, (Menu:File->Preferences>Debugger)
...
You will find that programs running while the debugger is
enabled will be a great deal slower than running them with it disabled
...
This must be kept in mind if you are developing speed critical
programs or need to time certain bits of code, etc
...

These are pretty self explanatory to use, the ‘DisableDebugger’ command disabled the debugger from
then on in your code and the ‘EnableDebugger’ command re-enables it
...
This is because ‘Debug’ commands are also
part of the debugger and they are not compiled if the debugger is disabled
...
The Error Log
(Menu:Debugger->Error Log) and the CPU monitor (Menu:Debugger->CPU Monitor) are always
accessible too
...
This makes sure
that the currently used code is not modified in any way, to provide a simple version control on your
code
...
These controls let you stop the program at any given time and examine any variable, array
or linked list value
...
The state of any program while using the debugger will be shown in the
IDE status bar and in the Error Log
...
23, these are also mirrored by commands in the ‘Debugger’ menu
...
23
To halt your program at any time and use the debugger controls, you can either use the ‘CallDebugger’
keyword in your code, use ‘Stop’ from the debugger menu (Menu:Debugger->Stop) or press the ‘Stop’
toolbar button while your program is running
...
To use a breakpoint within the IDE, put the cursor on the line where you would like the
program to halt and switch control to the debugger
...
You will notice that a small circle appears in the
line numbering gutter of the IDE
...

When this program is next run, it will halt on that line where the breakpoint is defined and then the
debugger program control functions will be available
...
Here is a short description of the
program control functions:

Good Programming Style

123

‘Stop’
This halts the program and displays the current line
...

‘Step’
This executes one line of source code and then stops the execution again
...

Here is a brief example of halting program execution using the ‘CallDebugger’ command:
CallDebugger
For x
...
You can step through it,
a line at a time using the ‘Step’ toolbar button
...
While a program
is halted in this way you can view any variable, array or linked list value by opening the Variable Viewer
(Menu:Debugger->Variable Viewer)
...
For more advanced information of what it is capable of, see the PureBasic Helpfile
...
Normally you would use the debugger during development to help catch
errors, but when you compile your final executable for distribution, you disable the debugger in order
to compile the smallest and fastest executable possible
...
Using the ‘OnError’ library it is easy to implement advanced error
checking and handling into a final executable and still have the full speed of PureBasic available
...
First, I’ll
show you how to effectively catch and describe an error without using the debugger
...

Null
...
l = 100 / Null

124

Good Programming Style

;Handle any system error that occurs
ErrorHandler:
Text
...
s + "Error ID number:" + #TAB$ + #TAB$ + Str(GetErrorNumber()) + #CRLF$
Text
...
s + "Error occurred on line:" + #TAB$ + Str(GetErrorLineNR()) + #CRLF$
Text
...
The
parameter of this command is a label destination of where to jump
...
This is because the ‘OnErrorGoto()’ command actually needs a pointer of the label passing
instead of just a label
...
A pointer
is a variable which contains a memory address of where something is stored, see Chapter 13 (Pointers)
for a more complete explanation
...

After the label has been specified using the ‘OnErrorGoto()’ command, then other ‘OnError’ library
commands help us to understand what went wrong and where
...

‘GetErrorNumber()’
This command returns the unique error number of the last error that occurred
...

‘GetErrorLineNR()’
This command returns the line number of where the error has occurred in your source code, either in
the main source file or in any included files
...

‘GetErrorModuleName()’
This command returns a String telling you in which source code file the error occurred in
...
For this command to work properly you must
switch on the ‘Enable OnError Lines Support’ compiler option before compiling your program
...
This is located in the compiler options within the
IDE, (Menu:Compiler->Compiler Options
...


Good Programming Style

125

To actually demonstrate the ‘OnError’ commands catching and handling an error, I’ve created a
reproducible error in the code
...

Null
...
l = 100 / Null

If the debugger is enabled then it would catch this easily but if we disabled it this error is missed
...
To run the example
and see it working properly, you need to first disable the debugger and enable the ‘Enable OnError
Lines Support’ compiler option
...
Fig
...


Fig
...
This command, however does not let you return from that label and continue with the
program, even if you use the ‘Return’ keyword
...
Using this command you can specify a label or a procedure as the error handler and this
command does let you return from these with the appropriate keyword
...
s = "Error count:" + #TAB$ + Str(GetErrorCounter()) + #CRLF$
Text
...
s + "Error description:" + #TAB$ + GetErrorDescription() + #CRLF$
Text
...
s + "Occurred in module:" + #TAB$ + GetErrorModuleName() + #CRLF$+#CRLF$
Text
...
l = MessageRequester("ERROR", Text, #PB_MessageRequester_YesNo)
If ReturnValue = #PB_MessageRequester_No
End
EndIf
EndProcedure
;Set the error handler

126

Good Programming Style

OnErrorGosub(@ErrorHandler())
;Trigger a classic 'divide by zero' error
...
l = 0
TestVariable
...
")
End

Here I demonstrate how to resume the program execution after an error, something which you can’t
do using the ‘OnErrorGoto()’ command
...
That’s why, if you give your program the ability to resume after an error,
depending on how serious the error was, you should inform the user what has happened and
encourage them to restart the program
...
Resuming gives them a chance to save what they
was doing in your program (if it has this functionality) before they restart it
...
The main difference between these two commands is wether or not the
error handler lets you return back to the normal program flow
...
Meaning that once an error is handled the program must quit immediately
...
This means you have the option of resuming
normal program execution after an error has been handled
...
If after an hour of
writing an unexplained error occurs and the program throws up an error message, Bob doesn’t want
to have wasted that last hour and lose his letter due to an error
...
An email address could even be displayed in the error message for Bob
to contact and explain what went wrong in order for the program writer to correct it
...
Sometimes however you
may want to raise your own error for the sake of customization
...


Good Programming Style

127

The ‘SetErrorNumber()’ command needs one parameter in order to work properly and this parameter
is a Long type number that identifies this error
...
txt") = #False
;If the file read fails then fire an error
SetErrorNumber(#ERROR_READFILE)
EndIf
End
;Handle any custom error that occurs
ErrorHandler:
Text
...
s + "Error ID number:" + #TAB$ + #TAB$ + Str(GetErrorNumber()) + #CRLF$
Select GetErrorNumber()
Case #ERROR_READFILE
Description
...
"
Case #ERROR_WRITEFILE
Description
...
"
EndSelect
Text
...
s + "Error occurred on line:" + #TAB$ + Str(GetErrorLineNR()) + #CRLF$
Text
...
txt’ cannot be read using the ‘ReadFile()’ command, I raise a
custom error using the ‘SetErrorNumber()’ command
...
Once an error has been triggered in this way the error
handler label or procedure is called
...
Depending on what the result is of this
command you can then tailor the error description to your hearts content
...
The pop-up error message then displays this description
...


II
Graphical
User Interfaces
In this next section I’m going to talk about Graphical User Interfaces and how they are created in
PureBasic
...
The operating system exposes
the user interface to programs through an Application Programming Interface (or API) through which
a program can tell the operating system how draw its user interface
...

PureBasic creates these graphical interfaces for your programs using the native application
programming interface of the system they've been compiled for
...
This is essential for all professional
application development
...
Later, I move on to explain how to create
programs with native user interfaces and how to add menus and graphics
...
Using this tool you can design an interface
visually as if you were painting it upon a program
...


9
131

Creating User
Interfaces
In this chapter I’ll explain how to create graphical user interfaces for your programs
...
I explain fully how to code the graphical interface, complete with menus and sometimes
with graphics
...
Hopefully after reading this chapter you will be well equipped
to create user interfaces for any program you decide to develop
...
Console programs, as the name suggests, are programs that use a console as their
user interface
...
On some operating systems the console can display simple graphics by substituting
some of the ASCII character set for graphical symbols instead of characters
...
These
types of programs are usually command line tools that are run from other consoles or things like CGI
programs that run in the background on web servers, etc
...
Commands that
create and work with a console interface are grouped inside the ‘Console’ library (Helpfile:Reference
Manual->General Libraries->Console)
...
Here is an example of how
to create a console program in PureBasic:
If OpenConsole()
Print("This is a test console program, press return to exit
...
The second command I’ve used is the ‘Print()’
command which accepts one String parameter that is printed to the console interface
...
The ‘PrintN()’ will also print a line
of text but it will append an end-of-line character on the end to move to a new line after the text has
been printed
...

The last command used in the above example is ‘Input()’
...
This command then returns any characters (as a
String) that were entered into the console before the Return key was finally pressed
...
If this command was omitted, then the
console would almost immediately close as soon as it had opened
...

Reading User Input
Sometimes in your console programs you may want to read user input, this could be a simple number
or a String of text
...
This next piece of code shows this, while
introducing some new console commands:
If OpenConsole()
EnableGraphicalConsole(#True)
Repeat
ConsoleColor(10, 0)
PrintN("TIMES TABLES GENERATOR")
PrintN("")
ConsoleColor(7, 0)
PrintN("Please enter a number, then press Return
...
q = ValQ(Input())
If Number = 0
ClearConsole()
Continue
Else
Break
EndIf
ForEver
PrintN("")

Creating User Interfaces

133

For x
...
")
Input()
CloseConsole()
EndIf
End

This example looks rather complicated but it’s not really if you read it a line at a time
...
This enables or disables the
graphical capabilities of the console program by passing either the ‘#True’ or ‘#False’ constants as a
parameter
...


Differences Between Graphical And Non Graphical Console Modes
Using the ‘EnableGraphicalConsole()’ command you can switch between text mode and graphical mode of
the current console
...

Output redirection using Pipes works correctly (Essential for CGI programs)
...

You can read and write data to the console that is not necessarily text based
...

Long Strings of printed text are truncated if they reach the end of the console window
...

‘ConsoleLocate()’ Moves the cursor to be able to print text in any position in the console window
...


I’ve also changed the console text color in some places by using the ‘ConsoleColor()’ command
...
The parameters are
numbers that range from ‘0’ to ‘15’ which represent different color presets, see the helpfile to see what
color is associated with each number (Helpfile:Reference Manual->General Libraries->Console>ConsoleColor)
...
I want a number to be entered so I use the
‘ValQ()’ command to change the String returned from the ‘Input()’ command into a Quad
...
If this is the case I clear the console of all output by using the ‘ClearConsole()’
command and force the loop to continue from the beginning, totally redrawing the original text and
requesting user input again
...

Reading User Input In Realtime
The last example showcased the ‘Input()’ command which is fine if you need to enter a String or such
but its only limitation is that you have to press the Return key in order for the input to be passed to
the program
...
Look at this next piece of code for an example on the usage of both:
Procedure DisplayTitle()
ConsoleColor(10, 0)
PrintN("KEY CODE FINDER")
PrintN("")
ConsoleColor(7, 0)
EndProcedure
Procedure DisplayEscapeText()
PrintN("")
ConsoleColor(8, 0)
PrintN("Press another key or press Escape to exit")
ConsoleColor(7, 0)
EndProcedure
If OpenConsole()
EnableGraphicalConsole(#True)
DisplayTitle()
PrintN("Press a key
...
s = Inkey()
RawKeyCode
...
The main difference is the ‘Repeat’ loop is continuously calling two
commands to determine which key, if any, has been pressed
...

The first command, ‘Inkey()’ returns a one character String of the key held down when this command
was called
...
Although this command is simple to understand you must remember that
the keys on a standard keyboard are usually printed in uppercase, while the ‘Inkey()’ command returns
them as lowercase unless the Shift key is held down at the same time
...

The second command for gathering information on what key has been pressed is a companion to the
‘Inkey()’ command, its name is ‘RawKey()’
...
In the above example, you can
see how to use both commands to extract information about which key is being held down during the
loop
...

Delaying Things A Little
You may notice that in the above example I’ve also used a ‘Delay()’ command to tell the program to
delay itself for ‘1’ millisecond
...
Because you will be using a multitasking operating system to run your programs,
it’s good programming practice not to monopolize CPU time if you can help it
...
Even a delay
of ‘1’ millisecond allows the operating system to free up the CPU long enough to let other programs
have a chance to run
...
If a ‘Delay()’ command is not used within such a loop then your program will take
up all the CPU’s resources until it has quit, leaving no processing power available for other programs
to run
...


136

Creating User Interfaces

Compiling A True Console Program
Running the console program examples in the IDE will build programs that look and act like real
console programs but won’t be console programs in the true sense until you compile them using the
‘Console’ executable format
...


Fig
...
25 shows a diagram of where the executable format option is in the ‘Compiler Options’ dialog box
(Menu:Compiler->Compiler Options
...
’ (Menu:Compiler->Create Executable
...

The PureBasic compiler will now build a true console program
...
These programs when run either by double
clicking or evoking them from a command line interface will always open a new console window before
proceeding
...


Creating User Interfaces

137

And that’s all there is to programming interfaces in console programs really
...
These interfaces are really used nowadays for displaying simple output from command
line tools
...
These are called ‘Native’
interfaces because PureBasic uses the underlying operating system’s API to draw the interface
components
...

All this talk of the operating system’s API may dishearten you, making you think that this all sounds
very complicated, but don’t panic
...
Just using PureBasic’s built-in libraries you can build powerful applications that rival
any other programming language
...
This has been proved many times
through small competitions created by members of PureBasic’s official online forums
...

Hello World
As is customary in the programming world, the first example of any programming language’s interface
commands is usually a ‘Hello World’ program
...
Start a new file in the IDE and type this in:
#WINDOW_MAIN = 1
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Hello World", #FLAGS)
Repeat
Event
...
26 overleaf
...
Even though this example only consists of a blank
window and a close button in the title bar, this is the start of all native user interfaces in PureBasic
...
If you open the helpfile and refer to the ‘OpenWindow()’ command
(Helpfile:Reference Manual->General Libraries->Window->OpenWindow) then look at the syntax
example, you can see I’ve used the ‘#PB_Window_SystemMenu’ and ‘#PB_Window_ScreenCentered’

138

Creating User Interfaces

Close Button

(Microsoft Windows example)

Fig
...
When using multiple flags like this, you join
them together using the bitwise ‘OR’ operator as shown in the code above
...

After the ‘OpenWindow()’ command is used I’ve then used a ‘Repeat’ loop to act as the Main Loop to
process any events that this window may encounter
...
However, if you use the
‘#PB_Window_ScreenCentered’ or ‘#PB_Window_WindowCentered’ flags in the same command call the
position parameters are ignored
...
If this is the case you can safely use ‘0’ for both the
position parameters or use the ‘#PB_Ignore’ constant to explicitly show in your source code that these two
parameters are been ignored because of the flags passed
...
It allows the program to continually
keep running while redrawing the interface (if it’s moved around the desktop) and handle any events
that the interface may generate
...

In my little ‘Hello World’ program I’ve used a ‘Repeat’ loop as my main loop, this gives me the ability
to keep the loop going forever until a particular condition is met, in this case, until I have encountered
an event of ‘#PB_Event_CloseWindow’ type, which is the event triggered when you click the close
button
...


Creating User Interfaces

139

Understanding Events
Every program you write using any programming language will use roughly the same way of handling
events
...
So what kinds of events are there? Well, an
event can be triggered by many actions within your programs, an event might be triggered by clicking
on a gadget, pressing a button on the keyboard, selecting an item from a menu or just by moving or
closing the program
...

To do this we use the ‘WaitWindowEvent()’ and ‘WindowEvent()’ commands
...
Microsoft Windows calls these ‘Controls’ and some Linux distributions calls these ‘Widgets’
...
All the different
interactive components that make up an interface, PureBasic calls gadgets
...
The difference between these two is that the
‘WaitWindowEvent()’ command halts your program until an event is detected, then returns the event
identifier and lets the program continue normally until it’s called again
...
) The ‘WindowEvent()’ command however, does not halt the program
at all, it just tests to see if there are any events to return
...
This command is very seldom used in user interfaces as it can make them very CPU ‘hungry’,
hogging the processing power of the computer on which they run
...
If this is the case and
you must use the ‘WindowEvent()’ command, good programming style dictates that you try to use the
‘Delay(1)’ trick with it (as explained in the console program section) to make sure your program is CPU
friendly
...

In the ‘Hello World’ program I’ve used a ‘WaitWindowEvent()’ command during the ‘Repeat’ loop to
halt the program until an event is triggered
...
The loop is then
coded to exit if ‘Event’ equals the value of ‘#PB_Event_CloseWindow’, which is a built-in constant that
contains the identifier of a ‘close window’ event from the interface
...

Events Happen All The Time
Even though no other events are handled in this small example, it doesn’t mean that they aren’t
occurring
...


140

Creating User Interfaces

Run the following piece of code, then move and click in and around the window
...

#WINDOW_MAIN = 1
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Hello World", #FLAGS)
Repeat
Event
...
This is completely normal and won’t noticeably slow your program
down in the slightest
...
In this next section I’ll show you how you can add gadgets
to your program’s window to increase functionality and interactivity
...

Enumeration
#WIN_MAIN
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration
Global Quit
...
l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()

Creating User Interfaces

141

Case #BUTTON_INTERACT
Debug "The button was pressed
...
Fig
...


(Microsoft Windows example)

Fig
...

This is needed to tell your window that you would like to draw gadgets on it
...

CreateGadgetList(WindowID(#WIN_MAIN))

...

After we create a gadget list within the main window we can draw gadgets upon it
...
If you open the helpfile and refer to the
‘ButtonGadget()’ page (Helpfile:Reference Manual->General Libraries->Gadget->ButtonGadget) you
will be able see in the syntax example exactly what parameters are expected by this command
...

To highlight another key area, if you look at the main loop, after an event identifier has been returned
from the ‘WaitWindowEvent()’ command and assigned to the ‘Event’ variable, I’ve used a ‘Select’
statement to test its value, like this:

...

EndSelect

...
This is a special
global event value, used to test an identifier to determine if it’s from a gadget, in other words, if ‘Event’
is equal to ‘#PB_Event_Gadget’ then ‘Event’ must hold an event identifier from a gadget
...

We do this using the ‘EventGadget()’ command which returns the PB number of the originating
gadget
...


...
"
Case #BUTTON_CLOSE
Quit = #True
EndSelect

...
If the return value from ‘EventGadget()’ equals ‘#BUTTON_INTERACT’ then
the ‘Click me’ button has been pressed
...
Then I type some code that I want executing when this button is
pressed on the next line after the ‘Case’ statement
...
If the return value equals
‘#BUTTON_CLOSE’ then the ‘Close window’ button has been pressed
...

This is why using a constant ‘Enumeration’ block is so incredibly helpful
...


Creating User Interfaces

143

Accepting Text Input
Let’s expand the last example a bit more and add a String gadget so we can enter some text that the
program can use
...
This next example is to show you how you can retrieve the value of the String
gadget, i
...
retrieve the text, and use it in your program
...
Fig
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Interaction", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
TextGadget(#TEXT_INPUT, 10, 10, 280, 20, "Enter text here:")
StringGadget(#STRING_INPUT, 10, 30, 280, 20, "")
ButtonGadget(#BUTTON_INTERACT, 10, 170, 120, 20, "Echo text")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Close window")
SetActiveGadget(#STRING_INPUT)
Repeat
Event
...
The first new gadget I’ve added is a text gadget which literally displays a noneditable text string on the window, I use one to display the String: ‘Enter text here:’
...


144

Creating User Interfaces

If you open the PureBasic helpfile on the ‘StringGadget()’ page (Helpfile:Reference Manual->General
Libraries->Gadget->StringGadget) you can see the parameters that this gadget can accept
...
For the ‘Content$’ parameter I’ve passed a blank String, which is expressed through two sets
of double quotation marks with nothing between
...

I’ve done this because the ‘Content$’ parameter sets an initial text value for the String gadget and I
want the String gadget to start off with none entered
...
28

Once this program is running you will notice that the text cursor is immediately flashing in the String
gadget
...
In my program I have set that gadget to be the active one on startup by
using the ‘SetActiveGadget()’ command
...
I’ve done this in this little
example to help the user and to save him or her a mouse click
...
You will now see that text echoed to the Debug Output
window
...
This line of code has been altered to now read ‘Debug
GetGadgetText(#STRING_INPUT)’
...
This command can be used
with many gadgets in PureBasic but with a String gadget it simply returns the text as a String which I
then immediately echo using a ‘Debug’ command
...
In this next
example I’ve added a list view gadget to display the input text in a list of non-editable Strings
...

PureBasic offers a lot of commands to work with list view gadgets, ranging from adding and removing
to counting and sorting of items contained within this type of gadget
...
Fig
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Interaction", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
TextGadget(#TEXT_INPUT, 10, 10, 280, 20, "Enter text here:")
StringGadget(#STRING_INPUT, 10, 30, 280, 20, "")
ListViewGadget(#LIST_INPUT, 10, 60, 280, 100)
ButtonGadget(#BUTTON_INTERACT, 10, 170, 120, 20, "Enter text")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Close window")
SetActiveGadget(#STRING_INPUT)
Repeat
Event
...
Reading the PureBasic helpfile on the ‘ListViewGadget()’ page (Helpfile:Reference
Manual->General Libraries->Gadget->ListViewGadget) will give you a good overview of this gadget
and what you can achieve using it
...
I’ve used the position and size parameters to put the list
view gadget in the middle of the main window, above the buttons but under the String gadget
...
29

Once this program is running, enter some text into the String gadget and press the ‘Enter text’ button
...
Once this is done the
program clears the String gadget to be ready for more input
...
Here are the three new lines I
have added to the ‘#BUTTON_INTERACT’ ‘Case’ statement:

...


The first line after the ‘Case’ statement adds an item to the list view gadget
...
The first parameter is the PB
number of the gadget you would like to add an item to, in our case it is ‘#LIST_INPUT’ which is a
constant that holds our gadget’s number
...
In the above example, I want this text to be added to the end of the list regardless of what that index
that may be, so I specify this parameter as ‘-1’
...


Creating User Interfaces

147

The third parameter is the actual String you want to add to the gadget
...
‘AddGadgetItem()’ takes more parameters than I’ve used here but the others are optional
and therefore not necessary so I haven’t used them
...
This is because, once text has been entered into the
list view gadget, I want to clear the String gadget ready for a new String to be entered
...

What Have We Learned So Far?
Hopefully the last few examples have been a good introduction to native graphical user interfaces and
provide a good starting point for further learning
...

The beginnings of every native interface in PureBasic is the same
...
Secondly, if you want to place gadgets upon this window you must
create a gadget list using the ‘CreateGadgetList()’ command and Third, you must have a main loop to
keep the program running and handle any events that may occur
...

Read The Gadget Section In The Helpfile
If you have understood what has been written so far you are on your way to fully grasping how to build
native interfaces in PureBasic
...
This can be achieved by reading through the
PureBasic helpfile in the ‘Gadget’ section (Helpfile:Reference Manual->General Libraries->Gadget)
...

Take for example, the ‘SetGadgetText()’ command, this can be used with many different gadgets
...

To cover all gadgets and the commands that work with them would take far too long here and probably
be another book in itself
...

Meanwhile, if you need a quick reference of what gadgets are available for use with PureBasic, then
have a look at Appendix B (Helpful Charts) for a full list of all gadgets and a brief description of each
one
...

When menu items are selected they trigger events just like gadgets and these events are handled in the
main loop alongside gadget events
...
Here is a small example:
Enumeration
#WINDOW_MAIN
#MENU_MAIN
#MENU_QUIT
#MENU_ABOUT
EndEnumeration
Global Quit
...
")
Repeat
Event
...
")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End

This small example shows a native menu added to an empty window
...
If you look at the above example, you can see how to create such a
menu
...
Once the window has been created, we create the menu
framework by using the ‘CreateMenu()’ command
...
This is very similar to the ‘CreateGadgetList()’ command’s syntax and I’ve also used the
‘WindowID()’ command here to provide the OS identifier of the main window
...
To do this, I begin with using a ‘MenuTitle()’ command
...
This command takes one String parameter which is the name of the title
...
Menu items are created by using the ‘MenuItem()’ command
...

In my example, I’ve defined one menu item under the ‘File’ menu title called ‘Quit’ then I’ve used the
‘MenuTitle()’ command again to create another menu title called ‘Help’
...
’ menu item
...
Almost exactly like detecting event from gadgets we use a global
event value called ‘#PB_Event_Menu’
...
I’ve used this command in a ‘Select’ statement like this:

...
")
EndSelect
EndSelect

...
This command returns the PB number of the menu item that triggered the event
...
In this ‘Select’ statement, if the value returned by the
‘EventMenu()’ command equals ‘#MENU_QUIT’ then the ‘Quit’ menu item has been selected and I

150

Creating User Interfaces

assign a true value to the ‘Quit’ variable which makes the main loop exit, thus ending the program
...
’ menu
item has been selected and I display a message requester displaying information about my program
...
These are menus which branch out from a parent menu into another connected child
menu
...
All
menu items inside these new child menus trigger events in exactly the same way as any other menu
item and can be caught in the same way in the main loop
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Menu Example", #FLAGS)
If CreateMenu(#MENU_MAIN, WindowID(#WINDOW_MAIN))
MenuTitle("File")
OpenSubMenu("Parent Menu Item")
MenuItem(#MENU_CHILD, "Sub Menu Item")
CloseSubMenu()
MenuBar()
MenuItem(#MENU_QUIT, "Quit")
MenuTitle("Help")
MenuItem(#MENU_ABOUT, "About
...
l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_CHILD
Debug "Sub menu item selected
...
")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End

Creating User Interfaces

151

A sub menu is created by using the ‘OpenSubMenu()’ command after a ‘MenuTitle()’ command
...
The ‘OpenSubMenu()’
command takes one parameter which is the String that is displayed in the menu in front of the sub
menu arrow
...
To close this sub menu to be able to add
more items to the main menu, you have to call the ‘CloseSubMenu()’ command
...

New menu items that are added to sub menus trigger events that can be caught in the main loop in the
same way as any other menu item
...
If the return value from ‘EventMenu()’ equals the
value of ‘#MENU_CHILD’ then the child menu item must of been selected, so I echo some text to the
Debug Output window to show this
...
This command
draws a nice graphical separator bar in the menu which is useful to separate certain menu items
...
It takes no parameters and is used wherever you would
like to place a separator in the current menu
...

Combining Gadgets And Menus In The Same Program
Including menus and gadgets in the same program is easy
...
Then you create a gadget list and draw your gadgets, it’s that simple
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 222, "Interaction", #FLAGS)
If CreateMenu(#MENU_MAIN, WindowID(#WINDOW_MAIN))
MenuTitle("File")
MenuItem(#MENU_QUIT, "Quit")
MenuTitle("Help")
MenuItem(#MENU_ABOUT, "About
...
l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_QUIT
Quit = #True
Case #MENU_ABOUT
MessageRequester("About", "This is your program description
...

In the above example, I’ve used both in the same ‘Select’ statement which tests the ‘Event’ variable, like
this:

...

;Menu events are handled here

...

Case #PB_Event_Gadget
Select EventGadget()

...

EndSelect
EndSelect

...
If an event is
triggered from a gadget then it is handled in the ‘#PB_Event_Gadget’ ‘Case’ statement and the exact
gadget can be determined by using the ‘EventGadget()’ command
...


Why Can’t I Put Icons In Menus?
You will probably notice in Fig
...
PureBasic is a cross-platform programming
language and PureBasic code, once written, should compile for any supported platform
...
Icons in menus were regarded
as being too difficult to support in a cross-platform way so they were omitted, from the final PureBasic
command set
...
To learn more about what a native API is and learn more
about the WinAPI, see Chapter 13
...
These shortcuts are just key combinations that you can press on the keyboard to trigger menu
items so you don’t physically have to select them from the menu
...

To demonstrate this we need to create a window with a menu
...
An accelerator is a computer term for the String on

Accelerators

Fig
...
30 shows
the accelerators defined in the PureBasic IDE’s file menu
...

You will also notice in Fig
...
This
is to make sure they are clearly marked and to keep the menu itself uncluttered
...

Enumeration
#WIN_MAIN
#MENU_MAIN
#M_QUIT
#M_ABOUT
EndEnumeration
Global Quit
...
" + #TAB$ + "Ctrl+A")
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_Q,#M_QUIT)
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_A,#M_ABOUT)
Repeat
Event
...
")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End

Creating User Interfaces

155

If you run the example, you will see that besides the menu items there are now accelerators
...

MenuItem(#M_QUIT, "Quit" + #TAB$ + "Ctrl+Q")

...
The first part is the menu item String, which in this case is ‘Quit’
...
This constant has the ASCII value of
‘9’ in String form
...

A tab is used here instead of a space so that the accelerators are always aligned to the right of the menu
regardless of the lengths of the menu item Strings
...
To add the shortcut functionality of the
accelerators we must use the ‘AddKeyboardShortcut()’ command
...

AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_Q,#M_QUIT)
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_A,#M_ABOUT)

...
The second parameter is a value that represents the
actual keyboard shortcut
...
On the first line in the above snippet, I’ve combined the constants
‘#PB_Shortcut_Control’ and ‘#PB_Shortcut_Q’ to specify that I want the shortcut to be ‘Control+Q’
on the keyboard
...

All shortcut constants available for use to create all other key combinations are listed in the PureBasic
helpfile on the ‘AddKeyboardShortcut()’ page (Helpfile:Reference Manual->General Libraries>Window->AddKeyboardShortcut)
...
On the first line in the above snippet, I’ve used ‘#M_QUIT’ which is the
same PB number I used to create the ‘Quit’ menu item earlier on
...

On the next line of the snippet I’ve repeated this command but with different parameters to provide a
keyboard shortcut for the ‘About’ menu item
...


156

Creating User Interfaces

Keyboard Shortcuts Without A Menu
Using the same keyboard shortcut commands you can create keyboard shortcuts without having a
menu to base them on
...
You then test for this value as a menu event in the main loop even
though there is no menu
...
l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #SC_EVENT
Debug "The shortcut was pressed"
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
EndIf
End

While the above example is running, press ‘Control+Z’ on your keyboard and you should see the text
‘The shortcut was pressed’ echoed to the Debug Output window
...
This is a handy trick to know if you
ever want to add keyboard shortcuts to your programs even though you don’t want a menu
...
In this next section I’ll show you how to add images to your interfaces in one of two ways
...
Second you can embed the image directly into your program so you only have one
executable file
...
Both these methods require an image gadget to be placed on your window to display the image
...

Loading Images Into Your Program
This method of loading images for use in your interface is reliant on external images
...
Here is an example:

Creating User Interfaces

157

Enumeration
#WIN_MAIN
#IMAGE_FILE
#IMAGE_DISPLAY
#BUTTON_CLOSE
EndEnumeration
Global Quit
...
bmp")
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_FILE))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Close window")
Repeat
Event
...
Once this is in place
the program (once run) will look something like Fig
...

In this example, I’ve used the ‘LoadImage()’ command to load the image from a place on the hard drive
into memory ready for displaying in the program, like this:

...
bmp")

...
If no file path information is included in the second
parameter the file location is assumed to be relative to the program itself
...
As usual I’ve tested the return value of this command with an ‘If’
statement to make sure it has loaded correctly before continuing with the rest of the program
...
If you look at the image gadget example, after I’ve created a gadget list, I’ve used the
‘ImageGadget’ command, like this:

...


‘ImageGadget()’ is a simple command to understand, the first parameter is the PB number that is
associated to this gadget, not the loaded image
...
The fifth parameter is where we specify what image this
gadget will display, so this parameter must be an OS identifier of a previously loaded image
...
In the above code I’ve used the ‘ImageID()’ command to retrieve the OS identifier of the
‘#IMAGE_FILE’ image which was loaded previously using the ‘LoadImage()’ command
...
31

This way of loading images to display them in an image gadget is a simple way of doing things, but you
must remember that when including images in your interfaces like this, you must always distribute the
images used along with your final executable file
...
If you want to embed your images within your
program completely, read on
...
This method uses what is known as a data section where you can embed binary files for the
executable to use when needed
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Image Example", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
If CatchImage(#IMAGE_MEMORY, ?Image)
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_MEMORY))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Close window")
Repeat
Event
...
bmp"
EndDataSection

This example is very similar to the previous one, except this one is embedding the image into a data
section when compiled
...
If you look at the example you can see the data section at the bottom
of the source code, it looks like this:

...
bmp"
EndDataSection

The commands ‘DataSection’ and ‘EndDataSection’ are the start and finish of the section
...
This command doesn’t use any
brackets, it just uses a String after it to define a file to embed
...
bmp’
...
This label enables your program
to find the start of this image in memory once loaded with this program
...

In the main code, we no longer use the ‘LoadImage()’ command to load the image into memory
...
So we use the
‘CatchImage()’ command to retrieve the image from the data section, like this:

...


If you look at the ‘CatchImage()’ command in the PureBasic helpfile (Helpfile:Reference Manual>General Libraries->Image->CatchImage) you can see this command takes three parameters, the first
is the PB number that will be associated with this image
...
If you remember, I’ve used a label in the data section to show this so I need
to get the memory address of this label
...
This question mark is a special one character function that returns the memory
address of any label
...
I’ve not used the
third parameter in this example because it is optional
...
Again, we use an image gadget and populate its parameters in the same way
as before:

...


Once you run this example it should look like Fig
...
This is because it is the same program, but
now it no longer needs the external ‘image
...

What Image Formats Can Be Used?
In the last few examples I’ve loaded and embedded images which are in Bitmap (*
...

As standard, PureBasic can load and display Bitmap (*
...
ico) format files but
sometimes these can be restrictive
...
These other decoders
are extremely simple to use, you just use the decoder command at the start of your source code and
from then on in your program all the image loading commands have full support of the image format
decoder used
...


Creating User Interfaces

161

Here are the other decoder commands:
‘UseJPEGImageDecoder()’
This decoder adds support for the Jpeg image (*
...
jpeg) file format
...
png) file format
...
tif/*
...

‘UseTGAImageDecoder()’
This decoder adds support for the Targa image (*
...

As stated before, using these decoder commands is simplicity itself
...
b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Image Example", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
If CatchImage(#IMAGE_MEMORY, ?Image)
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_MEMORY))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Close window")
Repeat
Event
...
jpg"
EndDataSection

In this example the only difference I’ve made to the source code to make it able to support Jpeg files
is I’ve added the ‘UseJPEGImageDecoder()’ command as the first line in the code and then changed
the image in the data section to a Jpeg format one
...

All other decoders are used in the same way, just add the decoder command at the top of your source
code to add support for these further file formats
...
This means in plain speak, that you can literally draw your gadgets upon a window to
create your interface and all the underlying PureBasic code is generated for you automatically and in
realtime
...
You should also be able to load the code back in
again at a later date if you need to add something or provide further functionality in your program
...
This is because the visual designer
generates code in a certain way and if a hand written file deviates from this format the designer might
have a hard time reading it in
...

Why Haven’t You Mentioned This Earlier?
I thought it was very important for you to learn how things work in PureBasic regarding gadgets,
menus and events, to give you a more solid grounding of the code generated by the VD
...

The Main Window
When you start the visual designer up it will look something like Fig
...
The main window is a multiple
document interface containing all the tools you will need to design your interface
...
To the left of the screen there is a long tool panel
containing the Gadget Tool Box and the Properties panel
...


Creating User Interfaces

163

Using The Visual Designer
If you look at Fig
...

This window is easy to spot because it is covered in tiny dots
...
These dots do not
appear on the finished program
...
32
Once the interface’s window has been resized to the desired dimensions you can then start placing
gadgets on it
...
You will now be drawing a dynamically resizing gadget of the selected tool type directly on the
window
...
These are

164

Creating User Interfaces

handles allowing you to resize and move the gadget after it has been drawn
...

Once all gadgets are placed and you have finished designing your user interface you can save your
project by clicking the disk button in the Toolbar
...

Pro’s and Con’s Of The Visual Designer
While the visual designer is a great tool to quickly and easily throw together user interfaces the format
of the code generated cannot be changed
...
This is
not really a problem if you are experienced with PureBasic but for the novice user, the exported code
can be quite complicated and advanced
...
You can throw together a useful user
interface in seconds and see how it looks and then just as easily move and resize the gadgets until you
get it just right
...
The amount of time you could save designing a user
interface using the VD is staggering, simply because you are negating the need to compile the program
to see how it looks
...
Some say that it’s best to
handle all the code yourself so you truly know what’s going on ‘under the hood’ while others argue that
in today’s competitive world you need a fast solution to designing interfaces
...
The tools are there it’s up to you if you want to
use them
...
To view it press ‘F1’ within the visual designer
and the helpfile will load
...

The new version of the visual designer which is (shown in Fig
...
There is an Internet link
given for this in Appendix A (Useful Internet Links)
...
When programming such cool stuff you need a computer language that will
provide you with the necessary tools to realize your ideas
...
In this section I will show you the basics of using graphics and sound within your
PureBasic programs
...
Then I’ll move on to show you how to open full size
graphical screens to be able to draw graphics onto
...

After that, we’ll move onto 3D graphics where I will introduce you to PureBasic’s adopted 3D engine
and show you the basics of using 3D graphics in PureBasic
...

The last chapter in this section deals with sound
...

The chapters contained in this section are not complete guides on how to achieve every graphical effect
or how to write games, I’ll leave that to other texts
...
Hopefully this section will give you a taste of what is possible
graphically using PureBasic and inspire you to create a cool demo or game
...
The term ‘2D graphics’
encompasses quite a large subject and many drawing operations fall beneath this descriptive umbrella
...
These graphical types can
also contain different complexities, from a single pixel right up to a full color image
...

Using 2D graphics, it’s possible to achieve some very impressive visuals and as a result, many games,
screensavers and demo’s have been created using PureBasic
...


2D Drawing Commands
PureBasic contains commands that allow you to draw primitive shapes and colors in your programs
...
These commands are useful for drawing simple shapes and
text in different colors and there is even a couple of commands to draw using a previously created or
loaded image
...
These six methods pretty much cover anything you might need to draw onto,
and each one is as easy to use as any other
...
To simplify things even further, all the output methods
share the same drawing command syntax
...
You probably will
never do this in a real world application but it’s a simple exercise for you to understand and learn the
syntax from
...
l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End

If you run the above example, you will see a window similar to Fig
...
These shapes are drawn directly onto the window itself and
no gadgets have been used
...


(Microsoft Windows
example)

Fig
...
This command tells PureBasic
that I wish to start drawing using the 2D graphics commands and specifies what the drawing
commands should draw on
...
These
are:
‘WindowOutput()’
Use this to draw onto PureBasic user interface windows
...

‘ScreenOutput()’
Use this to draw directly onto a PureBasic screen
...
This output method requires a PB number as a parameter to
specify what sprite to draw onto
...
This output method requires a PB
number as a parameter to specify what image to draw onto
...

‘TextureOutput()’
Use this to draw onto a 3D model’s texture
...

In my example I’ve specified that I want to start drawing onto a window, like this:

...


Once I have set up the drawing output like this, I am free to use any of the 2D drawing commands to
draw to it
...
Once you have used a
‘StartDrawing()’ command you must always use a ‘StopDrawing()’ command to finish off the drawing
operations
...
This is essential because it may cause bugs
in your program if you do not tell the compiler that you have stopped drawing
...
These are ‘Box()’, ‘Circle()’, ‘LineXY()’ and ‘FillArea()’
...
Nearly all the 2D commands share similar parameters
...
If we take the ‘Box()’ command for
example, the first two parameters are the position of the box on the output
...

Working With Colors
The colors in PureBasic are specified using a single 24 bit color value
...
To get a 24 bit value of a color we need to
use the ‘RGB()’ command
...
Each one of these parameters has a value range of ‘0’ to ‘255’
...
7 million colors as individual 24 bit values
...
33:

...


Here, I’ve used the ‘RGB()’ command inline as a parameter of the ‘Box()’ command
...
This means that the ‘RGB()’ command will return a 24 bit value that
describes a full red which is not mixed with any green or blue
...

LineXY(62, 140, 112, 220, RGB(0, 0, 255))
LineXY(112, 220, 12, 220, RGB(0, 0, 255))
LineXY(12, 220, 62, 140, RGB(0, 0, 255))
FillArea(62, 180, RGB(0, 0, 255), RGB(0, 0, 255))

...
33
...
The last command is a ‘FillArea()’
command that picks a point in the center of the triangle and fills it with the same color as the sides
...
The first and second
parameters of the ‘RGB()’ command representing red and green are at ‘0’ while the third parameter
representing blue is at ‘255’
...
The green circle in Fig
...

Circle(140, 125, 45, RGB(35, 158, 70))

...
Using colors like this, makes things simple in PureBasic and very easy to understand for
beginners
...


2D Graphics

171

While the ‘RGB()’ command can take red, green and blue values and return a combined 24 bit value,
there may be a time when you want to extract the red, green and blue component values from a single
24 bit color value
...

Look at this example:
ColorValue
...
On the first line in the above example, I
compose the 24 bit color value using (amongst the others) a red parameter value of ‘35’
...
The
other color commands work in exactly the same way
...
This is mostly because of the way different operating systems handle
the refreshing of the window display
...
This is because of the internal event handling that takes place within Microsoft
Windows
...
You can force the redraw of graphics after a window has passed in front of another
but this is advanced stuff and requires the use of API knowledge of the particular operating system you
are dealing with
...
Using an
image gadget makes sure that the window automatically takes care of any refreshing that may be
needed to keep the image visible
...
In this next example, I’m going to try to emulate the last program but
with a difference
...
This should then avoid any
window refresh issues and behave how we think it should
...
Here’s our example:
Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
EndEnumeration

172

2D Graphics

If CreateImage(#IMAGE_MAIN, 180, 220)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
;Because a new image has a Black background, draw a white one instead:
Box(0, 0, 180, 220, RGB(255, 255, 255))
;Now, continue drawing the shapes:
Box(5, 5, 75, 75, RGB(255, 0, 0))
Circle(130, 115, 45, RGB(35, 158, 70))
LineXY(52, 130, 102, 210, RGB(0, 0, 255))
LineXY(102, 210, 2, 210, RGB(0, 0, 255))
LineXY(2, 210, 52, 130, RGB(0, 0, 255))
FillArea(52, 170, RGB(0, 0, 255), RGB(0, 0, 255))
StopDrawing()
EndIf
EndIf
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 200, 240, "Drawing On A New Image", #FLAGS)
If CreateGadgetList(WindowID(#WINDOW_MAIN))
ImageGadget(#IMAGE_GADGET, 10, 10, 180, 220, ImageID(#IMAGE_MAIN))
Repeat
Event
...
The ‘CreateImage()’ command takes four parameters, the first is the PB
number associated with this new image
...
If the fourth
parameter is not used, like in my example, then it uses the same bit depth as your desktop
...

StartDrawing(ImageOutput(#IMAGE_MAIN))

...

This way of specifying an image to draw onto is not limited to a newly created image
...
As long as an image has a PB number
associated to it, then you can set the drawing output to draw on it
...

Because all newly created images in PureBasic start with a black background, the first drawing
operation I must make is to color the background with white
...
After this, I draw the
square, circle and triangle shapes as before
...

To display this image correctly and avoid the previous refresh problems of drawing directly onto a
window, I use an image gadget
...


What Is The Bit Depth Of An Image?
Each pixel on a computer display or in a digital image is described by binary numbers, as you would expect
on a computer
...
The number of bits describing a single pixel in any given digital
image or a computer display is called its bit depth
...

1 bit images can only describe black and white (2 color) images since the one single bit that describes each
pixel can either have a value of ‘1’ or ‘0’
...
Modern
computers nowadays tend to only use 32 bits per pixel
...
Using the ‘DrawingMode()’ command you can switch to outline mode for shape commands, draw
text with a transparent background or even mix (XOr) the output from a drawing command with the
background
...
l, YPos
...
l, Height
...
l, Green
...
l
Text
...
l MyRandom(Maximum
...
l = Random(Maximum)
Until (Number % 10) = 0
ProcedureReturn Number
EndProcedure
If CreateImage(#IMAGE_MAIN, ImageWidth, ImageHeight)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
For x
...
l = MyRandom(ImageWidth) + 1
YPos
...
l = (MyRandom(100) - 1) + 10
Height
...
l = Random(255)
Green
...
l = Random(255)
Box(XPos, YPos, Width, Height, RGB(Red, Green, Blue))
DrawingMode(#PB_2DDrawing_Outlined)
Box(XPos - 1, YPos - 1, Width + 2, Height + 2, RGB(0, 0, 0))
DrawingMode(#PB_2DDrawing_Default)
Next x
LineXY(ImageWidth - 1, 0, ImageWidth - 1, ImageHeight, RGB(0, 0, 0))
LineXY(0, ImageHeight - 1, ImageWidth, ImageHeight - 1, RGB(0, 0, 0))
Box(10, 10, 230, 30, RGB(90, 105, 134))
DrawingMode(#PB_2DDrawing_Outlined)
Box(10, 10, 231, 31, RGB(0, 0, 0))
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(21, 18, Text, RGB(0, 0, 0))
DrawText(19, 18, Text, RGB(0, 0, 0))
DrawText(21, 16, Text, RGB(0, 0, 0))
DrawText(19, 16, Text, RGB(0, 0, 0))
DrawText(20, 17, Text, RGB(255, 255, 255))
StopDrawing()
EndIf
EndIf
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN,0,0,ImageWidth+20,ImageHeight+20,"Abstract",#FLAGS)
If CreateGadgetList(WindowID(#WINDOW_MAIN))
ImageGadget(#IMAGE_GADGET,10,10,ImageWidth,ImageHeight,ImageID(#IMAGE_MAIN))
EndIf
Repeat
Event
...
With each box I draw, I switch the drawing
mode to outline and draw a black outline with the same dimensions over the top
...
Not only does each box have a random color but each one has a black outline too
...
Here are these constants and what they achieve:
‘#PB_2DDrawing_Default’
This is the default mode, text is displayed with a solid background color and graphic shapes are filled
...

‘#PB_2DDrawing_Transparent’
This sets the text background to transparent so only the ‘DrawText()’ front color parameter is used
...

Using this command is very easy
...
These constants can also be combined using the bitwise ‘Or’ operator
...

Once you run this example you will see a window very similar to Fig
...


(Microsoft Windows example)

Fig
...
To actually draw the text, I used the
‘DrawText()’ command
...
Because I’ve used a transparent background, the fifth
parameter is ignored
...
I’ve done this like this because the ‘#PB_2DDrawing_Outlined’ drawing mode does
not yet support text
...
If you look at the last example, you can see I’ve used
this command a few times
...
The third parameter is the actual string of text to draw
...
The front color means the actual text color and the back color
means the background color
...
These color parameters are 24 bit color values, composed easily using the ‘RGB()’
command
...
In this next example, I’ll show you
how you can take an external image and draw it onto another newly created image, in any position you
like
...
l, YPos
...
l, LoadedImageHeight
...
s
RequesterText
...
s = ""
Pattern
...
bmp)|*
...
ico)|*
...
l = 1 To 1000
XPos = Random(ImageWidth) - (ImageWidth(#IMAGE_SMALL) / 2)
YPos = Random(ImageHeight) - (ImageHeight(#IMAGE_SMALL) / 2)

2D Graphics

177

DrawImage(ImageID(#IMAGE_SMALL), XPos, YPos)
Next x
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, ImageWidth, ImageHeight, RGB(0, 0, 0))
StopDrawing()
EndIf
EndIf
#TEXT = "Drawing Using Images"
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN,0,0,ImageWidth+20,ImageHeight+20,#TEXT,#FLAGS)
If CreateGadgetList(WindowID(#WINDOW_MAIN))
ImageGadget(#IMAGE_GADGET,10,10,ImageWidth,ImageHeight,ImageID(#IMAGE_MAIN))
EndIf
Repeat
Event
...
Once this requester correctly returns an image file name, I load that
file using the ‘LoadImage()’ command, very similar to the image gadget example in Chapter 9
...
The resulting image is displayed on a window using an image gadget
...
35 you can see what it looks like after I have loaded a sphere shaped icon which is then
randomly drawn all over the new image and then displayed
...
35

178

2D Graphics

If you want to draw a loaded image onto a newly created image, you use the ‘DrawImage()’ command
...
The first is the OS identifier of
the image you would like to use to draw with and this can be retrieved by using the ‘ImageID()’
command
...
The fourth and fifth parameters are optional and I haven’t used them here but these
are the width and height in pixels of the drawn image
...
In my example, I’ve randomized most of the parameters to randomly
fill the new image with a thousand copies of the loaded image
...
This command opens an operating system
standard file requester for users to easily select a file
...
This can be demonstrated by this little
stand-alone snippet of code:
Global File
...
s = "Choose an image"
Global DefaultFile
...
s = "Bitmap (*
...
bmp|Icon (*
...
ico"
File = OpenFileRequester(RequesterText, DefaultFile, Pattern, 0)
Debug File

If you look at the ‘OpenFileRequester()’ page in the helpfile (Helpfile:Reference Manual->General
Libraries->Requester->OpenFileRequester) this command takes four parameters
...
The second is a String
parameter of a file name that this requester may be looking for
...
The third parameter is a file
pattern to allow the programmer to determine what files should and shouldn’t be displayed for
selection in the requester
...
In this snippet, ‘Bitmap’ is first selected because the file pattern index starts
at ‘0’
...
The file types are
broken down into chunks within the pattern String, divided by pipe characters ‘|’ identical to the
bitwise Or operator
...
For example, in the above snippet, the pattern looks like
this:
"Bitmap (*
...
bmp|Icon (*
...
ico"

If we break this into chunks using the pipe characters as separators we can see more clearly what is
being specified:
Bitmap (*
...
bmp

Icon (*
...
ico

The first chunk is a String to display in the ‘Files of type’ selection box within the requester, and once
this is selected, it uses the next chunk to tell the requester what type of files to display inside the main

2D Graphics

179

window, in this case all ‘
...
Remember, the asterisk used here is a String wildcard character to
signify any name
...
If you need to specify many extensions for one particular file type you can use the
semi colon to specify more extensions within a chunk, like this:
"JPEG|*
...
jpeg"

This will now display any files with the extensions of ‘
...
jpeg’ when the ‘JPEG’ String is selected
in the requester
...

Drawing Images With Alpha Channels
Sometimes you may need to draw an image which contains an alpha channel to preserve a drop
shadow or maybe parts of the image should be transparent
...
35 I used an icon to draw all over
the newly created image, and as standard PureBasic preserves any alpha channel information found
inside that icon
...
This command will preserve
any alpha channel found in image formats that support them, such as 32 bit Png or Tiff files
...
Here is an example of how the
command could be used:

...


The above line would display a Png format image and preserve its alpha channel, blending it nicely
over any background
...


Saving Images
Once you have created an image in your program, you may want to save it to disk
...
This command will save any image in your PureBasic program that
has a PB number
...
The first is the PB number of
the image you want to save
...
The third
parameter is optional and defines what image format this image should be saved as
...


180

2D Graphics

If we wanted to save the image created from the last example, we could add this line of code onto the
end of the example code
...

SaveImage(#IMAGE_MAIN, "Image
...


By default, PureBasic will save a Bitmap format image file when you use this command without the last
two optional parameters
...
bmp) when saved
...
This can be one
of these three built-in constants:
‘#PB_ImagePlugin_BMP’
Save the image in Bitmap format
...

‘#PB_ImagePlugin_JPEG’
Save the image in Jpeg format
...

‘#PB_ImagePlugin_PNG’
Save the image in Png format
...

When saving an image using either ‘#PB_ImagePlugin_JPEG’ or ‘#PB_ImagePlugin_PNG’ you must
put the appropriate encoder command at the top of your source code before using the ‘SaveImage()’
command to make sure it knows how to encode that given format
...
Here are they are:
‘ UseJPEGImageEncoder()’
This encoder adds support for the Jpeg image (*
...
jpeg) file format
...
png) file format
...
This is
the only image type that currently supports this fourth parameter
...
bmp")

This first example will save an image called ‘Image
...
Notice
that no encoder is needed because PureBasic supports Bitmap format images as standard
...

SaveImage(#IMAGE_MAIN, "Image
...
jpg’ in JPEG format using a default compression
value of ‘7’ because we haven’t specified one ourselves
...

SaveImage(#IMAGE_MAIN, "Image
...
jpg’ in JPEG format and use the maximum
compression value of ‘10’ as specified in the fourth parameter
...

SaveImage(#IMAGE_MAIN, "Image
...
png’ in PNG format
...
This screen is a purely graphical environment, created for the
one intention of displaying graphics such as output from 2D drawing, loaded images, loaded sprites
and loaded 3D models and worlds
...
As processing power of computers increased through the years, the special hardware
that was used to move and draw these images quickly was no longer needed
...

Today a sprite can be described as a small graphic (usually containing a transparent background) that can be
positioned and drawn independently on a screen to simulate animation or to provide static graphics
...
This is referred to as a
Windowed Screen
...


182

2D Graphics

The reason why screens are preferred to display graphics (instead of simply drawing onto windows) to
create games and the like, is that screens are fast,
...

Opening Your First Screen
To create and open a screen in PureBasic you need to follow a basic code template
...
This makes sure that everything is correctly initialized internally and the screen will be ready
for drawing operations
...

The code below shows a skeleton screen program with all crucial bits of code present to initialize the
sprite engine, open a screen, create a main loop and initialize the keyboard commands to provide a way
of closing the program
...
b = #False
;Simple error checking procedure
Procedure HandleError(Result
...
s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
HandleError(InitSprite(), "InitSprite() command failed
...
")
HandleError(OpenScreen(1024, 768, 32, "Fullscreen"), "Could not open screen
...

This example doesn’t really do anything other than open a blank screen and if you are looking at that
now you can exit the program by pressing ‘Esc’ on your keyboard
...

To start with I’ve created a simple error checking procedure as explained in Chapter 8 (How To
Minimize And Handle Errors) and used this to make sure that the ‘InitSprite()’, ‘InitKeyboard()’ and
‘OpenScreen()’ commands do not return ‘0’
...
If a failure occurs like this for whatever
reason, it is always best to close the program and inform the user of the problem
...

The commands needed to initialize the sprite engine and keyboard are just simple command calls,
these are ‘InitSprite()’ and ‘InitKeyboard()’, remember that we need to initialize the sprite engine
before we open a screen
...
This caption is what will be displayed in the
taskbar if you were to minimize the screen from view
...

These can all be found in the ‘Keyboard’ library helpfile page (Helpfile:Reference Manual->General
Libraries->Keyboard)
...

The ‘InitKeyboard()’ command initializes the keyboard and should be called before any other keyboard
command
...
The ‘KeyboardReleased()’ and ‘KeyboardPushed()’ commands return true if a given
key is either released or pushed respectively
...


The width, height and bit depth parameters are very important to get right as these define what size
and bit depth your screen will be
...
The width and height values
are collectively known as the resolution and this must be supported wholly by the graphics card and
monitor connected to the target computer or else an error will be raised and the ‘OpenScreen()’
command will not succeed
...
This is worth keeping in mind when writing a
program that relies on a screen
...
36 shows common screen resolutions and bit depths that should work on almost every modern
computer
...
The higher, the bit depth, the
more colors are able to be displayed and more lifelike graphics are able to be represented
...
36
Of course, instead of hard coding values like these into a program, it’s always best to test the ability of
the target computer to use these values
...
l = ScreenModeWidth()
Height
...
l = ScreenModeDepth()
Debug Str(Width)+" x "+Str(Height)+" x "+Str(BitDepth)
Wend
EndIf

Again in this snippet, we initialize the sprite engine before we use the ‘ExamineScreenModes()’
command, this initializes everything correctly to allow us to use these screen based commands
...
This is then echoed to the Debug Output window for us to examine
...

Double Buffered Rendering
When using a screen to display graphics you always need a main loop to keep the program running,
draw graphics and test for user input, etc
...

Here is the main loop taken from the skeleton screen program on the previous page:

...


2D Graphics

185

At first glace you can see it’s very similar to a normal main loop of any other program but there are a
few differences
...
Before I can go into more detail about these two
commands I must explain a graphical technique called double buffering
...
Because computer monitors constantly redraw the monitor screen usually sixty to
seventy (sometimes more) times a second, it’s hard to make changes to the screen, such as moving and
drawing new graphics without the display showing changes before you’ve actually completed them
...
If you wanted to avoid this
problem by clearing the screen every time before redrawing the whole screen again, it would cure the
corrupted graphic problem but it would make the screen flicker
...
Once a screen is opened it automatically gets
assigned two video buffers in memory, exactly the same size as the opened screen
...
When the monitor has finished
displaying the front buffer and the drawing operations are complete on the back buffer, both are
flipped over (swapped)
...
When the program draws its graphics again it draws on the newly flipped back buffer
...
Fig
...


Double Buffered Rendering
Buffer B

Buffer A

Buffer A

FlipBuffers()

Buffer B

Buffer B

FlipBuffers()

Buffer A

1

2

3

The screen is opened and
drawing starts on the back buffer
...

The new back buffer is cleared
and redrawn with updated graphics
...


(Buffer B is displayed on screen)

(Buffer A is displayed on screen)

(Buffer A is displayed on screen)

Fig
...
When we draw stuff using the PureBasic
drawing commands, we draw onto the backbuffer, indicated by ‘Buffer B’
...
This is shown in step 2
...
Again, once all drawing operation are done, we can flip the buffers again using
‘FlipBuffers()’ and we arrive at step 3, where ‘Buffer A’ is now drawn to the screen and ‘Buffer B’ is once
again the back buffer
...
If we want to create the illusion of movement to animate graphics,
we will have to clear these and redraw them in a new position before we flip the buffers again
...
‘ClearScreen()’ takes one parameter which is a 24
bit color value of the color you want to clear the screen with
...

The ‘FlipBuffers()’ command (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen>FlipBuffers) also has an optional parameter and can take these values:
‘0’ : Disable monitor vertical synchronization
‘1’ : Enable monitor vertical synchronization (default value)
‘2’ : Enable monitor vertical synchronization, using CPU saving mode (full screen mode only)
...
The only downside to this is that the monitor refresh rate
might not be fast enough to draw the new graphics in realtime so some visual tearing may occur as the
monitor tries to keep up with the flipped buffers
...
The only downside of this is that the frame rate can never exceed beyond the refresh rate of
the monitor
...

Using ‘2’ as a parameter will have the same effect as using ‘1’, but will switch to CPU saving mode to
ensure it does not run the CPU at a hundred percent so other program don’t have a chance to run
...
l = 1024
Global ScrH
...
l = 32
Global Quit
...
f = (ScrW / 2) - 64 : YOrigin
...
l, Text
...
")
HandleError(InitKeyboard(), "InitKeyboard() command failed
...
")
SetFrameRate(60)
;Create an image
If CreateImage(#IMAGE_MAIN, 128, 128)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
For x
...
f DegToRad(Angle
...
f * #PI / 180
EndProcedure
;Main loop
Repeat
ClearScreen(RGB(0, 0, 0))
Angle
...
0
Radius
...
l = 0 To 359 Step 45
XPos
...
f = YOrigin + (Radius * Sin(DegToRad(Angle + x)))
DrawImage(ImageID(#IMAGE_MAIN), XPos, YPos)
Next x
StopDrawing()
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End

In this example, I’ve created a new image using the ‘CreateImage()’ command and then later drawn
this image to the screen using a ‘StartDrawing()’ block
...


188

2D Graphics

You can see in the main loop, that the first thing I do is clear the screen using the ‘ClearScreen()’
command
...
After that I use some math to calculate new coordinates for my blob
images and use a loop to draw them
...
And so it goes on, clearing, drawing
and flipping, and between each flip, I change the position of the graphics
...
This command has one parameter that sets the number of times that ‘FlipBuffers()’
can be executed per second
...
This should limit this example to display updated graphics sixty times a second
...
Nothing actually
moves on screen, it’s really a slideshow of different images (buffers) in which graphics are in slightly
different positions
...

A Simple Starfield
This is one of the effects that any demo or game programmer will know how to draw
...
It
is an effect that draws and animates hundreds of pixels on the screen using different shades of color
to give the illusion of depth and movement
...
0"
#NUMBER_OF_STARS = 10000
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW
...
l = 768
Global ScrD
...
b = #False
Structure STAR
xPos
...
f
xStep
...
l
EndStructure
Global Dim Stars
...
l, Text
...
2
x < (#NUMBER_OF_STARS / 3) * 2
+ 0
...
2

;move stars on the 'x' axis
Procedure MoveStarsX()
For x = 0 To #NUMBER_OF_STARS
Stars(x)\xPos - Stars(x)\xStep
If Stars(x)\xPos < 0
Stars(x)\xPos = ScrW - 1
Stars(x)\yPos = Random(ScrH - 1)
EndIf
Next x
EndProcedure
;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed
...
")
HandleError(OpenScreen(ScrW, ScrH, ScrD, #APP_NAME), "Could not open screen
...
This command uses three
parameters, of which the third is optional
...
If the last parameter is not used then this command uses the default foreground
color, which is set using the ‘FrontColor()’ command
...
Each of the elements in the array describes the
position, color and step value of all of the individual pixels
...
) contained inside each structured
array element
...
Once this is done, I clear the screen and redraw again,
...
Doing things this way makes the code look cleaner, it’s much more easier to read and
allows you to update it easily at a later stage
...
You can do this using the ‘OpenWindowedScreen()’ command
...
Here is an example of using a windowed screen:
#WINDOW_MAIN = 1
#IMAGE_MAIN = 1
;Set the width, height and
;Abbreviated variables are
Global ScrW
...
l = 600
Global ScrD
...
b = #False
Global XOrigin
...
f = (ScrH /

bit depth of the screen
used here due to page width constraints :(

2) - 64
2) - 64

;Simple error checking procedure
Procedure HandleError(Result
...
s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

2D Graphics

;Convert Degrees to Radians
Procedure
...
f)
ProcedureReturn Angle
...
")
HandleError(InitKeyboard(), "InitKeyboard() command failed
...
l = 255 To 0 Step -1
Circle(64, 64, x / 4, RGB(255 - x, 0, 0))
Next x
StopDrawing()
EndIf
EndIf
;Main loop
Repeat
Event
...
f + 2
...
f = ((ScrH / 2) - 100) * Sin(DegToRad(Angle))
StartDrawing(ScreenOutput())
For x
...
f = XOrigin + (Radius * Cos(DegToRad(Angle + x)))
YPos
...
The
main difference being the ‘OpenWindowedScreen()’ command which takes eight parameters! The first
parameter is the OS identifier of the window it is to be opened on
...
The fourth and fifth parameters are the
width and height of the new screen
...
If this
parameter is set to ‘0’ then no automatic resizing takes place but if it is set to ‘1’ then the screen with
automatically resize itself to the maximum size that the window will allow, disregarding parameters
four and five
...
The seventh and eight parameters are
margins that you can specify for when auto-stretch is enabled
...

It is also very important when using a screen on a window, that you always handle the events properly
using the ‘WindowEvent()’ command
...
Using this command instead of ‘WaitWindowEvent()’ is a must because you don’t want to
halt the drawing and flipping of buffers for any length of time
...
Unlike images however,
sprites have their own command set, are optimized for speed and can be drawn in several special ways
to achieve many special effects
...
To familiarize yourself fully with what is capable using the sprite
commands, I would recommend reading both of these two sections
...
The first is what you would consider a normal
sprite, which is created from a user drawn or loaded image and which is displayed and manipulated
using the standard sprite library
...
Also, the commands used for drawing and manipulating this type, allow the programmer to
achieve graphical effects not possible with normal sprites
...
The 3D engine that performs the transformation and displaying
of the 3D sprites is not the OGRE engine as mentioned in the next chapter, but a small, self-contained
3D engine specifically created to handle this type of sprite
...

To load existing images to be used as sprites, the ‘LoadSprite()’ command is very similar to the
‘LoadImage()’ command and has three parameters
...
The second is the file name of the image you want to load as a sprite,
remembering of course, to use the correct image decoder if needed
...

To create your own sprite so you can draw on it using the 2D drawing commands, we use
‘CreateSprite()’
...
The first
parameter, is the PB number that you wish to associate to this sprite
...

Both of these two commands create a new sprite and both have an optional ‘Mode’ parameter
...
This format parameter is usually defined as a built-in constant, Fig
...

Depending on which sprite command you want to use to display your sprite, you have to use a correctly
formatted sprite with it, and this format is set when you create or load that sprite
...
Sprite is loaded into Video RAM (if possible)
...


#PB_Sprite_Alpha

Sprite must be 8 bit grayscale and will be prepared for use with the
‘DisplayAlphaSprite()’ or ‘DisplayShadowSprite()’ commands
...


#PB_Sprite_Texture

Sprite is created with 3D support, so that you can create a 3D Sprite
from it using the ‘CreateSprite3D()’ command
...
The image loaded must
be of an image format that can contain an alpha channel
...
(If
you intend on converting this sprite to a 3D sprite, the
‘#PB_Sprite_Texture’ mode needs to be specified as well)
...


Fig
...
Where
applicable, I’ve given an example of how to create and load a sprite with the correct mode settings, so
it will display properly when using the command before it
...
l, Height
...
bmp")

‘DisplaySprite3D()’
;Without an alpha channel
CreateSprite(#PB_NUMBER, Width
...
l, #PB_Sprite_Texture )
LoadSprite(#PB_NUMBER, "Image
...

LoadSprite(#PB_NUMBER,"Image
...
l, Height
...
bmp", #PB_Sprite_Memory)

‘DisplayAlphaSprite()’, ‘DisplayShadowSprite()’ & ‘DisplaySolidSprite()’
;Load in normal RAM for processing by the 'StartSpecialFX()' command
;and specify as an alpha type sprite
CreateSprite(#PB_NUMBER, Width
...
l, #PB_Sprite_Memory|#PB_Sprite_Alpha)
LoadSprite(#PB_NUMBER, "Image
...

You Can Draw On Sprites Too
Once you have created or loaded a sprite, you may want to draw on it
...
This allows you to use the 2D drawing commands to draw onto the sprite’s surface
...
To do this you must switch the sprite drawing output
from the back buffer to your target sprite
...
This
command takes one parameter which is the PB number of the sprite you want to direct all sprite output
to
...
When
you have finished, you can return the sprite display output back to the back buffer by using the
‘UseBuffer()’ command again, but this time with a parameter of ‘#PB_Default’
...
These are still normal sprites but work a lot
faster if they have the ‘StartSpecialFX()’ commands enclosing them
...
Here is a brief snippet
showing the usage of these commands:

...

StopSpecialFX()

...
All
special effects commands must go inside these two commands
...

If using these commands, it is very important to understand that these must be used before any other
graphics commands
...
Otherwise, if you use other graphics commands before a special effect block, they will be over
written on the backbuffer once the ‘StartSpecialFX()’ block starts
...
Another important point to make clear is that there should only ever be one ‘StartSpecialFX()’
block in any main loop, as this increases performance even further
...

Displaying Normal Sprites
Normal sprites are the foundations of making a 2D game in PureBasic
...
Here is a simple
example of creating a new sprite and rendering it all over the screen using the standard
‘DisplayTransparentSprite()’ command:

196

2D Graphics

#SPRITE_MAIN = 1
#NUMBER_OF_BALLS = 500
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW
...
l = 768
Global ScrD
...
b = #False
Structure BALL
x
...
f
XOrigin
...
l
Radius
...
f
Speed
...
BALL(#NUMBER_OF_BALLS)
;Simple error checking procedure
Procedure HandleError(Result
...
s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
;Convert Degrees to Radians
Procedure
...
f)
ProcedureReturn Angle
...
l = 0 To #NUMBER_OF_BALLS
Balls(x)\XOrigin = Random(ScrW) - 32
Balls(x)\YOrigin = Random(ScrH) - 32
Balls(x)\Radius = Random(190) + 10
Balls(x)\Angle = Random(360)
Balls(x)\Speed = Random(2) + 1
Next x
EndProcedure
;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed
...
")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Blobs"), "Could not open screen
...
f = 32
If CreateSprite(#SPRITE_MAIN, 64, 64)
If StartDrawing(SpriteOutput(#SPRITE_MAIN))
Box(0, 0, 64, 64, RGB(255, 255, 255))
For x
...
025
Circle(Offset, 64 - Offset, x / 8, RGB(0, 255 - x, 0))
Next x
StopDrawing()
EndIf
EndIf
TransparentSpriteColor(#SPRITE_MAIN, RGB(255, 255, 255))
InitialiseBalls()
;Main loop
Repeat
ClearScreen(RGB(56, 76, 104))
For x
...
This allows the sprite to not always appear square
...
Once this is done, I then draw a shaded green sphere on it using the ‘Circle()’ command
within a loop
...
After the drawing commands
have finished, I set all the white pixels in the new sprite to be flagged as transparent, using the
‘TransparentSpriteColor()’ command
...

Once the color has been picked, the next usage of ‘DisplayTransparentSprite()’ displays a sprite, minus
the transparent color
...
This is a great way to display sprites with a transparency
...
You can
use the normal sprite displaying commands by themselves
...
The
standard sprite displaying commands are:
‘DisplaySprite()’
‘DisplayTransparentSprite()’
Using Sprites3D’s
PureBasic calls it’s 3D sprites by the slightly mangled name of ‘sprite3D’
...
These polygons are drawn using a small 3D engine and can be transformed
in 3D but each sprite3D is ultimately drawn in 2D on the screen
...

A sprite3D in PureBasic is really a normal sprite that has had 3D support given to it and as such, this
different type needs a small 3D engine to display them
...
This is done by
using the ‘InitSprite3D()’ command
...

Every sprite3D starts life as a normal sprite, either loaded or created but with the
‘#PB_Sprite_Texture’ mode defined
...
This command
takes two parameters, the first is the PB number that you would like to associate to the new sprite3D
...

This is how this conversion procedure appears in PureBasic code:
LoadSprite(#NORMAL_SPRITE, "Image
...
To explain things a little more clearly, here’s an example of displaying
and manipulating sprites3D’s:
UsePNGImageDecoder()
Enumeration
#SPRITE_2D
#SPRITE_3D
EndEnumeration
#NUMBER_OF_FLOWERS = 150
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW
...
l = 768

2D Graphics

Global
;Other
Global
Global
Global

ScrD
...
b = #False
XOrigin
...
l = ScrH / 2

Structure FLOWER
XPos
...
f
Width
...
f
Angle
...
f
RadiusStep
...
FLOWER(#NUMBER_OF_FLOWERS)
;Simple error checking procedure
Procedure HandleError(Result
...
s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
;Convert Degrees to Radians
Procedure
...
f)
ProcedureReturn Angle
...
l = 0 To #NUMBER_OF_FLOWERS
Flowers(x)\Width = 0
Flowers(x)\Height = 0
Flowers(x)\Angle = Random(360)
Flowers(x)\Radius = 1
...
0
Next x
EndProcedure
;Reset a flower
Procedure ResetFlower(Index
...
0
Flowers(Index)\RadiusStep = (Random(30) / 10) + 1
...
")
HandleError(InitSprite3D(), "InitSprite3D() command failed
...
")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Flowers"), "Could not open screen
...
png",#PB_Sprite_Texture|#PB_Sprite_AlphaBlending)
CreateSprite3D(#SPRITE_3D, #SPRITE_2D)
InitialiseAllFlowers()
;Main loop
Repeat
ClearScreen(RGB(200, 100, 100))
HandleError(Start3D(), "Start3D() command failed
...
l = 0 To #NUMBER_OF_FLOWERS
Flowers(x)\Width + 1
...
5
Flowers(x)\Angle + 1
...
0 Or Flowers(x)\Height > 512
...
0
Flowers(x)\Height = 512
...
5
Flowers(x)\YPos - Flowers(x)\Radius / 3
...
This is essential to use any
sprite3D related commands
...
This image which is called ‘Flower
...
Loading a Png format image with an alpha channel like this requires you to define the
sprite mode correctly in the ‘LoadSprite()’ command
...
This tells the compiler I wish to use this
sprite as a sprite3D and it contains an alpha channel
...

Once the sprites have been created, it’s time to draw the sprites onto the screen
...
This looks something like this:

...


If you look at the flower example, the ‘Start3D()’ block is being checked using a small error checking
procedure to make sure it starts properly
...
If it doesn’t
start correctly, we must not draw any sprite3D’s or there may be serious program crash
...
Inside this block you must not use any commands from
the normal sprite library, this block is for sprite3D commands only
...

The first is the PB number of the sprite3D you wish to display
...
The fourth optional parameter is the alpha value of the sprite
...
This is an integer
which ranges from ‘0’, which is completely transparent, to ‘255’, which is completely opaque
...
These commands are very easy to understand and can be read about in more
detail in the PureBasic helpfile within the ‘Sprite3D’ section (Helpfile:Reference Manual->2D Games
Libraries->Sprite3D)
...
This
is done with the ‘Sprite3DQuality()’ command
...
The parameter is a numeric value which is equal to
a particular mode
...
If this command is not used however, the
default quality setting for that program is ‘0’, which doesn’t enable any filtering, leaving sprites3D’s
looking pixelated when manipulated
...
3D graphics uses imaginary 3D models to create believable worlds that give the
impression of width, height and depth, and the computer monitor is usually considered a window
through which you can view these 3D worlds
...
Luckily, PureBasic takes care of all the
mathematics that are needed to draw 3D graphics on screen by using the OGRE 3D engine
...
This makes
programming 3D graphics in PureBasic quick, fun and very easy
...


An Overview Of The OGRE Engine
To make it possible to draw three dimensional graphics on screen, as I said before, you have to use
complicated math routines to calculate the model shapes, model textures, positions and lighting, etc
...
Thankfully for users of PureBasic,
the OGRE 3D engine is used to take care of all this tedious stuff so you can concentrate on coding your
program
...
This engine is provided freely on the Internet
and available for anybody to use, free of charge, for any purpose
...
The engine itself is included with PureBasic as a dynamic linked library (DLL) and PureBasic’s
built-in 3D library is a wrapper to it
...
This is due to some incompatibilities with the language that OGRE was
programmed in and the time it takes the PureBasic team to implement and test new commands
...
You can view the
current OGRE command set in the helpfile under the ‘3D Games Libraries’ section (Helpfile:Reference
Manual->3D Games Libraries)
...
This is the OGRE ‘Mesh’ format and these model files will have the file extension
of ‘*
...

If you look on the OGRE website, in the downloads section, you will find many third party tools and
plugins that provide extra functionality to leading 3D modeling packages
...
In fact, it
is probably a good idea to look here first before deciding which 3D modeling package to use for your
mesh creation
...
This type of
program will allow you create a model using a three dimensional display
...
This type of program also
provides tools to allow you to add image textures, to give your model a graphical skin for when it’s rendered
in the 3D engine
...
This two dimensional unwrapped form can then be
exported as an image to provide a template from which you can draw your texture
...
Any 3D modeling program can
be used to create your 3D models as long as the finished model can be exported and saved as a ‘*
...


OGRE Texture Formats
Every model that is displayed using a 3D engine needs a texture
...
In fact some
people do indeed refer to textures as ‘skins’
...

When using textures to provide skins for your 3D models, you must use the correct image format,
otherwise the textures will not appear once your program is compiled
...
The OGRE engine used by PureBasic uses Png, Tga or Jpg files
...


3D Graphics

205

OGRE’s 3D Coordinate System
When drawing and manipulating objects in 3D space you need a good coordinate system to track an
object’s position in that space
...
In a coordinate system like this, the three
dimensions are assigned a different letter and this is where the ‘x, y, z’ comes from
...
Fig
...
This diagram also shows how three dimensional space can easily be
divided and referred to using three values
...


-

Coordinates Of OGRE’s 3D Space

Z

+

‘X’ = Width
‘Y’ = Height
‘Z’ = Depth

Y

-

X

+

Each point in 3D space can
be expressed by three ‘x, y, z’
values
...


10
9
8
7
6
5
4
3
2
1
0
0 1 2 3
4 5 6 7
8 9 10

0
1
2
3
4
5
6
7
8
9
10

Fig
...
The box on
the left in Fig
...
If you imagine the bottom left corner of your
computer monitor as existing at 3D coordinates; ‘0, 0, 0’
...
The ‘z’ coordinate is a little bit different, in that
it increases in value the further away from the screen, towards you, that you travel
...

Some people like to use the coordinates ‘0, 0, 0’ as the center of any given 3D space, and then
coordinates that refer to other objects within that world can either be positive or negative depending
on which way from the center, the point that you need to describe is
...

OGRE API Identifiers
While using PureBasic and OGRE to produce 3D visuals, you are effectively using the OGRE API
(application programming interface) to handle things behind the scenes
...
On occasion however, you will still need to refer to some OGRE objects by their OGRE

206

3D Graphics

identifier
...
To get the OGRE identifiers of various objects you can use these
PureBasic commands:
‘MaterialID(#MATERIAL)’
Returns the OGRE identifier of the material specified (as a PB number) in the parameter
...

‘TextureID(#TEXTURE)’
Returns the OGRE identifier of the texture specified (as a PB number) in the parameter
...
To make things a little bit more exciting, I’ve made the
model spin around and I’ve included a light, so the model doesn’t look too flat when being displayed
...
l = 1024
Global ScrH
...
l = 32
;Other global variables
Global Quit
...
l, Text
...
")
HandleError(InitSprite(), "InitSprite() command failed
...
")

3D Graphics

207

HandleError(InitKeyboard(), "InitKeyboard() command failed
...
mesh"), "Can't load mesh")
HandleError(LoadTexture(#TEX, "Invader
...
5)
RotateCamera(#CAMERA_ONE, -15, 0, 0)
;Main loop
Repeat
y
...
As always, the code should be pretty easy to follow but I’ll go through
the main points just so you don’t miss anything
...
This command call is necessary to load
the that contains the 3D engine from the compilers directory
...

Once the 3D environment has been initialized then a screen can be created in the normal manner
...
This has to be done in this order or a compiler
error will occur and the IDE will start complaining
...


208

3D Graphics

Including OGRE With Your 3D Program
When you create a 3D program using PureBasic and want to share it with other people, be it commercially
or as a freeware program, you must remember to distribute the OGRE 3D engine with it
...

When you compile your program, the OGRE commands are not embedded into your program like regular
built-in PureBasic commands
...
This means
that the DLL file must always accompany your executable file in order for it to run correctly
...
This ensures that testing the 3D commands is always as easy as possible
...

The two files that you must distribute with your 3D program for it to initialize and work properly, are:
‘Engine3D
...
dll’
Both of these files are found in the ‘\Compilers’ directory, within your PureBasic folder
...


Create A 3D Archive To Contain Media
After all the initializations are done we can start using the 3D commands and the very first thing we
must do is specify a ‘3D Archive’
...
You must have at least one 3D archive specified in your 3D
program or else the compiler will raise an error
...
This command takes two parameters, the first is a String specifying a file path and
the second is a built-in constant that tells the compiler what sort of path it is
...

‘#PB_3DArchive_Zip’
This tells the compiler that the path specified is a compressed ZIP file
...
Once specified like this, all
required media must be in this folder
...

LoadMesh(#MESH, "Invader
...


3D Graphics

209

When a command like this is encountered in our program that needs to load external media, OGRE
will look inside all specified 3D archives for this file, in this case OGRE will look in the ‘Data\’ folder
for the ‘Invader
...

If you want to order your media into a more strict filing system and include further subdirectories in
the ‘Data\’ folder, than you can do by all means
...

LoadMesh(#MESH, "Meshes\Invader
...
png")

...
If this syntax looks a little clumsy, then instead of defining the folder
names in the loading commands you could just as easily add further 3D archives for OGRE to look in
when requesting media, like this:

...


Now we can use simpler loading commands like this:

...
mesh")
LoadTexture(#TEX, "Invader
...


OGRE will now search the folders, ‘Data\’, ‘Data\Meshes\’ and ‘Data\Textures\’ for these files
...
This can help a lot when distributing a program,
because all of your media is enclosed within a single compressed file
...
This is achieved using the
‘#PB_3DArchive_Zip’ built-in constant as the type parameter in the ‘Add3DArchive()’ command
...

Add3DArchive("Data
...
mesh")
LoadTexture(#TEX, "Textures\Invader
...


210

3D Graphics

Creating A 3D Entity
When you have created a 3D archive you are ready to create an object that’s able to use your media
...
OGRE calls these 3D objects, ‘Entities’
...
Entities can be anything that is
modeled in 3D, they can be game maps or the characters that populate them
...


Load Mesh

2
...


Create Material
from Texture

4
...


Entity is Automatically displayed
when using ‘RenderWorld()’

Fig
...

Fig
...
I
have followed this flow diagram precisely in the previous Invader example
...

HandleError(LoadMesh(#MESH, "Invader
...
png"), "Can't load texture")
HandleError(CreateMaterial(#MAT, TextureID(#TEX)), "Can't create Material")
CreateEntity(#ENTITY_INVADER, MeshID(#MESH), MaterialID(#MAT))

...
The first one is the ‘LoadMesh()’ command
(Helpfile:Reference Manual->3D Games Libraries->Mesh->LoadMesh) which takes two parameters
...
The next command is ‘LoadTexture()’ (Helpfile:Reference Manual->3D
Games Libraries->Texture->LoadTexture) which also takes two parameters
...
When using images for textures, one thing to note is the image size in pixels
...
For maximum compatibility with older cards, I suggest you use these sizes too
...
41
shows the standard texture image sizes you can use to create materials safely
...


Fig
...
This material is a special OGRE
format texture that can have many different properties
...
I will talk about the more advanced materials a little later
...
The first is the PB number that
this material will be associated with, and the second is the OGRE identifier of a texture
...

Once we have the necessary ‘ingredients’ we can then create our entity
...

CreateEntity(#ENTITY_INVADER, MeshID(#MESH), MaterialID(#MAT))

...
The first is the PB number that
this entity will be associated with
...


212

3D Graphics

These last two OGRE identifiers can be returned by using the ‘MeshID()’ and ‘MaterialID()’ command
respectively
...

Once a 3D entity has been created it then is queued, ready to be drawn onto the screen at the
coordinates ‘0, 0, 0’ in three dimensional space
...

Lighting The Way
After the entity has been created, I’ve created a light to illuminate the scene better
...
When you
create a 3D environment it already contains a default amount of ambient light but this light is not
actually emitted from any one point, but instead as the name suggests it’s ambient
...

When you add a light to a scene, you allow the entity to change it’s facial lighting to simulate shine and
shade depending on where the light is located in relation to the mesh used
...
(Helpfile:Reference Manual->3D Games Libraries->Light>CreateLight)

...


This command takes five parameters, the first of which is the PB number that will be associated to this
light
...
The third, forth and fifth parameters are optional
and specify the position of the light in 3D space using the ‘x, y, z’ coordinate system
...
In the Invader example I’ve used the position of ‘0, 5, 0’, which elevates the light off the floor by
‘5’ units
...
39 for a graphical representation of 3D space using the ‘x, y, z’ coordinate system
...
OGRE calls these viewports, Cameras, but really we need to distinguish between the two to
avoid confusion
...
Once a camera viewport is created it automatically creates a 3D
camera positioned at coordinates ‘0, 0, 0’ and the newly created viewport displays what the 3D camera
is looking at
...

To create a camera viewport and automatically create a 3D camera in the current 3D world, you use
the ‘CreateCamera()’ command
...
The second and third parameters are the ‘x’ and ‘y’ positions of the
top left hand corner of the viewport on the 2D screen
...
When using this command it is very
important to understand the values it uses because they are very different to most PureBasic

3D Graphics

213

commands
...
In the Invader example I create a camera like this:

...


To understand this fully, let’s break down this command call on an individual parameter basis
...
The second parameter has been defined as a ‘0’
...
The third parameter is defined as ‘0’ too
...
The forth
parameter has been defined as ‘100’
...
The fifth parameter is also defined as ‘100’, and this will equate to one hundred
percent of the screen height, which is ‘768’
...

Percentages are used for this command instead of pixels, so that camera viewport positions are
completely independent of the screen size
...
For example, if I create a camera viewport half of the screen width and
height, this viewport will always be half of the screen width and height regardless of what screen
resolution used
...
Imagine if you need to
code a game in split or quad screen, you will need a good way to calculate the viewport size for each
given screen resolution (if it’s user selectable)
...
Also, when creating multiple cameras, the creation order is very important
...
For
example, look at this code:

...


Here, I create one camera viewport taking up the full screen and another camera viewport over the top
of it, in the top right hand corner
...
If the
smaller viewport was created first then it would be hidden by the bigger camera viewport
...
For example, you might use a second camera as a rear view
mirror in a 3D first person driving game
...


214

3D Graphics

Moving And Rotating Cameras
Once you have created a viewport you also automatically create a 3D camera which can rotate and
move around at will in the 3D scene
...
In my Invader example I’ve used
two commands to fine tune the position of the camera, like this:

...
5)
RotateCamera(#CAMERA_ONE, -15, 0, 0)

...
The first parameter is the PB number of the camera you want to move,
while the second, third and forth parameters are ‘x, y, z’ coordinates of where you would like to move
it to
...

This command also takes four parameters, with the first being the PB number of the camera you wish
to rotate
...


Rotations In 3D Space
+Y

Rotating something along the ‘Z’ axis,
rolls it left and right
...
+Z

The arrows show positive number rotations

Rotating something along the ‘Y’ axis,
rotates it side to side
...


+X

Rotating something along the ‘X’ axis,
rotates it up and down
...


Fig
...
42 you will see what axis refer to what type of rotation
...
When specifying numbers
for the ‘x, y, z’ coordinates in any 3D rotation command, number can be negative as well as positive,
this allow for the rotation to be reversed
...
42 these show the
direction that the rotation will occur if positive numbers are used
...
As a small example, if I wanted to twist my camera forty five degrees to
the left I would enter ‘45’ for the ‘y’ rotation parameter
...

All move and rotation commands can be used either inside or outside the main loop to rotate and move
cameras or other entities
...
Using these commands inside your main loop provides a way of
moving and rotating your entities in realtime, often reacting to user input
...
If you look inside
the main loop of the Invader example, I have used the ‘RotateEntity()’ command (Helpfile:Reference
Manual->3D Games Libraries->Entity->RotateEntity) to rotate the invader entity during runtime
...
42
...
42 can provide a reference for what rotation might be needed
...
(Helpfile:Reference Manual->3D Games Libraries->Camera)
Rendering The 3D World To The Screen
When using the 3D commands to create a 3D world, unlike the 2D commands, your meshes, lights and
particles, etc
...
Instead they exist in memory, ready to be
captured and drawn
...
These snapshots
are then drawn onto the backbuffer, scaled and positioned to the size and position of the related
camera’s viewport
...
You can see this in action in the Invader
example
...
Hopefully this is the Invader example fully explained now, so you should be able to load and
display models of your own using this example as a reference
...
The first thing I thought of when seeing the 3D capabilities of PureBasic is, I
wonder if I could make a first person shooter game? I came up with this next piece of code as an
example of how to code a first person camera within a 3D world
...
This code will show you how to create a
terrain and move the camera around using the cursor keys and mouse:
Enumeration
#TEXTURE_GLOBAL
#TEXTURE_DETAIL
#MATERIAL_TERRAIN
#CAMERA_ONE
EndEnumeration
#MOVEMENT_SPEED = 1
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW
...
l = 768
Global ScrD
...
b = #False
MouseXRotation
...
f,KeyX
...
f,DesiredCameraHeight
...
f = 545
CurrentCamZPos
...
l, Text
...
")
HandleError(InitSprite(), "InitSprite() command failed
...
")
HandleError(InitMouse(), "InitMouse() command failed
...
")
SetFrameRate(60)
;Set 3D Archive
Add3DArchive("Data\", #PB_3DArchive_FileSystem)
;Create Terrain
HandleError(LoadTexture(#TEXTURE_GLOBAL, "Global
...
png"), "Can't load texture")
CreateMaterial(#MATERIAL_TERRAIN, TextureID(#TEXTURE_GLOBAL))
AddMaterialLayer(#MATERIAL_TERRAIN,TextureID(#TEXTURE_DETAIL),#PB_Material_Add)
CreateTerrain("Terrain
...
f = TerrainHeight(CurrentCamXPos, CurrentCamZPos) + 10
CameraLocate(#CAMERA_ONE,CurrentCamXPos,DesiredCameraHeight,CurrentCamZPos)
;Main loop
Repeat
;Update Mouse
If ExamineMouse()
MouseYRotation = -MouseDeltaX() / 10
MouseXRotation = MouseDeltaY() / 10
EndIf
RotateCamera(#CAMERA_ONE, MouseXRotation, MouseYRotation, 0)
;Update Key Presses and position the Camera accordingly
If ExamineKeyboard()

3D Graphics

217

If KeyboardPushed(#PB_Key_Left) : KeyX = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Right) : KeyX = #MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Up) : KeyZ = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Down) : KeyZ = #MOVEMENT_SPEED : EndIf
MoveCamera(#CAMERA_ONE, KeyX, 0, KeyZ)
KeyX = 0
KeyZ = 0
CurrentCamXPos
...
f = CameraZ(#CAMERA_ONE)
DesiredCameraHeight
...
The main difference here in this example is that I’ve created
a terrain to provide a floor on which to walk about on
...

To create a multi-layered material you need to create a normal material then apply another material
layer to it
...

HandleError(LoadTexture(#TEXTURE_GLOBAL, "Global
...
png"), "Can't load texture")

...
The first image, ‘Global
...
The second image, ‘Detail
...
To actually
create the multi-layered material I’ve used these two commands:

...


The first line creates a standard, one layer material as explained in the Invader example
...
The
‘AddMaterialLayer()’ command (Helpfile:Reference Manual->3D Games Libraries->Material>AddMaterialLayer) takes three parameters
...
The second is the OGRE identifier of the texture you wish to add as another layer
...
This blending
mode can be defined as one of four built-in constants:
‘#PB_Material_Add’
Blends the new material layer with the existing one using an ‘Add’ operation
...

‘#PB_Material_AlphaBlend’
Blends the new material layer with the existing one using an ‘Add’ operation
...
Only Png and Tga image format textures are
supported
...

Once you have created a multi-layered material then you are ready to create a terrain using the
‘CreateTerrain()’ command (Helpfile:Reference Manual->3D Games Libraries->Terrain>CreateTerrain)
...

CreateTerrain("Terrain
...


The ‘CreateTerrain()’ command takes six parameters
...
The second is an OGRE identifier of a multi-layered
material to be used as the terrain surface
...
These values are multiplication values, meaning that if a value
of ‘1’ is used then the terrain will remain the same size on that axis
...
The sixth and final parameter is an optional terrain quality value which
ranges from ‘1’ to ‘20’
...
Higher values have the opposite effect
...
First this image must be square, as OGRE in PureBasic can only create square
terrains (although you can scale them during creation)
...
Pure black will be treated as a height of ‘0’ while full
white will be treated as a height of ‘255’
...
The size of a height map image
should be that of a normal texture size but plus one pixel on each dimension
...
Fig
...


Terrain Height Map Image Sizes
Width

Height

Terrain Polygons

65

65

8192

129

129

32768

257

257

131072

513

513

524288

1025

1025

2097152

All height map texture sizes are powers of ‘2’ + ‘1’
...
43

Looking at Fig
...
A higher resolution height map can improve the rendering accuracy of the terrain to the
height map but at the cost of slowing performance
...

Terrains And Automatic ‘Level Of Detail’
All terrains created in PureBasic using OGRE have automatic and dynamic levels of detail
...
Also when the camera has traveled a certain distance
from a terrain feature, that feature will automatically lower its complexity, lowering the polygon count
on screen to ease drawing a larger scene
...
You will see the
hill lower its complexity when being far away from the camera
...
The mouse
commands are:
‘MouseDeltaX()’
(Helpfile:Reference Manual->2D Games Libraries->Mouse-> MouseDeltaX)
This command returns the number of pixels the mouse has moved on the ‘X’ screen axis (left to right)
since the last iteration of the main loop
...


220

3D Graphics

These two returned values are then placed in the ‘x’ and ‘y’ parameters of the ‘RotateCamera()’
command to rotate the 3D camera by whatever value the mouse moves
...

If ExamineMouse()
MouseYRotation = -MouseDeltaX() / 10
MouseXRotation = MouseDeltaY() / 10
EndIf
RotateCamera(#CAMERA_ONE, MouseXRotation, MouseYRotation, 0)

...
Notice the minus sign in front of the ‘MouseDeltaX()’
command
...
The ‘MouseDeltaX()’
command returns these inverted due to it returning 2D screen coordinates instead of rotation angles
...

If ExamineKeyboard()
If KeyboardPushed(#PB_Key_Left) : KeyX = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Right) : KeyX = #MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Up) : KeyZ = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Down) : KeyZ = #MOVEMENT_SPEED : EndIf
MoveCamera(#CAMERA_ONE, KeyX, 0, KeyZ)
KeyX = 0
KeyZ = 0
CurrentCamXPos
...
f = CameraZ(#CAMERA_ONE)
DesiredCameraHeight
...


Here, I use the ‘KeyboardPushed()’ command to test wether or not a key is being held down
...

This will move the camera throughout the 3D world but doesn’t take into consideration the height of
the terrain
...
Because this command uses absolute values, I need to retrieve the current
‘x’ and ‘z’ coordinates of the camera so I can set these again when altering the ‘y’ value
...
These two command have only one parameter which is the
PB number of a camera to get the values from
...
To retrieve this I use the ‘TerrainHeight()’ command
(Helpfile:Reference Manual->3D Games Libraries->Terrain->TerrainHeight)
...
These are the ‘x’ and ‘z’ coordinates of the point of the terrain we wish to know the
height of
...
During every main loop iteration
a new ‘y’ coordinate is calculated to adjust the camera height when moving over the terrain
...
These
features include particles and a material scripts
...
I’ve
used them in the following example to simulate fire
...
Material scripts allow you to load a mesh containing a reference to a material and if that
material appears in a script file, then the mesh uses that material negating the need to do anything
further in your source code
...
In the following example, I’ve used a
material script to specify that the loaded mesh uses sphere texture mapping, something that is
otherwise unavailable
...
l = 1024
Global ScrH
...
l = 32
;Other global variables
Global Quit
...
l, Text
...
f DegToRad(Angle
...
f * #PI / 180
EndProcedure
;Initialize environment
HandleError(InitEngine3D(), "InitEngine3D() command failed
...
")
HandleError(OpenScreen(ScrW, ScrH, ScrD, ""), "Could not open screen
...
")
SetFrameRate(60)
Add3DArchive("Data\", #PB_3DArchive_FileSystem)
Parse3DScripts()
CreateEntity(#ENTITY, LoadMesh(#MESH, "Statue
...
png")
CreateMaterial(#MATERIAL, TextureID(#TEXTURE))
DisableMaterialLighting(#MATERIAL, 1)
MaterialBlendingMode(#MATERIAL, #PB_Material_Add)
CreateParticleEmitter(#PARTICLE_ONE, 2, 2, 0,#PB_Particle_Point,12
...
7)
ParticleSize(#PARTICLE_ONE, 5, 5)
ParticleMaterial(#PARTICLE_ONE, MaterialID(#MATERIAL))
ParticleEmissionRate(#PARTICLE_ONE, 50)
ParticleTimeToLive(#PARTICLE_ONE, 0
...
25)
ParticleColorRange(#PARTICLE_ONE, RGB(255, 0, 0), RGB(255, 200, 0))
ParticleVelocity(#PARTICLE_ONE, 1, 10)
CreateLight(#LIGHT_ONE, RGB(255,255,255))
CreateLight(#LIGHT_TWO, RGB(255, 200, 0), 12
...
7)
CreateCamera(#CAMERA_ONE, 0, 0, 100, 100)
;Main loop
Repeat
Angle
...
5
PosX
...
f = (50 * Sin(DegToRad(Angle / 2))) + 65
PosZ
...
First we
initialize the environment, open a screen and specify a 3D archive
...
This command, when called, will look inside all specified 3D archives
and read all script files that it finds in them
...

Material Scripts
Once the ‘Parse3DScripts()’ command is called, all material scripts are read and parsed from all
specified 3D archives
...
If a mesh is loaded later on which uses a
material that has the same name as one specified in a material script, it will use the textures and
properties as defined in the script
...
This allows you to specify the material when you are creating your mesh and
then easily load it into a PureBasic 3D program, retaining all material properties
...
The syntax of material scripts is described on the OGRE
website which can be found in Appendix A (Useful Internet Links)
...
material’:
material Statue
{
technique
{
pass
{
texture_unit
{
texture SphereMap
...
png’ as a texture, use spherical texture mapping and use trilinear filtering
...

If you look at the Statue example you can see I create an entity, fully textured using one line of code as
opposed to the Invader example where I had to use multiple lines to load textures and create materials
etc
...

CreateEntity(#ENTITY, LoadMesh(#MESH, "Statue
...


224

3D Graphics

This loads the ‘Statue
...
Because we are
using a material script to define the material, when using the ‘CreateEntity()’ command, the material
ID parameter must be ‘#PB_Material_None’
...

Particle Effects
Creating particles can be quite a complicated affair, especially when so many effects can be produced
by using them
...


Particle Scripts?
Like material scripts, particle scripts are a way of encapsulating complicated properties under a simple name
...
This makes testing and creating particle
effects quicker and easier
...
When asked, the
PureBasic team said that particle script support will be added to PureBasic in the near future
...
For more information refer to the OGRE website
and the online PureBasic forums, both addresses can be found in Appendix A (Useful Internet Links)
...
png’ image as a texture
...
A particle emitter is a coordinate in 3D space that will be the point that
all particles are emitted from
...

CreateParticleEmitter(#PARTICLE_ONE, 2, 2, 0,#PB_Particle_Point,12
...
7)

...
The first, as usual is the PB number that will be
associated to this particle emitter
...
The fifth is the particle mode
...
Emitter points are usually used for fire and
smoke, etc
...
The last three parameters are coordinates in the 3D world that
define where this emitter will be placed
...
You can later move the emitter by using the ‘ParticleEmitterLocate()’
command
...
These other commands are:

...
25, 0
...


All these commands are self explanatory and are capable of producing thousands of different effects
...

Looking At A Particular Point
In the Statue example I’ve used another new camera command which can very useful
...
(Helpfile:Reference Manual->3D Games Libraries->Camera) Using this,
it is possible to angle the camera to look at any point in 3D space with one command
...

CameraLookAt(#CAMERA_ONE, 0, 60, 0)

...
The second, third and
forth are the ‘x, y, z’ coordinates that you want this camera to look at
...

Dynamic Lighting
In the Statue example I’ve also used a couple of lighting tricks to help enhance the scene
...
This makes sure the statue mesh is always fully
lit
...
I do this by placing this command
in the main loop:

...


This command changes the specified light’s color whenever it is used
...

Because the light already has the red component set to ‘255’ and the blue component set to ‘0’ this
means that this light will flicker from red to yellow
...


226

3D Graphics

Using a few tricks like material scripts to build more complex materials and using particles to create
cool effects will help lift your game or demo above the rest in terms of quality and style
...
To learn more
about these commands try coding your own 3D programs and experiment with a few settings,
especially with the particle commands
...

I hope that you have been inspired to learn more about what PureBasic can achieve using the OGRE
engine
...
This chapter has not covered every command
that is contained there because of space and time constraints, but hopefully I’ve given you a good
primer on how to start, the rest now is up to you
...
The mathematics used in the examples in this chapter is quite
elementary and is something which I think every college student will probably know
...

There will be times when programming 3D graphics that you will be stopped dead in your tracks
because your math ability has fallen behind your programming ability, so it’s best to be prepared
...


227

12
Sound
At some point while programming, you may need sounds to be played by a program
...

However you use sound, you will need to know how to load and playback particular sound files
...


Wave Files
Wave files are one of the most common sound formats on personal computers, due to their creation
by a join effort between Microsoft and IBM
...
wav’,
are the native sound format used by all PCs
...

The following example loads a wave file called ‘Intro
...
wav")
PlaySound(#SOUND_FILE)
StartTime
...
First, we have to initialize the sound environment using the ‘InitSound()’ command
...
If this returns true, we
know that it has initialized properly and we can continue
...

Once the initialization is done and checked we load the sound file using the ‘LoadSound()’ command
(Helpfile:Reference Manual->2D Games Libraries->Sound->LoadSound)
...
The ‘LoadSound()’ command takes two parameters, the first is the PB
number that you wish to be associated to this sound file and the second is a String containing the
filename of the sound you wish to load
...

This command takes one parameter, which is the PB number of the sound file you wish to play
...
This is to stop this example program exiting too soon
...
I don’t want this to
happen straight away, so I’ve coded this loop to give the program eight seconds to play the file and then
exit
...

Embedding Wave Files
Sometimes in your programs you may not want to load external wave files, but have the files actually
contained within your program so the whole thing can be distributed as one file
...
There is one difference however, instead of using the
‘CatchImage()’ command to load the file from the ‘DataSection’ we use the ‘CatchSound()’ command
instead, here is an example:
#SOUND_FILE = 1
If InitSound()
CatchSound(#SOUND_FILE, ?SoundFile)
PlaySound(#SOUND_FILE)
StartTime
...
wav"
EndDataSection

The sound file is embedded in the ‘DataSection’ by using the ‘IncludeBinary’ command in exactly the

Sounds

229

same way as an image, and the label, ‘SoundFile:’ marks the start of the file in memory
...
This command takes two
parameters, the first is the PB number that will be associated to this sound and the second is the
address in memory where this sound file should be loaded from
...
To retrieve the address of any label we
use a question mark in front of its name, like this: ‘?SoundFile’
...
Once a wave file is ‘caught’ in this way, you can use it like you would any other
wave file, in this case, I play the sound by using the ‘PlaySound()’ command again
...

Altering Sounds In Realtime
Using the sound commands in the PureBasic sound library, it’s possible to do some cool volume
changes, sound pans and frequency shifts
...
To demonstrate these effects, I’ve created a small sound player program that uses realtime
volume, panning and frequency controls
...

Enumeration
#WINDOW_ROOT
#SOUND_FILE
#TEXT_FILE
#BUTTON_CHOOSE_FILE
#TEXT_VOLUME
#TRACKBAR_VOLUME
#TEXT_PAN
#TRACKBAR_PAN
#TEXT_FREQUENCY
#TRACKBAR_FREQUENCY
#BUTTON_PLAY_FILE
#BUTTON_STOP_FILE
EndEnumeration
Global FileName
...
")
TextGadget(#TEXT_VOLUME, 10, 70, 480, 20, "Volume")
TrackBarGadget(#TRACKBAR_VOLUME, 10, 90, 480, 20, 0, 100)
SetGadgetState(#TRACKBAR_VOLUME, 100)

230

Sounds

TextGadget(#TEXT_PAN, 10, 120, 480, 20, "Pan")
TrackBarGadget(#TRACKBAR_PAN, 10, 140, 480, 20, 0, 200)
SetGadgetState(#TRACKBAR_PAN, 100)
TextGadget(#TEXT_FREQUENCY, 10, 170, 480, 20, "Frequency")
TrackBarGadget(#TRACKBAR_FREQUENCY, 10, 190, 480, 20, 100, 10000)
SetGadgetState(#TRACKBAR_FREQUENCY, 4400)
ButtonGadget(#BUTTON_PLAY_FILE, 10, 220, 100, 20, "Play File")
ButtonGadget(#BUTTON_STOP_FILE, 130, 220, 100, 20, "Stop Sound")
If InitSound()
Repeat
Event
...
wav)|*
...
It doesn’t change the original
sound file in any way, it merely changes the volume of the sound when it’s played back
...
The volume level is a number between ‘0’
and ‘100’
...

‘SoundPan()’
This command pans the sound to and from the left and right channel
...
The first is the PB number of the sound you wish to pan and the second
parameter is the pan value
...
If you use a
value of ‘-100’, then the sound is fully panned to the left
...

‘SoundFrequency()’
This command changes the frequency of the sound to be played
...

For example, all music stored on a compact disc is sampled at a rate of 44
...
This means
that the waveform containing the sound information on a CD is read forty four thousand, one hundred
times a second
...
If a sound is encoded at 44
...
To use this command in PureBasic to change the frequency of a loaded sound, you pass it two
parameters
...
This second parameter must be between ‘1000’ to ‘100000’
...


Module Files
These types of files use formats that represents music using digital patterns
...
These patterns contain
note numbers, instrument numbers, and controller messages which tell the program reading the file
when to play notes, using what samples and for how long
...
The number of notes that can be played simultaneously

232

Sounds

depends on how many tracks there are per pattern
...
The biggest advantage of modules over standard sound
files is that modules include their own audio samples and should sound the same from one player to
another
...

This program, although originally poorly received, was eventually released into the public domain and
was cloned many times, sporting better features and different names such as ‘Noisetracker’ or
‘Protracker’, these became extremely popular especially with Commodore Amiga game and demo
creators
...

Module files can have many different file extensions because they come in many different formats,
these extensions usually reveal the file’s creator program
...
xm’)
Scream Tracker (‘*
...
mod’)
Impulse Tracker (‘*
...
Here is an example showing how to load and play any of the above types of
module:
#MODULE_FILE = 1
If InitSound()
If InitModule()
LoadModule(#MODULE_FILE, "Eighth
...
l = ElapsedMilliseconds()
Repeat
Delay(1)
Until ElapsedMilliseconds() > StartTime + 15000
StopModule(#MODULE_FILE)
End
EndIf
EndIf

First, we need to initialize the sound environment just like the wave file example by using the
‘InitSound()’ command
...
Both of these commands should be tested to ensure that both are
initialized correctly
...
This command takes two
parameters, the first is the PB number that you wish to be associated with this module and the second
is the filename of the module to be loaded
...
Just like the
‘PlaySound()’ command, this one takes one parameter, which is the PB number of the module you
want to play
...

The Downsides Of Using Modules
There are two big downsides of using modules in your PureBasic programs
...
This means that you
have to distribute all the used module files along with your executable
...
The second downside is that you have to distribute the ‘Midas11
...
This dynamic linked library is loaded by the command; ‘InitModule()’ and
will error if it doesn’t find it
...
This license also prevents the
‘Midas11
...

To learn about other commands that can be used to manipulate module files, see the module library
in the PureBasic helpfile (Helpfile:Reference Manual->2D Games Libraries->Module)
...

MP3 is an anacronym that stands for ‘MPEG-1 Audio Layer 3’ which is quite a mouthful, so you will
probably understand why it was shortened
...
It may
seem a little odd using the movie commands to play mp3 files but the movie commands are capable of
much more than just playing movies
...
Not only can you play movie formats
using these commands, but you can also play audio file formats
...
You may even be able to play more formats than
what is shown on this list:

234

Sounds

Movie Files:
Audio Video Interleave (‘*
...
mpg’)
Audio Files:
Midi Files (‘*
...
mp3’)
Ogg Vorbis (‘*
...
wav’)
The ‘Movie’ library may seem like a ‘one stop shop’ for all your media playing needs and some people
have even asked for it to be renamed to the ‘Media’ library, but the one thing to remember is that if
something loads and plays on your computer, it might not load and play on another person’s
computer
...
However, saying this, the list above seems to be pretty standard on most machines, but
don’t quote me on that
...
It may not rival WinAmp but it gives you an idea of how easy media players
are to create in PureBasic
...
s = ""
Global FilePaused
...
")
TextGadget(#TEXT_VOLUME, 10, 70, 480, 20, "Volume")
TrackBarGadget(#TRACKBAR_VOLUME, 10, 90, 480, 20, 0, 100)
SetGadgetState(#TRACKBAR_VOLUME, 100)
TextGadget(#TEXT_PAN, 10, 120, 480, 20, "Pan")
TrackBarGadget(#TRACKBAR_PAN, 10, 140, 480, 20, 0, 200)
SetGadgetState(#TRACKBAR_PAN, 100)

Sounds

235

ButtonGadget(#BUTTON_PLAY_FILE, 10, 180, 100, 20, "Play")
ButtonGadget(#BUTTON_PAUSE_FILE, 130, 180, 100, 20, "Pause")
ButtonGadget(#BUTTON_STOP_FILE, 250, 180, 100, 20, "Stop")
If InitMovie()
Repeat
Event
...
mp3)|*
...
l = GetGadgetState(#TRACKBAR_VOLUME)
Balance
...
To initialize the movie commands you use the
‘InitMovie()’ command
...
As with other initialization commands it must be tested and if it fails, you won’t be able to
continue using the movie commands
...
This command takes two parameters
...

Once the media has been loaded we can play it back using the ‘PlayMovie()’ command
(Helpfile:Reference Manual->General Libraries->Movie->PlayMovie)
...
The first parameter is the PB number
of the media you want to play, while the second parameter is an OS identifier of a window
...
If you are playing back a file that only consists of audio data (such as a MP3) then
you can use the built-in constant ‘#Null’ as an OS identifier, this doesn’t then associate any window to
the playback of the file:

...


Also in the example I’ve used the ‘PauseMovie()’ and ‘ResumeMovie()’ commands, these are simple to
use, they both take one parameter which is the PB number of the media you want to pause or resume
...
Again, this is a simple one to use, as you only need to pass it one parameter
...

Even though this is a skeleton of a media player and it only supports MP3’s, it would be a trivial task
to convert this code to make your own media player capable of handling all of the formats listed above
...
There are many free tools available on the Internet, for composing and burning
your music onto a CD
...
Here is an example which uses the PureBasic
‘AudioCD’ library, to create a very simple CD player:
Enumeration
#WINDOW_ROOT
#BUTTON_PREVIOUS
#BUTTON_PLAY
#BUTTON_STOP
#BUTTON_NEXT
#BUTTON_EJECT
#TEXT_STATUS
#PROGRESS_SONG
#LIST_TRACKS
EndEnumeration
;Global variables, etc
...
l
Global CurrentTrack
...
s ConvertToMin(Seconds
...
l)
If NumberOfTracks > 0
TrackLength
...
s = ConvertToMin(TrackLength)
TrackTimings
...
l = AudioCDTrackSeconds()
TrackTimings
...
f = (100 / TrackLength) * TimeElapsed
SetGadgetState(#PROGRESS_SONG, Progress)
EndIf
SetGadgetState(#LIST_TRACKS, Track - 1)
Else
SetGadgetText(#TEXT_STATUS, "Please insert an Audio CD")
EndIf
EndProcedure

238

Sounds

;Move to next track
Procedure NextTrack()
If CurrentTrack < NumberOfTracks
CurrentTrack + 1
UpdateStatusText(CurrentTrack)
If AudioCDStatus() > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndIf
EndProcedure
;Move to previous track
Procedure PreviousTrack()
If CurrentTrack > 1
CurrentTrack - 1
UpdateStatusText(CurrentTrack)
If AudioCDStatus() > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndIf
EndProcedure
;Populate the list to show all tracks on a disc
Procedure PopulateTrackListing()
ClearGadgetItemList(#LIST_TRACKS)
NumberOfTracks = AudioCDTracks()
If NumberOfTracks > 0
For x
...
s = ConvertToMin(AudioCDTrackLength(x))
AddGadgetItem(#LIST_TRACKS, -1, "Track "+Str(x)+" ("+TrackLength+")")
Next x
If CurrentTrack = 0
CurrentTrack = 1
EndIf
Else
CurrentTrack = 0
EndIf
EndProcedure
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_ROOT, 0, 0, 320, 250, "CD Player", #FLAGS)
If CreateGadgetList(WindowID(#WINDOW_ROOT))
ButtonGadget(#BUTTON_PREVIOUS, 10, 10, 60, 20, "Previous")
ButtonGadget(#BUTTON_PLAY, 70, 10, 60, 20, "Play")
ButtonGadget(#BUTTON_STOP, 130, 10, 60, 20, "Stop")
ButtonGadget(#BUTTON_NEXT, 190, 10, 60, 20, "Next")
ButtonGadget(#BUTTON_EJECT, 250, 10, 60, 20, "Eject")
TextGadget(#TEXT_STATUS, 10, 40, 300, 20, "", #PB_Text_Center)
ProgressBarGadget(#PROGRESS_SONG,10,65,300,10,0,100,#PB_ProgressBar_Smooth)
ListViewGadget(#LIST_TRACKS, 10, 90, 300, 150)

Sounds

239

If InitAudioCD()
PopulateTrackListing()
StartTime
...
l = WindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_PREVIOUS
PreviousTrack()
Case #BUTTON_PLAY
If NumberOfTracks > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
Case #BUTTON_STOP
StopAudioCD()
Case #BUTTON_NEXT
NextTrack()
Case #BUTTON_EJECT
EjectAudioCD(#True)
PopulateTrackListing()
Case #LIST_TRACKS
If EventType() = #PB_EventType_LeftDoubleClick
CurrentTrack = GetGadgetState(#LIST_TRACKS) + 1
UpdateStatusText(CurrentTrack)
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndSelect
EndSelect
CurrentTime
...
l = ElapsedMilliseconds()
EndIf
Delay(1)
Until Event = #PB_Event_CloseWindow
StopAudioCD()
EndIf
EndIf
EndIf
End

This example is an extremely simple CD player which provides the bare minimum of functionality to
control and play CD’s
...


240

Sounds

To use the ‘AudioCD’ commands you first have to initialize the resources needed to be able to play
CD’s
...
This command must be tested to determine if
it was successful or not
...
If the return value is ‘0’
then the computer either doesn’t have a CD drive installed or another problem has been encountered
which prevents the CD drive from playing music
...

Once the CD audio has been initialized, you are then free to use all of the other commands available in
the ‘AudioCD’ library
...
This
command takes two parameters
...
So for example, If I called the command like this:
PlayAudioCD(1, 3)

Track ‘1’ would start playing, then continue afterwards to the next track
...

‘StopAudioCD()’
This command can be used at any time to stop the playback of any track currently playing on the CD
...
This command only takes one parameter and if that parameter is ‘1’ the drive tray will be
opened, effectively stopping playback and ejecting the CD
...

‘AudioCDStatus()’
This command doesn’t have any parameters but returns a result that gives us a realtime status of the
CD in the drive
...
If this command returns the
value ‘0’ then a CD has been detected correctly and is in the drive but the CD is not playing
...
The number which
was actually returned, is the track number which is being played back
...


Sounds

241

‘AudioCDTrackLength()’
This command requires one parameter and that is a track number from a loaded CD
...

‘AudioCDTrackSeconds()’
This command doesn’t take any parameters
...

If you look closer at my CD player example, I’ve also used the command; ‘WindowEvent()’ instead of
‘WaitWindowEvent()’
...
I needed this particular program to do this because I use a timed procedure call in
the main loop to update the status text in the CD player’s graphical user interface
...

‘WindowEvent()’ and ‘WaitWindowEvent()’ are covered in more detail in Chapter 9 (Understanding
Events)
...
This section is for those who have further questions on a particular facet of PureBasic or want to
learn a little more about what goes on ‘under the hood’
...


245

13
Beyond
The Basics
This chapter contains a mish-mash of topics because I felt all these subjects needed to be explained but
each one really didn’t warrant a full chapter
...

Topics covered in this chapter include; Compiler Directives and how to control the compiler using
code, Advanced Compiler Options to get more from the PureBasic compiler, How to pass Command
Line Arguments to you program for writing command line tools, How PureBasic stores numeric data
types, What Pointers are and how to use them, What Threads are and how to use them, What
Dynamically Linked Libraries are and how to create them and How to use the Window Application
Programming Interface natively in PureBasic
...
As such,
these directives allow you to have total control over what parts of your source code are compiled and
allow you to retrieve information from the compiler
...
They cannot be utilized while your program is
actually running
...
Unlike directives,
compiler functions can be utilized while the program is running
...
This compiler directive switches the compiler to explicit

246

Beyond The Basics

mode and makes sure all variables are explicitly declared, making sure the scope and type of each new
variable is defined
...
These
compiler functions gather information from compiled structures and interfaces, such as the size in
Bytes of a particular structure in memory or the offset of where a particular field is within a structure
or interface
...

Reserved Compiler Constants
These built-in reserved constants are just like any other constant, but what is different is that their
values largely depend on the current state of the compiler
...
Here is a full list of the reserved compiler constants
and what information you may get from them
...
It also has some associated constants to help you determine what it’s value may mean
...

‘#PB_Compiler_Date’
This constant’s value contains a date in numeric form, which is the date of when your program was
compiled
...

‘#PB_Compiler_File’
This constant’s value is a String that contains the full path and name of the file (*
...

‘#PB_Compiler_Line’
This constant’s value is the line number of the current file which is being compiled
...

‘#PB_Compiler_Home’
This constant’s value is a String containing the full path of PureBasic’s installation folder on your
computer
...
If its value is equal to ‘#True’ then the debugger was enabled
before the program was compiled
...


Beyond The Basics

247

‘#PB_Compiler_Thread’
This constant can have one of two values
...
If its value is equal to ‘#False’ then the thread-safe compiler
mode wasn’t used
...
If its value is equal to ‘#True’ then the compiler was switched
to unicode mode before compilation
...

All these reserved compiler constants can be used as normal in statements and expressions, in fact you
can use them anywhere where you would use a normal constant
...

The ‘CompilerIf’ Directive
If you understand how to use ‘If’ statements in PureBasic you will understand how to use ‘CompilerIf’s
...
It’s basically a compiler version of an ‘If’ statement
...
In contrast, a normal ‘If’ decides which piece of (already
compiled) code to run based on a variable expression
...
If this
expression equals true then we know that this piece of code is being compiled on a computer running
Microsoft Windows
...
This seems pretty
straightforward but what’s clever about using ‘CompilerIf’s is that whichever branch the ‘CompilerIf’
statement takes, it will only compile that piece of code
...

A ‘CompilerIf’ statement consists of three commands, all of which are demonstrated in the above
example
...


248

Beyond The Basics

Some programmers use ‘CompilerIf’s to limit the functionality of a program especially if it’s compiled
as a trial version
...
I could
code my program like this:
#DEMO = #True
CompilerIf #DEMO
;Demo code
MessageRequester("Info", "This is a demo, You must buy the full version
...
d MyPI()
ProcedureReturn ACos(-1)
EndProcedure
Test
...
" + #LF$ + #LF$
Test
...
This is useful as it can prevent cracking of your demo programs
because they simply will not contain the code contained inside the full version
...

The ‘CompilerSelect’ Directive
The ‘CompilerSelect’ statement is a compiler version of the popular ‘Select’ statement
...
Similar to a ‘CompilerIf’, ‘CompilerSelect’s can only test constant values, this is again
because the test is done at compile time instead of runtime
...
")
CompilerCase #PB_OS_Linux
;Linux specific code
MessageRequester("Info", "This is being compiled on Linux
...
")
CompilerEndSelect

Using something like this, it’s possible to customize your program to exhibit different behavior based
on what operating system it’s compiled for
...

PureBasic provides support for several keywords to give a ‘CompilerSelect’ the same functionality as a
normal ‘Select’ statement
...
You have seen three of these commands in the ‘CompilerSelect’ example
above
...
")
CompilerDefault
;This code will compile on all other operating systems
...
")
CompilerEndSelect

In this example I’ve thrown up an error if someone tries to compile this code on AmigaOS but for all
other operating systems (handled by the ‘CompilerDefault’ keyword) it runs fine
...

This is so you can customize the compiling process using PureBasic code as much as you see fit
...
This is handy when you want to
stop the compilation process and give the user a graceful compiler error message
...
"
CompilerDefault
MessageRequester("Info", "This is code will compile fine on this OS
...
Instead we simply use the ‘CompilerError’ directive
with a literal String following it
...
When the compiler encounters an ‘CompilerError’ directive, the compilation is
stopped and the error text is presented
...
Subsystems are an easy concept to grasp, basically, if you are not happy with the
functionality of any of PureBasic ‘s built-in commands you can override them with your own versions,
these new versions are contained within a subsystem
...
These library files are
the ones that are replaced when a subsystem is used
...
A subsystem library merely takes priority over standard libraries
...
This new library must contain all
commands of the original library and all these commands must be named in exactly the same way as
the originals
...

Once you have done this, it should be an almost identical copy of the original library, apart from the
functionality of the commands it contains (you can write these to have any functionality you wish)
...
The name you give this new
folder will be the name of your new subsystem
...
So the directory
structure of these folders will looking something like this:

...
To do this
open the ‘Compiler Options’ window (Menu:Compiler->Compiler Options
...
When your program is next compiled, the compiler will scan the ‘SubSystems’ and
‘PureLibraries’ folders looking for libraries, if it finds that these two folders contain identically named
libraries, the compiler will always choose the specified subsystem over the standard one, therefore
replacing the original
...
If you look in there, you will
find a folder called ‘OpenGL’, inside which is a ‘PureLibraries’ folder, and inside that, there are
replacement libraries for ‘Screen’, ‘Sprite’ and ‘Sprite3D’
...
Once activated via a compiler flag, this subsystem will use OpenGL
for 2D graphics instead of DirectX
...

During compilation, the ‘Subsystem()’ compiler function lets you know if a particular subsystem has
been activated using a compiler flag
...
"
EndIf

The ‘Subsystem()’ compiler function takes one parameter, this is a literal String of the subsystem you
want to test for, (variables cannot be used here)
...

The ‘Defined()’ Compiler Function
Sometimes when coding software you need to test wether a particular data object has been defined
...
This function takes two parameters, the
first is a data object to test for, and the second is the data type of that object
...
The value of the object being
tested doesn’t matter, only that it has been defined
...

When using the ‘Defined()’ compiler function, the first parameter must only be the name of the data
object to test and must not contain any of the usual prefixes or suffixes that are usually used for that
object
...
For the second parameter, where you pass the type of the object you are
testing, you can use built-in constants, here is the full list of what is available:
‘#PB_Constant’
‘#PB_Variable’
‘#PB_Array’
‘#PB_LinkedList’
‘#PB_Structure’
‘#PB_Interface’

252

Beyond The Basics

I’ve made this command sound like it’s quite complicated to use, so I better dismiss that with a simple
example of how easy it really is
...
s’ has been defined, if not, it
defines it:
Global Name
...
s = "Name 2"
EndIf
Debug Name

You can test this piece of code by commenting out the first line
...
Code like
this is invaluable for large projects, where you may be including a lot of source code files into a main
one and you need to test if something important has been defined before
...


Advanced Compiler Options
When using PureBasic you may need to change modes on the compiler for a particular program or you
may need to have the compiler output specific information
...
You can enable or disable most of these options visually in the
IDE from within the ‘Compiler Options’ window (Menu:Compiler->Compiler Options
...

So what is a command line interface anyway? Well, it’s a small program that usually comes with your
operating system (sometimes called a Shell Interface), that allows you to navigate your computer’s
hard drive or start programs and control computer functions by typing in recognized text commands
...
There are numerous command line
interface programs available, and these seem to be some of the most popular:
‘CLI’ on AmigaOS
‘Command Prompt’ on Microsoft Window XP
‘BASH’ on Linux
‘Terminal’ on MacOS X
For these command line interfaces to work correctly with PureBasic, you may need to add the full
directory path to the compiler to your ‘PATH’ environment variable
...
Using an environment variable like this will
negate the need to type in the full path of the compiler when using it in a shell command
...
Saying that though, sometimes having a
compiler that you can use on the command line is useful, especially if you want to use your own code
editor, then you can set it up as an external tool
...
The actual compiler command itself must always start with the name of
the PureBasic compiler followed by any parameters that are required
...

Using the command line compiler in its simplest form to produce an executable file from a PureBasic
file, doesn’t need any optional parameters to be passed to it, but it does need the name of a ‘*
...

Open a command line interface window, type this in it and hit return:
PBCompiler MyProgram
...
pb’ file to it
...
This is probably the simplest way of compiling a program using the
command line
...
pb /exe "MyProgram
...
pb’ file and create an executable file from it
...
exe’ and will be placed in the same directory as the specified
‘*
...
Notice in this command we are using a new compiler option; ‘/exe’
...
The String after this compiler option is what that file
should be called
...
These two
examples are fairly easy to understand, but these actual commands are seldom used in practice
...
These two are useful to know
though, especially if you want to set up another code editor
...
For example, if I wanted to compile a ‘*
...
pb /exe "MyProgram
...
\icons\MyIcon
...

All command line compiler options must always be separated by spaces
...
Remember, most of these options can be
enabled visually in the IDE, using a checkbox or a drop-down menu in the ‘Compiler Options’ window
...
All these command line options are
also completely case insensitive, so you can enter them in upper or lowercase, it’s entirely up to you
...
The help page is printed to the shell interface window
...

PBCompiler /?

/Commented
This is another command line only option which creates a commented Assembly file in the
‘PureBasic\Compilers’ folder called ‘PureBasic
...
This file is
the raw output of the PureBasic compiler and contains the raw compiler generated assembly source
code of the ‘*
...
This file can be re-compiled into an executable file, using the ‘/reasm’ compiler
option, even if modifications are made to it
...
pb /commented

/Console
This compiler option enables you to compile a true console application
...
pb /exe "MyProgram
...

/Constant (Name=Value)
This is another command line only option which enables you to define a constant dynamically on the
command line
...
For example: ‘DEMO=1’ or ‘DEMO=0’
...
pb /exe "MyProgram
...

Also, if you are defining a String constant, I would advise enclosing it within double quotation marks
as in my example
...
For safety sake, use double quotes for Strings
...
If this option is used with the ‘/exe’ option, the console debugger
is embedded into the resulting executable file
...
Here’s these two examples:

Beyond The Basics

255

PBCompiler MyProgram
...
pb /exe "MyProgram
...
If this option is used during compilation, the resulting DLL file is created within the
‘PureBasic\Compilers’ folder called ‘PureBasic
...
This file can then be renamed as you see fit
...
lib’ and an export file called
‘PureBasic
...

PBCompiler MyProgram
...

Some of these procedure are specially named to give you extra functionality within your compiled
library
...

/DynamicCpu
This command line option is almost equivalent to specifying all the options; ‘/mmx’, ‘/3dnow’, ‘/sse’
and ‘/sse2’ in one go
...
What’s happens when this executable is run, is it looks
at the processor type of the system it’s being run on and chooses between the compiled routines to
select the one that matches that particular processor’s architecture
...
This could make the executable file larger
than usual because it may contain many versions of the same routine, but it can make the program run
faster because those different routines can contain specific processor optimized code
...
pb /exe "MyProgram
...
A String specifying the executable name must always follow the
‘/exe’ part and must always be contained within double quotation marks, otherwise you may get
unexpected results
...

PBCompiler MyProgram
...
exe"

/Icon "IconName"
This compiler option lets you specify an icon on your hard drive that you would like your executable
to use
...
The String
containing the location of the icon file can be a relative String if needed, as in this example:
PBCompiler MyProgram
...
exe" /icon "
...
ico"

256

Beyond The Basics

/IgnoreResident "FileName"
This is a command line only option which enables you to stop an installed resident file from loading
during compilation
...
If the installed resident file is not ignored and you are re-compiling
that file again, you may get ‘Already defined’ errors
...
pb /resident "MyResid
...
res"
PBCompiler MyProgram
...
exe" /ignoreresident "MyResid
...
The second line is an example of what you may need to do if you are re-defining constants or
structures in your program that are already present in an installed resident file
...
pb’ file
...

PBCompiler MyProgram
...
exe" /inlineasm

/LineNumbering
This compiler option adds support for internal line numbering of commands within your executable
file
...

PBCompiler MyProgram
...
exe" /linenumbering

Be aware that if you are using line numbering for your executable, it could slow down the speed with
which it runs, because you are adding slightly more ‘overhead’ to the executable than usual
...

PBCompiler MyProgram
...
exe" /linker "MyLinkerCommands
...
Only one of these options can be used at a time, as they tailor the executable file to only include
routines that specifically run on processors that support such extensions
...
For example, if you create an executable that uses the
‘/mmx’ compiler option, only the MMX routines used in the source code will be used for the final
executable and that executable will only run on processor that support the MMX extensions
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
This is handy when you want to use the compiler as an external tool from another code
editor, etc
...
pb /exe "MyProgram
...
asm’ file
...
asm’ files are created using the ‘/commented’
compiler option
...
asm /reasm

When using this command, the ‘*
...

/Resident "FileName"
This is a command line only option which enables you to create a resident file from a standard ‘*
...
Resident files are usually composed of constant and structure definitions only
...
pb /resident "MyResident
...
If this String is missing or not enclosed in
double quotes, then a compiler error will occur
...

/Resource "FileName"
This compiler option is for Microsoft Windows only as it appends a Windows resource file to the
compiled DLL or executable file
...
Only one resource file
may be added but this file can contain references to other resource files if needed
...

PBCompiler MyProgram
...
exe" /resource "MyResource
...
This is not a command that normal users would usually use because documentation
is very scarce regarding how to interface with the compiler once it’s loaded into memory
...

I’ve given subsystems a full description a little earlier in this chapter, so I’ll not repeat myself here
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...
pb /exe "MyProgram
...

/Thread
This compiler option will enable thread-safety for the compiled executable file
...
One thing to remember when using
this command is that the resulting executable file may run slightly slower than a non-threadsafe one
...

PBCompiler MyProgram
...
exe" /thread

More information about threads can be found later in this chapter
...
Unicode is a character
encoding scheme using 16 bits (2 Bytes) per character to allow all characters of all major world
languages, living and dead, to be encoded in a single character set
...

PBCompiler MyProgram
...
exe" /unicode

/Version
This is a command line only option, and its only function is to print the version of the PureBasic
compiler used in the command line interface window
...

PBCompiler /version

Beyond The Basics

259

/XP
This compiler option is for Microsoft Windows XP only
...

PBCompiler MyProgram
...
exe" /xp

Parsing Command Line Parameters
Sometimes when developing programs using PureBasic you may want to create command line tools
that accept certain parameters when being launched using a shell command
...
The program is started and parameters are passed to it, the values
of these parameters determine what function the program performs
...

Explaining Parameters?
When passing parameters (sometimes called arguments) to command line programs, you need to keep
in mind how they are passed and what actually constitutes a parameter
...
pb /exe "MyProgram
...
pb’, ‘/exe’ and ‘"MyProgram
...
Even though we are only using one
compiler option after the ‘*
...

When passing parameters to programs like this, the program makes a decision about how many
parameters are passed based on how many spaces it sees after the program name
...

For example, all these shell commands would pass two parameters to the program called ‘MyProgram’:
MyProgram
MyProgram
MyProgram
MyProgram

/a 105
/play /now
/play "Me And My Shadow"
"Put It In The" "Back"

As you can see from these examples, parameters can be either numbers or Strings, but when they are
passed into your program they are all automatically converted into Strings
...


260

Beyond The Basics

Reading Passed Parameters From Inside Your Program
When parameters are passed to your program from a shell command, they are stored internally for you
to read in your program when you see fit
...
When all parameters have been returned by the
‘ProgramParameter()’ command, it then returns an empty String
...
l = CountProgramParameters()
Text
...
l = 1 To NumberOfParameters
Text
...
s + "None"
EndIf
MessageRequester("Info", Text)

The first line of this example uses the ‘CountProgramParameters()’ command, this returns the exact
number of valid parameters that was passed to your program
...
If I compile this piece of code to an executable file and called it ‘ListParameters
...
Once this
command has been entered and the program has been launched
...
The first
time it’s used, the ‘ProgramParameter()’ command will return ‘/one’, the second time it’s used it will
return ‘/two’ and the third time ‘/three’ is returned
...


Testing Command Line Parameters Using The IDE
When developing an application in the IDE that will accept command line parameters, you don’t really want
to be compiling to a final executable and calling that through a command line interface every time you want
to test it
...
This field can
be found in the ‘Compiler Options’ window, which is accessible from the ‘Compiler’ menu
...
This is where you enter
parameters that you would like passing to your program when you hit the ‘Compile/Run’ button
...


Beyond The Basics

261

Making Decisions Based On Parameters
If you are using command line parameters to control the functionality or output of your program, you
will need it to perform different actions depending on the values of those passed parameters
...
Making decisions based on what parameters have been passed is not as hard as you may
think, you just use regular ‘If’ and ‘Select’ statements to test the values of the parameters
...
Try passing one or two of these parameters to this program to see the
output:
;Count parameters
NumberOfParameters
...
s()
If NumberOfParameters > 0
For x
...
s)
ForEach Parameters()
If Parameter = Parameters()
ProcedureReturn #True
EndIf
Next
ProcedureReturn #False
EndProcedure
;Check to see if the parameter 'Mouse' was passed
If ParameterPassed("MOUSE")
MessageRequester("Info", "'Mouse' was specified as a parameter
...
")
EndIf
;Check to see if the parameter 'Dog' was passed
If ParameterPassed("DOG")
MessageRequester("Info", "'Dog' was specified as a parameter
...
This so
I can perform String comparisons on the parameters without worrying about its case
...

This is good practice because it doesn’t matter how the user enters parameters (uppercase, lowercase,
mixed case) they will always be converted to uppercase before the ‘If’ comparison
...
However, giving your users the potential to use
your application or tool from the command line will get more people using it and will give the program
more versatility
...


A Closer Look At Numeric Data Types
Numeric data types allow you to store numbers in several different formats and each type allows you
to use slightly different amounts of memory to store those numbers
...
If you look
back in Chapter 2 at Fig
...
These
limits are imposed by the finite number of bits contained within the memory that these data types
allocate
...
b) you will see that it uses one Byte of memory,
which consists of eight binary digits or ‘bits’
...
In fact, eight bits can only be ordered into two hundred and fifty six (256)
unique patterns, with each bit being either ‘1’ or ‘0’
...

In this section I will explain to you, how numbers are stored in memory and how binary numbers are
actually calculated
...

When dealing with numbers in computer languages there needs to be made a clear distinction between
integers and floating point numbers
...
Floating point numbers on the other hand can be positive or negative but
always contain a decimal point
...

What Is Binary?
Binary Notation, or base-two as it’s sometimes called, is a numerical system where the digits of a
binary number can only have one of two values, ‘0’ or ‘1’
...

Let me explain this concept a little more clearly, here is an example of a decimal number:
542

In this example, the ‘2’ digit is in the position associated with the quantity one, the ‘4’ digit is in the
position associated with the quantity ten and the ‘5’ digit is in the position associated with the quantity
hundred
...
To find out what number this
represents you simply multiply the value of each digit by the quantity associated with that digit’s

Beyond The Basics

263

position and then add those results together i
...
(‘5’ x hundred) + (‘4’ x ten) + (‘2’ x one) = ‘542’ (five
hundred and forty two)
...
The position of each
digit in a binary number is also associated with a quantity, except that the quantity associated with
each position is twice that of the position to it’s right, this is base-two after all
...
Look at Fig
...


Unsigned Byte
Binary Digits (bits)

0

1

0

0

1

1

0

1

Associated Quantity 128 64 32 16

8

4

2

= 77

1

8 bit number
(1 byte)
Numerical range: ‘0’ to ‘255’

Fig
...
We multiply the value of each digit by the quantity associated with its position then add the
results
...
44 is ‘77’
...
So, if you look at Fig
...

You can probably see now from Fig
...
This is why certain types have certain limits, they simply run out
of bits to use
...

Signed And Unsigned Integers
Earlier on in Fig
...
These are known as Signed number types, because their values can potentially contain a
negative sign
...
The PureBasic Character type is an example of an
unsigned integer type and which is also shown in Fig
...
Because there is only a finite number of bits
allocated by these data types, there are two methods needed to interpret these binary numbers
depending on wether they should be read as signed or unsigned
...
45 every integer data type has two ways of being read
...
yes, zero is a number too!

264

Beyond The Basics

Data Type
Signed Byte
Unsigned Byte*
Signed Word
Unsigned Word*
Signed Long
Unsigned Long*

Numerical Range
-128 to 127
0 to 255
-32768 to 32767
0 to 65535
-2147483648 to 2147483647
0 to 4294967295

* Not available in PureBasic v4 (maybe in future versions?)

Fig
...
44
...
For example, the maximum
value of an unsigned Byte expressed using binary is ‘11111111’ (‘255’) where all the bits are set to ‘1’
...

Reading Signed Integers Using Binary
A signed integer follows slightly different rules to express using binary
...
In two's complement form, the left most bit of a signed
binary number (sometimes called the most significant bit) indicates if the actual sign (-) is present in
the integer
...
If the left most bit is ‘1’ the integer
being expressed is negative and must be read using two's complement form, as explained below
...
Let’s take a Byte as an example again, if
we left the sign bit as ‘0’ to express a positive number that only leaves us with seven remaining bits to
make a number out of, so we’ll turn all these to ‘1’, like this: ‘01111111’
...

If we want to express a negative integer using binary we have to do it in a slightly different manner
...
The left
most bit is zero so we know for definite this is a positive integer
...
So the number ‘-9’ looks like this: ‘11110111’
...
As you can see the left most bit is now ‘1’ indicating this binary
number represents a negative (signed) integer
...


Beyond The Basics

265

To convert this negative integer back to its positive form, you follow exactly the same procedure
...
Fig
...


Signed Byte
Sign (-) Bit
Binary Digits (bits)
Associated Quantity

1

1

1

1

0

1

1

1

64 32 16

8

4

2

= -9

1

8 bit number
(1 byte)
Numerical range: ‘-128’ to ‘127’

Fig
...
In all integer types the
associated quantities of each bit position grows by a power of ‘2’ as you move to the left within the
binary number
...

Floating Point Numbers And Binary
A floating point number is a number which contains a decimal point and which can be either negative
or positive
...
Using a storage method like this makes it
possible to have a huge range of numbers that can be stored but at the cost of numeric accuracy
...

PureBasic currently supports two data types to handle floating point numbers, these are the normal
Float type and the Double type
...
A Float uses 32 bits (4 Bytes) and a Double uses 64 bits (8 Bytes),
so obviously Doubles are a lot more accurate for holding large numbers
...
Floats can be a lot faster at reading from memory
especially when using large Float arrays
...
Usually programs such as games tend
to use Floats while programs that need more accuracy tend to use Doubles
...
This method is quite complicated and is described in the ‘IEEE 754’ standard for binary

266

Beyond The Basics

encoding of floating point numbers
...

First, all floating point numbers are stored in three binary parts
...
These three parts all fall inside the bit limit as defined by using either
a Float or a Double
...
47
...
47

Here, you can see how the type is divided internally to support each of the three sections
...
The sign bit is
probably the easiest of the sections to explain
...
Let’s start with an example number and
I’ll demonstrate how it is encoded into a 32 bit Float
...
625’
...
The
first, is we have to convert both sides of the decimal point into binary, like this:
‘10
...
101’
This might look a little odd because you will probably not have seen a decimal point (or radix point as
it’s more accurately called here) within a binary number
...
Encoding a number into binary like this is a little different from what was
explained before, because you are dealing with a whole number on one side of the radix point and a
fraction on the other side
...
44, i
...
decimal ‘10’ = binary ‘1010’
...
Also, for these binary numbers, we don’t
pad them with unnecessary zeros
...
5’
and decrease by a factor of ‘2’ the more right you go along the binary number
...
48
...
625
The whole number can be encoded like this:

Binary Digits (bits)

1

0

1

0

Associated Quantity

8

4

2

(8+2) = 10

1

Radix Point
The fractional number can be encoded like this:

Binary Digits (bits)
Associated Quantity

1

0

1

(0
...
125) =
...
5 0
...
125

Radix Point

Fig
...
5’ and
decreasing by a factor of ‘2’ in each place moving to the right, so they are calculated as, ‘0
...
25’,
‘0
...
The more places you go to the right the more precision a fractional number can contain
...
625’ it is easily represented by ‘0
...
125’ so that’s
where the binary ‘1’s appear
...
Luckily though there is an easy way to
encode these numbers using the ‘doubling’ trick
...
625’ and double it and see if it is above or equal to ‘1
...
If it is then
we mark down a binary ‘1’
...

If at any stage the doubling does not produce a number which is equal to or above ‘1
...
Here’s how this works in practice:

...
25 - This is above or equal to ‘1
...


...
5 - This is not above or equal to ‘1
...


...
0 - This is above or equal to ‘1
...


268

Beyond The Basics

When no more fractional parts are available to test or you have run out of bits to fill you stop
calculating
...
625’
...
So, step one was first to encode our number into a binary
form, like this:
‘10
...
101’
Step Two, Move The Radix Point And Calculate The Exponent
In this step we need to move the radix point, as this will not be encoded in the final binary number
...
To do this we shift the radix point along the binary number until there only remains a ‘1’ to
it’s left
...
Look at this example:
‘1010
...
010101’ (Radix point moved 3 places to the left)
When moving the radix point we need to note of how many places we move it
...
If the original binary number was something like ‘0
...
(I’ll explain about this ‘1’
always being to the left in a minute)
...
This exponent is then added to a preset number (depending on what size of floating
point type you are using), to make sure it is encoded as an unsigned number
...

In our original example, we moved the radix point ‘3’ places to the left (which is a positive 3), so we
add ‘127’ to ‘3’ and get ‘130’
...
44, which would be ‘10000010’
...
47
...
This limit is ‘127’ places to the left and ‘(-)126’ places to the right
...
’ is changed to a leading ‘0
...
In fact this is where the actual number is stored, the exponent merely tells you where the

Beyond The Basics

269

radix point should sit relative to the significand
...
010101’
To calculate the significand from this, we first completely disregard the ‘1’ at the beginning of this
binary number
...
Disregarding this number
allows us to gain one more bit within the significand to help us represent the original decimal number
...

After disregarding the ‘1’ in front of the binary number the radix point is then meaningless too, so we
can get rid of that as well
...
This is our significand
...
These zeros must be on the right hand side, like this:
‘01010100000000000000000’
...
47
...
625’ would be:
‘0 10000010 01010100000000000000000’
Limitations Of Floating Point Numbers
Even though floating point numbers are very versatile, they are also inherently inaccurate because of
the way the number is stored using binary
...
Only about 7 decimal digits are represented
correctly in single precision Floats, and about 16 in Doubles
...
This is always something to keep in mind when using Floats and Doubles
...
Using the percent sign like
this should not be confused with the modulo operator from Chapter 3 (An Introduction To Operators)
even though they use the same symbol
...
Here’s an example:
BinaryVariable
...


Pointers
I think its fair to say that pointers in computer programming scare a lot of people
...

Maybe it’s the fear of the unknown that makes people avoid them? I don’t know, but what I do know
is that, when pointers are explained to people properly, they always wonder why they avoided them for

270

Beyond The Basics

so long
...

So what is a pointer? Well, put simply, a pointer in PureBasic is a variable that holds a numeric address
of a location in memory
...

Every Byte in memory can be looked up via it’s number (address)
...

Getting A Memory Address
Now we know that a pointer is just a variable that holds a memory address, we now need to know how
to get the memory address of something useful
...


Memory Address Functions
Data Object

Function

Usage Example

Variables

@

@VariableName

Arrays

@

@ArrayName()

Procedures

@

@ProcedureName()

Labels

?

?LabelName

Fig
...
49 you can see the two special memory address functions and which data objects they work
with
...
The ‘?’
function is reserved for labels
...
b = 100
Debug MyByteVar
Debug @MyByteVar

In this example, I’ve defined a Byte variable called ‘MyByteVar’ which is given the value of ‘100’, which
is all pretty straightforward
...
Using ‘@’ like this will return the memory address of ‘MyByteVar’ which I’ve
then echoed to the Debug Output window
...
The address is typically a huge number, usually about seven or eight digits long
and this address may change depending on what computer you run it on
...


Beyond The Basics

271

When I run the this example on my PC, I get this displayed in the Debug Output window:
100
4298004

This tells me that the Byte variable which is used to store the value of ‘100’ is located at memory
address ‘4298004’
...
Here is an example which would be
pretty useless in the real world, but demonstrates getting the addresses of all these different data
objects and echoing these memory addresses to the Debug Output window:
MyByteVar
...
w = 2
MyLongVar
...
q = 4
MyFloatVar
...
d = 6
MyStringVar
...
l(8)
Procedure MyProcedure(Test
...
"
EndProcedure
Debug
Debug
Debug
Debug
Debug
Debug
Debug
Debug
Debug
Debug

"Byte variable address: " + Str(@MyByteVar)
"Word variable address: " + Str(@MyWordVar)
"Long variable address: " + Str(@MyLongVar)
"Quad variable address: " + Str(@MyQuadVar)
"Float variable address: " + Str(@MyFloatVar)
"Double variable address: " + Str(@MyDoubleVar)
"String variable address: " + Str(@MyStringVar)
"Array address: " + Str(@MyLongArray())
"Procedure address: " + Str(@MyProcedure())
"Label address: " + Str(?Label)

DataSection
Label:
Data
...
And even though the array
in the above example was defined like this:

...
l(8)

...
The same is also true for labels
...
To begin with, and for clarity’s sake, I would recommend that all
retrieved memory addresses are kept within variables, to keep code neat and readable, always
remembering to give them good meaningful names
...
For a start,
pointers in PureBasic are created by using an asterisk ‘*’ as the first character in its name
...
For example, on a 32 bit system, a pointer will use 4 Bytes of memory to
store a number, while on a 64 bit system, a pointer will use 8 Bytes to store a number
...
Meaning that if you define a
pointer using an asterisk along with any of the built-in numeric types, the built-in type is discarded to
make sure the pointer is the correct size for your particular computer architecture
...
b = @Variable

The Byte type is discarded and the pointer will still use 4 Bytes on a 32 bit system and 8 Bytes on a 64
bit system
...
For example, these
two are completely different and have no relationship towards each other:
MyVariable
...
l

Beyond The Basics

273

Even though the only difference between these variables is the asterisk, the first variable is a Long type
variable, while the second one is a pointer (defined by the asterisk)
...
They are treated as two entirely
different variables
...
In the helpfile, all the
syntax examples that deal with memory also use this convention to help programmers know where
pointers are needed
...

Using this convention, the first example can be re-coded like this:
MyByteVar
...

Accessing Memory In A Structured Way, Via A Pointer
In this next example I’ll show you how you can use a pointer to act as a structured variable
...

Structure DETAILS
Age
...
l
EndStructure
My
...
DETAILS = @My
Debug *Pointer\Age
Debug *Pointer\Height

Here, you can see I’ve defined a structure called ‘DETAILS’ which contains two Long fields
...
Now this is where the special function of the asterisk can be helpful when
creating a pointer
...
DETAILS = @My

274

Beyond The Basics

This creates a pointer called ‘*Pointer’ and sets its value to be the memory address of the ‘My’
structured variable
...

So these two lines that are echoing data to the Debug Output window:
Debug *Pointer\Age
Debug *Pointer\Height

are actually echoing the data contained within the ‘My’ structured variable, we are just retrieving this
data using our newly created pointer
...
Fig
...


The ‘My
...
50
So what is this useful for? Well, it could be used to return more than one value from a procedure
...
Then
return it’s memory address from the procedure
...
Kind
of like this:
Structure MEALS
Breakfast
...
s
Tea
...
l GetMeals()
Static Gary
...
MEALS = GetMeals()
Debug *Gary\Breakfast
Debug *Gary\Dinner
Debug *Gary\Tea

We use the ‘Static’ keyword here to preserve the data in the ‘Gary’ structured variable when the
procedure returns, otherwise it will be destroyed
...
We can then access
that memory using the ‘MEALS’ structure
...

For added flexibility memory addresses from any variable type can be assigned to a newly created
structured variable pointer, even PureBasic’s built-in types can be used
...
w
y
...
l = %00000011000000000000010000000000
*Screen
...
Then I assign its
memory address to a newly created structured variable pointer called ‘*Screen’
...
This allows me to return two values
from this one variable, giving you the two ‘x’ and ‘y’ values
...
This is the only way in PureBasic that you can actually pass a structured variable into a
procedure
...
What this means is that values aren’t actually ‘copied’ into any
parameters
...
One of the main things you need to consider when using this method, is that when
you pass a structured variable into a procedure, the parameter name of that procedure might not have
the same name as the structured variable you are passing, but whatever name you give to the
parameter, you are still manipulating the original passed structured variable
...
l
y
...
COORDINATES

276

Beyond The Basics

Procedure IncreaseValues(*Var
...
When all field values have been assigned to this variable, I then pass its memory address to the
‘IncreaseValues()’ procedure
...
COORDINATES’
...
The name ‘*Var’ can
be anything you like (as long as it’s prefixed by an asterisk), it’s merely used as a friendly way to
manipulate the passed pointer
...

*Var\x + 10
*Var\y + 10

...

Using this method of passing structured variables to procedures can be very handy for situations
where you want to pass lots of information nicely grouped together
...
Also using this method you can
have less parameters being passed to procedures, as you can pass them all in one structured variable
...
It just makes things a little more readable and manageable
...
Arguably the
most common way is reading values from that memory location or storing new data there
...
You use a ‘Peek’ command to retrieve data from a memory location and use
a ‘Poke’ command to store new data there
...
Each one of these commands are named in pretty much the same way, except
the last letter of the command name is the same as the type it works with
...
Similarly, if you wanted
to poke a String into a particular memory address, then you would use ‘PokeS()’
...

Peeking Values Held In Memory Locations
Using a peek command is quite straightforward, you pass it a memory location (maybe being held
inside a pointer) and the peek command will return the data that resides there
...
Here is an example of peeking a Byte from a
memory location using the ‘PeekB()’ command:
Weight
...
b = PeekB(*Weight)
Debug ReadValue

Here, I assign the value ‘30’ to a Byte variable named ‘Weight’
...
The next line contains the ‘PeekB()’
command which actually reads a Byte value from the passed pointer and returns it
...
b = 30
ReadValue
...
I guess it depends what you are most comfortable with
...

Poking Values Into Memory Locations
Poking values into memory locations is just as easy as using a ‘Peek’ command
...
Here’s an example
of poking a new Long value into an existing Long variable’s memory location:
Weight
...
Then I’ve created
a pointer called ‘*Weight’ which contains the memory address of ‘Weight’
...
The new
value of ‘Weight’ is then echoed to the Debug Output window
...
Using PureBasic’s memory commands can be
quite dangerous of you don’t know what you are doing
...
You could pass a random number to any ‘Poke’ command as a memory address and it will
quite happily poke a value into it
...
If you get it wrong, you could mess
up a memory location that some essential program might need to read
...

To safely poke values into memory you should poke into an existing variable or array’s memory
location or poke into memory allocated using the ‘AllocateMemory()’ command (Helpfile:Reference
Manual->General Libraries->Memory->AllocateMemory)
...
For example, it would be bad practice to poke a Long
value into a Byte variable’s memory location, because you are poking 3 more Bytes of data than you
should be
...

Using A Memory Address As A Start Index
When using contiguous blocks of memory to peek values from or to poke values into, it’s possible to
use the starting Byte’s memory address as a starting index for the rest of the block
...
Take a look at this example:
Dim Numbers
...
Once this is done I create a pointer called ‘*ArrayPointer’ which
holds the array’s memory address
...
The memory address returned by a memory
address function prefixing an array, is the address of the first index
...


Beyond The Basics

279

When we use a line of code like this:

...


We are peeking the value from the first index’s memory location
...
To peek other values from the array, we must use this
pointer as a starting location and add to it the number of Bytes we wish to move through memory by
...
The following lines of code, from the above
example does just that, they peek values from further into the array’s memory by using the array’s
pointer as a starting location
...

Debug PeekL(*ArrayPointer + 4) ;This echoes the second Long value: ‘200’
Debug PeekL(*ArrayPointer + 8) ;This echoes the third Long value: ‘300’

I’ve shown this visually in Fig
...
If I was using an array of Bytes then of course I would have to
increase the array’s pointer by ‘1’ to peek the second Byte and by ‘2’ to peek the third, etc
...


The ‘Numbers’ Array In Memory
Index ‘0’
Number Of Bytes

1

*ArrayPointer

2

3

Index ‘1’
4

5

6

*ArrayPointer + 4

7

Index ‘2’
8

9

10 11 12

*ArrayPointer + 8

Memory allocated for the ‘Numbers’ array
(12 bytes)

Fig
...
Any program can have several threads running concurrently, each performing a
different task, such as waiting for events or performing a time-consuming job
...
If the originating program is
closed, then the thread will automatically be stopped and destroyed too
...
For example, if you wrote a search tool to
search for files on your hard drive, you would probably write the search code to be executed from
within a thread
...
The searching could be done independently, without impairing the responsiveness of
the main interface
...

Because these files take quite a while to manipulate in whatever way, you may want to deal with them
in a thread, so that the main program can be doing other things
...

Using Threads
Before I continue showing you how to use threads, let me show you a simple program that isn’t
threaded to base a comparison upon
...
Notice that when you press the ‘Start Test’ button, you can’t move
the window or see any text actually being entered into the gadgets until both procedure calls have
finished
...
l)
For x
...
l = WaitWindowEvent()
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_TEST
InsertText(#LIST_ONE)
InsertText(#LIST_TWO)
EndSelect
EndSelect
Until EventID = #PB_Event_CloseWindow
EndIf
EndIf
End

Beyond The Basics

281

You will also notice that when you run this example, the two procedure calls to ‘InsertText()’ in the
main loop are run one after another
...
In this case, that doesn’t really matter
to us, because we can’t see any updates happening in the list view gadgets because of the ‘Delay()’
command used in the ‘InsertText()’ procedure
...
If you are using the compiler on the command line you can use the ‘/Thread’
compiler option or you can switch on thread safe compilation in the IDE from the ‘Compiler Options’ dialog
box (Menu:Compiler->Compiler Options
...

If this mode is not enabled and you are compiling and running your program, your finished executable might
not be one hundred percent thread safe
...
This is
especially true regarding String usage
...

Using the thread safe compilation mode comes at a small price though
...
This is why the decision to use threads
must be well thought out
...


This delay is even delaying the program from processing internal messages to re-draw the user
interface or handle the movement of the window within the operating system
...
Now
imagine if this was an image processing program, and these two procedures take thirty minutes to
finish whatever they do
...
We wouldn’t even be able to draw a progress bar!
If we want both of these procedure calls to run at the same time and be completely independent of the
main user interface, we could create two threads to run at the same time as the main program
...
l)
For x
...
l = WaitWindowEvent()
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_TEST
Thread1
...
l = CreateThread(@InsertText(), #LIST_TWO)
EndSelect
EndSelect
Until EventID = #PB_Event_CloseWindow
EndIf
EndIf
End

If you look closely, the only difference between these two examples is how the procedures have been
called
...
To create a thread from it, you use the
‘CreateThread()’ command (Helpfile:Reference Manual->General Libraries->Thread->CreateThread)
which itself takes two parameters
...
The second is a mandatory parameter which can be of any type
...

When creating a thread like this, if the ‘CreateThread()’ command returns a value that is greater than
zero the thread has been successfully created and has been immediately launched
...

So let’s recap on what rules we must follow to create a thread from a procedure
...
The thread procedure must have one, and only one parameter
...
No value can be returned by the thread procedure
...


Beyond The Basics

283

When this threaded example is run, you will see values being inserted to both of the list view gadgets
in realtime
...
The two newly created
threads have become independent parts of the same program, which run at the same time as it
...

If you notice any garbled text being inserted into any of the gadgets, you must ensure that the ‘Create
Threadsafe Executable’ compiler option is enabled, as described in the ‘Compiling Thread Safe
Programs’ box
...
If you use threads in your main program, they are always at the mercy of that program’s life
span
...

In PureBasic you can get around this problem by using the ‘WaitThread()’ command
(Helpfile:Reference Manual->General Libraries->Thread->WaitThread)
...
Here’s an example:
Procedure DrawNumbers(Unused
...
l = 1 To 20
PrintN(Str(x))
Delay(75)
Next x
EndProcedure
If OpenConsole()
ThreadID
...
This takes one
parameter which is a thread identifier of a previously created thread
...
The ‘WaitThread()’
command can take an optional second parameter if needed, which specifies a time-out value in
milliseconds
...
I’ve not used this optional second parameter in my example because I want to
make sure the threaded procedure has finished before you are able to ‘End’ the program
...
With the
‘WaitThread()’ command in place however, you have to wait for the thread to finish before the
keypress is acted on
...
Having many threads attempting to
read and write to the same file or memory location at exactly the same time is always going to end in
corrupted files and a lot of tears
...
This mechanism is in the form of
a Mutex
...
Once used in your code to protect a shared resource, a mutex will prevent threads from
proceeding unless they have locked it
...
If another thread tries to lock the same mutex in the meantime, that
second thread will be effectively paused until the mutex is unlocked by the first one, thus stopping it
from reading or writing to the shared resource
...

Global ConsoleAccess
...
l)
LockMutex(ConsoleAccess)
ConsoleLocate(ThreadNumber * 20, 0)
ConsoleColor((ThreadNumber + 1) * 3, 0)
Print("Thread " + Str(ThreadNumber) + " locked
...
l = 1 To 20
ConsoleLocate(ThreadNumber * 20, x + 1)
Print(Str(x))
Delay(75)
Next x
UnlockMutex(ConsoleAccess)
EndProcedure
If OpenConsole()
EnableGraphicalConsole(#True)
Thread0
...
l = CreateThread(@DrawNumbers(), 1)
Thread2
...


Beyond The Basics

285

The first line of code creates a new mutex object, this is done with the ‘CreateMutex()’ command
(Helpfile:Reference Manual->General Libraries->Thread->CreateMutex)
...
The
returned handle is a 32 bit numeric value, so I’ve stored it in a Long type variable called
‘ConsoleAccess’
...
To do this I need to add the lock and unlock commands to all thread
procedures that are going to use this shared resource
...
If I were to add more thread procedures that
printed to the console, I would have to code them to obey this mutex status too
...
This command takes one
parameter which is the mutex handle of the mutex object we want to lock
...
If, however, the mutex has
already been locked by another thread, the ‘LockMutex()’ command will pause the thread until it is
able to lock it itself, which would be after the other thread has unlocked it
...
Unlocking the
mutex object is as simple as calling the ‘UnlockMutex()’ command (Helpfile:Reference Manual>General Libraries->Thread->UnlockMutex) while passing a mutex handle as a parameter of the
mutex object you want to unlock
...
You may need your thread to
continue doing something else, or provide feedback on the mutex status itself
...
The ‘TryLockMutex()’ command does what it says on the tin, it tries to lock the
mutex specified in the first parameter
...
If, however, it is able to lock it, then this
command will return a non zero value (meaning a numeric value other than zero)
...
If any of them fail to do so then instead of just sitting idle and waiting
until it’s unlocked, they display the amount of time they have been waiting in the relevant String
gadget
...
l = CreateMutex()
Procedure Update(Gadget
...
l = ElapsedMilliseconds()
Repeat
If TryLockMutex(Lock)
For x
...
" + Str(x))
Delay(250)
Next x
UnlockMutex(Lock)
Break
Else
Time
...
" + Time)
Delay(1)
EndIf
ForEver
SetGadgetText(Gadget, Str(Gadget) + " has finished
...
l = WaitWindowEvent()
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_START
Thread1
...
l = CreateThread(@Update(), #TEXT_TWO)
Thread2
...
Once the mutex is locked, the thread counts to twenty, updating the
String gadget as it goes
...
An ‘If’ statement is used to test the
‘TryLockMutex()’ command to decide which course of action is required depending on the status of the
mutex
...

When compiling any program that uses threads I would recommend that you always use the threadsafe compiler option and try to use as few threads as possible
...
Before using threads you need to be completely
aware of their uses and limitations
...
DLLs enable
programmers to compile code into a shared library to enable many computer programs to use the code
contained within
...
When finished, the program can unload the library, freeing any memory associated with
its use
...
The reality however, especially
prevalent in Microsoft Windows operating systems, is that many different versions of the same DLL
are needed by different programs for compatibility reasons, meaning that sometimes many copies of
the same DLL (albeit different versions) are required
...

Operating system problems aside, DLLs can be very useful to break a program into a modular
approach
...

PureBasic makes using DLLs simple by providing a built-in library of commands (Helpfile:Reference
Manual->General Libraries->Library) to load and use DLLs, while the PureBasic compiler has an
option to compile your code to a DLL, making PureBasic the perfect choice for using and creating
DLLs
...
The first thing to remember when writing code to be used as a DLL is
that nearly all your code must be written inside procedures
...
Opening a
library doesn’t automatically run the DLL like a program, instead, you have to call procedures from it
...


288

Beyond The Basics

When writing code for DLLs there are four special reserved procedure names that are automatically
called by Windows once the DLL is loaded
...
I personally define these in all DLLs I write, even if I don’t use them
...
Here is a list of the four reserved procedure names and what conditions automatically
trigger their execution:
‘AttachProcess(Instance
...
This procedure is the only place in your
code that you can define arrays and linked lists
...
The only limitation of
this procedure is that DirectX initialization routines must not be written in here
...
l)’
This is called when the program closes this DLL
...

‘AttachThread(Instance
...

‘DetachThread(Instance
...

As you can see from this list, they are not very complicated to understand and use simple names
...
The ‘Instance’ parameter that all of these procedures create, is an instance handle
(sometimes called a module handle)
...
This
parameter always needs to be defined if you are using these procedures, even if you don’t intend on
using the parameter in your code
...

ProcedureDLL AttachProcess(Instance
...
s = "This is my DLL
...
The second procedure in this example is called ‘ShowAlert()’
...
As you can see the message requester defined in the
‘ShowAlert()’ procedure uses the String that’s defined in the ‘AttachProcess()’ procedure
...
This is essential for defining the special reserved
procedures and for any procedure you want to be available for other programs to use
...
These are mainly used for internal calculations, etc
...
So first things first, let’s compile this
example into a DLL
...
If your using the command
line you can do this by using the ‘/DLL’ compiler option or if your using the IDE you can set it visually
in the ‘Compiler Options’ dialog box (Menu:Compiler->Compiler Options
...
Fig
...
Once this has been set you can select ‘Create Executable
...
This allows you to specify a name and location for your
DLL
...


The ‘Compiler Options’ dialog box
as it appears on Microsoft Windows
...
52

290

Beyond The Basics

Once you have compiled your DLL, you will notice that the compiler creates three files
...
dll’, you will end up with these three files:
‘Demo
...
exp’

‘Demo
...
PureBasic only needs the DLL file to use the commands within, but the other files can be useful to
people who use this DLL with other languages
...

Using A DLL In Your Code
Using a DLL in a program is easy, you simply open the library and call the procedure you want to run
...
Here is an example of how we would call the ‘ShowAlert()’
procedure from the ‘Demo
...
Make sure you put the ‘Demo
...
dll")
CallFunction(#LIBRARY_DEMO, "ShowAlert")
CloseLibrary(#LIBRARY_DEMO)
EndIf

First, you open the library using the ‘OpenLibrary()’ command
...
To call a function from within the opened DLL you use the ‘CallFunction()’
command, which takes two mandatory parameters
...

Notice that when you specify the name of the procedure to call, you don’t need to include the brackets
on the end
...
This is
useful if the DLL procedure you are calling needs parameters to be passed
...

Creating and using DLLs can get a little more complicated than this, but the examples used here show
the outline of the whole process
...

When using a DLL like this you may be tempted to open the DLL, use a procedure and then
immediately close the library
...
A better way to do things is that when
your program initially starts up, open the DLL ready for use
...
Then, when your program shuts down, close the DLL library along with it
...


Beyond The Basics

291

Returning Values From DLL Procedures
When using procedures contained within DLLs, it may sometimes be necessary to return a value from
one of them
...
Here is a simple example of a DLL procedure coded to return a result
...
l MultiplyValues(x
...
l)
ProcedureReturn x * y
EndProcedure

As you can see it’s pretty straightforward and apart from the ‘ProcedureDLL’ keyword, it looks like any
other normal procedure
...
dll")
ReturnValue
...
The values I’m passing are ‘22’ and
‘33’
...
In this case, it multiplies them together and returns the result
...

I’ve used a Long type variable called ‘ReturnValue’ to hold the returned value from the DLL procedure,
which I then echo to the Debug Output window
...
For a start, any Strings that you need
to return from a DLL must be defined as global
...
Also, when a String is supposed to be returned from a DLL procedure, a memory address
for the String is actually returned instead, even if the return type was defined as a String in the
procedure definition
...
l)
Global MyString
...
"
EndProcedure
ProcedureDLL
...
Try compiling this to a DLL and call it using this code:

292

Beyond The Basics

#LIBRARY = 0
If OpenLibrary(#LIBRARY, "Demo
...
So, I’ve created a pointer called ‘*ReturnValue’ to hold the returned
memory address, from which, I read the String pointed to using the ‘PeekS()’ command
...
Bytes, Words and Longs are relatively painless to use and all DLL commands support them
but for the other types there can be a bit of a headache
...
While Floats seem to get completely
mangled when being returned from the DLL
...

To handle returning a Float from a DLL procedure your best bet is to return its memory address
instead and then read the returned value using ‘PeekF()’
...
First, here is the example DLL:
ProcedureDLL AttachProcess(Instance
...
f = 3
...
l GetPi()
ProcedureReturn @MyFloat
EndProcedure

Instead of returning the actual Float value, the DLL procedure ‘GetPi()’ is defined to return a Long
...
Once this is compiled into a DLL I can call it
using this code:
#LIBRARY = 0
If OpenLibrary(#LIBRARY, "Demo
...
In fact this trick of returning
memory addresses can be used in a similar fashion to return memory address to Quads and Doubles,
so in effect you can say PureBasic supports returning them
...

Using DLLs is quite simple once you’ve got your head around passing variables to the DLL and how
you return and use the returned values
...
There are a few issues regarding some built-in types but these can be overcome by
using more advanced methods, usually by just returning a pointer to what data you need returned
...
Just don’t be shocked if you can’t
understand them in your first go
...
This should give you a good understanding of what’s
available when you decide to develop your first real DLL
...
As standard PureBasic
assumes that any given DLL uses the ‘stdcall’ calling convention and that any DLLs created using PureBasic
via the ‘ProcedureDLL’ keyword are also considered to be using the ‘stdcall’ calling convention
...

If needed though, the ‘cdecl’ calling convention can be used by using the complementary ‘C’ functions from
the PureBasic ‘Library’ group of commands
...
The same goes for calling procedures from DLLs
...

There are more of these complementary ‘C’ functions available to be used in PureBasic, look at the helpfile in
the ‘Library’ section for a complete list
...
Well, I’m including it here because the
Windows version of PureBasic has a rather cool and useful ability to be able to use the Windows
Application Programming Interface natively
...

The Windows Application Programming Interface (Usually shortened to just the Win32 API) is found
in all new versions of the Microsoft Windows operating system and is a common interface available for
all computer programs to use
...
The API itself is part of the
operating system and available to be used by any computer program to carry out almost anything that
the operating system is capable of, e
...
opening windows, manipulating Strings, drawing shapes, etc
...
This can be done easily in PureBasic
using the ‘Library’ commands but because PureBasic for Windows supports the Win32 API natively,
you can use the API as easily as you would any other PureBasic command
...
dll")
MB_OK = 0
Caption
...
s = "This is a Win32 API Test"
CallFunction(#LIBRARY, "MessageBoxA", #Null, @TextString, @Caption, MB_OK)
CloseLibrary(#LIBRARY)
EndIf

As you can see, you would have to open the DLL where the required command resides, Here, it’s a
command called ‘MessageBoxA’ located in ‘User32
...
Once this is open, you can call the necessary
command passing any parameters needed
...
In PureBasic you can use that same command like this:
MessageBox_(#Null, "This is a Win32 API Test", "Test", #MB_OK)

Notice the underscore (‘_’) after the command name? That denotes that this is an API command and
calls it from the necessary DLL automatically
...
We are using the Win32 API command as if it were another native command in the standard
PureBasic package
...
For example,
there is a command called ‘CharUpper’ in the Win32 API for converting Strings to uppercase, we can
use this command as if it’s a native PureBasic command by using an underscore after it’s name and
before the brackets, like this:
TextString
...
"
CharUpper_(@TextString)
Debug TextString

This command needs a memory address of a String as a parameter according to the Win32 API
documentation, so that’s what I’ve passed
...


Beyond The Basics

295

Using the Win32 API like this alleviates all the hassle of opening the required DLLs yourself and allows
you to use an API command whenever you need to in your code
...

Using Win32 API Constants And Structures
To complement the ease of use of Win32 API commands in the Windows version of PureBasic, all the
associated constants and structures have also been predefined
...

You can see this in the PureBasic version of the ‘MessageBox’ command example on the other page,
where I’ve used the constant ‘#MB_OK’ without defining it
...
To use any Win32 API constant in PureBasic, you just
need to add the hash symbol (‘#’) to the beginning of the Win32 API constant name and it should then
be useable as if it was defined natively in your source code
...
)
The same goes for Win32 API structures, whenever you need to use one, you just use it
...
Take a look at this example:
DesktopInfo
...
l = GetDesktopWindow_()
GetClientRect_(DesktopHandle, @DesktopInfo)
DesktopSize
...
As you can see from the ‘RECT’ structure, all Win32 API structures have
been defined using uppercase names
...

This naming convention matches exactly the way in which structures are defined in the Win32 API
reference manuals and to avoid confusion when it comes to use them
...

Take this example text from the Win32 API documentation, detailing the ‘BeginPaint’ API command:

296

Beyond The Basics

The BeginPaint function prepares the specified window for painting and fills a
PAINTSTRUCT structure with information about the painting
...

lpPaint
Pointer to the PAINTSTRUCT structure that will receive painting information
...
If the function fails, the return
value is NULL, indicating that no display device context is available
...

To create such a variable in PureBasic we can do this:
PaintVariable
...
The ‘PAINTSTRUCT’ structure has already been defined internally, so we can just use it
without a definition
...

PaintVariable
...
l = WindowID(#MY_WINDOW)
HDC
...


Viewing Internally Defined Constants And Structures
So now you know that a lot of handy data has been defined internally but you don’t necessarily know
what exactly has been defined
...
This tool is called the ‘Structure
Viewer’ and can be found in the ‘Tools’ menu in the IDE (Menu:Tools->Structure Viewer)
...
53
shows the Structure Viewer as it appears on the Window operating system and notes many of the
features that make this such an useful tool
...
This list can be searched and filtered alphabetically by using the appropriate control
detailed in the diagram
...
Although interfaces haven’t been
discussed in this book, the constants list will be helpful to you as this shows all internally defined
constants and their values
...


Beyond The Basics

297

To view the actual definitions of internally defined structures you just double-click their names in the
data list
...
The ‘Insert Copy’
button inserts a copy of the structure definition into your PureBasic source, while the ‘Insert’ button
inserts code to actually use and define the fields within the structure
...


Data Tabs
(To View Other
Types Of Defined
Data)

Close Button

Alphabetical Filter

Defined Data List

Search Field

(Double Click On
An Entry To See
Its Definition)

(Type A Name To
Search For Data
In The Data List)

Insert Copy Button
(Inserts A Copy Of
The Definition As
PureBasic Code)

Back Button
(Used To Return
To The Main List)

Insert Button
Insert Name Button

(Inserts PureBasic
Code Necessary
To Define Fields Of
A Selected Structure)

(Inserts PureBasic
Code Needed To Use
The Selected Data)
The ‘Structure Viewer’ dialog box
as it appears on Microsoft Windows
...
53

Documentation On The Win32 API
When using the Win32 API you are going to need a good reference documentation to understand what
commands are available for use and to understand how to use them
...
msdn
...
I’ve found the best solution (for me
personally), is to consult a smaller more focused reference and then search the MSDN if more
information is needed about a particular command or syntax
...
hlp’ file, a Windows helpfile that contains a reference for the
Win32 API commands
...
Once you have the ‘Win32
...
If a ‘Help’ folder doesn’t appear inside your PureBasic folder
then just create one and place the ‘Win32
...
Sometimes the
helpfile is accompanied with other files such as ‘Win32
...
kwf’, if this is the case all must
be installed together
...

Once this file is correctly installed, you can select any Win32 API command within the IDE by placing
your cursor within it and then hitting ‘F1’
...
hlp’ file is opened on the correct page for the highlighted Win32 API command
...

Try it for yourself, type this code in from a previous example, place the flashing text cursor within the
‘GetClientRect’ command and hit ‘F1’
...
RECT
DesktopHandle
...
s = "Your current desktop size is: "
DesktopSize + Str(DesktopInfo\right) + " x "
DesktopSize + Str(DesktopInfo\bottom)
Debug DesktopSize

You should now see the ‘Win32
...
Don’t forget, the ‘Win32
...

Disadvantages Of Using The Win32 API In PureBasic
One of the biggest disadvantages of using the Win32 API in a PureBasic program is that you can only
use these commands on a Microsoft Windows operating system
...

Another big disadvantage is that the Win32 API was originally designed to be used by the C and C++
programming languages and as such contains references to many advanced data types that simply
don’t exist in PureBasic
...
Fig
...
For example, if you read in a Win32 API command description that a particular command needs
a variable of type ‘DWORD32’, looking at Fig
...


Beyond The Basics

299

PureBasic Substitute Types For Win32 API Types
Byte

Character

Word

Quad

*Pointer

BOOLEAN
BYTE
CHAR
UCHAR †

TBYTE †
TCHAR

SHORT
USHORT †
WCHAR
WORD

DWORD64
INT64
LONG64
LONGLONG
POINTER_64

DWORD_PTR
INT_PTR
LONG_PTR
UINT_PTR
ULONG_PTR

Float

Long
BOOL
COLORREF
DWORD
DWORD32
HACCEL
HANDLE
HBITMAP
HBRUSH
HCONV
HCONVLIST
HCURSOR
HDC
HDDEDATA
HDESK
HDROP
HDWP
HENHMETAFILE
HFILE
HFONT
HGDIOBJ
HGLOBAL
HHOOK
HICON
HIMAGELIST
HIMC
HINSTANCE
HKEY

HKL
HLOCAL
HMENU
HMETAFILE
HMODULE
HMONITOR
HPALETTE
HPEN
HRGN
HRSRC
HSZ
HWINSTA
HWND
INT
INT32
LANGID
LCID
LCTYPE
LONG
LONG32
LPARAM
LPBOOL
LPBYTE
LPCOLORREF
LPCRITICAL_SECTION
LPCSTR
LPCTSTR

LPCVOID
LPCWSTR
LPDWORD
LPHANDLE
LPINT
LPLONG
LPSTR
LPTSTR
LPVOID
LPWORD
LPWSTR
LRESULT
PBOOL
PBOOLEAN
PBYTE
PCHAR
PCRITICAL_SECTION
PCSTR
PCTSTR
PCWCH
PCWSTR
PDWORD
PFLOAT
PHANDLE
PHKEY
PINT
PLCID

PLONG
PLUID
POINTER_32
PSHORT
PSTR
PTBYTE
PTCHAR
PTSTR
PUCHAR
PUINT
PULONG
PUSHORT
PVOID
PWCHAR
PWORD
PWSTR
SC_HANDLE
SC_LOCK
SERVICE_STATUS_HANDLE
UINT †
UINT32 †
ULONG †
ULONG32 †
WPARAM

Types marked with ‘†’ need to be read correctly after a command call
...


FLOAT

Double
DOUBLE

Fig
...
54 are marked with a ‘†’ symbol
...
The reason for this mismatch is that all the
marked Win32 API types are unsigned (except for ‘TBYTE’) while the substitute PureBasic types are
all signed
...
The odd one out
is the API type: ‘TBYTE’, which is signed while the PureBasic Character type which substitutes it, is
unsigned
...
Here are a few
procedures that you could use to convert all these problem types:
;Returns the correct unsigned value from a UCHAR
...
w UCHAR(UCHAR
...

CompilerIf #PB_Compiler_Unicode
Procedure
...
c)
CompilerElse
Procedure
...
c)
CompilerEndIf
ProcedureReturn TBYTE
EndProcedure
;Returns the correct unsigned value from a USHORT
...
l USHORT(USHORT
...

Procedure
...
l)
ProcedureReturn UINT & $FFFFFFFF
EndProcedure
;Returns the correct unsigned value from a UINT32
...
q UINT32(UINT32
...

Procedure
...
l)
ProcedureReturn ULONG & $FFFFFFFF
EndProcedure
;Returns the correct unsigned value from a ULONG32
...
q ULONG32(ULONG32
...
b = 255 ; This represents '-1' signed and '255' unsigned
...

UnsignedValue
...


The only drawback in using these procedures is that the value they return, (although totally correct)
uses twice the amount of memory of the type you passed as a parameter
...
This accepts a Byte as a parameter of the ‘UCHAR’ you want to read,
and then returns a Word containing the correct unsigned value
...
This is done because nearly all PureBasic’s types are signed, so we have to use a big enough type
to correctly express an unsigned value, avoiding any wrapping issues
...
As shown in the last example, you
can assign an unsigned value to a signed type, but that value is always stored as a signed value
...
b = 255
Debug MyUCHAR

Would actually store ‘-1’ as its value
...

A Quick Note Regarding Win32 API String Pointer Types
When using Win32 API String pointer types, it’s useful to know how to read and write to memory
correctly for each of the different types of String they point to
...
Even though all String
pointers use a PureBasic Long type to represent the actual pointer and hold a memory location, you
have to peek and poke each one from memory using a different mode of the ‘PeekS()’ and ‘PokeS()’
commands to properly observe each String type’s character encoding
...

PeekS(StringPointer
...
l, Text
...

PeekS(StringPointer
...
l, Text
...

PeekS(StringPointer
...
l, Text
...
Sometimes when using PureBasic and writing software for
Microsoft Windows, you may need the occasional API command to provide extra functionality that is
not currently available natively in PureBasic
...
This supplementary material contains a variety
of useful information including useful Internet links, a few pages of helpful charts and a complete
computer science glossary
...


305

A
Useful
Internet Links

The following pages contain many useful web address from the Internet that you will want to take a
look at when starting out with PureBasic
...


PureBasic Beginners
http://www
...
co
...
Most of the code, images and sounds used in the examples
contained in this book can be downloaded from this website along with other useful tools and utilities,
including the elusive ‘Win32
...


Official PureBasic Website
http://www
...
com
The official website of PureBasic
...
You
can also find the latest development news on PureBasic and access support via the website’s menu
...
purebasic
...
All you need to do is register with
the forum and you can ask as many questions as you like
...
The wealth of information regarding PureBasic stored on this site should not be
underestimated
...


306

Appendix A - Useful Internet Links

PureArea
http://www
...
net
This site contains lots of PureBasic related material including, thousands of PureBasic code examples
contained in the downloadable Code Archive, downloadable third party user libraries and links to
hundreds of freeware and shareware utilities written in PureBasic
...


The PureBasic Visual Designer
http://www
...
be
This site contains news and updated builds of the new official PureBasic visual designer
...


PureProject
http://pureproject
...
org
More PureBasic code snippets including games and applications and more downloadable third party
user libraries
...


PureVision
http://purevision
...
org
A third party commercial replacement for the standard PureBasic visual designer
...


Microsoft Windows API Documentation
http://msdn
...
com/library
Microsoft’s Windows API website detailing all the Windows Application Programming Interface
...


API-Guide
http://www
...
net/agnet/apiguide
...

Details of all commands and parameters are given with examples for nearly all commands
...


The OGRE Engine
http://www
...
org/
The website of the OGRE 3D engine, this is the one that PureBasic uses to provide 3D graphics
...
s2
...
You will need to download the
‘midas11
...
This file is part of the
Housemarque ‘Standard distribution package’
...


307

B
Helpful Charts

This appendix contains many useful charts, some of which have already appeared earlier on in this
book
...


Operator Precedence
Priority*

Operators

1

(

2

~

3

<<

>>

4

|

&

5

*

/

6

+

-

7

>

8

And

)

%

!

>=

<

<=

Or

Not

XOr

* The operators at the top of this list are evaluated first
...
13

308

Appendix B - Helpful Charts

Operator Quick Reference
Operator

Description

=

Equals
...
The first is to assign the value of the expression on the RHS to the variable on the LHS
...


+

Plus
...
If the result of this operator is not used
and there is a variable on the LHS, then the value of the expression on the RHS will be added directly to the variable on the LHS
...
Subtracts the value of the expression on the RHS from the value of the expression on the LHS
...
If the result of this operator is not used and there is a variable on the LHS,
then the value of the expression on the RHS will be subtracted directly from the variable on the LHS
...


*

Multiplication
...
If the result of this operator is not used
and there is a variable on the LHS, then the value of the variable is directly multiplied by the value of the expression on the RHS
...


/

Division
...
If the result of this operator is not used and there
is a variable on the LHS, then the value of the variable is directly divided by the value of the expression on the RHS
...


&

Bitwise AND
...
The result of this operator will be the value of the expression on
the LHS AND’ed with the value of the expression on the RHS, bit for bit
...
(This operator cannot be used with strings)
...
You should be familiar with binary numbers when using this operator
...
Additionally, if the result of the operator is not used and there is a variable on the
LHS, then the result will be stored directly in that variable
...


!

Bitwise XOR
...
The result of this operator will be the value of the expression on
the LHS XOR’ed with the value of the expression on the RHS, bit for bit
...
(This operator cannot be used with strings)
...
You should be familiar with binary numbers when using this operator
...
i
...
the result will have it’s bits inverted compared to the value of the expression
...


<

Less than
...
If the value of the expression on the LHS is less than the value
of the expression on the RHS this operator will give a result of true, otherwise the result is false
...
This is used to compare the values of the expressions on the LHS and RHS
...


<=

Less than or equal to
...
If the value of the expression on the LHS is less than
or equal to the value of the expression on the RHS this operator will give a result of true, otherwise the result is false
...
This is used to compare the values of the expressions on the LHS and RHS
...


<>

Not equal to
...
If the value of the expression on the LHS is equal to the value
of the expression on the RHS this operator will give a result of false, otherwise the result is true
...
This is used to compare the values of the expressions on the LHS and RHS
...


Or

Logical OR
...
If the value of the expression on the LHS or the RHS is true
then the result is true, otherwise the result is false
...
This is used to perform logical negation of a boolean value
...
Conversely if the expression on the RHS of this operator returns false then Not will return true
...
This is used to compare the values of the expressions on the LHS and RHS
...
If both expressions are either true or both false then the XOr operator returns false
...
Shifts each bit in the value of the expression on the LHS left by the number of places given by the value of the expression on the
RHS
...
It probably helps if you understand binary numbers when you use this operator, although you can use it as if each position you shift by is
multiplying by an extra factor of 2
...
Shifts each bit in the value of the expression on the LHS right by the number of places given by the value of the expression on
the RHS
...
It probably helps if you understand binary numbers when you use this operator, although you can use it as if each position you
shift by is dividing by an extra factor of 2
...
Returns the remainder of the LHS divided by RHS using integer division
...
You can use sets of brackets to force part of an expression to be evaluated first, or in a certain order
...
In nested brackets the inner-most set are evaluated first and then each evaluated outwards
...
15

Appendix B - Helpful Charts

309

PureBasic’s Numeric Types
Type

Suffix

Memory Usage (RAM)

Numerical Limit

Byte


...
c

1 byte (8 bits)

0 to 255

Char (Unicode)


...
w

2 bytes (16 bits)

-32768 to 32767

Long


...
q

8 bytes (64 bits)

-9223372036854775808 to 9223372036854775807

Float


...
d

8 bytes (64 bits)

Unlimited*

Fig
...


PureBasic’s String Types
Type

Suffix

Memory Usage (RAM)

Character Limit

String


...
s{length}

4 bytes (32 bits)

User Defined*

Fixed Length String

${length}

4 bytes (32 bits)

User Defined*

* The ‘length’ parameter defines the string’s maximum length
...
3

310

Appendix B - Helpful Charts

PureBasic Substitute Types For Win32 API Types
Byte

Character

Word

Quad

*Pointer

BOOLEAN
BYTE
CHAR
UCHAR †

TBYTE †
TCHAR

SHORT
USHORT †
WCHAR
WORD

DWORD64
INT64
LONG64
LONGLONG
POINTER_64

DWORD_PTR
INT_PTR
LONG_PTR
UINT_PTR
ULONG_PTR

Float

Long
BOOL
COLORREF
DWORD
DWORD32
HACCEL
HANDLE
HBITMAP
HBRUSH
HCONV
HCONVLIST
HCURSOR
HDC
HDDEDATA
HDESK
HDROP
HDWP
HENHMETAFILE
HFILE
HFONT
HGDIOBJ
HGLOBAL
HHOOK
HICON
HIMAGELIST
HIMC
HINSTANCE
HKEY

HKL
HLOCAL
HMENU
HMETAFILE
HMODULE
HMONITOR
HPALETTE
HPEN
HRGN
HRSRC
HSZ
HWINSTA
HWND
INT
INT32
LANGID
LCID
LCTYPE
LONG
LONG32
LPARAM
LPBOOL
LPBYTE
LPCOLORREF
LPCRITICAL_SECTION
LPCSTR
LPCTSTR

LPCVOID
LPCWSTR
LPDWORD
LPHANDLE
LPINT
LPLONG
LPSTR
LPTSTR
LPVOID
LPWORD
LPWSTR
LRESULT
PBOOL
PBOOLEAN
PBYTE
PCHAR
PCRITICAL_SECTION
PCSTR
PCTSTR
PCWCH
PCWSTR
PDWORD
PFLOAT
PHANDLE
PHKEY
PINT
PLCID

PLONG
PLUID
POINTER_32
PSHORT
PSTR
PTBYTE
PTCHAR
PTSTR
PUCHAR
PUINT
PULONG
PUSHORT
PVOID
PWCHAR
PWORD
PWSTR
SC_HANDLE
SC_LOCK
SERVICE_STATUS_HANDLE
UINT †
UINT32 †
ULONG †
ULONG32 †
WPARAM

Types marked with ‘†’ need to be read correctly after a command call
...


FLOAT

Double
DOUBLE

Fig
...


Button Image Gadget

Creates a clickable button with a user defined
image
...


String Gadget

Creates an editable text field which can accept
typed text
...


Option Gadget

Creates radio buttons that can be toggled on
and off, alongside user defined text
...


IP Address Gadget

Creates a four field gadget for displaying
IP numbers
...


Progress Bar Gadget

Creates a user controllable progress bar to
show progress of a user defined action
...


Hyperlink Gadget

Creates a clickable, editable text label, similar
to a webpage hyperlink
...
Clicking the button on the right opens the
list fully for making another selection
...
Clicking the button on
the right allows another date to be chosen
...
55

312

Appendix B - Helpful Charts

Built-in PureBasic Gadgets continued
...
Each panel has a user defined label
and each one can hold a separate interface
...
This frame is purely for aesthetic
reasons only and provides a nice graphical
way of grouping associated interface items
...


Tree Gadget

Creates a gadget that displays user defined
strings in a tree-like structure
...


List Icon Gadget

Creates a gadget that contains rows and
columns which can be populated by user
defined strings and icons
...
55 continued
...

Gadget Name

Sample Image

Description

Image Gadget

Creates a gadget, within which you can display
an image
...


Container Gadget

Creates a container gadget that can hold many
other gadgets within
...
e
...


Scroll Area Gadget

Creates a scrollable area complete with scroll
bars
...


Explorer List Gadget

Creates a gadget that displays hard drive and
directory information in rows and columns
very similar to a List Icon Gadget
...


(Sample images from Microsoft Windows)

Fig
...


314

Appendix B - Helpful Charts

Built-in PureBasic Gadgets continued
...


Splitter Gadget

Creates a splitter between two other gadgets
which when moved will resize both
dynamically
...
Each
child window can contain it’s own interface
...
Any date can be displayed or
retrieved from this gadget
...
55 continued
...

/
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

00
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
10
11
12
13
14
15
16
17
18
19
1A
1B
1C
1D
1E
1F
20
21
22
23
24
25
26
27
28
29
2A
2B
2C
2D
2E
2F
30
31
32
33
34
35
36
37
38
39
3A
3B
3C
3D
3E
3F

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111
00001000
00001001
00001010
00001011
00001100
00001101
00001110
00001111
00010000
00010001
00010010
00010011
00010100
00010101
00010110
00010111
00011000
00011001
00011010
00011011
00011100
00011101
00011110
00011111
00100000
00100001
00100010
00100011
00100100
00100101
00100110
00100111
00101000
00101001
00101010
00101011
00101100
00101101
00101110
00101111
00110000
00110001
00110010
00110011
00110100
00110101
00110110
00110111
00111000
00111001
00111010
00111011
00111100
00111101
00111110
00111111

@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
?

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

40
41
42
43
44
45
46
47
48
49
4A
4B
4C
4D
4E
4F
50
51
52
53
54
55
56
57
58
59
5A
5B
5C
5D
5E
5F
60
61
62
63
64
65
66
67
68
69
6A
6B
6C
6D
6E
6F
70
71
72
73
74
75
76
77
78
79
7A
7B
7C
7D
7E
7F

01000000
01000001
01000010
01000011
01000100
01000101
01000110
01000111
01001000
01001001
01001010
01001011
01001100
01001101
01001110
01001111
01010000
01010001
01010010
01010011
01010100
01010101
01010110
01010111
01011000
01011001
01011010
01011011
01011100
01011101
01011110
01011111
01100000
01100001
01100010
01100011
01100100
01100101
01100110
01100111
01101000
01101001
01101010
01101011
01101100
01101101
01101110
01101111
01110000
01110001
01110010
01110011
01110100
01110101
01110110
01110111
01111000
01111001
01111010
01111011
01111100
01111101
01111110
01111111

Fig
...

Character

Ascii

Hex

Binary

Character

Ascii

Hex

Binary


?

ƒ




ˆ

Š

Œ
?
Ž
?
?







˜

š

œ
?
ž
Ÿ
NB Space
¡
¢
£
¤
¥
¦
§
¨
©
ª
«
¬
®
¯
°
±
²
³
´
µ

·
¸
¹
º
»
¼
½
¾
¿

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

80
81
82
83
84
85
86
87
88
89
8A
8B
8C
8D
8E
8F
90
91
92
93
94
95
96
97
98
99
9A
9B
9C
9D
9E
9F
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
AA
AB
AC
AD
AE
AF
B0
B1
B2
B3
B4
B5
B6
B7
B8
B9
BA
BB
BC
BD
BE
BF

10000000
10000001
10000010
10000011
10000100
10000101
10000110
10000111
10001000
10001001
10001010
10001011
10001100
10001101
10001110
10001111
10010000
10010001
10010010
10010011
10010100
10010101
10010110
10010111
10011000
10011001
10011010
10011011
10011100
10011101
10011110
10011111
10100000
10100001
10100010
10100011
10100100
10100101
10100110
10100111
10101000
10101001
10101010
10101011
10101100
10101101
10101110
10101111
10110000
10110001
10110010
10110011
10110100
10110101
10110110
10110111
10111000
10111001
10111010
10111011
10111100
10111101
10111110
10111111

À
Á
Â
Ã
Ä
Å
Æ
Ç
È
É
Ê
Ë
Ì
Í
Î
Ï
Ð
Ñ
Ò
Ó
Ô
Õ
Ö
×
Ø
Ù
Ú
Û
Ü
Ý
Þ
ß
à
á
â
ã
ä
å
æ
ç
è
é
ê
ë
ì
í
î
ï
ð
ñ
ò
ó
ô
õ
ö
÷
ø
ù
ú
û
ü
ý
þ
ÿ

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

C0
C1
C2
C3
C4
C5
C6
C7
C8
C9
CA
CB
CC
CD
CE
CF
D0
D1
D2
D3
D4
D5
D6
D7
D8
D9
DA
DB
DC
DD
DE
DF
E0
E1
E2
E3
E4
E5
E6
E7
E8
E9
EA
EB
EC
ED
EE
EF
F0
F1
F2
F3
F4
F5
F6
F7
F8
F9
FA
FB
FC
FD
FE
FF

11000000
11000001
11000010
11000011
11000100
11000101
11000110
11000111
11001000
11001001
11001010
11001011
11001100
11001101
11001110
11001111
11010000
11010001
11010010
11010011
11010100
11010101
11010110
11010111
11011000
11011001
11011010
11011011
11011100
11011101
11011110
11011111
11100000
11100001
11100010
11100011
11100100
11100101
11100110
11100111
11101000
11101001
11101010
11101011
11101100
11101101
11101110
11101111
11110000
11110001
11110010
11110011
11110100
11110101
11110110
11110111
11111000
11111001
11111010
11111011
11111100
11111101
11111110
11111111

Fig
...

In this appendix I’ve attempted to be as comprehensive and concise as possible in describing the
meaning of these words and terms to make your life a little easier when you come across something
your not familiar with
...
A 3D engine can be explained as a layer of abstraction to allow artists or developers quickly
put together 3D graphics using simplified methods rather than programming all the low level stuff
themselves
...
3D engines are sometimes provided with other helpful
features such as collision detection and physics modeling
...
An absolute value is a value that stands on it's own and is not relative
to another
...
For example, all Internet
addresses are absolute paths, as shown in the address bar of an Internet browser
...

ActiveX
A Microsoft specification for reusable software components
...
ActiveX controls can add further functionality to an
application by incorporating further pre-made modules within its interface
...
On the Internet, ActiveX controls can be
included in webpages and downloaded by an ActiveX-compliant browser
...

ActiveX controls can have full system access! In most instances this access is entirely legitimate, but
history has shown that this access has been exploited by malicious ActiveX applications
...

Alpha Channel
In an image, a portion of each pixel's data that is reserved for transparency information
...
The alpha channel is a mask
...

Anti-virus Software
Software that scans a computer's memory and disk drives for viruses
...

API (Application Programming Interface)
A set of functions that an application uses to request and carry out lower level services performed by
a computer's operating system or third party program command library
...
The Microsoft Win32 API is
probably the most famous of all the different API's
...

Array
A simple data structure for holding equally sized data elements, generally of the same data type
...
Some arrays are
multi-dimensional, meaning they are indexed by a fixed number of integers
...

ASCII (American Standard Code For Information Interchange)
A character encoding scheme that assigns numerical values to characters such as letters, numbers,
punctuation, and other symbols
...

The first 32 characters are unprintable control characters (line feed, form feed, etc
...
Extended ASCII adds an additional 128 characters that vary between
computers, programs and fonts
...

ASCII Art
Drawings created using the characters from a standard ASCII character set
...

ASM (Assembly Language)
A human readable notation for machine code that a specific computer architecture uses
...


Appendix C - Glossary

319

Assembler
A computer program for translating assembly language into object code
...
Attributes include: Read Only, Archive, Hidden or
System
...
Often programmers build back doors so they can fix bugs
...

Background Task
A program executed by the system that generally remains invisible to the user
...
Often malicious
software is executed by a system as a background task so the user does not realize unwanted actions
are occurring, e
...
viruses, spyware, etc
...

Batch files
Text files containing one MS-DOS command on each line of the file
...
One example of this is the Microsoft Windows file 'AUTOEXEC
...
These files have the extension '*
...

Binary
Refers to the base-two number system
...

BIOS (Basic Input/Output System)
A basic operating system that identifies a set of programs needed to initialize and start the computer
before locating the operating system boot disk
...

BIT (Binary Digit)
The smallest unit of information a computer can use
...

Bit Depth
The number of bits used to describe the color of a single pixel in any given digital image or computer
display is called it’s bit depth
...

Boot
To start (cold boot) or reset (warm boot) the computer so it is ready to run programs for the user
...


320

Appendix C - Glossary

Bug
An unintentional fault in a program that causes actions neither the user nor the program author
intended
...
Also the name of an integer that can be expressed using these eight
bits
...

CGI (Common Gateway Interface)
A standard for the exchange of information between a Web server and computer programs that are
external to it
...
CGI is not a programming language in
itself
...
The slightest change in a file changes its
checksum
...

Class
An OOP template that can be instantiated to create objects with common definitions, properties,
methods, operations, and behavior
...
A web browser is a client of a web server
...

Coding
A slang term for computer programming
...

Compiler
A software development tool that translates high level language program source codes into machine
code instructions (object code) that a particular computer architecture can understand and execute
...
Constants can be
used anywhere in your code in place of actual values
...

Cookies
Blocks of text placed in a file on your computer's hard disk
...
Cookies might contain login names and passwords or user preferences
...

CPU (Central Processing Unit)
The main processor responsible for the overall processing of a computer
...
Each instance
of an object retains a unique value for each data member in the class, as opposed to the class having
one variable that every instantiation shares
...

Data Type
The characteristics of a variable that describes whether it is numeric, alphabetic, or alphanumeric
...

DirectX
A set of low level application programming interfaces (API's) provided by Microsoft for creating high
performance multimedia applications
...
The DirectX API also allows
easy access to computers hardware such as sound cards, joysticks and even network adapters
...
Because
several different programs can reuse the same DLL instead of having that code in their own file, this
dramatically reduces required storage space for the executable
...

Double (Double Precision Floating Point Number)
A floating point number that uses double the memory of a normal floating point number to more
accurately calculate and store the information of the numbers beyond the decimal point
...

Encapsulation
An OOP scheme used for defining objects
...
Thus, users of an object only need to use these

322

Appendix C - Glossary

interfaces
...

Encryption
The scrambling of data so it becomes difficult to unscramble and interpret
...
Executable files can also be
executed from other programs, batch files or various script files
...

Expression
A combination of values, Strings, operators, commands or procedures, interpreted according to the
rules of precedence, which computes and returns a value
...

Firewall
These typically prevent computers on a network from communicating directly with external computer
systems
...

Floating Point Number (or a Real Number)
A number which has a decimal portion, even if that decimal portion is zero
...
Floating point numbers
typically use four Bytes in memory
...

Hexadecimal
A numbering system which uses a base of 16
...
This enables very large numbers to be expressed using very few characters
...
Webpages use hexadecimal numbers to express a 24 bit color value
...

Commands in this language must be translated by a compiler or interpreter before they can be
executed by a particular computer architecture
...
PureBasic is a high level language
...
HTML is used for creating
World Wide Webpages
...
HTTP defines how messages are formatted and
transmitted, and what actions Web servers and browsers should take in response to various
commands
...

Hyperlink
A link in a document that links to information within the same document or a different document
...
When a reader selects a hyperlink,
the computer display switches to the linked document or portion of the document referenced by the
hyperlink
...

Integer
A number without a decimal point
...

Internet
An electronic network of computers that today includes nearly every university, government, and
research facility in the world
...

Interpreter
A program that executes programs written in high level programming languages line by line directly
from the source code
...

IP (Internet Protocol) Address
A number that identifies each sender or receiver of information that is sent across a TCP/IP network
...
0
...
1
IRC (Internet Relay Chat)
A form of instant communication over the Internet
...

JavaScript
A scripting language that can run wherever there is a suitable script interpreter such as in web
browsers
...

Link Time
The time during executable compilation when object code is linked with the final executable file
...
Allowing elements to be
inserted and deleted dynamically during runtime
...
However, unlike an array, each element also holds pointers to the previous and
next element in the list, not allowing the list to occupy a sequential area in RAM and thus perform
slower than an array while retrieving data
...

A linker can also have other functions, such as creation of libraries
...

Linux
A free open source operating system based on Unix
...

Localhost
The computer system the user is working on, often assigned the IP address: 127
...
0
...

Low Level Programming Language
A programming language that provides little or no abstraction from a computer's microprocessor
...

Assembly is an example of a low level language
...
Mac OS
X, unlike it's predecessors, is based upon a Unix core with an updated user interface
...


Appendix C - Glossary

325

Malware
A generic term used to describe malicious software such as: viruses, trojan horses, spyware, adware,
etc
...
This program reads the partition table, determines
what partition to boot and transfers control to the program stored in the first sector of that partition
...

MBS (Master Boot Sector)
The first sector of a hard disk
...
The sector contains
the master boot record
...
This is another name for a Method
...

MS-DOS (Microsoft Disk Operating System)
The operating system Microsoft developed for the IBM platform before Windows
...
x, 95
and 98 rely heavily on MS-DOS and can execute most MS-DOS commands
...
An
Internet newsgroup allows people from around the globe to discuss common interests
...

NTFS (New Technology File System)
A file system used to organize and keep track of files which is the standard file system of Windows NT
and its descendants: Windows 2000, Windows XP and Windows Server 2003
...
This object inherits all the functionality and data programmed into the
originating class
...
There are a variety of standardized and proprietary object file formats, meaning that
development tools from one vendor can rarely read the object code produced by those of another
...

OCX controls have now been superseded by ActiveX controls
...
ocx'

326

Appendix C - Glossary

extension and even though superceded are still compatible with ActiveX, meaning some ActiveX
compatible programs can still use these modules
...

OOP (Object Oriented Programming)
A style of programming that supports encapsulation, inheritance, and polymorphism
...

Open Source Software
Refers to any program whose source code is made available for use or modification as users or other
developers see fit
...

OpenGL (Open Graphics Library)
A specification defining a language independent API for writing applications that render 2d and 3d
graphics
...

Operating System
The operating system is the underlying software that enables you to interact with the computer
...

Examples of common operating systems include: Mac OS X, Linux and Windows XP
...

Polymorphism
An OOP term that means allowing a single definition to be used with different types of data
...

POP (Post Office Protocol)
An email protocol to allow email clients to retrieve e-mail from a remote server over a TCP/IP
connection
...

Port
(1) An interface through which data is sent and received
...

Procedure
A named sequence of statements executed as a unit by calling it's name
...
Unlike subroutines, procedures can
return a calculated value
...

Process
A running instance of a program
...

Property
In OOP a Property is a variable defined and encapsulated within a class or object
...

Protocol
A formal description of message formats and the rules that two computers must follow in order to
exchange those messages
...

Radix Point
In mathematics, the radix point refers to the symbol used in numerical representations to separate the
integral part of the number (to the left of the radix) from its fractional part (to the right of the radix)
...
In base 10, the radix point is called the decimal point
...
The refresh rate is
expressed in hertz (Hz) so a refresh rate of 75 means the image is refreshed 75 times a second
...

Registry
An internal database that Microsoft Windows uses to store hardware and software configuration
information, user preferences and setup information
...
A relative value is one that relates to or builds upon another
...
Relative paths are usually used when specifying the location
of resources for a program in the source code, which are relative to the executable file
...


328

Appendix C - Glossary

Reset
To restart a computer without turning it off
...

RGB colors are usually composed of Red, Green And Blue values ranging from '0' to '255'
...
For example, when all color values are at maximum
(255) the color produced is white
...

SDL (Simple DirectMedia Layer)
An open source, application programming interface (API) for creating high performance multimedia
applications
...
OpenGL is often used
with SDL to provide fast 3D rendering
...

Server
Any application or computer that serves another, for example, the computers that hold webpages are
called servers since they serve web resources to client applications such as web browsers
...

Shareware
Software distributed for evaluation without cost, but that requires payment to the author for full rights
of usage
...
Using
unregistered shareware beyond the evaluation period is considered software piracy
...

Software Pirate
An individual who breaks the law regarding copyright of software
...

Source Code
The code that a program consists of before being compiled, i
...
the original building instructions of a
program that defines to a compiler what actions a program should perform once compiled to a binary
executable file
...
One or more statements are needed to create a program
...
Once a program is compiled it no longer needs the library, as all code is now inside the
executable file
...

Subroutine
A labeled sequence of statements executed as a unit by jumping to the start of the sequence, usually
using a 'Goto' or 'GoSub' command
...
Unlike procedures, subroutines cannot return
a calculated value
...

Syntax
The rules by which words in a program's source code are combined to form commands that are valid
to an interpreter or compiler
...
It is called the TCP/IP protocol suite, after the
two most important protocols in it: the Transmission Control Protocol (TCP) and the Internet Protocol
(IP), which were also the first two defined
...
A process can have several threads running concurrently, each performing a different task,
such as waiting for events or performing a time-consuming job that the program doesn't need to
complete before moving on to do something else
...
Multi-threaded programs can finish tasks quicker than non-threaded
programs if programmed right, because some processors support running two or more threads
simultaneously, such as the Intel Hyperthreading family of CPUs
...
Trojans are not viruses since
they do not replicate, but Trojan horse programs can be just as destructive
...
A UNC path uses double forward-slashes or double back-slashes to precede the
name of the computer
...
Microsoft Windows generally uses back-slashes and
Unix (Linux) uses forward-slashes
...
Unicode character sets can contain over 65,000 characters
...
Unix is well known for its hardware
independence and portable application interfaces
...
It, and it's derivatives (Linux) are the most common
operating systems for servers on the Internet
...
This is the unique
identifier, or address, of a webpage on the Internet
...
Usenet predates the Internet, although today most Usenet material is distributed over the
Internet
...
VBS programs can be embedded in HTML
files and provide active content via the Internet
...
vbs'
...
Some viruses attach to files so when the infected file
executes, the virus also executes
...
Some viruses display symptoms, and some viruses
damage files and computer systems, but neither symptoms nor damage is essential in the definition of
a virus, a non-damaging virus is still a virus
...
A virtual machine is a self-contained
operating environment that behaves as if it was a separate computer
...

VSync (Vertical Synchronization)
Vertical Synchronization is an option found in many games that allows the frame rate of the game to
be matched to the refresh rate of the monitor
...
The downside of the greater speed
is the potential for visual artifacts like graphics tearing to develop
...

WAN (Wide Area Network)
A group of computer networks connected together over long distances
...

Word
An integer that uses two Bytes in memory
...
It is named the web because it is made of many sites linked
together
...

Worm
Parasitic computer programs that replicate, but unlike viruses, do not infect other computer program
files
...

Wrapper
A programming interface between a program and a separate wrapped piece of code
...
The implication is that the wrapped code can only be accessed via a wrapper
...

XML (Extensible Markup Language)
A standard for creating markup languages which describe the structure of data
...
XML enables authors to define their own
tags
...
ZIP files are popular on the Internet
because users can deliver multiple files in a single container which also save disk space and download
time
...
24
%
...
21
( )
...
20
+
...
20
/
...
28
<<
...
29
<>
...
18
>
...
29
>>
...
22
~
...
167-202
2D Output Methods
...
208-209
3D Coordinates
...
203-226

Array Rules
...
52, 67
Arrays As Parameters
...
98
ASCII
...
4

A
Advanced Compiler Options
...
229-231
And
...
113
Cameras
...
237-241

B
BASH
...
262-269
Bit Depth
...
26
Bit Shift Right (>>)
...
21
Bitwise NOT (~)
...
22
Bitwise XOR (!)
...
3
Boolean Logic
...
33
Break
...
93
By Reference
...
293
Changing Drawing Modes
...
98
CLI
...
106
Code Format
...
253
Command Line Parameters
...
252
Comments
...
98
Compiler Constants
...
245-250
Compiler Functions
...
249-250
CompilerIf
...
248-249
Console Program Differences
...
131-136
Constants
...
48
CreateFile()
...
10, 262-269
Data Types Number Wrapping
...
11, 262-265
Debugger
...
123
Debugger Toggle
...
75
Define
...
13, 120
Defined()
...
99, 135
Dim (Arrays)
...
121
Division (/)
...
287-293
DLL Calling Conventions
...
184-192
Double Precision Floats
...
167
Drawing On A Window
...
171
Drawing Text
...
176-178
Dynamic Link Libraries
...
99
Else
...
40
Embedding Wave Files
...
121
EnableExplicit
...
116
Entities
...
16
Eof()
...
18
Error Handling
...
117-118
Events
...
266-268
F
False
...
108
File Buffer
...
106
File Requester
...
104
FileSeek()
...
100
First Person Camera
...
14
Floating Point Numbers
...
43
ForEach
...
59
G
Gadgets
...
37
Global
...
117
Good Programming Style
...
131
H
Hello World
...
6
IDE Error Log
...
9
IDE Quick Help
...
38
Images With Alpha Channels
...
156-161
Including Other Source Files
...
114
Integers
...
72
L
Labels
...
100
Less Than (<)
...
29
Level Of Detail
...
212, 225
Linked List Memory Usage
...
62, 69
Linked Lists As Parameters
...
108-109
Local
...
109
Logical AND (And)
...
31, 37
Logical OR (Or)
...
32
Loops
...
138
Memory Address
...
148-156
MessageRequester()
...
102
Minus (-)
...
231-233
Modulo (%)
...
28
More Than Or Equal To (>=)
...
27, 264

Index
MP3 Files
...
54, 57
Multiple Commands On Same Line
...
20
Mutex
...
137-164
NewList
...
31, 37
Not Equal To (<>)
...
10
O
OffsetOf()
...
205-206
OGRE Engine
...
204
OGRE Texture Format
...
53
One Pass
...
125-126
OnErrorGoto()
...
105
Operator Precedence
...
18, 36
Optional Parameters In Procedures
...
32, 37
OS Identifiers
...
221, 224-226
Passed By Reference
...
95-96
PB Numbers (Dynamic)
...
95-96
Peek
...
19
Pointers
...
273-276
Poke
...
92
Procedure Positioning
...
74
Program Scope
...
79

Index
PureBasic Helpfile
...
3
PureBasic's Development Philosophy
...
266, 268-269
Random()
...
105
Reading From Files
...
132-135
Redefining Arrays
...
60
Rendering A 3D Scene
...
46
Returning Value From A Procedure
...
7
S
Saving Images
...
181-188
Select Default
...
41
Select Statement
...
80
Sign
...
263-265
Significand
...
50
Sorting Arrays
...
69-70
Sound
...
181, 192-202
Static
...
61
Static Arrays
...
293
Str(), StrF(), StrQ(), StrD()
...
12
Structure Inheritance
...
50
Structure Unions
...
56, 58, 68
Structured Linked Lists
...
49
Subroutine Positioning
...
71

335
Subsystems
...
252
Terrains
...
143
Threads
...
38
Two Dimensional Arrays
...
264-265
U
Unary operator
...
263-265
User Defined Errors
...
122
V
Val(), ValF(), ValQ(), ValD()
...
12
Variables As Parameters
...
15
Vertical Synchronization
...
162-164
W
Wave Files
...
45
Win32 API
...
301
Working With Colors
...
104-106
X
XOr
...
8, 125

336

About The Author
Gary Willoughby is a professional graphic artist,
Internet web developer and software developer
...

After using C++ for a while and noticing the
massive marathon of programming needed for even a simple piece of software, a search began for a
simpler, more intuitive and elegant programming language to realize well designed software within a
shorter time frame
...
The programming language they developed and marketed was PureBasic
...


U
Pu pda
r e te
ba d
sic for
v4

Purebasic
A Beginner’s Guide To Computer Programming

Purebasic - A Beginner’s Guide To Computer Programming is an essential
guide for newcomers to Purebasic or computer programming in general
...

Purebasic makes a great first language for anyone wishing to learn to program
computers and this book is designed to guide them through their first steps
...



...


Book highlights include:
A history of the Purebasic programming language
A complete reference for all core language features
A primer on how to use the Purebasic helpfile, IDE and visual designer
Guidelines on writing good code
Tutorials on creating graphical user interfaces
Examples of 2D & 3D graphics
A whole section devoted to simplifying advanced topics
Extensive Appendices containing Internet Links and helpful charts
A full computer science glossary to educate new programmers


...


...


Download Contained
Code Examples from

www
...
co
...
99

- $39
...
99

9 781427 604286

02199


Title: A Beginners Guide(purebasic programming )
Description: A beginners guide to learn basic programming