issue #4

Want to print? Use this version

Back issues are in the Archive

Go back to the main site

REM 'Letter from the Editor
Welcome to Issue 6 of Qbasic: The Magazine
ON KEY 'Hot List
News from the QB world
INPUT 'Your Stuff
Survey #4 results plus yer letters!
! mov 'asm Intro: part 2
Petter gives ya a big installment of your favorite series!
DRAW 'Cutscenes
Master artist Enigma shows ya how to do 'em right!
PRINT '3d: Part I
MA SNART starts his series on the world of 3d!
REM 'The Future of Qbasic
What qb'll be like in 1999...and in 2009!
PRINT 'Test Machines
We all do playtesting. What about hardware testing?
END 'Next Issue
What's up in our next issue?

 

Letter from the Editor

By ZKman

qb:tm hits the half-year mark with the super-fab Issue 6!

Heya! Qbasic: the Magazine hits the half year mark with the super-fab Issue 6 and a brand new look! Hope everyone likes our newer and easier to read format! For articles this month, Hal_8900, Ma Snart, Petter Holmberg, Enigma and myself tell ya ev'rything ya need to know in the qb world. Petter has the 3rd installment of his great asm series...this month we'll learn arithmetic, logic operators and much more! Hal_8900 tells ya how to buy a "test machine". What's that, ya ask? Well, how else are ya gonna make sure your game you've been dev'ing on a P-II will operate right on a p-100? Enigma rants on about the subject he knows most about: Art. This month he's talking about cutscenes. Everyone loves 'em in FFVII and others...so why not put them in your game? Ma Snart starts what will become a great 3d series by explaining polys vs. Voxels, camera, scenes, objects and more! But what about his RPG Script article? We're going to delay the rest of this series for now, but be assured it will be finished at some point in the future.

 

Is a .zip version coming in your future?

Speakin' of the Future, we've talked with some of the leaders in qb development and are here to tell ya what you can expect from the future of qbasic. What trends are developing? What will we see in the future? It's all right here. Who loves ya, baby?

We've had a lot of questions asking about a possible .zip version of the mag, or an email version. How many of you are up for this? **watches Lynx users hands raise**. Right now, we're sticking with the printable version of the issue (which I encourage all of you to use...tis a great reference!), but if you all bombard me with email concerning this, umm, we might change our minds. ^_^

So, hope everyone got what they wanted for the holidays (I'm enjoyin' my new Voodoo very much, thank you ^_^), and let's make this year the best year for qbasic ever!

See ya' next month!

zkman

 

Back to top

qbasic Hot List

Compiled by ZKman

 

What da ya MEAN "for sale"?
Last month, we reported that the qbt50 was reportedly for sale at a price of $1500 American. The sale must not have happened, however, as Steve Martin from the qbt50 is now reporting that he has decided to rewrite the cgi scripts for the site over the summer making maintenence easier and will not be selling after all.

You can contact Steve at this address

quickbasic.com, the qbt50 sale, lib updates, and more

 

 

TMJ at the drawing board
Danny Gump's premier qbasic game, The Mystical Journey, has hit the drawing board again. Despite the game having progressed thru many alpha versions with a large world map, intro scenes, battles, spells and more (in fact, enough for it to get quite a few votes for "best game" in the survey!), Danny will be redoing the game from step one.

Why has this sudden change of heart occured? According to a report on his web page, Danny felt that the engine (which did have a slightly antiquated graphical style) was not competitive with such newer games as "Wrath of Sona and Sypharage". Check out the progress of the new TMJ at VirtuaSoft.

 

Codex: December Winners
The December winners of Tek's qbasic contest "codex" have been announced. Codex is a program where each month, a programming application must be developed to show skill among the top qb prers. Last month's challenge was to create a program which would "write" numbers out: i.e, an input of 64 would return "sixty-four". Vamooshka was the big winner by making a prog that could take in a number with 66 places before the decimal and 65 after, in addition to accepting negative numbers!

If you're interested in seeing the other winners, or gaining more information about this month's challenge, surf on over to Neozones and click on "codex" in the sidebar.

 

DarkDread != RavenNight
Last month, we reported on rumours that a person referring to themselves as "RavenNight" was claiming to be DarkDread, legendary qb programmer of games such as Legend of Lith 2 and Lianne...In the Dark Crown. We've learnt from sources in contact with the "real" DarkDread that he has nothing to do with the page which RavenNight put up. So, another rumour hits the dust. ^_^

 

Qlympics Delayed
As was surmised in Issue 5, SonicBlue and the rest of the Qlympics organisers have put off the deadline for entries into the Qlympics until the end of this month, on January 31. At that point, the finalists will be declared. Look to the official site for the winners or check into the February issue of qb:tm.

 

Another Month...another dqb version
Since last month's issue, version1.3 and version1.4 of dqb were released, in addition to a bug fixer named version1.42. Many of the dqb functions recieved speed boosts in this latest round, as well as having all of the dqb functions split into .obj files to save program's memory. Unfortuantely, we couldn't dig up dqb1.5 specs for ya, but if it's anything like the last couple updates, it's one to look forward to.

 

Meanwhile, over with Dash
Danny Gump over at Dash's camp didn't release much new on that front this month, and basing on the survey results this issue, that has hurt his user base. However, Dash is certainly not dead. Check out these specs to be put into future Dash versions:
-- EMS/XMS support
-- Load BMP (8 or 24 bit!), Load PCX, Load BSV
-- Much accelerated VSTexture for 3d progs
-- Keyboard handling

The library wars aren't over yet! If you'd like more info on Dash, visit VirtuaSoft. Information on dqb can be derived from Enhanced Creations.

 

In even more! library news
3d libraries are coming quickly into favour in the qbasic community. Currently, the only existing 3d lib is DirectPB by Quixoft. Unfortunately, this program is a PowerBasic-only library. But, we have heard that at least one library set for 3d is coming into play in the middle of this year. The planned feature-set include texture-mapping, gourard-shades, and more.

 

www.quickbasic.com
Many have been speculating since www.qbasic.com was purchased as a domain by Mallard that quickbasic.com wouldn't be far behind. Well, that time has arrived. ChUcK of Dark Elf has purchased the domain www.quickbasic.com. Although there was no content on the page at press time, the "teaser" featured at the site promises of a bright future, and hopefully a great resource for qbasic prers.

 

Wrath of Sona: The Revenge
As frequent readers know, I've got ... umm ... something against the game "Wrath of Sona". The newest version has been released by nekrophidius, so, y'know, just to be fair, I went to download the new demo.

It was NINE separate zips for a total of an almost TEN megabyte download! The game unzipped was THIRTEEN MEGABYTES!!!.

Somewhere around this point, after having unzipped the demo's fifth megabyte of .mod's, I started thinking, "hmm....lotsa stuff, this game must be good now! It must be GODLY!" I was only fooling myself.

Ludicrously bad graphics, an increase in the amount of porno, and an ok backstory were brought together into a 13mb mess. I must admit, though, the sound was the best qb sound I'd ever heard (although methinks it wasn't 6 megabytes good ^_^), and the engine promises a couple of original npc ideas. Better luck next time, I guess...

 

Toshi does 18-bit style
Toshi has produced us an excellent demo this month of the graphical style. How does quasi-18-bit colour sound to you? Pretty friggin' good. That's what I thought. ^_^

