QB CULT MAGAZINE - Issue 3 - May 2000             
                          Editor: Matthew R.Knight
                       Email: horizonsqb@hotmail.com
             Design and HTML coding: Merlin of Master Creating
                       Email: mail@master-creating.de
                     Website: http://master-creating.de            
              QBCM archive, latest news, and discussion forum: 
             QBCM is also available on the following host sites:
Much thanks to the owners of the above sites for hosting QBCM. If you are 
hosting QBCM on your site, and it is not listed above then please contact me
at horizonsqb@hotmail.com so that it can be added.
We need QBCM to be available on as many Qbasic related websites as possible.
That way ALL Qbasic coders can benefit from it. If you have a website 
dedicated to Qbasic then please become a host of QBCM too! 
All you have to do to become a host is email me telling me the URL of your
site, and then I'll send you the new issues every month, and your site will
be listed on the QBCM host list!
Copyright (C), 2000, All rights reserved worldwide. QB Cult Magazine is the 
exclusive property and copyright of Horizons Interactive Entertainment. The
HTML coding and magazine design is the exclusive property and copyright of
Master Creating. 
Welcome to the third issue of Qbasic's #1 magazine!
You'll recall that last issue was really huge and very different from the 
issue before it, well, this month see's some big changes once again in 
QB Cult Magazine! Merlin of Master Creating is now doing the design and 
HTML coding for QBCM and as you can see, he is doing a much better job of
this than I did with last issue! Thanks again Merlin :)
QBCM now has an official archive and discussion forum! Much thanks goes to
Chris Charabaruk for this. It is greatly appreciated. Be sure to check this
out at http://picksoft.zext.net in the QBCM section.
Many of you probably heard the rumours early last month that QBCM is closing
down. This is NOT going to happen. QBCM will continue for a very, very long
time I can assure you. Certain unforseen circumstances last month almost
brought about an end to QBCM. These have fortunately been resolved. Once
again, I will NOT be stopping QBCM, and can't forsee doing so.
As far as errors in the last issue are concerned, it appears that there was
only one. In my review of Mysterious Song, I awarded the game 90%. At the
time of writing the review I had played very little of the game. However,
I have since completed it, and I must say that the game is far better than
I originally thought. I was highly impressed with Mysterious Song at the
time of reviewing it, however, having now played the entire game, it has
become apparent that the game deserves far more credit than I gave it. It
would be a crime for it to get anything less than 100%. It is not often that
a game leaves such an impression on me...however, Mysterious Song is more
than just a game. It has a wonderfull and touching story, behind which are
some very original and intelligent philosophies. In addition to that, the
game boasts stunning visuals, beautifull background music, and gripping
gameplay. Everything in MS has been seemlessly integrated and moulded
with such perfection - it's almost magical! So, let me now take this
oppertunity to correct this mistake and give Mysterious Song the rating it
truly deserves - 100%. My sincere apologies go to Darkness Ethereal for not
giving MS the review it deserved in the first place.
The rate at which QBCM has grown never ceases to amaze me. What started out
as only a small text-based magazine two months ago, has grown into the
biggest and quite possibly the best Qbasic magazine our community has ever
seen. Every time I check my email I have loads of emails from fans of QBCM,
which is very nice to see. Unfortunately however, few people are actually
contributing towards QBCM. I simply do not have the time to write as many
articles for QBCM as I'd like, so if you want QBCM to be really big and
interesting, then it's really up to you. I can't write more than 3 articles
per issue. I'd like to have at least 6 articles every issue, but that is far
more than I can write in a month. So PLEASE CONTRIBUTE SOME ARTICLES PEOPLE!
Please send all articles to me at horizonsqb@hotmail.com
The phenomenal growth of QBCM, not only in size but also in quality, is
by no means due to my efforts alone. I would like to take this oppertunity
to thank the many people who have contributed in some way or other to
QB Cult Magazine. Your efforts and support are greatly appreciated.
Even more amazing than the growth of QBCM is the growth in the number of 
quality Qbasic programs. What seemed impossible in the language only a year
ago is a reality today. Needless to say, this is due to the sudden surge in
the amount of libs over the past year, or so. Keep coding everyone...from 
now on QuickBASIC is the only language we need! POWER TO QB!!! ^_^
Hope ya like this issue! Enjoy! ^_^
-Matthew River Knight
 Horizons Interactive Entertainment 
                              YOUR LETTERS
QBCM takes a lot of time and work to complete every month, and I am thus
always delighted to hear from its readership. Please write to QBCM at
horizonsqb@hotmail.com with your comments and suggestions, or basically
anything you have on your mind to do with Qbasic ^_^
All of last months letters were lost due to unforseen circumstances. My
sincere apologies go to all QBCM readers for this. 
                          ASK QB CULT MAGAZINE
Don't you just hate it when you are really stuck on something in Qbasic and
no matter how hard you try you just can't figure it out? Doesn't it drive
you completely nuts? Yep, I thought so, so that's why I included this
section in the mag for ya! If you get stuck on anything in Qbasic, just send
an email to me at horizonsqb@hotmail.com and you'll get a reply within three
days. In addition to that, your problem will be printed here in QBCM, along
with my reply, so it can help other coders too! ^_^
All of last months questions were lost due to unforseen circumstances. My
sincere apologies go to all QBCM readers for this. 
* April was a very bad month for Nekrophidius. Amongst other things, a great
  deal of his work was lost due to a virus. Consequently, Nek soon announced
  his retirement from, not only the QB world, but programming in general.
  Fortunately, Nek later changed his mind. Almost all work on most of his
  projects has been lost due to the virus. The only project untouched by the
  virus was Killers. Nek has decided to start both QuickPower and Wrath of
  Sona from scratch! We wish Nek the very best of luck in getting these
  projects up and running again. Nek is probably one of the most intelligent
  coders in the Qmunity today, and also one of the most helpfull, having
  helped countless coders with their coding problems. It's sad that such a
  cool guy became the victim of the stupidity that exists in the world
  today - people who write viruses think they're being clever...heh,
  BULLS**T! They are just showing how damn stupid they are, being incapable
  of thinking of something constructive to do.