Anyway, this demo does 18-bit color (which, if I'm not mistaken, is the same that comes out of your tv) and it looks REALLY nice, not to mention that it uses little memory. A major drawback is it's lack of speed, though. Check it out.

 

Oops!
Whoa. heheh. We made, umm.., a couple of mistakes last month. Of course, we're going to use Bill Clinton tactics to get out of them.
* Apologies to MA SNART. The day we released the mag, it was discovered that Thav's name was credited to the article he wrote. This was, however, corrected the next day. Obviously the fault of a partisan C++ commitee.
* We said that syn nine's next game, Vampira, used voxels. We did, however, forget to mention that only the battles (as far as we can tell) use voxels. Wait! Define "voxels"!
* We also mentioned that DA2 would be a first in qb for using svga technology. LordQB corrected us, rightly, as there were a couple of lesser-known (and complete) games using svga from a year or so back. None of these ever became qb legends, however. Umm..."qb:tm has never had gameplay relations with those games. Honest".
* Finally, in our review of SFB2 a couple of issues back, we wondered why the game didn't use it's "3d" engine to fight in 3d. The reason for this was because the game only used scaling 2d primitives, and not true 3d (fooled us, though!). Recent popularity ratings have shown that the American people think we are doing good at our job and that you people should stay out of our personal articles anyway! (or something like that ^_^)

 

Xeno, Project RT, DA2, the universe, and everything!

Latest Game updates:
I'm sure all of you went to go grab the demo of the "top secret" project "XENO" from last month from MA SNART. This demo featured a frog graphic who showed off a lush polygonal world, completed with scrolling background and palette rotations. But that's not the best part: The Xeno engine source has been released! If you've always wanted to see some nice 3d pre, pick this up. Now. I'll try to bring more on the plot/style of the game the Xeno engine is being used for next month.

 
 

 
Peanut Patrol, a side-scroller platform game by NutzBoy is on the verge of it's second demo. With many levels of Mario-style design already written, plus some nice enemy AI pre and a good graphical style, this is one to look out for.

A clone of Zelda I from the Nintendo Entertainment System is in the works! Killian and the people over at Future Software are working on the project, which will be an exact reproduction in full qb of one of the greatest action/adventure games of all time. Based on early screenshots, the game looks to be coming out very well. It looks like the shots we're taken off of the emulated version! Pay attention to this game...it's gonna be hot!

Hmmm....what's this game? Oh...Charter Magica. Yay. Anyways, this action/adventure in development by...errr...me, is coming along well and should have a demo out around the time of the next issue. The game already features 144 maps complete with 7 enemies, full enemy AI, sword swings, and a rotating palette! Super-cool! Anyways, you can get more on the game by clicking the little "Grand Scimitar" button in the frame to your left.

Entropy has quite a few projects in the works. A demo has been released for his major project called "THEM". This project has been put on hold for a little bit, but looks to have quite a good look to it as of now. We anticipate this title fairly highly.

Wow! Have I heard a lot of speculation about Project RT! Angelo and company must be doing a good job keepin' their secret because no one has guessed right as to what Project RT will be. ^_^ Anyways, we'll continue to pester Angelo and Petter until they're forced into submission. Hopefully, more in this section next month.

Here are this month's sound bites: Dark Ages 2, our feature from last month, is coming along well. The game packs it's wicked scrolling engine, and great graphics by Gavan. Sometime near when you're reading this, expect a technology demo to show off the basic engine (although it is stressed that this is NOT the "real" demo!). New screen shots, such as one of a beach scene, are up now at The DA2 homepage... Looking for a way to save memory with EMS but don't want to become a "lib person"? In addition to Entro's work, you can try the trusted and true QBV by Pasco, and get the glory without the disgrace ^_^. Pick up QBV at Pasco's Page... FrozenEmu has a great project in the works in his game "Untitled RPG". The title may not be the best, but the game has a cool anime look to it, and even some gameplay already (although it's still demo form)! The game promises to play like Final Fantasy Tactics ... finally, Jaws-V is the man! If you haven't played Cookie Delivery, go get it now. It's not an epic quest of a young hero; it's the story of a ghost-smashing cookie delivery girl. And it rules.

That's all the latest news for this month. Remember, if you have any news or rumours, send them along to Qbasic: The Magazine

 

Back to Top

Input: Your Stuff

By ZKman

 

 

Here's what you had to say about last month. Be sure and send us more letters soon!

Contrary to something mentioned in your article, many games have already been released in SVGA, such as Zoltrax, and non-RPG games like the completed Meteor Attack.

LordQB

Correct you are! Dark Ages 2 won't be the first qbasic game to be done in svga and completed. However, it will definitely be the first to have widespread distribution.

 

  After reading your latest issue, I have a few things to say. First off, some of your info seems a little... well... incorrect. I may just have been misinformed, but I don't think synnine's RPG, vampira, uses voxels. It's just a 3/4 perspective game. When I think of voxels, I think of real-time 3-D landscapes. As you said, a voxel is a volumetric pixel, which is used to quickly draw an area of a 3D landscape (at least, that's what I've heard). Also, as far as I know, vampira uses tiles. So, there's no reason for synnine to plot voxels when he an just PUT tiles. Another error on your part is about The Labyrinth, by SEAV. It is not DD's engine! If you had read SEAV's awesome site, you would have known that he is writing all of his own ASM routines so it runs much smoother and faster. I know you never actually said the two engines were the same, that is easily implied. Plus, SEAV's engine is much more advanced, and uncomparable to DD's.The rest of the info in the issue seemed valid, but unfairly distributed. You're message that Eldim had been delayed was hard to see, while it should have stuck out, and I would hardly consider it breaking news, as Enigma announced it close to a week ago. And regarding Pasco's projects, you didn't mention QBV, his graphic routines that allow virtual pages without the use of libraries. Iwould consider this to be bigger news than yet another "secret project" that will probably never be finished or revealed. Now, I just have a few things to say about your layout. To be frank, I hate it. Four frames?! And the latest news gets about 4 squareinches. I would suggest leaving the top-left frame as is. Either removing the articles list and linking to it from the left frame, or moving it to the right of the main portion. And putting the news inthe main portion. So you'd end up with two or three frames: left, main, and possible right.Also, I suggest changing the text color from grey to white, and changing the font to Verdana or Arial. Just my opinions.

Entropy

hmm....some valid concerns. First, about syn nine's rpg Vampira. We mentioned it uses voxels, but neglected to say that it uses them ONLY in the battle screen (as far as we've been informed). Sorry about the oversight. As for Seav's routines, we know they are much smoother than DD's, but they are still a first-person, tile-based engine, which is what DD wrote. Although I look forward greatly to labyrinth, as the gameplay of course is not comparable to a DarkDread game; it's better.

About our web site layout, we hope you like the "new" look. It's a bit cleaner than the admittantly somewhat cluttered old layout. As you may have noticed, we do use White Arial for the issue, but for the other pages, which involve less "reading", we are keeping the old colors.

 

 

 

ZKMan, Wow ! QB:tm was damn good this issue. Well done for a great publication. Now here's the question: Can I mirror the mag on my site QBNews qbnews.8m.com please ? I need the hits and can provide it over 8m's fast servers. I think this would benefit both of us in the future.Oh yeh. Can I just write an article and send it in ? I have some cool ideas for one Cheers,

Ice1000

We've had a couple requests for mirror sites. Unforunately, we're not very interested at this time. However, if anyone out there wants to do a translation, that would of course be encouraged! About articles: we tend to take solicited articles only now. However, if you have a good idea and good writing talent, send me your idea and I'll take a look.

 

 

 

I think qbasic magazine is one of the best qb publications out there. It covers EVERYTHING!!!!! I had questions about qb and since reading Qbasic Magazine for the first time and all my questions have been answered. I was just wondering: could I please add a link to your site from my site? In case you want to, click on here to visit my site. Well, thanks for considering and keep up the good work!

Anonymous

Of Course! Feel free to link us. Right now, you'd have to use a text link, but I should have banners up within the week that this issue is released in 3 sizes. Check ya later.

 

 

 

I think you should have downloadable zip files that contain the html file and all the images. That way, you could download them for 'offline viewing'.

Anonymous

hmm...we did do a downloadable version of qb:tm in Issue 3. However, we've dropped that in favor of printable versions. However, as I said in the Letter from the Editor, if you bombard me with mail, I might change my mind ^_^

 

 

qbasic: the magazine reserves the right to edit any letter recieved for purposes of clarity and space. But you already knew that.

 
 

Here's the results of the fourth survey from Qbasic: The Magazine! We need more people to Vote! So do it!

 Favourite Game     |  Last Month  | Change    
 1. Wetspot 2              1           <> 
 2. Dark Ages              2           <> 
 3. SFB2 (t)               3(t)        <>  
 3. Mystic. Journey (t)    --          --
 3. Soccer (t)             --          -- 
    
 Comments: Best game list stays pretty much
   the same. Monospace Shooter and Groov 
   Buggies were replaced by The Mystical 
   Journey and Pasco Soccer.

 Favourite Utility  |  Last Month  | Change
 1. DirectQB               1           <>
 2. DashX (t)              2(t)        <>
 2. Qmidi (t)              -           --
 2. PP256 (t)              -           --

 Comments: Also, very little change on this
   list, although dqb pulled WAY ahead of 
   Dash. Dash supporters, where are you? 
   PP256 makes the list for the first time 
   this month.

 Best Upcoming      |  Last Month  | Change
 1. Dark Ages 2            1           <> 
 2. "Project RT"           2(t)        <>
 3. Labyrinth (t)          -           --
 3. VSPaint (t)            -           --
      
 Comments: DA2 and Project RT controlled 
   the voting this month, and we finally 
   have stability in the Best Upcoming list
   ^_^! Some surprises not making the list 
   include Wrath of Sona, Groov 2, Soccer
   and Mario Clone.

Vote today by emailing your votes for:
favourite game
favourite utility
Game/utility that you're most looking forward to.
Send your vote here

 

You need this stuff!

Must Downloads returns for another showing. This month, no changes were made to the list, although the demo and source of "Xeno" was very close to being included. Everyone knows that there are a god-awful amount of qb games out there, but what's worth downloading? These, my friend. Here, you'll find a list of the best of the best in QB progs. See something that should be here? Tell us and we'll check it out. You HAVE to have this stuff!

 
Absolute Assembly
Petter Holmberg of Enhanced Creations's assembly converter. By typing in normal asm, this proggy will convert the asm into goods that qb will understand. Super-spiffy!

Dark Ages
One of the most engaging QB games ever, as well as one of the only complete rpg's. This was featured in PC Gamer! Check it out!

Groov Buggies
The best QB racer ever. Although it has some control problems and some clipping glitches, this wireframer set a new standard.

Lianne...in the Dark Crown
Darkdread best and most complete game. Many hours of gameplay, and featuring a battle system that's been imitated in countless qb projects since. Not to mention you get cat food from the enemies!

Monospace Shooter
Gradius' 2 color side-scrolling space shooter. Featuring very detailed enemies, flickerless animation and a devious AI, this game is a classic

Wetspot & Wetspot 2
Wetspot, the bubble-bobble like block-pushing action game was one of the best QB games when it came out, but W2 is just incredible. Super midi sound, great fast graphics, tons of variety, an insane number of levels...everything you could want. GET this game. Now.

SFB2
One of only 2 fighters in QB (the other being Sphere Fighter) this newly released game is Super-fab. Even though it's wireframe, it has cool particles and smooth animation as well as rippin' gameplay.

PP256
Called the best tile editor in QB ever, PP256 has loads of tile-editing options at your disposal. If you use tiles in your game, you can't live without this.

DirectQB/DashX/Blast!
These 3 sets of libraries take QB graphics to the extreme. They all have strenghts and weaknesses, but you should check them all out before you start a big project. You'll save a lot of coding plus get a big speed increase (and in DQB's case, save memory). Try these now.

QMIDI4.1
This is the best version of Qmidi. Play .mid's in your game! The new qmidi4.1 rules! It has tons of features and a "light" version. Get it now!

Pb3d
Marko Dokic's 3d routines. Phong shading, gourard shading, environment mapping, you name it- it's here. If you want to see how to do good 3d, come here!

 

All Basic Code
 

This month's site of the Month is probably the biggest collection of qbasic source in existence. More than 1200! programs are housed here, released in "packets" every few months. Whatever you need can be found here: dqb, Huffman Compression, AI routines. And all qbasic.

The site I'm talking about is All Basic Code Homepage. This hugely popular site in some circles is a fantastic resource and the qb:tm Site of the Month for Issue 6. Congratulations!

ABC Packets Rules. End Story.

Back to Top

assembly tutorial

By Petter Holmberg

More assembly: Served Fresh every month...

Hi!
it's time for the third part of my assembly tutorial. I've had some very positive response to the two earlier parts, mainly form people saying it's the first assembly tutorial they've read where they understand everything. I'm glad to hear this, because that was my intention with this tutorial series. There are too many texts that explains things in such a hurry that you have a problem understanding it.

 

 

In the previous part of this tutorial, I showed you how to use my program Absolute Assembly - with a little help from Microsoft's DEBUG - to make an assembly routine run in QBASIC. Using that knowledge, we can now start writing assembly pre and see it run. In order to do that we need to know more assembly instructions, so that's what this part mainly is about. When you've read through it you will have enough knowledge to start making your own experiments. But first, let's repeat the important parts from the last time!

the registers:
As discussed in the last part of this tutorial, registers are an important part of assembly programming. Registers are memory cells in the CPU that keeps track of numbers important to the computer. Some of them has specific tasks to perform, while others can be used freely by the assembly programmer. There are four basic registers that you will use often: AX, BX, CX and DX. They work like integer variables in QBASIC. There's also a register called DS, used to store a memory segment address when reading/writing from/to the memory. The two registers SI and DI are used to store the offset address. There are other important registers that still has to be discussed, but We'll get to that later on.

the stack:
The stack is an important part of assembly programming. It's an area in memory allocated by the program as a place to store temporary values that can't fit into the registers. A register can be put on the stack with the assembly instuction PUSH. It is returned with an instruction called POP. The stack has to be properly maintained, or else the program will most likely crash. When writing assembly routines in QBASIC, the stack must be in the same state before and after the routine was called. Two specific stack registers were discussed: SP and BP. More about the stack will be discussed in this part.

MOV:
The most universial of assembly instructions, MOV, was also explained. This is the assembly instruction used to exchange values between the registers and the memory. MOV is used very frequently in assembly programs as you soon will see.

I also introduced a sequence of four assembly instructions that you will use a lot in the future:

PUSH BP
MOV BP, SP
POP BP
RETF

They will be the base for many of the assembly routines that you will write, and you will soon understand why.
Now it's time for more assembly instructions:

arithmetic operations:
One of the most primary requirements a programming language must fulfill is the ability to perform calculations on numbers. Since assembler is a direct translation from machine language, the language of the CPU, it naturally has assembly instructions for the most primary arithmetic operations. First of all, you must have the ability to perform additions and subtractions between numbers. This is pretty easy to do in assembler. The instructions needed are ADD and SUB. I believe it's pretty clear what they stand for. The general syntax for these instructions are:

ADD Destination, source

And:

SUB destination, source

Just like with MOV, the destination is where the result of the operation is placed. It can be a register or a pointer to a memory address. The source can be a register, a memory pointer or a direct value. Let's consider an example: If you would like to see the result of a subtraction of 4 from the value 5 in the AX register, you could test it like this:

MOV AX, 5
SUB AX, 4

The number 5 gets into the AX register with MOV, and then it's subtracted by 4 using SUB. The result, 1, will be in the AX register. Another example: Let's imagine you want to add 2 to the byte value at memory address 3:3, and put the answer in the CH register. Then you could write:

MOV BX, 3
MOV DS, BX
MOV SI, 3
MOV CH, (SI)
ADD CH, 2

As explained in the last part of this tutorial, the first four lines are an example of reading a byte from the memory and putting it into a register. The ADD instruction then adds 2 to the value located in CH.

There are also two special case instructions for additions and subtractions. If you only want to add or subtract the number 1 from a value, you can use the instructions INC or DEC (short for Increase and Decrease). These instructions are performed faster by the processor than ADD and SUB, at least by older processors. They are also very easy to use. They only take one argument: The destination. It's recommended that you use INC X/DEC X instead of ADD X, 1/DEC X, 1. An example: You want to increase the value in the AL register with 1. The you just type:

INC AX
Could it be any easier?
There are more things you probably want to do. How about multiplications and divisions? Well, you can certainly do that too, using the instructions MUL and DIV. They are a little harder to use though. The MUL instruction only takes one operand, like this:

MUL source

The source cannot be a direct number, it has to be either a register or a memory pointer. If the source value is an 8 bit number, it will be multiplied with the value in the AL register, and the answer gets into the AX register. This is because the product of two 8 bit numbers can be 16 bits long. For example, suppose we want to multiply 100 with 200. We can do that like this:

MOV AL, 100
MOV DL, 200
MUL DL

The result, 20000, will fill up the whole AX register since it wouldn't fit into one byte. What about 16 bit numbers then? Well, since DEBUG cannot handle 32 bit registers, the solution looks somewhat different. If we use a 16 bit number as source, it is multiplied with the whole AX register and the result goes into DX:AX. That means that the high 16 bits goes into DX and the low 16 bits goes into AX. In many cases you, the programmer, knows that a multiplication won't have a product that exceeds 16 bits, so you can ignore the DX register. But if you have an important number in the DX register before the multiplication it will be lost anyway. Division is similar to multiplication. The syntax for DIV is:

DIV source

Like with MUL, the source must be a register or a memory pointer, not a direct value. If the value is 8 bits, the whole 16 bit number in AX is divided by the source. The quotient of the division goes into AL and the remainder into AH. If the value is 16 bits, the number in the DX:AX register pair is divided by the source and the quotient goes into AX and the remainder into DX. This tells us that DIV can only perform integer division, like the \ sign in QBASIC, which is unfortunately true. For the sake of clarity, let's make an example: We want to divide 5 by 2, which would result in a quotinent of 2 and a remainder of 1. Let's try it:

MOV AL, 5
MOV DL, 2
DIV DL

Now the number 2 would be in AL and the number 1 in AH. As you can see, multiplications and divisions are trickier than additions and subtractions. Multiplications and divisions are also very slow compared to additions and subtractions. If you want to make a really fast assembly routine, try to avoid MUL and DIV as much as possible. One of the tricks to do that will be showed later.

There's also another thing about multiplications and divisions I have to tell you about. The MUL and DIV instruction only works with unsigned values, which means values that are positive. If you want to do multiplications or divisions with signed values, values that are negative, you must instead use the instructions IMUL and IDIV. They work with both positive and negative numbers, and works in the same way as MUL and DIV. But if you know that you only have positive values, use MUL and DIV for clarity purposes. That was the important stuff about arithmetic operations in assembler.

Logical instructions:
There's another set of instructions that are very important in assembler: The logical instructions. They are not as easy to understand as the arithmetic ones, but they are extremely useful. These instructions also exists in QBASIC, so you can easilly play around with them in order to understand how they work.

There are four arithmetic instructions in assembler: AND, OR, XOR and NOT. They have the same names in QBASIC. The processor has no problems executing these instructions, because it works with logical instructions for almost everything it does. Basic operations like additions and subtractions are performed as a series of logical instructions within the small semiconductive transistors in the CPU. Executing logical assembly instructions are therefore also one of the fastest operations the CPU can perform. Let's begin exploring These instructions!

Logical instructions doesn't treat the numbers in the computer as numbers, they operate on the individual bits in the number. So you won't understand the logical instructions if you look at what happens to the numbers you pass to them. You must study the individual bits.

The first logical instruction we will look at is NOT. It's a little different from the other three, and it's also the easiest to understand. NOT inverts all the bits in a number. So if you perform a NOT on the binary 8 bit number 00001111, you will get the result 11110000. If you NOT the number 10101100, you get 01010011 and so forth. The NOT instruction only takes one argument:

NOT destination

The destination can be a register or a memory pointer. The other three instructions, AND, OR and XOR, takes two arguments:

AND destination, source
OR destination, source
XOR destination, source

AND works like this: The destination value is compared bitwise against the source value, and only in the case where both corresponding bits are 1, the result will be 1. Otherwise it will be 0. So if you AND the value 11110000 with 10101010, you will get the result 10100000. 11001100 AND 10101010 will give the result 10001000 and so forth. The name of the instruction can be used as a remainder of its use: If bit A AND bit B is a 1, the result will be 1. Otherwise it will be 0.

OR is similar to AND, but it works in the opposite way. If both bits are 0, the result will be 0. Otherwise it will be 1. Or you can also say that if at least one of the bits is 1, the result will be 1. 11110000 OR 10101010 is therefore 11111010, and 11001100 OR 10101010 is 11101110. If you want to use the name as a remainder, you can say that if bit a OR bit b is a 1, the result will be 1. Otherwise it will be 0.

XOR is perhaps the most interesting logical instruction. The names stands for eXclusive OR. It works like OR except for one detail: If both bits are 1, the result is 0. You can also say that the two compared bits must be different if the result should be a 1. 11110000 XOR 10101010 is therefore 01011010, and 11001100 XOR 10101010 is 01100110. If this has made you dizzy, we better summarize the four logical instructions in a table:

    AND:          
-----------  
0 AND 0 = 0  
0 AND 1 = 0  
1 AND 0 = 0  
1 AND 1 = 1  
    OR:
-----------
0 OR 0 = 0
O OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1
    XOR:
-----------
0 XOR 0 = 0
O XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
    NOT:
-----------
NOT 0 = 1
NOT 1 = 0

Now, what use can we have for logical instructions then? Well, there are several neat things you can do with them. AND can be used as a filter if you only want to read special bits in a number. For example, if you have a number in the AL register and you want to take away the four highest bits in the number. Then you only AND it with the binary number 00001111. Let's suppose the number in AL was 10010011. The result will then be 00000011. Notice how the four high bits have been filtered away. If you check the table above you can probably figure out why this works.

We covered the binary numbering system in part 1 of this tutorial, and if you remember it, you know that the bits in a binary number are "worth" 1, 2, 4, 8, 16, 32, 64, 128 and so forth if you count from right to left. Notice how only one of these numbers are odd? That's right: the first one. This implies that if a number is odd, it MUST have the binary digit worth 1 set. With a little help from AND, you can then test if any number is odd. Let's test the number 5. 5 in binary is 00000101. If we AND this with 00001111, we get the result 00000001. The result is 1, so 5 must be odd. If we test 10 instead, we get: 00001010 AND 00000001 = 00000000. The result is 0, so 10 must be an even number. Test this in QBASIC!

XOR also have some nice uses. One of the most common ones uses the fact that if both bits compared with XOR are the same, the resulting bit is 0. This means that if you compare a number against itself, the result must always be 0 no matter what the number is, because all bits always are the same. For example, 11001100 XOR 11000011 = 00000000. This works no matter what number you use. Remember what I said about the speed of logical instructions? These two facts together suggests that:

XOR AL, AL

is faster than:

MOV AL, 0

And that is certainly true! At least with older processors. This trick is often used by assembly programmers. Rather than just setting a register to 0, you XOR the register with itself, thus getting the same result faster. XOR can also be used for very simple data encryption. Take any number and XOR it with a number X. You will probably get a result that makes no sence. If you then XOR it again with the same number X, you get the original number back! Cool, huh? Let's test it: We have the top secret number 10011011. Now we use the secret pre key 10110110 to encrypt it, using XOR. The result is 00101101. you can't se any connection to the original number, can you? Then we "unlock" the number with our pre key and XOR again. The result is now 10011011. Wow! Our secret number is back! Of course you won't see Pentagon using this not too sophisticated encryption scheme for their secret documents, but maybe you'll have some private use for it? Test this in QBASIC too and make sure I'm not lying to you!

Shift and rotation opertations:
Finally I thought I'd go through another part of assembly programming: Shifts and rotations. These operations also work with the individual bits, and they also have the nice properties of being really fast, just like the logical instructions.

I'll begin by explaining shifts. Shift instructions are not too hard to understand. Their purpose is to move all the bits in a number a certain amount of bit positions in a certain direction. There are two basic shift instructions SHL and SHR, short for Shift Left and Shift Right. If you have the binary number 00111001 and shift it left one position, you get the number 01110010. If you shift it right one position, you get the number 00011100. Get it? It's like taking away one bit at one end of the number, move all the others one step to fill up the hole, and put a 0 in the empty place at the other end.

The shift instructions are not too hard to use. The basic syntax for the two shift instructions are:

SHL source, count
SHR source, count

The source can be a register or a memory pointer. The count value tells the CPU the amount of bits to shift. Here comes a little quirk though: The 8086 processor only allowed the count to be the number 1 or the contents of the CL register. The instruction SHL AL, 2 was therefore not valid. Later Intel processors can use any direct number. BEBUG however, only supports the basic 8086/8088 assembly instructions, so we must use the CL register if we want to shift a number more than one bit position. If we want to shift the contents of the BH register four steps to the right, we must then type:

MOV CL, 4
SHR BH, CL

What can we use shift instructions to then? Well, there's a very neat use for it that often comes in handy. Remember what I said about the slowness of multiplications and divisions? Well, certain multiplications and divisions can be done with shift instructions, making them even faster than additions and subtractions! In the binary world, you double the value of a bit if you move it one step to the left. The binary number 100 is two times as big as the number 10 and so forth. Therefore, shifting a number one step to the left is the same as multiplying it by two. If you shift it two steps you multilply it by four and so on. So if you want to multiply a number with 2^x, for example 128, you can use a SHL instruction instead. Let's try it! Suppose we want to multiply the number 10 with 8, you can either type the slow:

MOV AL, 10
MOV DL, 8
MUL DL

Or, you could type the much faster:

MOV AL, 10
MOV CL, 3
SHL AL, CL

Get it? The same goes for division, but then you use SHR instead. The only thing you have to watch out for is that the shift instructions may push some ones over "the edge" of the register, and then you will get an incorrect answer. So make sure the numbers you want to multiply doesn't get bigger than 8 bits. Or 16 bits if you're dealing with bigger numbers.

Rotations works like shifts, but they don't throw away any bits. The bits that disappears on one side of the number, are put on the other side. So if you rotate the number 10100110 two steps to the left, the result will be 10011010. The 10 that was pushed away at the left edge, are moved to the new, empty spaces at the right edge. A rotation of a byte eight steps in any direction would not modify the byte at all because all the bits would be rotated to the same positions that they were at from the beginning. The two instructions needed are ROL and ROR, short for Rotate Left and Rotate Right. The basic syntax is exactly the same as for SHL and SHR, and the count value can be either 1 or the contents of the CL register. If you want to rotate the byte in AL four steps to the right, you simply type:

MOV CL, 4
ROR AL

Passing values between QBASIC and the assembly program:

Okay: Now We've been going through 16 basic assembly instructions: ADD, SUB, INC, DEC, MUL, IMUL, DIV, IDIV, AND, OR, XOR, NOT, SHL, SHR, ROL and ROR. With these at your hand you can do many things. Now you probably want to test this in reality, using QBASIC. But there's no way you can watch the results of these calculations in QBASIC yet. Therefore, we must learn how to pass variables between QBASIC and assembly routines.

Last time, you saw how an assembly routine could be called with the CALL ABSOLUTE keyword. The syntax for CALL ABSOLUTE is:

CALL ABSOLUTE(offset)

Where offset is the offset address of the string/array that contains the machine pre you want to execute. The segment address must be set with a DEF SEG before the call. If you want to pass variables to the routine, you do so by putting them before the offset specification. This is what I mean: Suppose you want to pass the integer variables a% and b% to the assembly routine. You then type:

CALL ABSOLUTE(a%, b%, offset%)

This will ensure that the a% and b% variables are passed to the assembly routine. Exactly how this works will be explained in just a minute. First I must point out that CALL ABSOLUTE can only pass variables of the type INTEGER. LONG variables, SINGLE and DOUBLE variables, strings, user data type variables and arrays can NOT be passed to your assembly routines. If you have the need to do that you must instead pass two integer variables, describing the segment and offset address of the variable you really want to send.

How can you read the variables in your assembly pre then? Now it's time to look back on the four golden lines that were presented in the last part:

PUSH BP
MOV BP, SP
POP BP
RETF

When QBASIC executes a CALL ABSOLUTE instruction, the segment and offset address of the next QBASIC instruction is pushed onto the stack. That is 4 bytes. If you add variables to the CALL ABSOLUTE line, these are also pushed onto the stack, BEFORE the BASIC segment/offset pair. They are pushed in the order they appear inside the parantheses after the CALL ABSOLUTE statement. Now, the first assembly instruction above pushes the BP register onto the stack. BP tells the program on what offset the bottom of the stack is located. Then, the contents of SP is copied into BP. SP tells the program where the top of the stack is. Now the computer thinks that the stack starts in the end. This comes in handy, because it is possible to fetch a byte from the memory like this:

MOV BX, (BP)

If we use the BX register as destination, we can get the two bytes located at the memory position SS:BP. The SS register is a new register to you. It contains the segment address of the stack. It's rarely used by assembly programmers though. Anyway, it is also possible to get the two bytes at a position RELATIVE to SS:BP. Let's say we want the word (a two byte number is called a word in assembler) 5 bytes above SS:BP. We then type:

MOV BX, (BP + 5)

If we want the word 8 bytes below SS:BP, we type:

MOV BX, (BP - 8)

Now, remember that I said last time that the stack is like a stack of plates turned upside-down, i.e. the stack grows DOWNWARDS as you push values onto it. The values already pushed on the stack are thus at higher memory adresses than the current SP value. Since we put the contents of the SP register in BP, we can now find our variables by searching at memory addresses above SP:BP. The current value of BP points at the value that was last pushed onto the stack. We just pushed the original BP value, so that's what We'll find that. At BP+2, we'll find the next value. Before QBASIC gave our assembly routine the control of the program flow, CALL ABSOLUTE pushed the segment and offset of the next QBASIC instruction onto the stack, so on BP+2 and BP+4 you'll find these values, numbers that are of no interest to us. It is after that, at BP+6 and above, that we'll find our variables. If you wrote:

CALL ABSOLUTE(myvariable%, offset%)

myvariable% would be located at BP+6. If you wrote:

CALL ABSOLUTE(x%, Y%, z%, offset%)

x% would be at BP+10, y% at BP+8 and z% at BP+6. This may sound confusing, but QBASIC pushes the variables in the order they appear inside the parantheses. x% will therefore have the highest memory address in the stack. The last variable will always be the closest one to BP. If you use PUSH in your own assembly pre, you can read them without using POP in the same way you read the QBASIC variables. The first value you push will be at BP-2, the second one at BP-4 and so on.

Let's suppose you want to get the value of the variable x% into the AX register. Then you only type:

PUSH BP
MOV BP, SP
MOV BX, (BP + 6)
MOV AX, BX

Right?
Wrong! You will discover that the value in AX is not the value you had in the x% variable in QBASIC. Why?

As if our problems weren't enough, QBASIC hasn't passed the value of x% to the stack. The number at BP+6 is the OFFSET addres of the x% variable in the memory. This makes things a little harder to grasp, but as you'll see, this can be very useful.

But first, let's solve this new problem in QBASIC. If you use the QBASIC BYVAL clause before the variable, your problems will be solved. This is what I mean:

CALL ABSOLUTE(BYVAL x%, offset%)

Now, QBASIC won't push the offset of the variable x% on the stack. It now pushes the actual value of x%. Now you can use these lines to get the value of x% in the AX register:

PUSH BP
MOV BP, SP
MOV BX, (BP + 6)
MOV AX, BX

Wow! Now we can pass variables from QBASIC to an assembly routine. Now we can use ADD, OR, SHL or any other instruction to modify the values in cool ways. Well, even if that's certainly true, we won't have much use for it if we couldn't pass the modified values back to QBASIC again. How can we do that then? Well, we need to know the memory addresses of the QBASIC variables from within our assembly routine in order to change them. If we just let QBASIC push the values of some variables onto the stack, we can read them, but we cannot return any values, because we don't know where the variables reside. This is the reason QBASIC as default pushes the offset of the variables instead of their values. Let's try to solve the problem without using BYVAL:
it's actually not that hard to get the value of variable x% into AX without using BYVAL. We only need some extra brackets on the final row:

PUSH BP
MOV BP, SP
MOV BX, (BP + 6)
MOV AX, (BX)

Now, the third line won't get the actual value of x%, but the offset address where x% can be found. BX now knows where the variable is. The last line doesn't just copy the value of BX like before. Now it gets the word located at the MEMORY POSITION pointed out by BX. Wow! That's the value that was in x% from the beginning! Are you getting dizzy yet? ;-) If you're confused, just read the last lines again and again until you get it.

Now you know how to get values of QBASIC variables into a registers both with and without BYVAL. When your assembly routine only needs to read values from QBASIC, you can use any of these two methods. I usually use BYVAL, Because it's easier to read the values from the assembly pre then. When you want to pass values back to QBASIC, you don't have any option: You cannot use BYVAL. Passing values to QBASIC is not any harder than to read them though. Let's imagine we want to do the opposite of the previous example of getting the value of the x% variable into AX: Getting the value of AX into x%, readable by QBASIC: You call the routine like before, but without BYVAL:

CALL ABSOLUTE(x%, offset%)

Then, you only need to type this in assembler:

PUSH BP
MOV BP, SP
MOV BX, (BP + 6)
MOV (BX), AX

The only line that has been changed from the last example is the last one. Instead of getting the value at the offset of BX into AX, we now put the value of AX at the offset of BX. When the control has been returned to QBASIC again, you'll find that the x% variable has changed! Now the topic of variable passing is almost completed. Just a few more things:

First, let's return to the last two lines in the set of four lines that I showed you already in the last part of this tutorial:

POP BP
RETF