* Tsugumo recently posted the following article on the Darkness Ethereal
  discussion board: 
  Bear with me, this is long winded. It also might not describe the board
  it's posted on, but check it out and see what you think.  
  After visiting boards around the net, FrozenEmu and myself have found that
  basically WWWBoards suck right now. They generally have only a few people
  that visit, and even less posts that even relate to game development. The
  boards that are still active (except for a few) are active only because of
  people posting new flames and such. This is usually because the
  maintainer of the board doesn't give a crap and lets idiots run free.
  From going around, we've found that there are a lot of people who want to
  get back to game discussion, the way things used to be a few years ago...
  So what we want to do is start up a central WWWBoard, not attatched to
  anyone's game/site, where everyone can meet.
  The benefits of a board like this, is imagine if everyone went to one
  place to release and find information. For the people who want to know
  what's going on, they need only stop at one board, rather than search
  through the spam at 30 different boards around the net. For the people who
  want to show off new demos, screenshots, or whatever, they only have to
  post on one board for a ton of people to see it and give feedback.
  The board will be moderated by FrozenEmu and myself, and we will delete
  threads that get way out of hand, spammers, etc. and ban people that need
  banning. Like many others, we want a WWWBoard where we can go to discuss
  game related stuff without the worry of being flamed or being faced with
  tons of idiots.
  Anyway, we're calling it the Game Developer's Refuge:
  (http://www.swoo.net/gdr/index.pl) and we're posting this to whatever
  WWWBoards we know of...Please spread the URL around so we can get a
  "community" together like the old days. You can read more about our
  philosophy and rules at http://www.swoo.net/gdr/rules.htm because believe
  it or not, this is the "short" version, heheh... 
  We're also working on a good design, graphical and game-ish looking and
  such, but it's not ready yet and we want to see if we can draw many
  people to this idea first.
  So for a greater communication level throughout the programming world,
  please take part."
* There's quite a bit of news from Darkness Ethereal. Firstly, serious work
  has started on Dark Crown. DarkDread has announced that he hopes to have
  a tech demo up within the next month or so. 
  On the Distant Promises side of things...well, there hasn't been much said
  about that in ages! DarkDread has however announced that he still intends
  to complete the project. Nekrophidius is still composing some awesome
  tunes for it. DD is also considering re-coding the game, so it might take
  a bit longer than originally anticipated for the game to come out. One more
  demo is planned to come out, before the final release. ^_^
  Oh no! My favoutite upcoming Darkness Ethereal game, Eternal Frost, has
  hit the QB dustbin. =( This has been done, as DarkDread said, because he
  simply doesn't have enough time to make this game of the quality he'd
  like it to be.
  But wait...DarkDread has announced that Mysterious Song 2 will be made!
  It's a long time off, but this is very good news indeed! :) The story
  will continue where the first one left off...hmm...this is good...I still
  would like to know what happened to...ehm, I don't want to give away the
  story to those who haven't finished episode 1...so never mind ;)
  Visit the Darkness Ethereal website at http://welcome.to/DarknessEthereal
* Jaws V soft, best known for their MiniRPG series, have just released
  MiniRPG1 Boardgame! This game totally rocks!!! It is available for
  download at http://members.aol.com/changev/index.htm
* The new game engine behind Magnet Entertainment's RPG, Dark Aura, is
  pretty much complete. I saw a demo of it, and it's certainly much better
  than the old engine. Check out the Magnet Entertainment website at
* The second demo of Badjas (of Future Software)'s 3d engine has been
  released. A lot of new stuff has been added to the demo, and it's also
  running at a MUCH better pace. Visit Future Software's awesome webiste
  at http://www.qb45.com  
* Zed (aka Kristoffer Ström) is busy on a console style RPG called Dark
  Fall. The game boasts many new and original features, an intelligent
  and well-conceived story, and high quality visuals and sound. Good luck
  on this game Zed! We'll keep you posted on the latest developments
  regarding this project as it arrives. 
* Will Moores is busy on a 13h graphics library called ZipLib. It's still
  in the early stages of production, however, I saw an early demo of it
  and it ran at a good pace. Good luck on this project Will! More news on
  this will follow, as it arrives.
* AlienQB is busy on a pretty rockin' new SVGA game called Infernal Forces!
  Find out everything you could possibly want to know about this cool new
  project at http://alienqb.cjb.net
* Dark Ages II, demo 9 has been released! Go check it out RIGHT NOW!!! You
  can download it from http://www.tcnj.edu/~hoopman2
* CarterSoft has released a cool new 32 bit BASIC variant called Novascript.
  Check out this month's review to see if it's da bomb or a bomb! You can
  get Novascript from http://www.cole_carter.tripod.com/novascript1.zip
* Gabriel Fernandez has released a very fast, 90% QB compatible compiler
  that works in pmode!!! It's called GABASIC and you get get it from
  http://gab_soft.tripod.com. The compiler still needs a bit of work, but
  it looks to be the one to watch.
* Phat Kids has returned to the QB scene. They dissapeared several months
  ago, but it was recently announced at the Darkness Ethereal discussion
  board that they're back and will be completing Kids of Karendow as
  planned! Yay!!! ^_^
That's all the news we got for you this issue. Please send any news or
rumours to us at horizonsqb@hotmail.com 
             OBJECT ORIENTED BASIC - Possibility or Pipe Dream?
Writer: Unknown
1.0 Introduction
1.1 Key Terminology and Concepts
2.0 BASIC-Specific Considerations of Object Paradigm Implementation
2.1 Standardization of Terms in Object Oriented BASIC
2.2 An Introduction to Advanced Topics in OOP
3.0 Closing Notes
1.0     Introduction
BASIC has evolved from the time-sharing "Beast of Dartmouth" into a
powerful, structured language fit for the programming needs of the
nineties.  Despite this evolution, however, major software compiler
developers have failed to introduce object oriented extensions into
the language.
This article will explore some possible extensions to modern
BASIC that would truly expand the language.  Since, because of its
nature, this article will use a speculative approach, the reader
should bear in mind that no particular implementation is being
suggested as the "best" way to bring object-orientation to
BASIC.  Moreover, some BASIC programmers may feel that certain low
level features such as in-line assembler and more diverse data
types should be introduced into the BASIC language before object-
orientation is even considered.  These readers should remember the
theoretical nature of this discussion, and leave all such
preferences out of the exploration at hand.
1.1     Key Terminology and Concepts
First, I must define some key terms and concepts.  My use of the generic
term BASIC (Beginner's All-purpose Symbolic Instruction Code) will,
unless otherwise stated, refer to the Microsoft QuickBASIC v4.5 dialect
of BASIC, since this represents a widely accepted implemenation of
modern, structured BASIC.  The term OOP (Object Oriented Programming)
will be used to refer to those programming practices that rely on the
object paradigm.  Although the terminology differs from compiler to
compiler, the object oriented paradigm is considered by modern usage to
intrinsically encompass the following concepts, to be defined later:
    1.  Encapsulation
    2.  Inheritence
    3.  Polymorphism
    4.  Overloading
Therefore, when I say that a given concept is "object oriented" I
specifically mean that it involves the above four concepts.
Other important terms that cannot be ignored in any discussion of OOP,
due to their repeated use in the discussion of such are:
    5.  Class
    6.  Method (or Member Function)
    7.  Object (or Class Instance)
    8.  Information or Data Hiding
Not able to decide which term to define first, I will begin with a
general overview fo the underlying philosophy of OOP.
In classical structured programming, data and code are considered
separate entities.  Code manipulates data.  Data fuels code.  For
example, wanting to implement a graphics font engine, a classical
BASIC programmer might read a list of DATA statements into a globally
accessible array, and then have a series of globally accessible
SUBPROGRAMS manipulate those raster data on the screen in such a
way as to produce the desired visual effect.  The problem with this
approach is that both the data and the related code are equally
accessible, and they are only loosely cohesive.  Wanting to enhance
code written by a colleague, a second programmer will encounter
data structures that he should neither modify nor even poll, but
that may not always be possible.  Having modified an essential
data structure, the second programmer may introduce errors
into the whole underlying logic of the system.
For instance, suppose the original programmer had defined the
font data structure thus:
    TYPE FontDataType
        FontName AS STRING * 12
        FontPointSize AS INTEGER
        RasterDataPtr AS LONG
Now, looking at this, Programmer Two decides that he can avoid a
FUNCTION call to funGetFontPointSize() by just reading the value of
Font.FontPointSize directly.  Programmer Two alters his code to
access this variable directly, and in doing so, avoids what he
considers costly calls to funGetFontPointSize().  He is
promoted to another department (presumably for having sped up the
code of his predecessor).  Enter Programmer Three.  Quite within
his bounds, he discovers that point size is never greater than 255,
and so redefines the whole structure to account for this, thereby
reducing overall memory consumption by one byte:
    TYPE FontDataType
        FontName AS STRING * 12
        FontPointSize AS STRING * 1
        RasterDataPtr AS LONG
Of course, being conscientious, he modifies funGetFontPointSize()
to account for this innovation.  He compiles the program.  It crashes.
Why?  Because, this is now an illegal statement:
    Font.FontPointSize = 12
What to do?  He must use his search and replace to go through the
entire program and change all such instances to:
    Font.FontPointSize = CHR$(12)
Or, he can forget his alterations altogether.
In BASIC, there is no INFORMATION HIDING that would prevent such
problems from occuring.  Since FontPointSize is a public member
of FontDataType, Programmer Two was well within his rights to do
as he saw fit as far as accessing it.  Had the original programmer
had an object oriented BASIC, however, he could have prevented the
entire problem with little difficulty by making FontPointSize a
PRIVATE data member of the CLASS font.  This might have looked
similar to this:
    CLASS FontClass
        FontName AS PUBLIC STRING * 12
        FontPointSize AS PRIVATE INTEGER
        RasterDataPtr AS PRIVATE LONG
        funGetFontPointSize AS PUBLIC FUNCTION
        subSetFontPointSize AS PUBLIC SUB
    DIM Font AS FontClass
[Please bear with the strange new syntax, since it will be covered
in more detail in section 2.0.]
Now, the only way to access Font.FontPointSize is indirectly.  This
would NOT work, since this data member is now PRIVATE:
    Font.FontPointSize = 12
This, then, would be the ONLY way to achieve such a thing:
    Font.subSetFontPointSize 12
In the above example, the item Font is what is called a CLASS INSTANCE.
That is to say, Font is "an instance of the class FontClass." This is
what is commonly called an OBJECT, and it is from this that we arrive at
the phrase "object oriented" programming.
Now, when Programmer Two comes along, he CANNOT pull off his stunt,
and he is not promoted to another department.  Programmer Three comes
along, and sees room for improvement and redefines the class thus:
    CLASS FontClass
        FontName AS PUBLIC STRING * 12
        FontPointSize AS PRIVATE STRING * 1
        RasterDataPtr AS PRIVATE LONG
        funGetFontPointSize AS PUBLIC FUNCTION
        subSetFontPointSize AS PUBLIC SUB
Since all calls to change FontPointSize are through the centralized
subSetFontPointSize, Programmer Three just modifies that a bit, and
earns himself a nice raise in salary for shaving a byte off the
memory requirements of the structure.
Consider the above example.  The data are:
    1. FontName
    2. FontPointSize
The code portions (called MEMBER FUNCTIONS or METHODS, since they
are "methods of acting upon or accessing" the data) are:
    1. funGetFontPointSize
    2. subSetFontPointSize
Since it is unlikely that subSetFontPointSize will ever be needed for
anything other than the setting of FontPointSize, it makes sense to
bind the code to the data it works with.  This binding is called
Having examined these more essential terms, there is the issue of
OVERLOADING.  Although not object oriented in the strictest sense,
it does aid in generalizing classes to an extent that they can
operate upon different types of data.
Consider the following:
    subQuickSort A%()
Now, in classical BASIC programming, if we wanted to sort anything
other than INTEGER arrays, we would have to write another SUBPROGRAM
and modify the algorithm to account for this new data type.  This
SUBPROGRAM would have to be named something other than subQuickSort.
For example:
    subQuickSortSTR A$()
might be used for STRING arrays, and
    subQuickSortLONG A&()
might be used for LONG INTEGER arrays.  And, of course, should a
programmer ever want to sort a user-defined TYPE array:
    subQuickSortUserTYPE UserArray()
would be the only way to do it.
But, consider the above.  All of these routines do the same thing.  It
seems a waste to have three names to do what amounts to the same thing:
sorting arrays.  The answer is to "overload" a SUBPROGRAM name with
three corresponding pieces of code.  Once subQuickSort is overloaded, it
can do tripple-time thus:
    subQuickSort A%()
    subQuickSort A$()
    subQuickSort UserArray()
Of course, each call invokes DIFFERENT CODE to do the actual sorting,
but this detail is handled by the compiler in a transparent fashion.
The programmer's only responsibility would be to provide the code for
each instance of subQuickSort, in the following manner:
    SUB subQuickSort (Array AS INTEGER)
        code to sort INTEGER arrays goes here
    SUB subQuickSort (Array AS LONG)
        code to sort LONG INTEGER arrays goes here
    SUB subQuickSort (Array AS UserDefinedType)
        code to sort arrays of UserDefinedType goes here
Upon seeing the second instance of subQuickSort in the source listing,
the object oriented BASIC compiler would know that it is dealing with
an overloaded SUBPROGRAM.
Overloading is already done by BASIC compilers, but it is done at a
level not within the control of the programmer.  Consider:
    PRINT a
    PRINT a$
Each case of PRINT prints a different data type.  The PRINT statement,
we could say, then, is overloaded.  Also to consider is the overloading
of operators such as occurs already in BASIC:
    A$ = B$ + C$
    A% = B% + C%
The addition operator is serving two masters here.  In the first case,
it is being used to concactenate strings.  In the second, it is being
used to add two numbers.  The processes are internally dissimilar.
How, then, does the BASIC compiler contend with these cases?  The
addition operator is overloaded at an internal level.  If a programmer
using an object oriented BASIC were to step into the scene, however,
we very well might see this type of overloading of the addition and
assignment operators:
    OVERLOAD "+" FOR ArrayOne(), ArrayTwo()
        TotalElements = UBOUND(ArrayOne) + UBOUND(ArrayTwo)
        DIM ReturnArray(TotalElements)
        FOR i = 1 to UBOUND(ArrayOne)
            ReturnArray(i) = ArrayOne(i)
        NEXT i
        FOR q = i + 1 TO i + UBOUND(ArrayTwo)
            ReturnArray(q) = ArrayTwo(q-i)
        NEXT q
        REDIM ArrayOne(TotalElements)
        ' The following uses an overloaded assingment operator
        ' whose overload definition follows.
        ArrayOne() = ReturnArray()
    OVERLOAD "=" FOR ArrayOne(), ArrayTwo()
        FOR i = 1 TO UBOUND(ArrayOne)
            ArrayOne(i) = ArrayTwo(i)
        NEXT i
This bit of sophisticated operator overloading would allow the
programmers to add entire arrays to one another as follows:
    NewList() = ListOne() + ListTwo()
For some readers, all this may be a new concept in programming.  If
it seems hard to understand, please take time to reread this section
before continuing, since the next part of this discussion relies on
the reader's comprehension of all eight terms pertinent to the object
oriented programming paradigm, which are, again:
    1.  Encapsulation,
    2.  Inheritence,
    3.  Polymorphism,
    4.  Overloading,
    5.  Class,
    6.  Method (or Member Function),
    7.  Object (or Class Instance),
    8.  Information or Data Hiding.
[Polymorphism has been purposely avoided for the purposes of this
discussion, due to its rather esoteric nature.]
2.0     BASIC-Specific Considerations of Object Paradigm Implementation
When considering whether BASIC in its present form could
be expanded to include object oriented extensions, we must first look
at what is already possible in standard BASIC.  For example, the
following code resembles inheritence, at least in part:
    TYPE ColorType
        R AS INTEGER
        G AS INTEGER
        B AS INTEGER
    TYPE CoordinateType
        X AS INTEGER
        Y AS INTEGER
    TYPE CircleType
        Point AS CoordinateType
        Color AS ColorType
        Radius AS INTEGER
This is not classical inheritence, but the analogy suffices.  Looking
at the syntactical elements of the above code, we see that a similar
structure could easily be adopted for use with CLASS definitions:
    CLASS CircleClass
        Point AS CoordinateType
        Color AS ColorType
        Radius AS INTEGER
A question arises, however.  The above definition of the CircleClass
CLASS is not executable code, but merely a definition template.  It
defines CircleClass, but does not assign a "class instance."  That is
to say, there are not yet any objects of CircleClass defined in the
program.  Consider this standard BASIC:
    TYPE AddressType
        Street AS STRING * 10
        City AS STRING * 32
        State AS STRING * 2
        ZIP AS STRING * 12
    DIM Envelope AS AddressType
The DIM statement is used to create an instance of a variable
called Envelope that is of the user defined type AddressType.  It
makes perfect sense, then, that the DIM statement could be used
in this manner:
    CLASS CircleClass
        Point AS CoordinateType
        Color AS ColorType
        Radius AS INTEGER
    DIM Orb AS CircleClass
(Remember, having DIM serve this double purpose is known as
overloading the DIM statement.)  This syntax serves our purposes
wonderfully, since it does not involve the introduction of completely
foreign operators and follows the present syntactical structure of
standard BASIC.
Another consideration in the creation of classes is the fact that
classes may contain both variables and methods in their definitions,
as shown in the introduction:
    CLASS FontClass
        FontName AS PUBLIC STRING * 12
        FontPointSize AS PRIVATE INTEGER
        RasterDataPtr AS PRIVATE LONG
        funGetFontPointSize AS PUBLIC FUNCTION
        subSetFontPointSize AS PUBLIC SUB
This shows a suggested means of expressing both the scope and the
type of each part of the definition.  Note, however, that, although
subSetFontPointSize is defined in this template, there is, as yet,
no code attached to the definition.  It is said, in OOP parlance, that
the "the scope of the member function is unresolved."  The method is
prototyped, but that is all.  In C++, what is known as the "scope
resolution operator" is used to resolve a method, that is, assign
executable code to it.  This is done as follows:
    void FontClass::subSetFontPointSize (int PointSize)
    code to achieve this end goes here
Essentially, this translates into the English statement:
    "Define funGetFontPoint size of the class FontClass as follows...."
In an attempt to avoid convoluted syntactical introductions into the
BASIC language, what follows is a possible solution:
    SUB FontClass.subSetFontPointSize (PointSize AS INTEGER)
        code that assigns the point size goes here
Since the compiler would presumably recognize FontClass as being a
class from the earlier CLASS ... END CLASS block, this should suffice
as a means of resolving the scope of the method subSetFontPointSize,
while avoiding the introduction of :: as a new BASIC operator.
Next comes the issue of overloading both keywords and operators.  A
simple extension of BASIC would allow this to be sufficient in the
    SUB subQuickSort (Array AS STRING)
    SUB subQuickSort (Array AS INTEGER)
The second SUB definition would imply overloading. This would be
prototyped at the beginning of the source listing thus:
    DECLARE SUB subQuickSort (Array AS STRING)
    DECLARE SUB subQuickSort (Array AS INTEGER)
Operators, however, are completely different in that BASIC has
no way of referring to them explicitly.  A proposed extension:
    OVERLOAD "=" FOR LeftArgument, RightArgument
        definition code goes here
        result returned in LeftArgument
Of course, the "=" could be any ASCII character or even multiple
ASCII characters.  This would allow the object oriented BASIC program
to do this, for example:
    OVERLOAD "**" FOR LeftArgument, RightArgument
        ' Some langauges use ** for raising to a power
        LeftArgument = LeftArgument ^ RightArgument
The following, however, would not be possible, since it would involve
late binding and interpreted evaluation at run-time:
    OVERLOAD Operator$ FOR LeftArgument, RightArgument
        SELECT CASE Operator$
            CASE "**"
                LeftArgument = LeftArgument ^ RightArgument
        END SELECT
2.1     Standardization of Terms in Object Oriented BASIC
Before the discussion continues, perhaps it would be wise to step
aside to establish a set of standard terms.  Since certain
OOP concepts carry many different names (ie. "member function" is
also "method") a standard way of refering to any particular device
should be adopted.  But, really, this could become quite involved;
what is more appropriate, the term "method" or "member function?"
Perhaps, rather than debate too long and hard on the subject,
Microsoft's terminology as used for Visual Basic should be adopted:
    1.  OBJECT rather than "class instance"
    2.  METHOD rather than "member function"
    3.  PROPERTY rather than "member variable"
For terms not used by Visual Basic, I suggest the following use by
object oriented BASIC:
    1.  DATA HIDING rather than "information hiding"
    2.  METHOD DECLARATION rather than "scope resolution"
    3.  METHOD DECLARATOR rather than "scope resolution operator"
    4.  OBJECT BINDING rather than "encapsulation"
    5.  OVERLOADING remains unchanged
    6.  CLASS remains unchanged
I use these substitutes for the other terms because they have a
BASIC sound to them, whereas the other terms, like "scope resolution
operator" may sound odd to BASIC programmers.  DECLARATOR rings of
BASIC's DECLARE statement, thereby reducing the foreigness of the
term METHOD DECLARATOR.  (In case you have forgotten, the :: is
the scope resolution operator in C++, whereas the . is used in this
theoretical object oriented BASIC of ours.)
Using this terminology, we have this model:
      / CLASS VectorClass  ' This is a CLASS DECLARATION
      |     X AS PRIVATE INTEGER   ' This is a PROPERTY of VectorClass
 O B  |     Y AS PRIVATE INTEGER   ' As is this
 B I  |     '    ^^^^^^
 J N  |     ' Use of PRIVATE demonstrates DATA HIDING
 E D  |     ' Whereas use of PUBLIC demonstrates the oposite--\
 C I  |     '                                                 |
 T N  |     '                 /-------------------------------/
   G  |     '               VVVVVV
      |     subSetVector AS PUBLIC SUB ' This is a METHOD
      \ END CLASS
        '  This operator is the METHOD DECLARATOR in this context
        '              |
        '              V
    D / SUB VectorClass.subSetVector ( X AS INTEGER, Y AS INTEGER )
    E |
 M  C |
 E  L |
 T  A |
 H  R |
 O  A |
 D  T |
    I |
    O |
    N \ END SUB
2.2     An Introduction to Advanced Topics in OOP
To this point, most fundemental concepts of the object oriented
paradigm have been examined.  The reader should have a concept of
class, object binding, method declaration, overloading, and
data hiding, and should also understand the essence of how these
object oriented extensions may be added to BASIC.
There are other considerations, however.  When an object is created,
for instance, how is it initialized?  That is to say, how are its
properties set to appropriate starting values?  A typical standard
BASIC program might accomplish this thus:
    CALL subFontInit()
This is fine, but remember that there can be more than one OBJECT of
the same CLASS as in this case:
    DIM Helvetica AS FontClass
    DIM Courier AS FontClass
    DIM TimesRoman AS FontClass
Now, to initialize the data for each of these, we must do something
like this:
    CALL subFontHelveticaInit
    CALL subFontCourierInit
In C++, there is away around this that we can adopt for BASIC use.
In every class in C++ there is an implied "constructor."  This is
a new term.  Essentially, the constructor is a method within the
class definition that is executed whenever an object is created.
For an example of this, consider this method declaration:
    SUB FontClass.FontClass
        code to initialize object goes here
(Visual Basic programmers will recognize this as being analogous to
the Load_Form event.)  Note that the method declaration uses FontClass
twice.  This informs the compiler that it is dealing with the explicit
definition of a CONSTRUCTOR.
In the actual binding declaration of the class, this syntax is
    CLASS FontType
        FontType AS CONSTRUCTOR
The CONSTRUCTOR type then, signifies that this template will be
followed by a method declaration for a constructor.  Now, when the
programmer includes this code:
    DIM Helvetica AS FontType
The compiler will include appropriate initialization routines.
Another aspect of this, the "destructor," is exactly the same, except
that it operates after the object falls from scope.  (Visual Basic
programmers again will note the analagous use of the Form_Unload event.)
Destructors deinitialize data, cleaning up things when the program ends
execution, for instance.  In C++, a special operator is used to indicate
the deconstructor: ~FontClass.  This use of the tilde is foreign to
BASIC, however, so perhaps it would be better to introduce another
keyword rather than a new operator:
    CLASS FontType
        FontType AS CONSTRUCTOR
        FontType AS DESTRUCTOR
Now, the method would simply be declared:
    SUB FontType.FontType DESTRUCTOR
        code to deinitialize data structures goes here
This is syntacally familiar to a BASIC programmer in another form:
    SUB subPrintToScreen (InText AS STRING) STATIC
The STATIC keyword modifies the nature of the SUBPROGRAM.  Consquently,
I have suggested the DESTRUCTOR keyword be used in a similar syntactical
3.0     Closing Notes
Indeed, BASIC has evolved from the time-sharing days of Dartmouth.
Despite this evolution, however, major software compiler developers
have failed to introduce object oriented extensions into the language.
Perhaps this article has introduced some new concepts to the reader,
perhaps not.  At the very least, it has explored some ways
an object oriented paradigm might be introduced successfully into
BASIC programming with as little pain possible.  Programmers tend to
maintain their old programming habbits despite the innovations that
come into their languages, and consequently, any major changes to
the way BASIC operates may prove to be obstacles rather than useful
tools.  I feel that my suggestions involve minimal relearning of the
syntax of BASIC, since they adopt the flavor of existing structures.
In the end, though, the question is not what is the better method
or terminology to use, really, but rather:
    "Object Oriented BASIC, possibility or pipedream?" 
                            BUILDING A LIBRARY
Writer: Chris Charabaruk
Instead of having some dumb ole introduction, I am going to cut to the chase
here regarding making your own library. I'm sure you've thought of making
something to compete with Future.Library or DirectQB, but for this article,
I won't be dealing with making a library like those. Instead, I will describe
to you how to create a library with your own routines or with other people's
OBJ files.
A library is really nothing except a bunch of OBJ files each with one or more
routines (read SUBs or FUNCTIONs) inside, none of which are called main
(main is only found in executable files). Let's not discuss libraries for a
minute though, I want to talk about these routines. In languages like C or
C++, everything is in a routine, even the actual program. You see, when the
operating system runs an executable file, it actually calls the main()
routine inside the program. main() is like a FUNCTION, because it takes in
an array of characters (a string) and returns an integer value. In C/C++ you
write the main() routine like this:
int main()
// code goes here
return 0
Each QuickBasic program that's compiled has this main() routine as well,
except that by just using QB, you can't return an "errorcode" (the value that
main() returns). There is a way, however, but I won't be telling you about
it here. A SUB in QuickBasic is similar to a FUNCTION when written in C/C++,
it looks like this:
void mysub()
// code goes here
The "void" means that the routine does not return a value, unlike the main()
routine above which returns an integer with value 0. Since mysub() is void,
you can forget about putting in "return", or you can add "return null" which
says to the compiler, return nothing. Now that we have covered routines,
now we can go on to OBJ files.
An OBJ (object) file is nothing more than one or more routines ready to be
put in a library or linked to make an executable file. When you use
QuickBasic's compiler at the command line, all that it does is generate a
bunch of OBJ files. Then, you have to use the LINK program to turn them into
an executable, or LIB to make them into a library. If you use the options in
QB or QBX's run menu, it does the entire process of compiling and
linking/libbing for you, but you have less control over it all. I generally
use the command prompt or a makefile to do the job for me.
So you have the routines, you've used the compiler to make the OBJ files (or
you've found some OBJ files that you know have some useful stuff in them),
now how to make it into a library you can use in QuickBasic? Well, actually,
to make a library for QB, you have to use LINK as well as LIB. You need LINK
to make the QLB file for running the program that needs the routines inside
the IDE and the LIB file for compiling. So let's look at how to make this
LIB, according to it's online documentation that came with MASM 6.11, is to
create and to maintain libraries of compiled or assembled object modules.
LINK, on the other hand, is to create an executable program out of these OBJ
files. So how does that help us make a QLB file? Well, the version of LINK
that comes with QB4.5 and all of Microsoft's PDS packages have a /Q switch
which tells LINK to make a QLB file instead of an EXE. So say that your
routines are in the object files mysubs.obj and myfuncs.obj, to make a
QuickLibrary named mylib.qlb, use this line at the command prompt:
LINK /Q mysubs.obj myfuncs.obj, mylib.qlb,,qbqlb.lib;
Or if you use QBX/PDS use this instead:
LINK /Q mysubs.obj myfuncs.obj, mylib.qlb,,qbxqlb.lib;
That makes the QLB file. To make the normal LIB file, you use LIB like this:
LIB mylib.lib + mysubs.obj + myfuncs.obj
So now you have your library. But later on, you have some more routines
(new.obj) you want to add. So rename your mylib.lib and mylib.qlb files to
myoldlib.lib and myoldlib.qlb, and do this to rebuild the QLB:
LINK /Q new.obj myoldlib.lib, mylib.qlb,,qbqlb.lib;
Or for QBX:
LINK /Q new.obj myoldlib.lib, mylib.qlb,,qbxqlb.lib;
To rebuild the LIB file:
LIB mylib.lib + new.obj + myoldlib.lib
So there you go. There's one more topic that I want to mention though,
granularity. When you use a library, all the routines that share an OBJ with
the ones you were using are included in the program. It's better to have each
routine in it's own file because this way, only what is used from the library
is incorporated into your program. On the other hand, if a routine in your
library needs to call another included routine, then it's best to have them
share a BAS file, and therefore a OBJ file.
Well, that's the basics of making your own library. If I was too confusing,
then just email me at evilbeaver.picksoft@zext.net and I will help you
further if I can. 
                    INTRODUCTION TO QBASIC SERIES #3
Writer: Matthew River Knight
Welcome to the third part in the Introduction to Qbasic Series! We went
over quite a lot of information last time, having covered some more of the
capabilites of Qbasic with regard to the handling of text, demonstrated how
to allow the user input from the keyboard, did some LOOPing, and we even took
a brief look at how to display graphics in Qbasic. This time I'd like to 
cover some more of these simple things before we go onto more difficult areas
of programming, hopefully picking up some information that we left out along
the way.
First of all, let's take a look at what else we can do with Qbasic as far as
text handling is concerned. For starters, it would be nice if we could place
text at a specific location on the screen wouldn't it? Lucky for us, Microsoft
wrote made a nice little routine to do this for us. This is the LOCATE 
statement. The LOCATE statement tells the computer at which location on the
screen the next PRINTed text must be placed. You'll recall that last issue,
in order to explain how PSET works, I described the screen as a grid. When
using LOCATE you also have to think of the screen as a grid, but it works
a little differently. The 'grid' that we're talking about when using LOCATE
is not made up of pixel spaces, it is made up of much larger blocks that are
basically the same size as your average ASCII character. And what is an 
ASCII character you ask? Well, all the letters and numbers you see on the
screen in DOS are ASCII characters. Apart from the number and letter
characters, there are also some other ASCII's which look quite strange. You
have seen some of them before. Some of them are used by the Qbasic editor
to draw the menu's and the scrollbar, etc. ASCII stands for American Standard
Code for Information Interchange. 
Another way of thinking about how LOCATE works is like this: suppose you
wanted to put some text, for example "Qbasic rulz!", 5 ASCII spaces across
the screen, and 10 ASCII spaces down. Then all you'd have to do is this:
LOCATE 10, 5
PRINT "Qbasic rulz!"
Try experimenting with different numbers and see what results you get. Using
LOCATE will make your life much easier when using text! There are some other
similar text handling routines, but there is no need to use them since LOCATE
is generally capable of doing exactly the same as them, but is easier to use
and more versatile.
Okay, now onto something more fun ^_^ Last time when we looked at using
graphics in Qbasic we really didn't do very much. All we used was PSET and
LINE - not too interesting. So we'll cover some better stuff this time round.
It is sometimes necessary that you know the color code of a certain pixel on
the screen. You can actually do some pretty cool graphics effects just by
knowing this simple information. In Qbasic, we use the POINT statement to
obtain the color code of a certain pixel on the screen. The POINT statement
is very versatile in the way that it may be used, and this makes it very
easy to understand.
For example, if you wish to get the color of a pixel at the coordinates (2,5)
on the screen 'grid' into the Col variable then all you do is this:
PSET (2, 5), 2  'Place a green pixel at coodinates (2,5)
Col = POINT(2, 5)  'Get the color code of the pixel at (2,5)
You can also use POINT like this:
IF POINT(2, 5) = 2 THEN PRINT "That pixel is green"
Try playing around with this, and maybe you'll figure out how to do something
cool using a combination of POINT and one of the other Qbasic drawing routines.
I once wrote a little program using PSET and POINT that allowed you to print
text on the screen, and it melted what looked like lava around it. There is
no reason why you couldn't write a program to do exactly that!
Okay, now on to something a bit more cool. You have probably found that using
LINE to draw graphics is rather difficult and time consuming. There is
another Qbasic command for drawing that is much easier to use. It's called
DRAW! It works quite unlike any other Qbasic routines we have covered so
far, as you'll soon see.
The DRAW statement has its own commands for doing things. For example, it
has the U command for drawing lines up, and the D command for drawing lines
down. Let's demonstrate this by means of an example:
PSET (10, 10), 2  'Start drawing at (10,10) in green
DRAW "U100"  'Draw a line up, 100 pixels in length
PSET (100, 100), 14  'Start drawing at (100,100) in yellow
DRAW "D20"  'Draw a line down, 20 pixels in length
There are lots of commands used with DRAW, but you'll probably never use half
of them. We'll cover the most commonly used ones. If you want to know the
others then you'll have to take a look at the Qbasic help file.
You have probably already guessed that in order to draw right, you use the
DRAW command R, and to draw left you use L. This should have been obvious.
But what if you want to draw diagonally? Well, to draw diagonally up and
right you use the DRAW command En, where n is a number specifying the pixel
length of the line to be drawn. To draw diagonally down and right you use the
commnd, F. To draw diagonally down and left you use G, and lastly, to
draw diagonally up and left you use H. Simple no? Okay, here's an example:
PSET (160, 100), 2  'Start drawing at (160,100) in green
DRAW "H20 E20 F20 G20"
Note that I have put a space between each of the DRAW commands in order to
make it easier for you to read. You don't have to do it this way though. You
could just as easily have left them out, and it would do exactly the same
thing. Like this:
PSET (160, 100), 2  'Start drawing at (160,100) in green
DRAW "H20E20F20G20"
It really doesn't make a difference. 
Another usefull DRAW command is C which sets the DRAWing color. All you do
is say Cn where n is the color code of the color in which you'd like to 
DRAW, and voila - you're DRAWing in that color. Could it really be any 
easier?! Let's demonstrate this by means of an example:
PSET (160, 100), 2  'Start drawing at (160,100) in green
DRAW "C2 H20 C3 E20 C4 F20 C5 G20"
Once again you can see that I've put spaces between each of the DRAW commands
in order to make this easier to read and understand. If I were writing a 
program in which readability was not a necessity, I'd have left the spaces
out since they're a waste of space.
There are many other DRAW commands that can be used, but I'm not going to 
cover it all here, when there is a perfectly good description of all of them
sitting right there in the Qbasic help files. One thing that I should 
mention before we go onto something else is that you are able to use DRAW 
with strings instead of specifying it right after the command. This allows
you to save a lot of space. To clarify this further, here's an example:
Diamond$ = "C2 H20 C3 E20 C4 F20 C5 G20"
PSET (160, 100), 2  'Start drawing at (160,100) in green
DRAW Diamond$
In the above example you can clearly see that we have used DRAW with a string
variable, instead of placing all the commands right after the DRAW statement.
You will find this ability very usefull when you find the need to DRAW an
object more than once. Without this ability you'd have to specify all those
commands to draw the object again, and again, and again, which is really a
waste of space.
Right. Now we've covered PSET, POINT, LINE and DRAW. With that you can, with
some ingenuity, draw some fairly good graphics. But what if you want to draw
a circle? Can you imagine writing the DRAW code for all of that! Yeah, it 
would be a total nightmare! Fortunately there is a Qbasic statement called
CIRCLE which allows you to draw circles. It's actually a bit more versatile
than that in the light that it can not only draw circles, but also ellipses,
and fractions of circles/elipses. It's a really great little routine. So
let's learn how to use it!
We'll start off using CIRCLE just to do simple stuff, and then we'll work
our way up, step-by-step, finally getting onto some more difficult stuff.
Okay. In order to draw a yellow (color code 14) circle with a radius of 15 at
the coordinates (160,100) on the screen 'grid' we'd type the following code:
CIRCLE (160, 100), 15, 14
Now that wasn't so hard, was it? Right, now that we've mastered the drawing
of circles, I think it's time that we move onto ellipses. You may not have 
heard of an ellipse before, so this is what it is: an ellipse is, in the
most simple terms I can think of, basically like a squashed circle! You can
probably imagine what I mean. It can be squashed from the top, or from the
side. It doesn't really matter. Any squashed circle is an ellipse!
Let's, for example, say you wanted to have a circle that looked squashed 
from the top. First thing you have to think about is how squahed you want it
to be. If we wanted to squash the circle, from the top, by 50% then we'd do
CIRCLE (160, 100), 15, 14, , , 50 / 100
If we wanted it squashed by 70%, from the top, then we'd do this:
CIRCLE (160, 100), 15, 14, , , 30 / 100
Simple no? Unfortunately, although we are able to describe the squashing 
effect in degrees here, the CIRCLE routine doesn't actually think of it that
way, and that makes life quite difficult when we want to squash a circle
from the sides - the degrees thing doesn't work anymore. It actually works
like this: the division (above it is 29/100) which is actually called the
aspect describes the ratio of the x radius to the y radius (x;y). The 
defualt aspect ratio depends on the screen mode, but gives a visual circle
in any graphics mode, assuming a standard monitor screen aspect ratio of 4:3.
Did that make you a little dizzy? Yep? Okay, well, then let's go about it
this way...practise! Play around with this until you understand! That's the
best way to understand programming. Just to get you started, here's an
example program showing you how to squash a circle from the side:
CIRCLE (160, 100), 15, 14, , , 170 / 100
Play around with this and it'll soon make sense.
Okay, as I mentioned earlier, it is possible to draw fractions of the circle,
but that is slightly mathematical so I'll leave that for another time. I
think I've confused you enough for one day!
There are still other graphics routines to cover, but we'll have to leave 
that for another issue. We have said more than enough about graphics this
Okay, we'll cover one more aspect of programming before I leave you to play
around with what you've learned this issue. Sound in Qbasic! Before we 
even start this I need to explain one simple thing - Qbasic is, ordinarily,
only able to produce sound through the internal PC speaker. You probably
didn't even know that you have a speaker inside your computer, but you do.
In the old days of computing there was no such thing as sound cards, and
sound amplifiers for the computer. Such things were unheard of. In those
days everyone used to have to play sound through the little speaker inside
the computer. Unfortunately the internal speaker is really junky. Any sound
that comes from it sounds terrible. But, as a newbie, it's the only sound 
that'll be available to you for a while. There are ways to use the sound 
card in Qbasic, but it's really difficult, so we are not going to cover that
at this stage.
Okay, I have rambled on long enough! We have quite a few Qbasic statements
at hand which generate sound through the PC speaker. We'll start off with
some simple stuff. It's fairly clear that the simplest form of sound we
could possibly get the computer to do is just a beep. What could be easier 
than that? Well, there is a Qbasic statement called BEEP that does just that!
BEEP generates a beep-like noise from the internal speaker at 800hz (800 
cycles per second) for one-quarter of a second. It's really easy to use 
BEEP. Let's test it:
Yep! That's it! That's all you have to type to use BEEP. Could anything be
any easier than that?! Well congratulations, you've just mastered yet another
Qbasic statement, and it's only taken you two seconds! ^_^
Okay, soon you're likely to get bored with BEEP. With BEEP you are not able
to specify the pitch of the BEEP and the duration for which it plays. And
that is no good. No good at all. Okay, well this isn't much of a problem.
There is a Qbasic statement called SOUND which allows you to do exactly 
what BEEP won't allow you to do! The syntax of SOUND is:
SOUND frequency, duration
frequency is the pitch of the sound. For those of you who don't know what this
means (get a dictionary!) here's some examples - an example of a low pitch
would be thunder. It sounds deep and has a low pitch. An example of a high
pitch would be the squeek of a mouse. It has a high pitch. The higher the
number is in place of frequency, the higher the pitch of the sound. The 
frequency may not be lower than 37, and not higher than 32767.
duration specifies the amount of time the computer has to spend making the
sound. It is measured in clock ticks. Clock ticks occur 18.2 times per 
second. The duration may not be less than 0, and not higher than 65535.
Ah, okay, now is a good time for an example, no?
SOUND 300, 70
If you really want to give yourself a headache (why would you want to do 
that?!) then run the following program:
SOUND 5000, 65535
I would not advise running that program. You'll get a terrible headache. You
could easily write a program that would trick somebody into thinking there's
a mosquito in the room ;)
Now the problem with this stuff is that it's really hard to write music 
with it. It's even harder to try and write sound effects. With music we
are accustomed to sounds being described as A,B,C,D,E,F and G. Well 
here's a list of the equivelent frequency's for them! ^_^
I took this list from a book I have on Qbasic. For some reason there are
a number of different A's, B's, C's...etc. I know nothing about music so
I have no idea why this is the case. Those of you who know about music will
be able to make more sense of this than I can ;)
Note   Frequency   Note   Frequency
C      130.810     C*     523.250
D      146.830     D      587.330
E      164.810     E      659.260
F      174.610     F      698.460
G      196.000     G      783.990
A      220.000     A      880.000
B      246.940     B      987.770
C      261.630     C     1046.500 
D      293.660     D     1174.700
E      329.630     E     1318.500
F      349.230     F     1396.900
G      392.000     G     1568.000
A      440.000     A     1760.000
B      493.880     B     1975.500
*Middle C.
By doubling or halving the frequency, the coinciding note values can be 
estimated for the preceding and following octaves.
To produce periods of silence, use the following statement:
SOUND 32767, duration
To calculate the duration of one beat, divide the beats per minute into the
number of clock ticks in a minute (1092).
The following table illustrates tempos requested by clock ticks:
Tempo       Notation       Beats/Minute       Ticks/Beat
very slow   Larghissimo
            Largo          40-46              27.3-18.2
            Larghetto      60-66              18.2-16.55
            Adagio         66-76              16.55-14.37