When you've done what you wanted in your assembly routine, you must return to QBASIC properly. As we pushed the original value of BP before and changed it, we must change it back before we get back to QBASIC. The POP instruction ressurects the old value. Then comes the RETF instruction. RETF, short for Return Far, will POP back the segment and offset that CALL ABSOLUTE pushed onto the stack, and jump to that memory position. The control has returned to QBASIC! But when you passed variables to your assembly routine, CALL ABSOLUTE pushed them on the stack also. RETF alone won't clean up the mess you left in the stack and QBASIC will lock up your computer when it gets the wrong values from the stack. In order to fix things up, you must tell RETF to POP away the extra words that you put there by passing variables to your assembly pre. This is easy to do. Let's say you only passed one variable. One integer variable takes two bytes, so you change the RETF to RETF 2, and two extra bytes will be popped away into cyberspace! If you passed four variables, you must take away 2 * 4 = 8 bytes. RETF 8 fixes it! And finally: Remember that you can ONLY use BX when reading values relative to the offset of BP!

An example program:
We've been going through a lot in this issue, so a short example program to demonstrate this would be a good idea. I thought we could write a simple assembly program that could add two QBASIC variables together and return the answer in a third variable. Not too exciting, but it's a good excercise. Let's begin in QBASIC: First we type in the core program:

CLS
PRINT "This program adds two numbers together 
  through an assembly routine."
PRINT
INPUT "Type the value of number 1: "; a%
INPUT "Type the value of number 2: "; b%

' We'll put some assembly pre here later!
CALL ABSOLUTE(a%, b%, c%, offset%)

PRINT
PRINT "The result of the addition is"; c%

Now we have the skeleton pre for our program. Let's start a text editor and write the assembly pre:

PUSH BP
MOV BP, SP
MOV BX, [BP+0A]
MOV AX, (BX)
MOV BX, (BP + 8)
MOV CX, (BX)
ADD AX, CX
MOV BX, (BP + 6)
MOV (BX), AX
POP BP
RETF 6

If you feel confused, here's some explanations:
The first two lines should be familiar to you by now. The two following lines puts the value of the variable a% in the AX register. This variable is located at BP+10. DEBUG handles all numbers as hexadecimal, so we cannot write 10, as it would interpret that into the decimal number 16. So we write 0A instead. Just A would have been enough, but I usually put a 0 in the beginning, just because it looks nice :-)
The a% variable now is in AX. The following two lines puts the contents of the b% variable in CX in the same way. They are then added together with ADD. Now we have the result in AX. BX then gets the offset address of the variable c%, and the contents of AX is copied to that memory position with the last MOV instruction. BP is then popped back to its old value and RETF returns the control to QBASIC, popping away 6 extra bytes to get rid of the three variables that CALL ABSOLUTE put there in the beginning. 11 lines just to add two numbers together! Well, that's as easy as it gets in assembler.

In order to make this program run, you must now use Absolute Assembly like I showed you in the last part of this tutorial. Call the pre string add$, answer yes to the question about appending the destination file and answer no to the question about adding call absolute pre to the program, and then you'll get the following QBASIC program:

CLS
PRINT "This program adds two numbers together 
   through an assembly routine."
PRINT
INPUT "Type the value of number 1: "; a%
INPUT "Type the value of number 2: "; b%

' We'll put some assembly pre here later!
CALL ABSOLUTE(a%, b%, c%, offset%)

PRINT
PRINT "The result of the addition is"; c%

' ------ Created with Absolute Assembly 2.1 by 
   Petter Holmberg, -97. ------- '

add$ = ""
add$ = add$ + CHR$(&H55)           
     ' PUSH BP
add$ = add$ + CHR$(&H89) + CHR$(&HE5)
     ' MOV BP,SP
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HA)
     ' MOV BX,[BP+0A]
add$ = add$ + CHR$(&H8B) + CHR$(&H7)       
     ' MOV AX,[BX]
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8) 
     ' MOV BX,[BP+08]
add$ = add$ + CHR$(&H8B) + CHR$(&HF)          
     ' MOV CX,[BX]
add$ = add$ + CHR$(&H1) + CHR$(&HC8)             
     ' ADD AX,CX
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6)
     ' MOV BX,[BP+06]
add$ = add$ + CHR$(&H89) + CHR$(&H7)             
     ' MOV [BX],AX
add$ = add$ + CHR$(&H5D)                      
     ' POP BP
add$ = add$ + CHR$(&HCA) + CHR$(&H6) + CHR$(&H0)
     ' RETF 0006
' ------ Created with Absolute Assembly 2.1 by 
   Petter Holmberg, -97. ------- '

Now, move up the pre declaration above the CALL ABSOLUTE line and add a DEF SEG to set the segment address of the string before the call, and you'll end up with this program:

CLS
PRINT "This program adds two numbers together 
   through an assembly routine."
PRINT
INPUT "Type the value of number 1: "; a%
INPUT "Type the value of number 2: "; b%

add$ = ""
add$ = add$ + CHR$(&H55)                       
   ' PUSH BP
add$ = add$ + CHR$(&H89) + CHR$(&HE5)         
   ' MOV BP,SP
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HA)
   ' MOV BX,[BP+0A]
add$ = add$ + CHR$(&H8B) + CHR$(&H7)            
   ' MOV AX,[BX]
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8)
   ' MOV BX,[BP+08]
add$ = add$ + CHR$(&H8B) + CHR$(&HF)           
   ' MOV CX,[BX]
add$ = add$ + CHR$(&H1) + CHR$(&HC8)           
   ' ADD AX,CX
add$ = add$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6)
   ' MOV BX,[BP+06]
add$ = add$ + CHR$(&H89) + CHR$(&H7)           
   ' MOV [BX],AX
add$ = add$ + CHR$(&H5D)                       
   ' POP BP
add$ = add$ + CHR$(&HCA) + CHR$(&H6) + CHR$(&H0)
   ' RETF 0006
DEF SEG = VARSEG(add$)
CALL ABSOLUTE(a%, b%, c%, SADD(add$))
DEF SEG
PRINT
PRINT "The result of the addition is"; c%

Notice how I exchanged the offset% variable in the CALL ABSOLUTE line with SADD directly. It's not necessary to put the offset in a variable before using it with CALL ABSOLUTE.

Test this program and you'll see that it works, at least when the numbers you add won't give a result that is above the 16 bit limit. This program can now serve as a base for more experiments. You can test all the instructions I've been presenting in this part of the tutorial with only small modifications of the assembly pre in this example. I encourage you to do so. It's the best way to learn how to use them.

Phew! That was all for this part of my assembly tutorial, the longest one so far. Now you know 20 assembly instructions: MOV, PUSH, POP, RETF, ADD, SUB, INC, DEC, MUL, IMUL, DIV, IDIV, AND, OR, XOR, NOT, SHL, SHR, ROL and ROR. You also know of 10 registers: AX, BX, CX, DX, DS, SI, DI, SS, BP and SP. There are more assembly instructions and registers to cover, but with the ones you master now, together with the knowledge on how to use CALL ABSOLUTE, you know enough to start writing some basic assembly routines yourself. There are many more things to know about assembly programming though. In the next part of this tutorial, we'll look at the possibilities to control the program flow, learn more about memory access, discover the extra features of Absolute Assembly, and finally, open the door into one of the most interesting parts of assembly programming in QBASIC, using an assembly instruction that will make you sit up for whole nights programming!

Until the next time, experiment with the new things I've presented in this part until you feel familiar with them. Now we're really getting somewhere!

Happy coding!

Petter Holmberg

 

Back to Top

cutscenes

By Enigma

 

They took up nearly 2/3rds of the 3 Final Fantasy 7 CDs. They're jam packed onto every Playstation game existing. And people were shocked when they appeared for over an hour in Zelda: The Ocarina of Time.

I cannot be talking about anything other than cutscenes. They can either be showy CGI cinematics, or real-time movement coupled with some impresive camera positions. But, are they really necessary, you question?

Hell yeah. Do all you Zelda owners remember when you walked into Kakariko Village and then saw the cutscene involvnig Shiek and a nasty little shadow enemy? Was I the only one that was duely impressed by that?
Maybe.

I mean, what better way to reward your players after hours of strenouous gameplay than with a long, involving cutscene? I personally, think it's the best way.

I dunno, this article is on a swerving track to oblivion. Maybe it wouldn't be so crappy if I wasn't in a big rush to finish this article before the deadline because I'm a procrastinating bastard child of Satan. Or maybe the topic's too vague for a loser such as moi to go into detail. Or maybe I need a shot of bourbon...oh wait, I don't drink.

-Enigma, signing off of a really lame-ass article that never should have been published (^_^...editor)

Enigma rants again... "on a swerving track to oblivion."

Back to Top

3d: Part I

By MA SNART

See! 3d's not that hard after all...umm...no, really!

Almost every video game you can buy today is presented in 'Incredible NEW!' 3D graphics. However the basics of 3D graphics have been with us long before the computer was invented. Not until recently has the processing speed been fast enough to draw the graphics in real time. In this series of articles I will show you the basics of how 3D is done in games, the concepts involved, and the limitations that have yet to be overcome.

 
 

First off there are currently two distinctly different ways for game developers to implement 3D: the extremely popular polygonal way...and the voxel way. The polygonal way is obviously used the most. Because 3D polygon objects in games don't take up a lot of PC memory, Objects can have very few polygons and as such take less time to RENDER, To get realistic results depends more on the 2D textures that cover objects. These 2D textures are easier for artists to make because they are similar in design to the 2D tiles they have made for years. There are also many ways to optimize these 3D engines by using BSP-tree techniques or 3D accelerator cards. However with many developers depending on many large texture-maps and intricate mesh designs you need quite a bit of memory to run some of the latest games...Also with the large burden on texture-mapping related techniques today's 3D game engines are still limited to how many polygons can be viewed...Also the reliance on polygons ultimately limits the ability to render organic forms... With voxels on the other hand organic forms are very easy to render. Also a 'scene' can be much more complex than a comparable polygon environment. Rendering such a scene isn't anymore of a time consuming burden than rendering a simple object [ideally]. However, a voxel model takes up a LOT of memory, in fact this is a primary reason why this form of 3D hasn't been implemented as much. But it has been used [in a limited form] as a 'landscape' render for some games, and as '3D sprites' in such games as SHADOW WARRIOR and TOTAL ANNHIALATION. And a upcoming game called OUTCASTS will use voxels in ways yet unseen in games...[sorry I'm a bit bias, I prefer voxels to polygons :)] Anyhow the concepts that follow are used by both rendering techniques.

POINTS...
Points are a very important concept in 3D graphics. Without them NOTHING can be done. POINTS come in a couple flavors: points, Vertices and Vectors. A point is just a generic term used [especially by me] for many different geometric concepts. [caution: I tend to use it interchangeley to mean a Voxel, verticy and vector]...A point is a single definable location in space. It is commonly graphed as a little black dot [and can be considered to be a single little pixel, or voxel]. Points are used to define the locations of vertices. With another point as reference to then define vectors, and are also considered reference points for OBJECT and ENTITIES locations, as well as many other assorted 3D functions.

Remember this: two points define a line [or vector] three points define a plane and three or more points on the same plane define a polygon. A Verticy is one of a number of points that define a polygon [or in Voxel graphics: it could just be considered a voxel]. Also any number of polygons can use the same verticy [this is important]. A vector is a point that is used to move [or translate and rotate] vertices [and points] from one place to another. That is, 'basically' what thay are used for. Example: [on a tile-engine] to get the player from point A [say x=10, Y=10] to point B [say X=11, Y=10) you find the difference of point A from point B [B'sX=11 minus A'sX=10 which equals 1...and B'sY=10 minus A'sY=10 equaling 0] this difference is the VECTOR. To use the VECTOR you add it to the the current point to transform it to the desired point [point A [X=10,Y=10] plus the vector [X=1,Y=0] equals point B [X=11,Y=10]]. This may seem overly obvious [and simple] but it is a very important concept to understand.

MEASURMENT...
To put it simply 3D uses three dimensions, Labeled X,Y, and Z. You may recognize X and Y from various tile engines [or sprite editors], but Z is probably new to you. To put it shortly the X dimension travels across in a left-right [or right-left] direction; this is just like graphics on all the various SCREEN modes. The Y dimension travels top-to bottom [or bottom to top] again this is just like regular 2D graphics. Then [this is the cool part] the Z dimension travels from behind you then forward into the screen [or reversed as front to back]. The biggest difference all these dimensions have with normal 2D graphics is that the measured amount can be positive [like +9] or negative [as in -7] in any one of these three Dimensions [so instead of the player being at X=20,Y=8 they can be at X=23,Y=-7,Z=-2]. In this manner the point 0,0,0 [X=0,Y=0,Z=0] is considered to be the center of the screen. With positive X [like +12] being on the right of center and negative X [like -4] being on the left of center, and positive Y [+3] is below center [bottom half of the screen]. Negative y [-14] is above center, the top half of the screen. Conversely a positive Z [+12] travels into the screen and negative Z is behind, you, the viewer [NOTE: This is not set in stone, as many games can use a reverse of the positive/negative direction of travel for one or more of the dimensions]. I used the screen to describe how the coordinate measuring system works. But to be honest this SCREEN measuring system is considered a component of CAMERA space. Fortunately this same measuring system is used, as is, for each different type of SPACE [meaning, for example, that negative Y always points to the sky and positive Z always points forward].

SPACES...
In 3D game graphics there are primarily three different spaces: object, world and camera.

The object space is simply an area that contains a unique object. An object being a 3D model of a unique game element [like the unique models for the player character, or a particular monster, and even the level itself]. Every point [be it a verticy of a polygon or a single voxel] of the object is measured, just like a vector, from the OBJECT space reference point [x=0;y=0;z=0]. None of these points HAVE to be located at 0,0,0; in fact the whole object doesn't HAVE to be anywhere near the reference point [the models in QUAKE are located above it, appearing to 'stand' on it].

The world space is the area where ENTITIES preside. Everything in WORLD space is [just like OBJECT space] a measurement from the WORLD reference point [also 0,0,0]. An ENTITY is actually what players control and interact with during a game. Each ENTITY has variables attached to it for things like location, facing vector, movement vector, rotation angles for the x/y/z axis and a POINTER to whatever object represents it [think of OBJECTS as sprites for your game. ENTITIES are then the specific monsters, creatures and effects that inhabit the world. Even if two monsters use the same set of sprites they would be considered different]. With that understanding then the first step of RENDERing: [in order to view any OBJECT that an ENTITY represents] The object [actually a copy of it residing in OBJECT space] must be transformed to WORLD space by using the attributes of the particular ENTITY. [just remember that ENTITIES have world coordinates, just like, in a tile-engine, the player has map coordinates]

Even though the camera is in essence just another ENTITY [it uses WORLD coordinates] in order for it to be used [for you to 'see the world'] the WORLD space must be transformed into CAMERA space. This is the second step of rendering [after the OBJECTS are transformed to WORLD space]. In CAMERA space [just like OBJECT and WORLD spaces] every point of every polygon and voxel is just a measurement from the CAMERA reference point [again 0,0,0]. At this step in the rendering process the third and final step can be performed...PROJECTION.

PROJECTION
But before the PROJECTION step can occur, the engine must take all the polygon data that was transformed into CAMERA space and figure out which of it is useful. It does this by doing two things:

SUB-STEP 1: This step takes all the listed [CAMERA space transformed] polygons and removes the ones that wouldn't be visible. Like those that are behind the camera or that are considered to far away. It is also at this point that polygons that are in direct contact with the camera or are partially visible are 'clipped'. In 'clipping' the engine takes the regular full size polygon and 'removes' the unwanted portion. This 'visible' polygon list is then sent to SUB-STEP 2[the 'Z-buffer']

SUB-STEP 2: This is commonly called a z-buffer [NOTE: by doing some pre-runtime calculations and other tricks [this step may not be needed]. Basically what happens is that the polygon list that ends up here gets sorted into a list that re-orders the polygons from those farthest away from the CAMERA to those nearest to the CAMERA [along the Z dimension]. This is done so that, when they are drawn, those farthest away are first followed, in order, by those that are closer [the close ones are usually larger and need to be drawn over portions of those farther away]. At last, this new list of polygons is ready for PROJECTION.

DRAWING THE POLYGONS
The list only contains the polygons in there X,Y,Z form. Because the screen is 2D these 3D coordinates must be transformed [yet another transformation] into something the screen can use. This transformation is basically done by dividing the polygon vertices X and Y by it's Z [or screenX = vertX / vertZ and screenY = vertY / vertZ...NOTE: there is more to it then just this] It can then just go down the list drawing one polygon right after the other until done.

And when it's done it can start all over again transforming the OBJECT space to WORLD space and so on for frame number two... As, you can imagine, 3D is a very math intensive format. A lot has to happen between frames in order to 'see' what is happening in the game 'world'. However the math isn't all that complicated once broken down into it's basic concepts: rotation and translation. Next time I'll cover these core math concepts in depth.

 

Back to Top

Future of Qbasic

By Zkman

  The future of qbasic. No one can quite put a finger on exactly what the future holds. However, based on discussions with top developers and current trends in upcoming games, we can come pretty friggin' close. Here, we've identified the top 5 trends we see affecting qbasic, and also 5 things that are on their way out (or perhaps already gone). Read on...

what is the future? can qbasic survive Win2000?

 

 

TREND #1:

The third dimension. No one doubts that 3d will have the biggest impact on qbasic programs in coming years. Whether it comes in the forms of voxels (which is doubtful, because of the low amount of memory qbasic has) or polygons, 3d will shape future games. Only minimalistic flat-shaded (Lambert Shaded) games currently exist, but in the next year or two, you WILL see games with full 3d levels, gourard shading, and high-quality texture-mapping.

Where does this sudden revelation come from? As it was reported in the Hot List this month, 3d libraries are going to be coming within the year. They'll do for 3d apps what directqb did for side-scrollers. It makes them accessible to those without the years of experience required for a fast mapping loop or something of that sort. In addition, the controls for Glide can most certainly be accessed from qbasic (because they do work on DOS-based applications) and we will possibly see 3d-acceleration in some of these future games.

So whether the "breakthrough" lies in Xeno, Groov Buggies 2, or a 3d prog still in pre-coding, one game will do for 3d what DarkDread did for roleplaying. End Story.

TREND #2:

More and more libraries! So, ya think Blast, Dash, DashX, and dqb are enough and that qbasic won't be able to support more? Think again. The next 2 years will bring, at our estimate, another 3-5 library sets. From the already planned "Nemesis" and 3-d libraries to "all-inclusives" (i.e., those libraries which include graphical, text, sound, and loading functions), and even specialized libraries like a "graphical-effects" set (i.e., fire and starfields), you'll be overwhelmed by the choice in the coming years.

Although many may be against the idea of libraries (because they essentially allow newbies to do many things that would normally takes years to learn), qb:tm thinks that anything which will keep programmers in qbasic and bring new coders to this somewhat antiquating, but fun, languague, is a good thing.

So, if you're one who is in the "anti-library" league, your number will soon be degrading. "Professional" coders use many different libs, whether thru Win32 API's or console dev systems. These qlb's will allow qbasic to survive longer and make it possible for qbasic games to increase their quality at an ever increasing rate.

TREND #3:

Svga! This one word will affect qbasic more and more, starting with this year. Dark Ages 2 will be the first major title to use svga, although it (and, I believe, Sypharage) are running at 640x480x256, which means we're still limited to 256 colors. This will change VERY quickly, however.

16-bit, 18-bit, and possibly 24-bit color have been proven able to be done in qbasic (with 16-bit routines fairly easy to find). Right now, only veteran programmers will use high-color svga in their games, and these "hi-color" titles could begin appearing by 3rd or 4th quarter of this year. Around that time, I believe the first fast svga library set will appear; one that is accessible to the main part of the qbasic community (the current 16-bit routines are somewhat complicated to navigate for beginner/intermediates). So, the first "wave" of svga games will appear in early 2000. By 2001, Vga will be used as much as SCREEN 9 or SCREEN 7 is used today; that is, not much.

TREND #4:

EMS/XMS. No one can doubt that this will be hugely important to the future of qbasic. To put it lightly, the amount of memory qbasic "normally" has access to is VERY small. Current RPG's are barely getting by with the amount of memory they have right now. Memory is at a premium. EMS and XMS routines get by this premium by accessing megabytes of storage (mostly used for graphical arrays or (in 3d games) division and sin/cos tables) that qbasic normally can't.

Unfortunately, EMS and (especially) XMS routines are VERY difficult to write, especially for newbies. So, once again, libraries will become a greater and greater force. Hopefully, the use of these EMS libs and virtual screens will bring an end of flicker by the end of 1999. Any game released at that time with flicker will be inexcusable.

TREND #5:

Multiplay. Wetspot II across a modem? Of course not. Internet-based multiplayer Dark Ages? No way! Right now, qbasic games that are playable (and fun!) across a modem do not exist. Why is this if multiplay is so common in "mainstream" games? Because TCP/IP routines that were capable of sending/recieving packets across the internet did not used to exist! Although there were tons of LAN routines and IPX routines, TCP/IP (which is the main way of communication between modems across the internet) has not existed prior in qbasic.

That will change. Qb:tm has heard that early, working TCP/IP routines are being developed. It is predicted that modem qbasic games could show up by the middle of this year, and will be fairly common, once again, when they are incorporated into a library. The year 2000 could bring modem-play to the forefront of future qbasic projects.

 

So, the future of qbasic looks pretty bright, eh? Maybe not. Rumours are circulating that Windows2000 (formerly known as nt5.0) will not support DOS Real-mode and also will not include qbasic1.1. What does this mean? A MUCH smaller qbasic community. Most qb coders were introduced to qbasic at school or have been using it since the days of DOS. I don't think that, if it is not included on the Win2000 cd, schools will be willing to teach the language anymore. This could potentially be a bad thing for our favourite language.

But we certainly hope not! Happy coding!

5 qbasic trends soon to be gone:

#1: The RPG Crusades will slow. Although RPG's will continue to be much used, they won't dominate qbasic like they do today

#2: VGA. This will take a couple of years, but rising svga libraries will eventually relegate vga to the way it is currently used in mainstream games: Very rarely.

#3: The Lone Wolf. Solitary programmers will still be around, but their numbers will dwindle as teams from 2 (an artist and a programmer) to more start to increase in amount.

#4: All qb code. In order to "keep up", qb programmers will begin to boost their code with more and more assembly, especially for 3d applications.

#5: Regular Text. Screen 13 text is almost gone now, and will dissapear totally soon. It looks SOOOOO bad. ^_^

Back to Top

Test Machines

By Hal_8900

Everyone playtests. What about Machine Testing?

So, have you made the next Mortal Kombat game.. in QB? Incredible! Fantastic! SLOW!!!! Uh-oh, looks like you have a problem, considering the fact that your game runs at 70 FPS on your CRAY XMP. How were you supposed to know that it was slower than the 7 year itch on everyone else's machine? Sure, you could send every new version of your game to your best friend, Bob, the 486-100 guy, but that takes a lot of time, considering Bob only has a 2400 baud modem. What else can you do to insure that your game runs fine on all systems, not just your supercomputer? Well, you can build your own system!

 

 

Now, I know what you're thinking.... "build my own system? This guy is crazy!" but, really, it's not as hard as you may think. You can get a 486 motherboard nowadays for $5, and hard drives and RAM are the cheapest that they've ever been! There are also a lot of advantages to having a second computer in the house. Got a brother or sister (or spouse) that is busy typing something up on your machine? Well, you can get on your second computer, to make sure you dont miss that important email. Ever wanted to run Linux, but didn't want to screw up your good computer? Put it on your home-built! Remember, you dont need a fancy p2/450, a p-100 should be fine. You dont need a CD-ROM drive (although it would be useful), and you dont need a 19" 1024x768 res monitor! Just get the basics!

Well, heres a list of resources you can check out: Web Sites:

Always get printed catalogs from places, and look for electronics surplus, and robotics shops, they usually carry support for older systems. You should be able to find a good test machine (something around a p-100, 8 or 16mb ram) for only about 199 american dollars. Remember, this is just another way of playtesting and a good way to make sure your game will handle "lesser" systems.

 

Back to Top

next issue

By ZKman

 

Thanks for reading Issue 6! Next issue is coming on 13 January, so mark your calenders! We should have the next asm article, another part of the 3d series, a review and the second ever entry into the qbasic Hall of Fame! Who will join DarkDread? Will it be Mallard? Angelo Mottola? Danny Gump? Mike Hoopman? Class-? Also, don't forget to register your QB company with the Visionaries Exchange. Till next time... END

 

Back to Top