slow        Adagietto
            Andante        76-108             14.37-10.11
medium      Andantino
            Moderato       108-120            10.11-9.1
fast        Allegretto
            Allegro        120-168            9.1-6.5
very fast   Prestissimo
Like I said, I know nothing about music, and I thus have no idea what the
above table is talking about. The only thing that I know about music is
that it comes out of the radio! ;) Those of you who know about music will
probably find the above information very usefull, but as for the rest of you
who know no more about that stuff than me, don't worry about it. It's still
possible to do cool stuff with SOUND without any knowledge of music.
There's another way to use music with the internal speaker in Qbasic, but
we'll cover that (and other things) next issue. Until next month, just play
around with what you have learned, and see if you can come up with something
cool. If you make a little program, and you are proud of it and would like
others to see it, then email it to me at horizonsqb@hotmail.com and I'll
include with the next issue of the QBCM! Have fun with Qbasic!!! ^_^
Cya next month!  
                       MANIPULATING SOUND IN QBASIC
(A while ago I found a bunch of ZIPs which contained posts from old Qbasic
BBS's. Most of the posts were from 1991-93. A lot of the information in the
ZIP's was either very primitive or was just code with no explanation of
how it works. I did however find this one good tutorial which explains some
very cool stuff about the use of sound in Qbasic. This document has been
left in its original state. -ed)
 From:  EDWARD SCHLUNDER          Sent: 07-24-93 05:18
   To:  MATTHEW MCLIN             Rcvd: -NO-
   Re:  FORMAT OF MOD, SAM (1/9)
<-=-=-=-=- Matthew Mclin to All -=-=-=-=>
 MM> Does anybody know the format of MOD/SAM/WAV/VOC file? Info on any
 MM> of those formats (how to read/write/play them using a PC Speaker
 MM> LPT 1 with a mono DAC) would be greatly appreciated.
      You know, you are quite lucky that I just decided to pickup the
   Pascal echo even though I'm not a Pascal programmer. I have ALL of
   these file formats! Lucky you! I have had to search high and low all
   over the place for this junk and you're getting it all in one shot.
      Not only do I have those file formats, but I also understand how
   to play them back on the PC's Internal Speaker, LPT DACs, and Sound
   Blaster. I'll be posting that too.
      I have been interested in this field for quite a while, that's how
   I gather up all this information. If I had enough ambition, time, and
   patience, I'd probably write a book on it all because there is not
   ONE SINGLE book that explains how to play digital sound directly (ie,
   without specail drivers), with such drivers, what the file formats
   are, and includes code to do all that stuff.
      Gee, I bet that would make a lot of money, perhaps I should do
   that after all.... Those guys on the 80XXX Assembler echo would
   probably be able to do a better job as they are more knowledgable on
   this, but most of them are into writing demos and creating
   faster/better MOD players..
      Ok, since this will take up a lot of room, I'll be splitting it up
   into seperate messages. The simpilest stuff goes in this message.
 MM> I would also like info on raw sound data and how to edit/play it.
      Newbe to Digital Sound, eh? Well, you've come to the right place
   for information, or rather, the right person has come to you. Ok, the
   basics. A digital sound file is basically just a bunch of volume
   settings. On the PC, a volume setting of 128 is normally silence.
   Values farther away from 128 in either direction are louder depending
   on its distance from 128. 0 and 255 are the loudest volumes. One
   thing I should make clear, 128 is not nessicarily silence. When
   making a recording, there is always background noise. So, what may
   sound like silence to you, is actually 126-130 or so.
      Now, you have probably seen those neat little graphs that some
   programs make when displaying a digital sound file. VEdit (which
   comes with the Sound Blaster) shows the waveform in the modify part
   of it. If you wanted to display a graph yourself, you could just load
   in a byte from the file, then, use that byte for the Y location. The
   X location is where in the file you are at (which byte). You just
   keep loading in bytes until the end of the screen. I could go on and
   on, but this is just a message, not a book! Hmm, you said you wanted
   to play a digital sound file on the PC's Internal Speaker and on a
   printer port DAC. Well, here comes that part. I'll explain usage of
   printer port DACs first because they are easier to understand. To
   play a VOC, WAV, SND, etc file on the DAC, you just read in one byte
   from the file, output it to the printer port, and do it again but on
   the next byte. To get the I/O address of the printer port, read the
   word at memory location 40h:8h for LPT1, 40h:0Ah for LPT2, 40h:0Ch
   for LPT3, and if on a non-ps/2, 40h:0Eh for LPT4.
      The internal speaker is a bit more tricky, you have to do certain
   things to set it up correctly before outputting sound. Before you do
   ANY sound output, you must do the following (sorry, I'm not a Pascal
   programmer, so this is in Assembler):
   Out   43h, 0B6h                     ;Please make note: This code was
   Out   42h, 0FFh                     ;written by a friend of mine in
   Out   42h, 0                        ;australia named Phil Inch. He
   Out   43h, 90h                      ;posted code in the 80x86 Assembler
   In    ax, 61h                       ;echo (GTPN, not Fido) for the
   Or    ax, 3                         ;public domain. Thanks Phil!!
   Out   61h, ax
      Ok, the above sets the timer chip up correctly. From there it is
   pretty simple. Get a byte from the sound file. Divide the byte by a
   'shift' number (I'll explain about this later). Then, output this new
   byte to port 42h. Repeat this for the whole file.
      Ok, now, about that shift value. The PC's Internal Speaker wasn't
   designed for playing digital sound on it, it's just that brainy guys
   like Phil have figured out how to do with software what should have
   been done with hardware.. Anyway, the PC's Internal Speaker isn't
   very loud, so the range of volumes is much less than on a Sound
   Blaster or printer port DAC. This shift value varies from computer to
   computer, it depends on the size of your speaker and other stuff.
   Genernally, a shift value of 4 works on all computers. On my
   computer, I can get anyway with 3 on most files. The smaller the
   shift value, the louder the file will be played, but too small a
   shift value will cause distortion. Experiment! After you are finished
   playing the sound file, you must put the timer chip back the way it
   was supposed to be, or otherwise the next program that tries to make
   a noise on the internal speaker will make the noise but will not
   stop! Here is the code for that (again, sorry about the Assembler,
   it's just that I'm not a Pascal programmer):
   Out   43h, 0B6h
   In    ax, 61h
   And   ax, 0FCh
   Out   61h, ax
      There, that should do it. I hope I haven't totally confused you.
   Please write back if you have ANY questions what-so-ever. Gee, I'm
   already on line 107, time to go to a new message!
<-=-=-=-=- Matthew Mclin to All -=-=-=-=>
 MM> Note that these .MOD
 MM> and .SAM files are in the Amiga Module format (just incase there are
 MM> any others). Oh, there's also the .SND files. Or even .MID/.MDI files
 MM> if you can play them thru a DAC on an LPT port or the PC Speaker. Note
 MM> that I don't have a Sound Blaster (or any other sound card). Thanks.
SAM Files:
      As far as I know, these do not contain any header or specific
   structure. They are just raw sound files. The only trick you have to
   remember about these files are that they are signed, which means that
   when the 7th bit is set, the number is negative. When the 7th bit is
   clear, the number is positive. This is completely different from
   digital sound files that originated on the PC. Remember, MOD and SAM
   files originated from the Amiga, so they have this weird encoding.
     To convert a signed file to an unsigned file, just read in one byte
   from the original file. Add 128 to that byte. Output the answer to a
   new file. In the Amiga world, a byte of 0 is equalivilent to silence.
   A byte of -128 (and +128) is as loud as it gets on the Amiga.  On the
   PC, however, 0 (and 255) is as loud as it gets. A byte of 128 is
   equalivilent to silence on the PC. So, when we add 128 to a -128, we
   get a zereo, which is the same volume for a 128 on the Amiga.
      The following text was written by Edward Schlunder and was based
   on information provided by Tony Cook on the GT Power Network's 80x86
   Assmebler echo.
                               WAV File Format
                       By: Edward Schlunder. 5-17-93
 00 - 03        "RIFF"                        Just an identification block.
                                              The quotes are not included.
 04 - 07        ???                           This is a long integer. It
                                              tells the number of bytes long
                                              the file is, includes header
 08 - 11        "WAVE"                        Just an other I.D. thing.
 12 - 15        "fmt "                        Just an other I.D. thing.
 16 - 19        16, 0, 0, 0                   Size of header to this point.
 20 - 21        1, 0                          Format tag.
 22 - 23        1, 0                          Channels
 24 - 27        ???                           Sample rate, or (in other
                                              words), samples per second.
 28 - 31        ???                           Average bytes per second.
 32 - 33        1, 0                          Block align.
 34 - 35        8, 0                          Bits per sample. Ex: Sound
                                              Blaster can only do 8, Sound
                                              Blaster 16 can make 16.
                                              Normally, the only valid values
                                              are 8, 12, and 16.
 36 - 39        "data"                        Marker that comes just before
                                              the actual sample data.
 40 - 43        ???                           The number of bytes in the
VOC File Format:
      This file format was written by Phil Inch on the 80x86 Assembler
   echo on the GTPN. Thanks Phil!!
00 - 19        "Creative Voice File", 26     Just an identification block.
                                             The quotes are not included,
                                             and the 26 is byte 26 (1Ah) which
                                             is an end-of-file marker. There-
                                             fore, if you TYPE a VOC file, you
                                             will just see Creative Voice File.
20 - 21        26, 00                        This is a low byte, high
                                             byte sequence which gives
                                             the offset of the first
                                             block of sound data in the
                                             file.  Currently this is 26
                                             ( 00 x 256 + 26 ) which is
                                             the length of the header,
                                             but it's probably good
                                             programming practice to
                                             read and use this value
                                             anyway in case the format
                                             changes later.
22 - 23        10,1                          These bytes give the
                                             version number of the VOC
                                             file, subnumber first, then
                                             main number. The default,
                                             as you can see, is 1.10.
24 - 25        41,17                         These bytes are "check
                                             digits". These allow you to
                                             be absolutely SURE that you
                                             are working with a VOC
                                             file.  To use them, convert
                                             the version number (above)
                                             and this number to
                                             integers. Do this with the
                                             formula below, where for
                                             convention the above bytes
                                             have been listed as byte1,
                                             Therefore, for the default
                                             values we get the following
                                             (1 x 256)+10 =  266 (17
                                             x 256)+41    = 4393
                                             When you add the two
                                             results, you get 4659.  If
                                             you do these calcs and get
                                             4659, then you can be
                                             almost certain you're
                                             working with a VOC file.
OK, that takes care of the header information.  I hope you realise that
I'll never get a registration for VOCHDR now!  Oh well <sigh> perhaps
people will buy my games!
   Having gotten to byte 26, we now start encountering data blocks.
There are eight types in all, conveniently numbered 0 - 7.  For each
block, the first byte will always tell you the type.
For notational convenience, bx means byte x, eg b5 means byte 5.
   Structure:     Byte 1: '0' to denote "end block" type
   This block is located at the END of a VOC file.  When a VOC player
   encounters a block 0, it should stop playing the VOC file.
   Structure:     Byte 1: '1' to denote "data block" type
                       2: \
                       3: | These bytes give the length:
                       4: / b2 + (b3*256) + (b4*65536)
                       5: Sampling rate: Calculated as 1000000 / (256-b5)
                       6: Pack type byte:
                              0 = data is not packed
                              1 = data is packed to four bits
                              2 = data is packed to 2 bits
                              3 = data is packed to 1 bit
                       7: Actual sample data starts here
   Structure:     Byte 1: '2' to denote "more data block" type
                       2: \
                       3: | These bytes give the length:
                       4: / b2 + (b3*256) + (b4*65536)
                       5: Actual sample data starts here
   The point of this is simple:  If you have a sample that you want to
   chop up into smaller portions (the maximum block length in a VOC file
   is 16,842,751 bytes but who's counting?), then define a "more data"
   block. This "carries over" the previously found sampling rate and
   pack type byte, so a "data block" should have been encountered
   earlier somewhere along the line.
   Structure:     Byte 1: '3' to denote "silence block" type
                       2: \
                       3: | These bytes give the length:
                       4: / b2 + (b3*256) + (b4*65536)
                          (Note that this value is usually 3 for a
                          silence block.)
                       5: Duration ( b5+(b6*255) ).  This gives the equivalent
                       6: number of bytes to "play" during the silence.
                       7: Sampling rate: Calculated as 1000000 / (256-b5)
   A silence block is used for long periods of silence.  When long
   silences are required, it's more efficient in size terms to insert
   one of these blocks, as seven bytes can then represent up to 65,536.
   Structure:     Byte 1: '4' to denote "marker block" type
                       2: \
                       3: | The length of the block, as usual
                       4: /
                       5: Marker value, as low-high (ie b5 + (b6*255) )
   The marker block is read by CT-VOICE.DRV.  When a marker block is
   encountered, the value in the marker value bytes (5 and 6) is copied
   into the status word specified when CT-VOICE was initialized.
   This allows your program to judge where in the sample you currently
   are, thus allowing for progress counters and the like.  It's also
   useful if you're trying to synchronize other processes to the playing
   of the sound.
   For example, by using appropriate marker blocks, you could send
   signals to your software to move the lips of a person on-screen in
   time with the speech in the VOC.  However, this does take some doing
   and a VERY good VOC editor!
   Structure:     Byte 1: '5' to denote "message block" type
                       2: \
                       3: | The length of the block, as usual
                       4: /
                   5 - ?: Message, as ASCII text.
                       ?: 0, to denote end of text
   The message block simply allows you to embed text into a VOC file.
   Presumably you could use this to detect when other people have
   pinched your VOC files for their own applications.
   Structure:     Byte 1: '6' to denote "repeat block" type
                       2: \
                       3: | The length of the block, as usual
                       4: /
                       5: Number of times that data should be repeated
                       6: Total = 1 + b5 + (b6*255)
   Every "playable" data block between a block 6 and a block 7 will be
   repeated the number of times specified in b5 and b6.  Note that you
   add one to this value - the data blocks are ALWAYS played at least
   once.  However, if b5 and b6 are zero, then you really don't need a
   repeat block, do you!
   I'm told that you cannot "nest" repeat blocks, but I've never tried
   it. This limitation would only apply to CT-VOICE.DRV I would have
   thought, but it depends how good other VOC players are.
   Structure:     Byte 1: '7' to denote "end repeat block" type
                       2: \
                       3: | The length of the block, as usual
                       4: /
   This, as explained, marks the end of the block of blocks (!) that you
   wish to repeat.  Note that the "length" is always zero, so I don't
   know why the length bytes are required at all.
   There, finally... Ahh. Well, next up is the MOD and SND file
This was picked up off the 80XXX Assembler echo on FidoNet. There are
many other file formats for MODs, but I have found this one to be most
Protracker 2.3A Song/Module Format:
Offset  Bytes  Description
------  -----  -----------
   0     20    Songname. Remember to put trailing null bytes at the end...
               When written by ProTracker this will be only uppercase;
               there are only historical reasons for this. (And the
               historical reason is that Karsten Obarski, who made the
               first SoundTracker, was stupid.)
Information for sample 1-31:
Offset  Bytes  Description
------  -----  -----------
  20     22    Samplename for sample 1. Pad with null bytes. Will only
               be uppercase.  The samplenames are often used for storing
               messages from the author; in particular, samplenames
               starting with a '#' sign will generally be a message.
               This convention is a result of a player called
               IntuiTracker displaying all samples starting with # as a
               message to the person playing the module.
  42      2    A  WORD with samplelength for sample 1.  Stored as number of
               words.  Multiply by two to get real sample length in
               bytes. This is a big-endian number; for all PC
               programmers out there, this means that to get your
               8-bit-orginated format, you have to swap the two bytes.
  44      1    Lower four bits are the finetune value, stored as a
               signed four bit number. The upper four bits are not used,
               and should be set to zero. They should also be masked out
               reading; you can never be sure what some stupid program
               could have stored here...
   45      1   Volume for sample 1. Range is $00-$40, or 0-64 decimal.
   46      2   Repeat point for sample 1. Stored as number of words
               offset from start of sample. Multiply by two to get
               offset in bytes.
  48      2    Repeat Length for sample 1. Stored as number of words in
               loop. Multiply by two to get replen in bytes.
Information for the next 30 samples starts here. It's just like the info
for sample 1.
Offset  Bytes  Description
------  -----  -----------
  50     30    Sample 2...
  80     30    Sample 3...
 890     30    Sample 30...
 920     30    Sample 31...
Offset  Bytes  Description
------  -----  -----------
 950      1    Songlength. Range is 1-128.
 951      1    This byte is set to 127, so that old trackers will search
               through all patterns when loading. Noisetracker uses this
               byte for restart, ProTracker doesn't.
 952    128    Song positions 0-127.  Each hold a number from 0-63 (or
               0-127) that tells the tracker what pattern to play at
               that position.
1080      4    The four letters "M.K." - This is something Mahoney &
               Kaktus inserted when they increased the number of samples
               from 15 to 31. If it's not there, the module/song uses 15
               samples or the text has been removed to make the module
               harder to rip. Startrekker puts "FLT4" or "FLT8" there
               instead. If there are more than 64 patterns, PT2.3 will
               M!K! here. (Hey - Noxious - why didn't you document the
                           part here relating to YOUR OWN PROGRAM? -Vishnu)
Offset  Bytes  Description
------  -----  -----------
1084    1024   Data for pattern 00.
xxxx  Number of patterns stored is equal to the highest patternnumber
      in the song position table (at offset 952-1079).
  Each note is stored as 4 bytes, and all four notes at each position in
the pattern are stored after each other.
00 -  chan1  chan2  chan3  chan4
01 -  chan1  chan2  chan3  chan4
02 -  chan1  chan2  chan3  chan4
Info for each note:
 _____byte 1_____   byte2_    _____byte 3_____   byte4_
/                \ /      \  /                \ /      \
0000          0000-00000000  0000          0000-00000000
Upper four    12 bits for    Lower four    Effect command.
bits of sam-  note period.   bits of sam-
ple number.                  ple number.
      One thing you should keep in mind about MOD files is that they
   originated from the Amiga, so the samples are signed, see the
   discussion about SAM files for more information.
      Sounder and Sound Tool both use the same file extension, but have
   different file formats. To tell the difference, Read the first 6
   bytes of the file. If it matches the magic number for Sound Tool .SND
   files, it is a Sound Tool file. Else, it's a Sounder file or a raw
Sounder File Format:
 00 - 01        0, 0                          Bits per sample. Ex: Sound
                                              Blaster can only do 8,
                                              Sound Blaster 16 can make
                                              16. Normally, the only
                                              valid value is 0, which is
                                              the code for an 8 bit
                                              sample. Future versions of
                                              Sounder and DSOUND.DLL may
                                              allow 16 bit samples and
 02 - 03        ???                           Sampling rate. Currently,
                                              only 22 KHz, 11 KHz, 7.33
                                              KHz, and 5.5 KHz are
                                              valid. If given a value
                                              like 9 KHz, it will be
                                              played at the next closest
                                              rate (in this case, 11
                                              KHz). The sampling rate is
                                              calculated as follows:
                                              SampRate = Byte1 + (256 * Byte2)
 04 - 05        ???                           Volume to play the sample
                                              back at. Note: On the PC's
                                              Internal Speaker, there is
                                              a definite upper limit as
                                              to the volume, depending
                                              on the shift value (see
                                              below). The Sound Blaster
                                              and the Disney Sound
                                              Source aren't quite as
                                              restricted, but still are
                                              at some high value.
 06 - 07        4, 0                          Shift value. This is the
                                              number that each byte is
                                              divided by to "scale" the
                                              volume down to a point
                                              where the PC's Internal
                                              Speaker can handle it. See
                                              the discussion on playing
                                              back digitalized sound for
                                              more details.
   Information from Sounder text files and Sound Tool help (.HLP) files.
Sound Tool File Format:
 00 - 05        "SOUND", 26                   Just an identification
                                              thing. Helps a lot when
                                              you are trying to
                                              distinguish between
                                              Sounder .SND files and
                                              Sound Tool .SND files.
 08 - 11        ???                           This is the number of
                                              bytes in the sample. It is
                                              calculated as follows:
       ByteSam = Byte1 + (256 * Byte2) + (512 * Byte3) + (768 * Byte4)
 12 - 15        ???                           This points to the first
                                              byte to play in the file.
                                              It is calculated the same
                                              way as the number of bytes
                                              in the sample (see above).
 16 - 19        ???                           This points to the last
                                              byte in the sample to
                                              play. Calculated the same
                                              as above.
 20 - 21        ???                           Sampling rate of the
                                              sample. Valid values are
                                              22 KHz, 11 KHz, 7.33 , and
                                              5.5 K, but if given a
                                              number not listed above,
                                              it will be played at the
                                              closest valid sampling
                                              rate. So, 9 KHz would be
                                              played at 11 Khz. This is
                                              calculated as follows:
                                              SamRate =  Byte1 + (256 *
 22 - 23        ???                           Bits per sample. Ex: Sound
                                              Blaster can only do 8,
                                              Sound Blaster 16 can make
                                              16. Normally, the only
                                              valid value is 0, which is
                                              the code for an 8 bit
                                              sample. Future versions of
                                              Sounder and DSOUND.DLL may
                                              allow 16 bit samples and
 24 - 25        ???                           Volume to play the sample
                                              back at. Note: On the PC's
                                              Internal Speaker, there is
                                              a definite upper limit as
                                              to the volume, depending
                                              on the shift value (see
                                              below). The Sound Blaster
                                              and the Disney Sound
                                              Source aren't quite as
                                              restricted, but still are
                                              at some high value.
 26 - 27        4, 0                          Shift value. This is the
                                              number that each byte is
                                              divided by to "scale" the
                                              volume down to a point
                                              where the PC's Internal
                                              Speaker can handle it. See
                                              the discussion on playing
                                              back digitalized sound for
                                              more details.
 28 - 123       ???                           This is the name of the
                                              sample. It is followed by
                                              an ASCII 0.
   Information from Sounder text files and Sound Tool help (.HLP) files.
      Whoo! That was a TON of typing. WHOA!! I just literaly spend all
   night preparing those messages for you. I believe I started it around
   12:00 am and now it's 5:00 am! Let me apologize if I made any
   mistakes in the previous messages, hard to type perfectly when your
   eye lids keep falling down <g>.
      I don't know the file format for MDI and MID files, and I don't
   think that they can be played on the internal speaker or printer port
   DACs. Sorry!
      Well, I hope I've answered all your questions, if you get anymore,
just post to me! Have fun with the new information!  
                     INTRODUCTION TO 3D SERIES #1
Writer: Matthew River Knight
Have you ever played Quake and wished you could make a similar game in
Qbasic? Have you ever tried to learn how to code a 3d program in Qbasic,
only to find that there are no good tutorials out there? Yep? Well then
this tutorial is just for you! ^_^
I remember when I wanted to learn how to do 3d, it was a total nightmare.
I went to every shop I knew of in search of a book - they had books on the
subject, but they were all aimed at C programmers...there was nothing for
Qbasic coders such as myself. Next I decided to search around the internet
for a decent tutorial. I found several tutorials, but to my alarm, they were
all so complicated! I'm sure that some of you have, at some stage,
downloaded a certain 3d tutorial by Matt Bross. What a mistake that was eh?!
It is a pathetic excuse for a tutorial. It consists only of extremely 
complicated and difficult to read code, then followed by a very brief
explanation of what it does, and an even briefer explanation of how it goes
about achieving this.
In order to fill the obvious void in the QB world for a decent 3d programming
tutorial, I have decided to do a series about it right here in QBCM! We are
going to take things step-by-step, progressing from the very simplest 
aspects of 3d programming, right up to the more complicated, but extremely
fun stuff! ^_^
Don't worry if you aren't good at maths, or aren't a programming guru. I
am going to explain things in such a way that they are going to be very
easy to understand, regardless of your ability! I do however recommend that
you have at least an intermediate knowledge of Qbasic. As far as the maths
is concerned, there is a large misconception amongst the programming circles
that in order to do 3d, you have to be a genius with mathematics. Not so.
You will need to have a good knowledge of Algebra, Geometry, and Analytical
Algebra. That's it. It does help to know Trigonometry, but it is not a
Okay, I have rambled on long enough! Let's start learning how to program
in 3d!!! To begin with, we need to know how to define a point in a 3d world.
You already know how to define a point in 2d - it's simple...you have your
X coordinate to describe the point/pixel's location across the screen, and
you have your Y coordinate to describe the point/pixel's location down the
screen. In 3d it works exactly the same way, however, we have to add another
coordinate: Z. The Z coordinate describes the depth, or in other words,
how far the point/pixel is away from the viewer. In a 3d world, the exact
center of the world is X,Y,Z = (0,0,0). So, a point that is 100 pixels
to the left of the center of the 3d world would be at (-100,0,0). A point
that is 50 pixels to the right of the center of the 3d world, 100 pixels
higher than the center of the 3d world, and 10 pixels closer to the viewer
than the center of the 3d world, would be at (-50,-100,10). All of the
points in your 3d world are collectively called the world coordinates.
Using the above method, it is easy to create a 3d world. If, for example,
you wanted a quadrilateral (such as a cube) in your 3d world, you would
compose it by defining points which are the vertices of the object. Later
on, when actually drawing the object on the screen, we connect all of the
points/pixels together by using the LINE statement. This gives us what is
called a wireframe representation of the object. But, before we can draw
our 3d objects on the screen there's some stuff you have to know - we'll
cover that at a later stage.
Once we have defined all of our world coordinates, we have to place the
camera in the 3d world. The camera (also called the eye or the viewer) is
what actually looks at the world. If you place it high above the 3d world,
then you see the world in much the same way that it would be seen from a
high tree, or a building. If you place the camera much lower down, then
you will see the 3d world from an ants point of view! The camera's position
is defined in exactly the same way as the world coordinates: you describe
the camera's position in the 3d world with X, Y, and Z coordinates. It is
important to note that the camera will ALWAYS 'look' to the center of the
3d world (0,0,0).
Now that we have defined our world coordinates, and have defined our camera
position, we have to find a way to plot the 3d world on the screen, relative
to the camera's point of view. Now the most obvious question is "how on
Earth do I plot a 3d object on a 2d surface like the screen??!!" Well, let's
take this one step at a time.
Okay, let's say we have defined a single point in a 3d world where:
x_world = 100
y_world = 20
z_world = 10
The first step in getting our 3d world onto the screen is changing these
world coordinates into what is called the camera coordinates. The camera
coordinates describe the world coordinates as they are seen from the
camera's point of view.
Now, in order to change the world coordinates into camera coordinates, we
have to use a set of mathematical formulae. "Nooooo!" I hear you say. Heheh,
don't worry, it isn't difficult at all...and I am going to explain how it
works. ^_^
Now let's think about this logically. Suppose we are in a 3d car racing
game. Our camera (which is basically the same as the person inside our
car in the game) is at (100,10,10) and is looking at the center of the 3d
world (0,0,0) (you will recall that the camera in a 3d world will always
look to the center of this world). With the camera at this position, the
center of the world is at (-100,-10,-10). From this information, it seems
x_camera = x_world - camerapos_x
y_camera = y_world - camerapos_y
z_camera = z_world - camerapos_z
x_camera = x coordinate of a point (camera coordinate system).
           Ditto with y_camera, and z_camera.
x_world = x coordinate of a point (world coordinate system).
          Ditto with y_world, and z_world.
camerapos_x = x coordinate, describing the position of the camera in the 3d
              world. Ditto with camerapos_y, and camerapos_z.
And guess what...those equations are actually the equations we use to
convert world coordinates into camera coordinates!!! ^_^
It is important to note that you can place the camera anywhere in the 3d
world, except for one place - you CANNOT place the camera in the center of
the 3d world (0,0,0). You can put it anywhere but there. Why? Well, since
the camera will always look to the center of the world, if the camera was
in the center of the world it would be looking at itself. Can you look at
your eyes??!! Nope, of course not (not without a mirror anyway.) So you
can't put the camera at (0,0,0). If you do put the camera in the center of
the world, then some of the mathematical formulae which we are about to
describe will not work, and the program will crash.
Okay, so now we have converted our world coordinates into camera
coordinates. But we still can't draw our 3d world/object(s) on the screen
yet. We still have points which are described by X, Y, and Z, but the PSET
and LINE statements can only draw with points defined by X and Y (which is
2d) - this is logical really...the screen is, after all, a 2d surface.
In order to draw in 3d on the screen using PSET or LINE, we have to convert
our camera coordinates (which describe the 3d world coordinates relative to
the camera's point of view) into 2d screen coordinates. How? Simple. We use
a set of mathematical formulae!!! (Do I hear groaning?! ^_^)
Once again, we have to think about the problem at hand with a bit of logic
and common sense. In real life, objects that are further away from us
look smaller than they do when you are right next to them. The principle
is the same with 3d computer graphics. For example, imagine that in our
3d world we have two points/pixels that are 10 pixels length apart. If their
Z coordinates are both decreased by 1, then the two points are each going to
move one pixel length closer to the other. This information demonstrates
the golden wisdom of every 3d programmer: "The screen coordinates could be
calculated by dividing the X and Y position through the depth (z coord-
This shown as a formula is:
x_screen = x_camera / z_camera
y_screen = y_camera / z_camera
x_screen = x coordinate of the pixel on the screen.
y_screen = y coordinate of the pixel on the screen.
x_camera, y_camera, z_camera = (see above).
However, we have several different screen modes at our disposal, and (0,0)
on the screen is actually the top left hand side of the screen, so we have
to change the formulae a little if we want the 3d object to be centered on
the screen and if we want the program to work in all screen modes. The final
set of formulae for conversion of camera coordinates to screen coordinates
is as follows:
x_screen = (x_camera / z_camera) * srx + srx / 2
y_screen = (y_camera / z_camera) * sry + sry / 2
srx and sry describe the screen resolution. In SCREEN 13, srx would be
equal to 320, and sry would be equal to 200.
Another very important thing that I must mention is that if any of our
points in the 3d world go behind the camera, or in line with the camera,
then the math for projection of the camera coordinates onto the screen goes
all haywire. This is logical really. In real life, if an object is behind
you, or in line with your eyes on the side, then you cannot see it. This is
the same with 3d computer graphics, but the problem is that the computer
doesn't yet know that we must not be able to see these points, so it
attempts to use the math on them anyway, and it goes nuts!!! ;)
We'll say that points in our world coordinates that are in line with or
behind the camera are "out of range". In order to fix this problem, it is
necessary that we do a test on all of the points in our 3d world (the world
coordinates) to see if they are "out of range" and if they are, then we
have to temporarily eliminate them. When they are back in range again, then
we can put them back and have them plotted on the screen. Let's explain this
another way: if the value of the world Z coordinate of a point is equal to
camerapos_z or greater than camerapos_z then it is "out of range" and we
must eliminate it (ie. we don't draw it!) Simple eh?! Here's some code
for this:
IF x_world >= camerapos_z THEN 'Don't PSET this point!
Please note that when you are doing a 3d engine you should NEVER use PSET
do draw everything in the world. That would be terribly slow. LINE is a
much faster alternative, however, I used PSET here in order to make the
explanation easier to understand.
Well, this concludes the first entry into the INTRODUCTION TO 3D SERIES. I
hope you enjoyed it! Next issue we'll be covering 3d rotation, how to code
a 3d program in which you can 'walk' about the world, and hidden surface
removal. We'll also add some source code to help ya out! ^_^
Cya next month!  
                        QB TIPS, HACKS, AND TRICKS
Using COM 3 and 4
Writer: Matthew River Knight
One of the biggest reasons that we don't see many QB programs around that 
use the modem is that Qbasic is limited to using COM ports 1 and 2. The
problem with this is that these days most people have internal modems, and
most of these modems use either COM ports 3 or 4 - and Qbasic can't access
them. However, fear not, there's a way around this! ^_^ Here it is:
EXAMPLE 1: Accessing COM3 from Qbasic.
DEF SEG = 64    'Move QB segment pointer to BIOS data area.
POKE &H00,&HE8  'Change COM1 address in BIOS data area to COM3.
DEF SEG         'Return to QB's DGROUP.
'Open COM3 by issuing OPEN "COM1:" command.
OPEN "COM1:1200,N,8,1" FOR OUTPUT AS #1
PRINT #1,"ATDT844-1212"  'PRINT to COM port.
CLOSE #1           'Close COM port.
DEF SEG = 64    'Point to BIOS data area.
POKE &H00,&HF8  'Restore COM1 address in BIOS data area to COM1.
DEF SEG         'Return to DGROUP.
EXAMPLE 2: Accessing COM4 from Qbasic.
DEF SEG = 64    'Move QB segment pointer to BIOS data area.
POKE &H02,&HE8  'Change COM2 address in BIOS data area to COM4.
DEF SEG         'Return to DGROUP.
'Open COM4 by issuing OPEN "COM2:" command.
OPEN "COM2:1200,N,8,1" FOR OUTPUT AS #1
PRINT #1,"ATDT844-1212" 'PRINT to COM port.
CLOSE #1  'Close COM port.
DEF SEG = 64    'Point to BIOS data area.
POKE &H02,&HF8  'Restore COM2 address in BIOS data area to COM2.
DEF SEG         'Return to DGROUP.
Fun with the keyboard
Writer: Matthew River Knight
Hmmm...how about we disable all input from the keyboard??!! ^_^
Heheh, this is a really nasty trick to do to someone...you could compile the
following program and add a line to AUTOEXEC.BAT to run the proggy when the
computer is next rebooted ;)
It could also make a great addition to a security program...if the wrong
password is entered then you disable the keyboard ^_^
To disable all input from the keyboard:
DEF SEG = 64
OUT 97, 204
To re-enable input from the keyboard:
DEF SEG = 64
OUT 97, 76
As soon as the computer is rebooted, the keyboard will revert back to its
normal self. However, that can always be fixed by running the proggy again!
Heheh ;)
Last year I played this prank on my computer teacher...she went off to get
some diskettes from the stock room, so while she was away I copied this
program onto her computers hard-drive, and added a line to AUTOEXEC.BAT to
automatically run it. Heheheheheh ^_^ If you also want to try this at
school and you get caught, don't blame me! ^_^
That's all the tips, hacks, and tricks we have for ya this issue. If you
know and cool QB tips, hacks, or tricks, then please share them with us by
emailing them to me at horizonsqb@hotmail.com so I can print them in the
next issue of QBCM!!!  
                              BASIC MUSEUM
Writers: Daniel P.Hudson, Jean E.Sammet, and Matthew R.Knight 
Over the last two issues of QBCM we have covered the history of raytracers/
raycasters, and the history of 3d in BASIC, however we have yet to actually
look at the history of BASIC itself. Thusly, in this month's BASIC MUSEUM,
we are going to take a brief look at how the BASIC cult began ^_^
BASIC (standing for Beginner's All Purpose Symbolic Instruction Code) is a
system developed at Dartmouth College in 1964 under the directory of
J.Kemeny and T. Kurtz. It was implemented for the G.E.225. It was meant to
be a very simple language to learn and also one that would be easy to
translate. Furthermore, the designers wished it to be a stepping-stone for
students to learn one of the more powerful languages of that time such as
Bill Gates and Paul Allen had something different in mind. In the 1970's
when M.I.T.S.'s Altair personal computer was being conceived Allen convinced
Gates to help him develop a BASIC language for it. When M.I.T.S. answered
with interest, the future of BASIC and the PC began. Gates was attending
Harvard at the time and Allen was a Honeywell employee. Allen and Gates
licensed their BASIC to M.I.T.S. for the Altair. This version took a total
of 4K memory including the code and data used for source code!
Gates and Allen then ported BASIC to other various platforms and moved back
to their hometown of Seattle where they had attended grade school together.
It was at this time that the Microsoft Corporation began it's reign in the
PC world. By the late 70's, BASIC had been ported to platforms such as the
Apple, Commodore and Atari computers and now it was time for Bill Gates's
DOS which came with a BASIC interpreter. 

The Commodore 64 was probably the most popular home-computer throughout the 
80's. Almost every game ever made for the machine was coded with a mixture 
of BASIC and ASM.

The IBM-DOS version of this interpreter became known as BASICA, and at the
time IBM was in major competition with clones so it was setup to require
the BIOS distributed with IBM computers. The version distributed with
MS-DOS was GW-BASIC and ran on any machine that could run DOS. There were
no differences between BASICA and GW-BASIC which seems to make IBM's idea
Microsoft realized just how popular their BASIC interpreter was and decided
to distribute a compiler so users could code programs that ran without an
interpreter. QuickBASIC was the solution Microsoft came up with. It was
distributed on through the years until version 4.5. At this time Microsoft
decided to release a product with more kick and started distributing
PDS BASIC (Professional Development System) and ended it with version 7.1
(Also called QuickBASIC Extended), PDS was a short lived idea and was not
followed through to its true capabilities. [Though it was an improvement
over QB4.5]. Microsoft got hooked on GUI's and started Visual BASIC both a
DOS and WIN version. The DOS version was ended at 1.0 with a professional
update. Differences between VB for DOS and QB are not as much as one might
think, in fact VB still compiles QB4.5 code and the professional edition
will compile PDS7.1 Code. One last thing: PDS will compile to true OS/2 
code, VB-DOS Pro/std and QB4.5 will not.
BASIC is still in a state of change and progression. Visual BASIC is still
being updated and improved, and a number of other variants of this great
language are also being churned out from various sources. Although many
people may currently say that the future of BASIC lies within the Windows
OS, it is likely that this is not so. Linux has grown enormously in
popularity over the past few years, and is continuing to do so. It is more
than likely that in a few years Linux will be the OS of choice. It is
difficult to say exactly where the future of BASIC lies, however, the
obvious pro's of the language, along with its vast user base who's love of
the language exceeds a hundred fold what it visible with other languages,
should be more than enough to keep BASIC as one of the leading programming
languages for decades to come. 
We have three programs for review this month. So check out these reviews
to see if they're da bomb or a bomb ^_^ If you have a Qbasic program that
you would like us to review, then please email me at horizonsqb@hotmail.com
and tell me the URL of the website where I can get the program from. Please
DO NOT email your program to me!
Program: Botwarz
Program type: Game
Developer: Psycorey
Minimum system: 286, 640KB RAM
Recommended: As above
Available at: http://www.angelfire.com/nh/elfingo
You own a copy of QuickBASIC. You walk up to me in the street and prod me
gently but firmly in the chest with a well manicured forefinger. "Hey
fella," you demand aggressively, "which is the best two player shooter
currently available on God's own recently resurrected programming platform?"
I would have no hesitation in recommending several releases to you, The
Labyrinth, Space War, even my own Qbasic Tank Commander II (at a push) but
crucially, I would stop short of urging anyone to go out and spend a minute
downloading Botwarz.
Botwarz, as the name suggests, is a two player game in which you and a
friend (or foe) take the role of robots, and go around trying to shoot
eachother up. There is also a one player mode, however, it really isn't
worth playing, and the two player mode is far more enjoyable. One of the
coolest things about this game is the number of different weapons you have
at your disposal. In addition to that, you have a wide selection of
different robots to choose from, which makes the game a lot more
interesting than it would otherwise have been.
The graphics are of a VERY low standard. Although the game uses SCREEN 13,
there is no shading, no form of lighting in any way, and it is impossible
to see what any of the graphics are actually supposed to represent. There is
no background graphics either, just a plain black screen, which is very
boring indeed. The animation, while fast and flicker free, shows absolutely
no effort whatsoever. Just static bots sliding across the screen...yawn! As
far as the sound department is concerned, well, I don't really know. There
are a number of WAV's included with the game, but I couldn't get the
sound to work on my computer, so I can't really say. It does seem pretty
odd, I must confess, that the sound never worked...I have a Sound Blaster
16 sound card...that's pretty much standard in the computer world...
And this, my friend, is the graphics...need I really say more?

Okay, so now we know the graphics and sound aren't any good...how about the
gameplay? Argh, I wish you hadn't asked! Let's start with the one player
mode...well, as I have said before, it isn't really worth playing. There's
no plot, no mission, no real levels...so it's all pretty pointless. The two
player mode is a little better...at least it is worth playing, but the
controls are unwieldy, and the poor graphics, and in my case lack of sound,
makes even the two player game a torture to play. And anyway, there's many
two player Qbasic games out there, much higher in quality...so why bother
with Botwarz in the first place?
I must admit, I hate to give programmers bad reviews on their games, and I
always try to like something about the game, but Botwarz was depressing
from the very beginning...sigh...you can't say I didn't try to like it :(
Program: Diamond Fighter IV
Program type: Game
Developer: Master Creating
Minimum system: 486DX2/66, 4MB RAM
Recommended: Pentium 100, 4MB RAM
Available at: http://master-creating.de
Master Creating is a fine old development company who've been turning out
classic games since the days of the Spectrum and Commodore 64. Shadow of
Power was theirs, and now they're back with Diamond Fighter IV. The Diamond
Fighter series goes back a long way. The first episode in the series was
in fact created on a Commodore 64 almost a decade ago!
Diamond Fighter is an interesting piece of work in the light that it's a
puzzle game - a genre that has been subject to much neglect in the QB world
since its very birth. The game throws you into futuristic USA, where the
aim of the game is to complete each of the various levels in order to
complete the game. Completing a level is easier said than done! It involves
solving a sequence of puzzles in order to get to various parts of the level,
whilst collecting all of the diamonds found there. Once you have collected
each diamond, then you may proceed to the next level. There are many levels
in the game (each state in the USA represents a level) and they are all
nicely varied and have been realised with much care and imagination.
The graphics in DF are of an exceptional standard. Most of the graphics is
in SVGA, and surprisingly, it runs at an acceptable pace on even the most
humble of systems. All of the artwork is nicely detailed, and there's also
some nice effects such as flashing lights, various lighting effects, and
many others, which look very cool indeed. There's one effect where the
aliens sort of melt into a fleshy pile on the floor, which I found pretty
amusing...if not disgusting! As would be expected with a game from Master
Creating, the sound effects are utterly fabulous. There's also a bit of
speach now and again, which is all in German, but has been nicely done. My
only reservation is that there's no music in the game. I usually find that
some catchy tunes add immeasurably to the enjoyment derived from a game.
Diamond Fighter IV is an addictive game, and has been produced with quality
in mind. You may find it difficult to figure the game out at first, however,
it shouldn't take you long, and once you have mastered the basics, this game
will be a big favourite in your collection. Highly recommended.
Program: Novascript 1.0 beta
Program type: Programming language
Developer: CarterSoft
Minimum system: 386, 640KB RAM
Recommended: As above, or better
Available at: http://www.cole_carter.tripod.com/novascript1.zip
Yet another Qbasic contender steps into the ring. Take your places
gentlemen. ^_^
Qbasic is, politely spoken, starting to get a bit, well, old, and sooner or
later we are going to going to either need a new version, or convert to
some other variant of BASIC. Many are in production right now, and while
the Qbasic world merrily twiddles its thumbs waiting for Nekrophidius'
QuickPower, Novascript intends to dash swiftly into the gap.
As Qbasic contenders go, NS scores and fails on various points. It scores
because it is quite a bit faster than Qbasic in every respect, 386+
registers and opcodes are used, and users of the language will be able to
get help easily since NS's creator can easily be contacted through email
or via #qbchat. However, NS fails on various points too. For one, NS cannot
be called a true variant of BASIC. The code resembles C in many ways, and
for this reason, it's unlikely that QB users will want to convert to it.
Here's some example NS code serving as proof of its similarities to C:
-- Press Shift + F5 to execute this example
-- Let's the user type in musical notes
-- 8:14AM  4-3-00 
-- You have a royalty-free right to use, modify, reproduce
-- and distribute the sample applications  provided with
-- Novascript for MS-DOS (and/or any modified version)
-- in any way you find useful, provided that you agree that
-- CarterSoft has no warranty, obligations or liability for
-- any of the sample applications or.
Declare; music$
Printw; Type in some musical notes
itext = Notes...
input music$
!notes$ music$
printw; Thank You for playing Music
end }
The way in which the code is used is also very inconsistent which makes the
language difficult to learn. Another problem is that there is no real
syntax or anything in NS for many of the commands. For example, to use the
LINE statement, you first have to define variables for drawing the line
from one point to the other, for the color of the line, etc. Here's a bit
of example code:
-- =============================
-- This Sample graphic examples
-- (c) 2000 CarterSoft 
-- =============================
scrn 2
Printw; Circle
C1# 320
C2# 100
C3# 200
scrn 13
Printw; Line
L1# 0 
L2# 100
L3# 319
L4# 100
scrn 1
Printw; Triangle
Pict C2
Pict F60 L120 E60
Pict BD30
Pict P1,2
end }
Lastly, the language is not as versatile as Qbasic, and the user doesn't
have quite as much power, or control over the machine. However, it's
more than likely that the missing features will be there in the full
version. The IDE itself is very much like the one employed by Qbasic. It
is pleasing to use, and easy to master. There is also some fairly good
documentation on the language, however, the online help feature has yet to
be implemented.
Well, NS 1.0 beta is far from complete, so I'll, for the most part, reserve
my judgement until the final release. The speed of NS, and the high quality
IDE, makes NS a promising project, and one certainly worth keeping an eye
on. Be sure to check it out!
QBCM mini game of the month
This is a competition for the best Qbasic game under 40KB ZIPed. The best
game I recieve will be included with the next issue of QBCM! In order to
enter this competition, simply email your game to me at horizonsqb@hotmail.com
This month's winner is Joe King for his little game, Toadman. Congrats! It
has been included with this issue of QBCM...it's TOADMAN.ZIP!
Those of you who entered your games and didn't win, don't worry. They are
automatically re-entered into the competition for the following month, so
who know...maybe you will be the winner next month! ^_^
QBCM website of the month
This is a competition for the best website dedicated to Qbasic. To enter,
simply email the URL of your site to me at horizonsqb@hotmail.com. This
month the winning site is Chris Charabaruk's site: http://picksoft.zext.net
                              CLOSING WORDS
I must say that I thoroughly enjoyed compiling this issue of QBCM. I hope
it has been just as much fun for you to read it! It really amazes me how
much this magazine has grown over the past three months. I certainly have
no doubt that it will continue to do so!
Once again, please email any articles, letters, etc to me at
horizonsqb@hotmail.com. Any input you can provide will be greatly
appreciated. :)
Thank you for reading issue 3 of QBCM! Keep codin' in QB!
Cya next month!!! ^_^
-Matthew River Knight