Hello there. My name is Denthor (Grant Smith) of the South African demo group ASPHYXIA. This is a trainer that have been writing on and off for the last few months in order to help out budding young graphics programmers. Currently there are nine tutorials in all, each with a text file and accompianing pascal source file. Also included are two or three "bonus" pascal files with various effects. I have left the files in their origional form, so they contain some local stuff which you can ignore. PLEASE LEAVE A RESPONSE! Any comments/criticisms/flames/suggestions etc are very welcome (I love getting mail!) Leave all comments to smith9@batis.bis.und.ac.za Hope to hear from you soon! -- DENTHOR, coder for ... _____ _____ ____ __ __ ___ ___ ___ ___ __ _____ / _ \ / ___> | _ \ | |_| | \ \/ / \ \/ / | | / _ \ | _ | \___ \ | __/ | _ | \ / > < | | | _ | \_/ \_/ <_____/ |__| |__| |__| |__| /__/\__\ |__| \_/ \_/ smith9@batis.bis.und.ac.za The great South African Demo Team! Contact us for info/code exchange! �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 1 ]==-- � Introduction Hi there! This is Denthor of ASPHYXIA, AKA Grant Smith. This training program is aimed at all those budding young demo coders out there. I am assuming that the reader is fairly young, has a bit of basic Std. 6 math under his belt, has done a bit of programming before, probably in BASIC, and wants to learn how to write a demo all of his/her own. This I what I am going to do. I am going to describe how certain routines work, and even give you working source code on how you do it. The source code will assume that you have a VGA card that can handle the 320x200x256 mode. I will also assume that you have Turbo Pascal 6.0 or above (this is because some of the code will be in Assembly language, and Turbo Pascal 6.0 makes this incredibly easy to use). By the end of the first "run" of sections, you will be able to code some cool demo stuff all by yourself. The info you need, I will provide to you, but it will be you who decides on the most spectacular way to use it. Why not download some of our demos and see what I'm trying to head you towards. I will be posting one part a week on the Mailbox BBS. I have the first "run" of sections worked out, but if you want me to also do sections on other areas of coding, leave a message to Grant Smith in private E-Mail, or start a conversation here in this conference. I will do a bit of moderating of a sort, and point out things that have been done wrong. In this, the first part, I will show you how you are supposed to set up your Pascal program, how to get into 320x200x256 graphics mode without a BGI file, and various methods of putpixels and a clearscreen utility. NOTE : I drop source code all through my explanations. You needn't try to grab all of it from all over the place, at the end of each part I add a little program that uses all the new routines that we have learned. If you do not fully understand a section, leave me private mail telling me what you don't understand or asking how I got something etc, and I will try to make myself clearer. One last thing : When you spot a mistake I have made in one of my parts, leave me mail and I will correct it post-haste. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Disclaimer Hi again, sorry that I have to add this, but here goes. All source code obtained from this series of instruction programs is used at your own risk. Denthor and the ASPHYXIA demo team hold no responsibility for any loss or damage suffered by anyone through the use of this code. Look guys, the code I'm going to give you has been used by us before in Demos, Applications etc, and we have never had any compliants of machine damage, but if something does go wrong with your computer, don't blame us. Sorry, but that's the way it is. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The MCGA mode and how you get into it in Pascal without a BGI Lets face it. BGI's are next to worthless for demo coding. It is difficult to find something that is slower then the BGI units for doing graphics. Another thing is, they wern't really meant for 256 color screens anyhow. You have to obtain a specific external 256VGA BGI to get into it in Pascal, and it just doesn't make the grade. So the question remains, how do we get into MCGA 320x200x256 mode in Pascal without a BGI? The answer is simple : Assembly language. Obviously assembly language has loads of functions to handle the VGA card, and this is just one of them. If you look in Norton Gides to Assembly Language, it says this ... ____________________________________________________________________ INT 10h, 00h (0) Set Video Mode Sets the video mode. On entry: AH 00h AL Video mode Returns: None Registers destroyed: AX, SP, BP, SI, DI �������������������������������������������������������������������������� This is all well and good, but what does it mean? It means that if you plug in the video mode into AL and call interrupt 10h, SHAZAM! you are in the mode of your choice. Now, the MCGA video mode is mode 13h, and here is how we do it in Pascal. Procedure SetMCGA; BEGIN asm mov ax,0013h int 10h end; END; There you have it! One call to that procedure, and BANG you are in 320x200x256 mode. We can't actually do anything in it yet, so to go back to text mode, you make the video mode equal to 03h, as seen below : Procedure SetText; BEGIN asm mov ax,0003h int 10h end; END; BANG! We are back in text mode! Now, cry all your enquiring minds, what use is this? We can get into the mode, but how do we actually SHOW something on the screen? For that, you must move onto the next section .... =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Clearing the screen to a specific color Now that we are in MCGA mode, how do we clear the screen. The answer is simple : you must just remember that the base adress of the screen is $a000. From $a000, the next 64000 bytes are what is actually displayed on the screen (Note : 320 * 200 = 64000). So to clear the screen, you just use the fillchar command (a basic Pascal command) like so : FillChar (Mem [$a000:0],64000,Col); What the mem command passes the Segment base and the Offset of a part of memory : in this case the screen base is the Segment, and we are starting at the top of the screen; Offset 0. The 64000 is the size of the screen (see above), and Col is a value between 0 and 255, which represents the color you want to clear the screen to. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Putting a pixel on the screen (two different methoods) If you look in Norton Guides about putting a pixel onto the screen, you will see this : �������������������������������������������������������������������������� Writes a pixel dot of a specified color at a specified screen coordinate. On entry: AH 0Ch AL Pixel color CX Horizontal position of pixel DX Vertical position of pixel BH Display page number (graphics modes with more than 1 page) Returns: None Registers destroyed: AX, SP, BP, SI, DI �������������������������������������������������������������������������� As seen from our SetMCGA example, you would write this by doing the following: Procedure INTPutpixel (X,Y : Integer; Col : Byte); BEGIN asm mov ah,0Ch mov al,[col] mov cx,[x] mov dx,[y] mov bx,[1] int 10h end; END; The X would be the X-Coordinate, the Y would be the Y-Coordinate, and the Col would be the color of the pixel to place. Note that MCGA has 256 colors, numbered 0 to 255. The startoff pallette is pretty grotty, and I will show you how to alter it in my next lesson, but for now you will have to hunt for colors that fit in for what you want to do. Luckily, a byte is 0 to 255, so that is what we pass to the col variable. Have a look at the following. CGA = 4 colours. 4x4 = 16 EGA = 16 colors. 16x16 = 256 VGA = 256 colors. Therefore an EGA is a CGA squared, and a VGA is an EGA squared ;-) Anyway, back to reality. Even though the abouve procedure is written in assembly language, it is slooow. Why? I hear your enquiring minds cry. The reason is simple : It uses interrupts (It calls INT 10h). Interrupts are sloooow ... which is okay for getting into MCGA mode, but not for trying to put down a pixel lickety-split. So, why not try the following ... Procedure MEMPutpixel (X,Y : Integer; Col : Byte); BEGIN Mem [VGA:X+(Y*320)]:=Col; END; The Mem command, as we have seen above, allows you to point at a certain point in memory ... the starting point is $a000, the base of the VGA's memory, and then we specify how far into this base memory we start. Think of the monitor this way. It starts in the top left hand corner at 0. As you increase the number, you start to move across the screen to your right, until you reach 320. At 320, you have gone all the way across the screen and come back out the left side, one pixel down. This carries on until you reach 63999, at the bottom right hand side of the screen. This is how we get the equation X+(Y*320). For every increased Y, we must increment the number by 320. Once we are at the beginning of the Y line we want, we add our X by how far out we want to be. This gives us the exact point in memory that we want to be at, and then we set it equal to the pixel value we want. The MEM methood of putpixel is much faster, and it is shown in the sample program at the end of this lesson. The ASPHYXIA team uses neither putpixel; we use a DMA-Straight-To-Screen-Kill-Yer-Momma-With-An-Axe type putipixel which is FAST. We will give it out, but only to those of you who show us you are serious about coding. If you do do anything, upload it to me, I will be very interested to see it. Remember : If you do glean anything from these training sessions, give us a mention in your demos and UPLOAD YOUR DEMO TO US! Well, after this is the sample program; have fun with it, UNDERSTAND it, and next week I will start on fun with the pallette. See you all later, - Denthor �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 2 ]==-- � Introduction Hi there again! This is Grant Smith, AKA Denthor of ASPHYXIA. This is the second part of my Training Program for new programmers. I have only had a lukewarm response to my first part of the trainer series ... remember, if I don't hear from you, I will assume that you are all dead and will stop writing the series ;-). Also, if you do get in contact with me I will give you some of our fast assembly routines which will speed up your demos no end. So go on, leave mail to GRANT SMITH in the main section of the MailBox BBS, start up a discussion or ask a few questions in this Conference, leave mail to ASPHYXIA on the ASPHYXIA BBS, leave mail to Denthor on Connectix, or write to Grant Smith, P.O.Box 270 Kloof 3640 See, there are many ways you can get in contact with me! Use one of them! In this part, I will put the Pallette through it's paces. What the hell is a pallette? How do I find out what it is? How do I set it? How do I stop the "fuzz" that appears on the screen when I change the pallette? How do I black out the screen using the pallette? How do I fade in a screen? How do I fade out a screen? Why are telephone calls so expensive? Most of these quesions will be answered in this, the second part of my Trainer Series for Pascal. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is the Pallette? A few weeks ago a friend of mine was playing a computer game. In the game there was a machine with stripes of blue running across it. When the machine was activated, while half of the the blue stripes stayed the same, the other half started to change color and glow. He asked me how two stripes of the same color suddenly become different like that. The answer is simple: the program was changing the pallette. As you know from Part 1, there are 256 colors in MCGA mode, numbered 0 to 255. What you don't know is that each if those colors is made up of different intensities of Red, Green and Blue, the primary colors (you should have learned about the primary colors at school). These intensities are numbers between 0 and 63. The color of bright red would for example be obtained by setting red intensity to 63, green intensity to 0, and blue intensity to 0. This means that two colors can look exactly the same, eg you can set color 10 to bright red and color 78 to color bright red. If you draw a picture using both of those colors, no-one will be able to tell the difference between the two.. It is only when you again change the pallette of either of them will they be able to tell the difference. Also, by changing the whole pallette, you can obtain the "Fade in" and "Fade out" effects found in many demos and games. Pallette manipulation can become quite confusing to some people, because colors that look the same are in fact totally seperate. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do I read in the pallette value of a color? This is very easy to do. To read in the pallette value, you enter in the number of the color you want into port $3c7, then read in the values of red, green and blue respectively from port $3c9. Simple, huh? Here is a procedure that does it for you : Procedure GetPal(ColorNo : Byte; Var R,G,B : Byte); { This reads the values of the Red, Green and Blue values of a certain color and returns them to you. } Begin Port[$3c7] := ColorNo; R := Port[$3c9]; G := Port[$3c9]; B := Port[$3c9]; End; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do I set the pallette value of a color? This is also as easy as 3.1415926535897932385. What you do is you enter in the number of the color you want to change into port $3c8, then enter the values of red, green and blue respectively into port $3c9. Because you are all so lazy I have written the procedure for you ;-) Procedure Pal(ColorNo : Byte; R,G,B : Byte); { This sets the Red, Green and Blue values of a certain color } Begin Port[$3c8] := ColorNo; Port[$3c9] := R; Port[$3c9] := G; Port[$3c9] := B; End; Asphyxia doesn't use the above pallete procedures, we use assembler versions, which will be given to PEOPLE WHO RESPOND TO THIS TRAINER SERIES (HINT, HINT) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do I stop the "fuzz" that appears on my screen when I change the pallette? If you have used the pallette before, you will have noticed that there is quite a bit of "fuzz" on the screen when you change it. The way we counter this is as follows : There is an elctron beam on your monitor that is constantly updating your screen from top to bottom. As it gets to the bottom of the screen, it takes a while for it to get back up to the top of the screen to start updating the screen again. The period where it moves from the bottom to the top is called the Verticle Retrace. During the verticle retrace you may change the pallette without affecting what is on the screen. What we do is that we wait until a verticle retrace has started by calling a certain procedure; this means that everything we do now will only be shown after the verticle retrace, so we can do all sorts of strange and unusual things to the screen during this retrace and only the results will be shown when the retrace is finished. This is way cool, as it means that when we change the pallette, the fuzz doesn't appear on the screen, only the result (the changed pallette), is seen after the retrace! Neat, huh? ;-) I have put the purely assembler WaitRetrace routine in the sample code that follows this message. Use it wisely, my son. NOTE : WaitRetrace can be a great help to your coding ... code that fits into one retrace will mean that the demo will run at the same speed no matter what your computer speed (unless you are doing a lot during the WaitRetrace and the computer is slooooow). Note that in the following sample program and in our SilkyDemo, the thing will run at the same speed whether turbo is on or off. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do I black out the screen using the pallette? This is basic : just set the Red, Green and Blue values of all colors to zero intensity, like so : Procedure Blackout; { This procedure blackens the screen by setting the pallette values of all the colors to zero. } VAR loop1:integer; BEGIN WaitRetrace; For loop1:=0 to 255 do Pal (loop1,0,0,0); END; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do I fade in a screen? Okay, this can be VERY effective. What you must first do is grab the pallette into a variable, like so : VAR Pall := Array [0.255,1..3] of BYTE; 0 to 255 is for the 256 colors in MCGA mode, 1 to 3 is red, green and blue intensity values; Procedure GrabPallette; VAR loop1:integer; BEGIN For loop1:=0 to 255 do Getpal (loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]); END; This loads the entire pallette into variable pall. Then you must blackout the screen (see above), and draw what you want to screen without the construction being shown. Then what you do is go throgh the pallette. For each color, you see if the individual intensities are what they should be. If not, you increase them by one unit until they are. Beacuse intensites are in a range from 0 to 63, you only need do this a maximum of 64 times. Procedure Fadeup; VAR loop1,loop2:integer; Tmp : Array [1..3] of byte; { This is temporary storage for the values of a color } BEGIN For loop1:=1 to 64 do BEGIN { A color value for Red, green or blue is 0 to 63, so this loop only need be executed a maximum of 64 times } WaitRetrace; For loop2:=0 to 255 do BEGIN Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]); If Tmp[1]0 then dec (Tmp[1]); If Tmp[2]>0 then dec (Tmp[2]); If Tmp[3]>0 then dec (Tmp[3]); { If the Red, Green or Blue values of color loop2 are not yet zero, then, decrease them by one. } Pal (loop2,Tmp[1],Tmp[2],Tmp[3]); { Set the new, altered pallette color. } END; END; END; Again, to slow the above down, put in a delay above the WaitRetrace. Fading out the screen looks SO much more impressive then just clearing the screen; it can make a world of difference in the impression your demo etc will leave on the people viewing it. To restore the pallette, just do this : Procedure RestorePallette; VAR loop1:integer; BEGIN WaitRetrace; For loop1:=0 to 255 do pal (loop1,Pall[loop1,1],Pall[loop1,2],Pall[loop1,3]); END; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing Well, there are most of those origional questions answered ;-) The following sample program is quite big, so it might take you a while to get around it. Persevere and thou shalt overcome. Pallette manipulation has been a thorn in many coders sides for quite some time, yet hopefully I have shown you all how amazingly simple it is once you have grasped the basics. I need more feedback! In which direction would you like me to head? Is there any particular section you would like more info on? Also, upload me your demo's, however trivial they might seem. We really want to get in contact with/help out new and old coders alike, but you have to leave us that message telling us about yourself and what you have done or want to do. IS THERE ANYBODY OUT THERE!?! P.S. Our new demo should be out soon ... it is going to be GOOOD ... keep an eye out for it. [ And so she came across him, slumped over his keyboard yet again . 'It's three in the morning' she whispered. 'Let's get you to bed'. He stirred, his face bathed in the dull light of his monitor. He mutters something. As she leans across him to disconnect the power, she asks him; 'Was it worth it?'. His answer surprises her. 'No.' he says. In his caffiene-enduced haze, he smiles. 'But it sure is a great way to relax.' ] - Grant Smith Tue 13 July, 1993 2:23 am. See you next week! - Denthor �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 3 ]==-- � Introduction Greetings! This is the third part of the VGA Trainer series! Sorry it took so long to get out, but I had a running battle with the traffic department for three days to get my car registered, and then the MailBox went down. Ahh, well, life stinks. Anyway, today will do some things vital to most programs : Lines and circles. Watch out for next week's part : Virtual screens. The easy way to eliminate flicker, "doubled sprites", and subjecting the user to watch you building your screen. Almost every ASPHYXIA demo has used a virtual screen (with the exception of the SilkyDemo), so this is one to watch out for. I will also show you how to put all of these loose procedures into units. If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith in private mail here on the Mailbox BBS. 2) Write a message here in the Programming conference here on the Mailbox (Preferred if you have a general programming query or problem others would benefit from) 3) Write to ASPHYXIA on the ASPHYXIA BBS. 4) Write to Denthor, Eze or Livewire on Connectix. 5) Write to : Grant Smith P.O.Box 270 Kloof 3640 6) Call me (Grant Smith) at 73 2129 (leave a message if you call during varsity) NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Circle Algorithim You all know what a circle looks like. But how do you draw one on the computer? You probably know circles drawn with the degrees at these points : 0 ��|�� ���|��� 270 ----+---- 90 ���|��� ��|�� 180 Sorry about my ASCI ;-) ... anyway, Pascal doesn't work that way ... it works with radians instead of degrees. (You can convert radians to degrees, but I'm not going to go into that now. Note though that in pascal, the circle goes like this : 270 ��|�� ���|��� 180 ----+---- 0 ���|��� ��|�� 90 Even so, we can still use the famous equations to draw our circle ... (You derive the following by using the theorem of our good friend Pythagoras) Sin (deg) = Y/R Cos (deg) = X/R (This is standard 8(?) maths ... if you haven't reached that level yet, take this to your dad, or if you get stuck leave me a message and I'll do a bit of basic Trig with you. I aim to please ;-)) Where Y = your Y-coord X = your X-coord R = your radius (the size of your circle) deg = the degree To simplify matters, we rewrite the equation to get our X and Y values : Y = R*Sin(deg) X = R*Cos(deg) This obviousy is perfect for us, because it gives us our X and Y co-ords to put into our putpixel routine (see Part 1). Because the Sin and Cos functions return a Real value, we use a round function to transform it into an Integer. Procedure Circle (oX,oY,rad:integer;Col:Byte); VAR deg:real; X,Y:integer; BEGIN deg:=0; repeat X:=round(rad*COS (deg)); Y:=round(rad*sin (deg)); putpixel (x+ox,y+oy,Col); deg:=deg+0.005; until (deg>6.4); END; In the above example, the smaller the amount that deg is increased by, the closer the pixels in the circle will be, but the slower the procedure. 0.005 seem to be best for the 320x200 screen. NOTE : ASPHYXIA does not use this particular circle algorithm, ours is in assembly language, but this one should be fast enough for most. If it isn't, give us the stuff you are using it for and we'll give you ours. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Line algorithms There are many ways to draw a line on the computer. I will describe one and give you two. (The second one you can figure out for yourselves; it is based on the first one but is faster) The first thing you need to do is pass what you want the line to look like to your line procedure. What I have done is said that x1,y1 is the first point on the screen, and x2,y2 is the second point. We also pass the color to the procedure. (Remember the screens top left hand corner is (0,0); see Part 1) Ie. o (X1,Y1) ooooooooo ooooooooo oooooooo (X2,Y2) Again, sorry about my drawings ;-) To find the length of the line, we say the following : XLength = ABS (x1-x2) YLength = ABS (y1-y2) The ABS function means that whatever the result, it will give you an absolute, or posotive, answer. At this stage I set a variable stating wheter the difference between the two x's are negative, zero or posotive. (I do the same for the y's) If the difference is zero, I just use a loop keeping the two with the zero difference posotive, then exit. If neither the x's or y's have a zero difference, I calculate the X and Y slopes, using the following two equations : Xslope = Xlength / Ylength Yslope = Ylength / Xlength As you can see, the slopes are real numbers. NOTE : XSlope = 1 / YSlope Now, there are two ways of drawing the lines : X = XSlope * Y Y = YSlope * X The question is, which one to use? if you use the wrong one, your line will look like this : o o o Instead of this : ooo ooo ooo Well, the solution is as follows : *\``|``/* ***\|/*** ----+---- ***/|\*** */``|``\* If the slope angle is in the area of the stars (*) then use the first equation, if it is in the other section (`) then use the second one. What you do is you calculate the variable on the left hand side by putting the variable on the right hand side in a loop and solving. Below is our finished line routine : Procedure Line (x1,y1,x2,y2:integer;col:byte); VAR x,y,xlength,ylength,dx,dy:integer; xslope,yslope:real; BEGIN xlength:=abs (x1-x2); if (x1-x2)<0 then dx:=-1; if (x1-x2)=0 then dx:=0; if (x1-x2)>0 then dx:=+1; ylength:=abs (y1-y2); if (y1-y2)<0 then dy:=-1; if (y1-y2)=0 then dy:=0; if (y1-y2)>0 then dy:=+1; if (dy=0) then BEGIN if dx<0 then for x:=x1 to x2 do putpixel (x,y1,col); if dx>0 then for x:=x2 to x1 do putpixel (x,y1,col); exit; END; if (dx=0) then BEGIN if dy<0 then for y:=y1 to y2 do putpixel (x1,y,col); if dy>0 then for y:=y2 to y1 do putpixel (x1,y,col); exit; END; xslope:=xlength/ylength; yslope:=ylength/xlength; if (yslope/xslope<1) and (yslope/xslope>-1) then BEGIN if dx<0 then for x:=x1 to x2 do BEGIN y:= round (yslope*x); putpixel (x,y,col); END; if dx>0 then for x:=x2 to x1 do BEGIN y:= round (yslope*x); putpixel (x,y,col); END; END ELSE BEGIN if dy<0 then for y:=y1 to y2 do BEGIN x:= round (xslope*y); putpixel (x,y,col); END; if dy>0 then for y:=y2 to y1 do BEGIN x:= round (xslope*y); putpixel (x,y,col); END; END; END; Quite big, isn't it? Here is a much shorter way of doing much the same thing : function sgn(a:real):integer; begin if a>0 then sgn:=+1; if a<0 then sgn:=-1; if a=0 then sgn:=0; end; procedure line(a,b,c,d,col:integer); var u,s,v,d1x,d1y,d2x,d2y,m,n:real; i:integer; begin u:= c - a; v:= d - b; d1x:= SGN(u); d1y:= SGN(v); d2x:= SGN(u); d2y:= 0; m:= ABS(u); n := ABS(v); IF NOT (M>N) then BEGIN d2x := 0 ; d2y := SGN(v); m := ABS(v); n := ABS(u); END; s := INT(m / 2); FOR i := 0 TO round(m) DO BEGIN putpixel(a,b,col); s := s + n; IF not (s 0) do begin BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead); Count := Count + 1024; end; close (Fil); end; BEGIN Loadcel ('Tree.CEL',addr (tree)); END. We now have the 50x50 picture of TREE.CEL in our array tree. We may access this array in the usual manner (eg. col:=tree [25,30]). If the frame is large, or if you have many frames, try using pointers (see previous parts) Now that we have the picture, how do we control the object? What if we want multiple trees wandering around doing their own thing? The solution is to have a record of information for each tree. A typical data structure may look like the following : TYPE Treeinfo = Record x,y:word; { Where the tree is } speed:byte; { How fast the tree is moving } Direction:byte; { Where the tree is facing } frame:byte { Which animation frame the tree is currently involved in } active:boolean; { Is the tree actually supposed to be shown/used? } END; VAR Forest : Array [1..20] of Treeinfo; You now have 20 trees, each with their own information, location etc. These are accessed using the following means : Forest [15].x:=100; This would set the 15th tree's x coordinate to 100. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Restoring the Overwritten Background I will discuss three methods of doing this. These are NOT NECESSARILY THE ONLY OR BEST WAYS TO DO THIS! You must experiment and decide which is the best for your particular type of program. METHOD 1 : Step 1 : Create two virtual pages, Vaddr and Vaddr2. Step 2 : Draw the background to Vaddr2. Step 3 : Flip Vaddr2 to Vaddr. Step 4 : Draw all the foreground objects onto Vaddr. Step 5 : Flip Vaddr to VGA. Step 6 : Repeat from 3 continuously. In ascii, it looks like follows ... +---------+ +---------+ +---------+ | | | | | | | VGA | <======= | VADDR | <====== | VADDR2 | | | | (bckgnd)| | (bckgnd)| | | |+(icons) | | | +---------+ +---------+ +---------+ The advantages of this approach is that it is straightforward, continual reading of the background is not needed, there is no flicker and it is simple to implement. The disadvantages are that two 64000 byte virtual screens are needed, and the procedure is not very fast because of the slow speed of flipping. METHOD 2 : Step 1 : Draw background to VGA. Step 2 : Grab portion of background that icon will be placed on. Step 3 : Place icon. Step 4 : Replace portion of background from Step 2 over icon. Step 5 : Repeat from step 2 continuously. In terms of ascii ... +---------+ | +--|------- + Background restored (3) | * -|------> * Background saved to memory (1) | ^ | | +--|------- # Icon placed (2) +---------+ The advantages of this method is that very little extra memory is needed. The disadvantages are that writing to VGA is slower then writing to memory, and there may be large amounts of flicker. METHOD 3 : Step 1 : Set up one virtual screen, VADDR. Step 2 : Draw background to VADDR. Step 3 : Flip VADDR to VGA. Step 4 : Draw icon to VGA. Step 5 : Transfer background portion from VADDR to VGA. Step 6 : Repeat from step 4 continuously. In ascii ... +---------+ +---------+ | | | | | VGA | | VADDR | | | | (bckgnd)| | Icon>* <|-----------|--+ | +---------+ +---------+ The advantages are that writing from the virtual screen is quicker then from VGA, and there is less flicker then in Method 2. Disadvantages are that you are using a 64000 byte virtual screen, and flickering occurs with large numbers of objects. In the attached sample program, a mixture of Method 3 and Method 1 is used. It is faster then Method 1, and has no flicker, unlike Method 3. What I do is I use VADDR2 for background, but only restore the background that has been changed to VADDR, before flipping to VGA. In the sample program, you will see that I restore the entire background of each of the icons, and then place all the icons. This is because if I replace the background then place the icon on each object individually, if two objects are overlapping, one is partially overwritten. The following sections are explanations of how the various assembler routines work. This will probably be fairly boring for you if you already know assembler, but should help beginners and dabblers alike. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The ASM Putpixel To begin with, I will explain a few of the ASM variables and functions : There are 4 register variables : AX,BX,CX,DX. These are words (double bytes) with a range from 0 to 65535. You may access the high and low bytes of these by replacing the X with a "H" for high or "L" for low. For example, AL has a range from 0-255. You also have two pointers : ES:DI and DS:SI. The part on the left is the segment to which you are pointing (eg $a000), and the right hand part is the offset, which is how far into the segment you are pointing. Turbo Pascal places a variable over 16k into the base of a segment, ie. DI or SI will be zero at the start of the variable. If you wish to be pointing to pixel number 3000 on the VGA screen (see previous parts for the layout of the VGA screen), ES would be equal to $a000 and DI would be equal to 3000. You can quite as easily make ES or DS be equal to the offset of a virtual screen. Here are a few functions that you will need to know : mov destination,source This moves the value in source to destination. eg mov ax,50 add destination,source This adds source to destination, the result being stored in destination mul source This multiplies AX by source. If source is a byte, the source is multiplied by AL, the result being stored in AX. If source is a word, the source is multiplied by AX, the result being stored in DX:AX movsb This moves the byte that DS:SI is pointing to into ES:DI, and increments SI and DI. movsw Same as movsb except it moves a word instead of a byte. stosw This moves AX into ES:DI. stosb moves AL into ES:DI. DI is then incremented. push register This saves the value of register by pushing it onto the stack. The register may then be altered, but will be restored to it's original value when popped. pop register This restores the value of a pushed register. NOTE : Pushed values must be popped in the SAME ORDER but REVERSED. rep command This repeats Command by as many times as the value in CX SHL Destination,count ; and SHR Destination,count ; need a bit more explaining. As you know, computers think in ones and zeroes. Each number may be represented in this base 2 operation. A byte consists of 8 ones and zeroes (bits), and have a range from 0 to 255. A word consists of 16 ones and zeroes (bits), and has a range from 0 to 65535. A double word consists of 32 bits. The number 53 may be represented as follows : 00110101. Ask someone who looks clever to explain to you how to convert from binary to decimal and vice-versa. What happens if you shift everything to the left? Drop the leftmost number and add a zero to the right? This is what happens : 00110101 = 53 <----- 01101010 = 106 As you can see, the value has doubled! In the same way, by shifting one to the right, you halve the value! This is a VERY quick way of multiplying or dividing by 2. (note that for dividing by shifting, we get the trunc of the result ... ie. 15 shr 1 = 7) In assembler the format is SHL destination,count This shifts destination by as many bits in count (1=*2, 2=*4, 3=*8, 4=*16 etc) Note that a shift takes only 2 clock cycles, while a mul can take up to 133 clock cycles. Quite a difference, no? Only 286es or above may have count being greater then one. This is why to do the following to calculate the screen coordinates for a putpixel is very slow : mov ax,[Y] mov bx,320 mul bx add ax,[X] mov di,ax But alas! I hear you cry. 320 is not a value you may shift by, as you may only shift by 2,4,8,16,32,64,128,256,512 etc.etc. The solution is very cunning. Watch. mov bx,[X] mov dx,[Y] push bx mov bx, dx {; bx = dx = Y} mov dh, dl {; dh = dl = Y} xor dl, dl {; These 2 lines equal dx*256 } shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 {; bx = bx * 64} add dx, bx {; dx = dx + bx (ie y*320)} pop bx {; get back our x} add bx, dx {; finalise location} mov di, bx Let us have a look at this a bit closer shall we? bx=dx=y dx=dx*256 ; bx=bx*64 ( Note, 256+64 = 320 ) dx+bx=Correct y value, just add X! As you can see, in assembler, the shortest code is often not the fastest. The complete putpixel procedure is as follows : Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); { This puts a pixel on the screen by writing directly to memory. } BEGIN Asm push ds {; Make sure these two go out the } push es {; same they went in } mov ax,[where] mov es,ax {; Point to segment of screen } mov bx,[X] mov dx,[Y] push bx {; and this again for later} mov bx, dx {; bx = dx} mov dh, dl {; dx = dx * 256} xor dl, dl shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 shl bx, 1 {; bx = bx * 64} add dx, bx {; dx = dx + bx (ie y*320)} pop bx {; get back our x} add bx, dx {; finalise location} mov di, bx {; di = offset } {; es:di = where to go} xor al,al mov ah, [Col] mov es:[di],ah {; move the value in ah to screen point es:[di] } pop es pop ds End; END; Note that with DI and SI, when you use them : mov di,50 Moves di to position 50 mov [di],50 Moves 50 into the place di is pointing to =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The Flip Procedure This is fairly straightforward. We get ES:DI to point to the start of the destination screen, and DS:SI to point to the start of the source screen, then do 32000 movsw (64000 bytes). procedure flip(source,dest:Word); { This copies the entire screen at "source" to destination } begin asm push ds mov ax, [Dest] mov es, ax { ES = Segment of source } mov ax, [Source] mov ds, ax { DS = Segment of source } xor si, si { SI = 0 Faster then mov si,0 } xor di, di { DI = 0 } mov cx, 32000 rep movsw { Repeat movsw 32000 times } pop ds end; end; The cls procedure works in much the same way, only it moves the color into AX then uses a rep stosw (see program for details) The PAL command is almost exactly the same as it's Pascal equivalent (see previous tutorials). Look in the sample code to see how it uses the out and in commands. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In Closing The assembler procedures presented to you in here are not at their best. Most of these are procedures ASPHYXIA abandoned for better ones after months of use. But, as you will soon see, they are all MUCH faster then the original Pascal equivalents I originally gave you. In future, I hope to give you more and more assembler procedures for your ever growing collections. But, as you know, I am not always very prompt with this series (I don't know if even one has been released within one week of the previous one), so if you want to get any stuff done, try do it yourself. What do you have to lose, aside from your temper and a few rather inventive reboots ;-) What should I do for the next trainer? A simple 3-d tutorial? You may not like it, because I would go into minute detail of how it works :) Leave me suggestions for future trainers by any of the means discussed at the top of this trainer. After the customary quote, I will place a listing of the BBSes I currently know that regularly carry this Trainer Series. If your BBS receives it regularly, no matter where in the country you are, get a message to me and I'll add it to the list. Let's make it more convenient for locals to grab a copy without calling long distance ;-) [ There they sit, the preschooler class encircling their mentor, the substitute teacher. "Now class, today we will talk about what you want to be when you grow up. Isn't that fun?" The teacher looks around and spots the child, silent, apart from the others and deep in thought. "Jonny, why don't you start?" she encourages him. Jonny looks around, confused, his train of thought disrupted. He collects himself, and stares at the teacher with a steady eye. "I want to code demos," he says, his words becoming stronger and more confidant as he speaks. "I want to write something that will change peoples perception of reality. I want them to walk away from the computer dazed, unsure of their footing and eyesight. I want to write something that will reach out of the screen and grab them, making heartbeats and breathing slow to almost a halt. I want to write something that, when it is finished, they are reluctant to leave, knowing that nothing they experience that day will be quite as real, as insightful, as good. I want to write demos." Silence. The class and the teacher stare at Jonny, stunned. It is the teachers turn to be confused. Jonny blushes, feeling that something more is required. "Either that or I want to be a fireman." ] - Grant Smith 14:32 21/11/93 See you next time, - DENTHOR These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) ���������������������������������������������������������������ͻ �BBS Name �Telephone No. �Open �Msg�File�Past� ���������������������������������������������������������������͹ �ASPHYXIA BBS #1 �(031) 765-5312 �ALL � * � * � * � �ASPHYXIA BBS #2 �(031) 765-6293 �ALL � * � * � * � �Connectix BBS �(031) 266-9992 �ALL � * � * � * � �For Your Eyes Only BBS �(031) 285-318 �A/H � * � * � * � ���������������������������������������������������������������ͼ Open = Open at all times or only A/H Msg = Available in message base File = Available in file base Past = Previous Parts available �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 8 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hello everybody! Christmas is over, the last of the chocolates have been eaten, so it's time to get on with this, the eighth part of the ASPHYXIA Demo Trainer Series. This particular part is primarily about 3-D, but also includes a bit on optimisation. If you are already a 3-D guru, you may as well skip this text file, have a quick look at the sample program then go back to sleep, because I am going to explain in minute detail exactly how the routines work ;) If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write a message in the Programming conference on the For Your Eyes Only BBS (of which I am the Moderator ) This is preferred if you have a general programming query or problem others would benefit from. 4) Write to Denthor, EzE or Goth on Connectix. 5) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal 6) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity) 7) Write to mcphail@beastie.cs.und.ac.za on InterNet, and mention the word Denthor near the top of the letter. NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Optimisation Before I begin with the note on 3-D, I would like to stress that many of these routines, and probably most of your own, could be sped up quite a bit with a little optimisation. One must realise, however, that you must take a look at WHAT to optimise ... converting a routine that is only called once at startup into a tightly coded assembler routine may show off your merits as a coder, but does absolutely nothing to speed up your program. Something that is called often per frame is something that needs to be as fast as possible. For some, a much used procedure is the PutPixel procedure. Here is the putpixel procedure I gave you last week: Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); BEGIN Asm push ds { 14 clock ticks } push es { 14 } mov ax,[where] { 8 } mov es,ax { 2 } mov bx,[X] { 8 } mov dx,[Y] { 8 } push bx { 15 } mov bx, dx { 2 } mov dh, dl { 2 } xor dl, dl { 3 } shl bx, 1 { 2 } shl bx, 1 { 2 } shl bx, 1 { 2 } shl bx, 1 { 2 } shl bx, 1 { 2 } shl bx, 1 { 2 } add dx, bx { 3 } pop bx { 12 } add bx, dx { 3 } mov di, bx { 2 } xor al,al { 3 } mov ah, [Col] { 8 } mov es:[di],ah { 10 } pop es { 12 } pop ds { 12 } End; END; Total = 153 clock ticks NOTE : Don't take my clock ticks as gospel, I probably got one or two wrong. Right, now for some optimising. Firstly, if you have 286 instructions turned on, you may replace the 6 shl,1 with shl,6. Secondly, the Pascal compiler automatically pushes and pops ES, so those two lines may be removed. DS:[SI] is not altered in this procedure, so we may remove those too. Also, instead of moving COL into ah, we move it into AL and call stosb (es:[di]:=al; inc di). Let's have a look at the routine now : Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); BEGIN Asm mov ax,[where] { 8 } mov es,ax { 2 } mov bx,[X] { 8 } mov dx,[Y] { 8 } push bx { 15 } mov bx, dx { 2 } mov dh, dl { 2 } xor dl, dl { 3 } shl bx, 6 { 8 } add dx, bx { 3 } pop bx { 12 } add bx, dx { 3 } mov di, bx { 2 } mov al, [Col] { 8 } stosb { 11 } End; END; Total = 95 clock ticks Now, let us move the value of BX directly into DI, thereby removing a costly push and pop. The MOV and the XOR of DX can be replaced by it's equivalent, SHL DX,8 Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler; asm mov ax,[where] { 8 } mov es,ax { 2 } mov bx,[X] { 8 } mov dx,[Y] { 8 } mov di,bx { 2 } mov bx, dx { 2 } shl dx, 8 { 8 } shl bx, 6 { 8 } add dx, bx { 3 } add di, dx { 3 } mov al, [Col] { 8 } stosb { 11 } end; Total = 71 clock ticks As you can see, we have brought the clock ticks down from 153 ticks to 71 ticks ... quite an improvement. (The current ASPHYXIA putpixel takes 48 clock ticks) . As you can see, by going through your routines a few times, you can spot and remove unnecessary instructions, thereby greatly increasing the speed of your program. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Defining a 3-D object Drawing an object in 3-D is not that easy. Sitting down and plotting a list of X,Y and Z points can be a time consuming business. So, let us first look at the three axes you are drawing them on : Y Z /|\ / | / X<-----|-----> | \|/ X is the horisontal axis, from left to right. Y is the vertical axis, from top to bottom. Z is the depth, going straight into the screen. In this trainer, we are using lines, so we define 2 X,Y and Z coordinates, one for each end of the line. A line from far away, in the upper left of the X and Y axes, to close up in the bottom right of the X and Y axes, would look like this : { x1 y1 z1 x2 y2 z2 } ( (-10,10,-10),(10,-10,10) ) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Rotating a point with matrixes NOTE : I thought that more then one matix are matrisese (sp), but my spellchecker insists it is matrixes, so I let it have it's way ;-) Having a 3-D object is useless unless you can rotate it some way. For demonstration purposes, I will begin by working in two dimensions, X and Y. Let us say you have a point, A,B, on a graph. Y | /O1 (Cos (a)*A-Sin (a)*B , Sin (a)*A+Cos (a)*B) |/ (A,B) X<-----|------O--> | | Now, let us say we rotate this point by 45 degrees anti-clockwise. The new A,B can be easily be calculated using sin and cos, by an adaption of our circle algorithm, ie. A2:=Cos (45)*A - Sin (45)*B B2:=Sin (45)*A + Cos (45)*B I recall that in standard 8 and 9, we went rather heavily into this in maths. If you have troubles, fine a 8/9/10 maths book and have a look; it will go through the proofs etc. Anyway, we have now rotated an object in two dimensions, AROUND THE Z AXIS. In matrix form, the equation looks like this : [ Cos (a) -Sin (a) 0 0 ] [ x ] [ Sin (a) Cos (a) 0 0 ] . [ y ] [ 0 0 1 0 ] [ z ] [ 0 0 0 1 ] [ 1 ] I will not go to deeply into matrixes math at this stage, as there are many books on the subject (it is not part of matric maths, however). To multiply a matrix, to add the products of the row of the left matrix and the column of the right matrix, and repeat this for all the columns of the left matrix. I don't explain it as well as my first year maths lecturer, but have a look at how I derived A2 and B2 above. Here are the other matrixes : Matrix for rotation around the Y axis : [ Cos (a) 0 -Sin (a) 0 ] [ x ] [ 0 1 0 0 ] . [ y ] [ Sin (a) 0 Cos (a) 0 ] [ z ] [ 0 0 0 1 ] [ 1 ] Matrix for rotation around the X axis : [ 1 0 0 ] [ x ] [ 0 Cos (a) -Sin (a) 0 ] . [ y ] [ 0 Sin (a) Cos (a) 0 ] [ z ] [ 0 0 0 1 ] [ 1 ] By putting all these matrixes together, we can translate out 3D points around the origin of 0,0,0. See the sample program for how we put them together. In the sample program, we have a constant, never changing base object. This is rotated into a second variable, which is then drawn. I am sure many of you can thing of cool ways to change the base object, the effects of which will appear while the object is rotating. One idea is to "pulsate" a certain point of the object according to the beat of the music being played in the background. Be creative. If you feel up to it, you could make your own version of transformers ;) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Drawing a 3D point to screen Having a rotated 3D object is useless unless we can draw it to screen. But how do we show a 3D point on a 2D screen? The answer needs a bit of explaining. Examine the following diagram : | ________------------- ____|___------ o Object at X,Y,Z o1 Object at X,Y,Z2 Eye -> O)____|___ | ------________ | -------------- Field of vision Screen Let us pretend that the centre of the screen is the horizon of our little 3D world. If we draw a three dimensional line from object "o" to the centre of the eye, and place a pixel on the X and Y coordinates where it passes through the screen, we will notice that when we do the same with object o1, the pixel is closer to the horizon, even though their 3D X and Y coords are identical, but "o1"'s Z is larger then "o"'s. This means that the further away a point is, the closer to the horizon it is, or the smaller the object will appear. That sounds right, doesent it? But, I hear you cry, how do we translate this into a formula? The answer is quite simple. Divide your X and your Y by your Z. Think about it. The larger the number you divide by, the closer to zero, or the horizon, is the result! This means, the bigger the Z, the further away is the object! Here it is in equation form : nx := 256*x div (z-Zoff)+Xoff ny := 256*y div (z-Zoff)+Yoff NOTE : Zoff is how far away the entire object is, Xoff is the objects X value, and Yoff is the objects Y value. In the sample program, Xoff start off at 160 and Yoff starts off at 100, so that the object is in the middle of the screen. The 256 that you times by is the perspective with which you are viewing. Changing this value gives you a "fish eye" effect when viewing the object. Anyway, there you have it! Draw a pixel at nx,ny, and viola! you are now doing 3D! Easy, wasn't it? =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Possible improvements This program is not the most optimised routine you will ever encounter (;-)) ... it uses 12 muls and 2 divs per point. (Asphyxia currently has 9 muls and 2 divs per point) Real math is used for all the calculations in the sample program, which is slow, so fixed point math should be implemented (I will cover fixed point math in a future trainer). The line routine currently being used is very slow. Chain-4 could be used to cut down on screen flipping times. Color values per line should be added, base object morphing could be put in, polygons could be used instead of lines, handling of more then one object should be implemented, clipping should be added instead of not drawing something if any part of it is out of bounds. In other words, you have a lot of work ahead of you ;) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing There are a lot of books out there on 3D, and quite a few sample programs too. Have a look at them, and use the best bits to create your own, unique 3D engine, with which you can do anything you want. I am very interested in 3D (though EzE and Goth wrote most of ASPHYXIA'S 3D routines), and would like to see what you can do with it. Leave me a message through one of the means described above. I am delving into the murky world of texture mapping. If anyone out there has some routines on the subject and are interested in swapping, give me a buzz! What to do in future trainers? Help me out on this one! Are there any effects/areas you would like a bit of info on? Leave me a message! I unfortunately did not get any messages regarding BBS's that carry this series, so the list that follows is the same one from last time. Give me your names, sysops! Aaaaargh!!! Try as I might, I can't think of a new quote. Next time, I promise! ;-) Bye for now, - Denthor These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) ���������������������������������������������������������������ͻ �BBS Name �Telephone No. �Open �Msg�File�Past� ���������������������������������������������������������������͹ �ASPHYXIA BBS #1 �(031) 765-5312 �ALL � * � * � * � �ASPHYXIA BBS #2 �(031) 765-6293 �ALL � * � * � * � �Connectix BBS �(031) 266-9992 �ALL � * � � � �For Your Eyes Only BBS �(031) 285-318 �A/H � * � * � * � ���������������������������������������������������������������ͼ Open = Open at all times or only A/H Msg = Available in message base File = Available in file base Past = Previous Parts available �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 9 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hi there! ASPHYXIA is BACK with our first MegaDemo, Psycho Neurosis! A paltry 1.3MB download is all it takes to see the group from Durbs first major production! We are quite proud of it, and think you should see it ;) Secondly, I released a small little trainer (a trainerette ;-)) on RsaPROG and Connexctix BBS mail, also on the ASPHYXIA BBS as COPPERS.ZIP It is a small Pascal program demonstrating how to display copper bars in text mode. Also includes a check for horizontal retrace (A lot of people wanted it, that is why I wrote the program) (ASPHYXIA ... first with the trainer goodies ;-) aargh, sorry, had to be done )) Thirdly, sorry about the problems with Tut 8! If you had all the checking on, the tutorial would probably die on the first points. The reason is this : in the first loop, we have DrawPoints then RotatePoints. The variables used in DrawPoints are set in RotatePoints, so if you put RotatePoints before DrawPoints, the program should work fine. Alternatively, turn off error checking 8-) Fourthly, I have had a surprisingly large number of people saying that "I get this, like, strange '286 instructions not enabled' message! What's wrong with your code, dude?" To all of you, get into Pascal, hit Alt-O (for options), hit enter and a 2 (for Enable 286 instructions). Hard hey? Doesn't anyone EVER set up their version of Pascal? Now, on to todays tutorial! 3D solids. That is what the people wanted, that is what the people get! This tutorial is mainly on how to draw the polygon on screen. For details on how the 3D stuff works, check out tut 8. If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to Denthor, EzE or Goth on Connectix. 3) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity) 5) Write to mcphail@beastie.cs.und.ac.za on InterNet, and mention the word Denthor near the top of the letter. NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How to draw a polygon Sounds easy enough, right? WRONG! There are many, many different ways to go about this, and today I'll only be showing you one. Please don't take what is written here as anything approaching the best method, it is just here to get you on your way... The procedure I will be using here is based on something most of us learned in standard eight ... I think. I seem to recall doing something like this in Mrs. Reids maths class all those years ago ;) Take two points, x1,y1 and x2,y2. Draw them : + (x1,y1) \ \ <-- Point a somewhere along the line \ + (x2,y2) Right, so what we have to do is this : if we know the y-coord of a, what is it's x-coord? To prove the method we will give the points random values. + (2,10) \ \ <-- a.y = 12 \ + (15,30) Right. Simple enough problem. This is how we do it : (a.y-y1) = (12 - 10) {to get a.y as though y1 was zero} *(x2-x1) = *(15 - 2) {the total x-length of the line} /(y2-y1) = /(30 - 10) {the total y-length of the line} +x1 = +2 { to get the equation back to real coords} So our equation is : (a.y-y1)*(x2-x1)/(y2-y1)+x4 or (12-10)*(15-2)/(30-10)+2 which gives you : 2*13/20+2 = 26/20+2 = 3.3 That means that along the line with y=12, x is equal to 3.3. Since we are not concerned with the decimal place, we replace the / with a div, which in Pascal gives us an integer result, and is faster too. All well and good, I hear you cry, but what does this have to do with life and how it relates to polygons in general. The answer is simple. For each of the four sides of the polygon we do the above test for each y line. We store the smallest and the largest x values into separate variables for each line, and draw a horizontal line between them. Ta-Dah! We have a cool polygon! For example : Two lines going down : + + / <-x1 x2->| <--For this y line / | + + Find x1 and x2 for that y, then draw a line between them. Repeat for all y values. Of course, it's not as simple as that. We have to make sure we only check those y lines that contain the polygon (a simple min y, max y test for all the points). We also have to check that the line we are calculating actually extends as far as where our current y is (check that the point is between both y's). We have to compare each x to see weather it is smaller then the minimum x value so far, or bigger then the maximum (the original x min is set as a high number, and the x max is set as a small number). We must also check that we only draw to the place that we can see ( 0-319 on the x ; 0-199 on the y (the size of the MCGA screen)) To see how this looks in practice, have a look at the sample code provided. (Mrs. Reid would probably kill me for the above explanation, so when you learn it in school, split it up into thousands of smaller equations to get the same answer ;)) Okay, that's it! What's that? How do you draw a vertical line? Thats simple ... =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Drawing a vertical line Right, this is a lot easier than drawing a normal line (Tut 5 .. I think), because you stay on the same y value. So, what you do is you set ES to the screen you want to write to, and get DI to the start of the y-line (see earlier trainers for a description of how SEGMENT:OFFSET works. IN : x1 , x2, y, color, where asm mov ax,where mov es,ax mov di,y mov ax,y shl di,8 { di:=di*256 } shl ax,6 { ax:=ax*64 } add di,ax { di := (y*256)+(y*64) := y*320 Faster then a straight multiplication } Right, now you add the first x value to get your startoff. add di,x1 Move the color to store into ah and al mov al,color mov ah,al { ah:=al:=color } then get CX equal to how many pixels across you want to go mov cx,x2 sub cx,x1 { cx:=x2-x1 } Okay, as we all know, moving a word is a lot faster then moving a byte, so we halve CX shr cx,1 { cx:=cx/2 } but what happens if CX was an odd number. After a shift, the value of the last number is placed in the carry flag, so what we do is jump over a single byte move if the carry flag is zero, or execute it if it is one. jnc @Start { If there is no carry, jump to label Start } stosb { ES:[DI]:=al ; increment DI } @Start : { Label Start } rep stosw { ES:[DI]:=ax ; DI:=DI+2; repeat CX times } Right, the finished product looks like this : Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler; { This draws a horizontal line from x1 to x2 on line y in color col } asm mov ax,where mov es,ax mov ax,y mov di,ax shl ax,8 shl di,6 add di,ax add di,x1 mov al,col mov ah,al mov cx,x2 sub cx,x1 shr cx,1 jnc @start stosb @Start : rep stosw end; Done! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing This 3D system is still not perfect. It needs to be faster, and now I have also dumped the problem of face-sorting on you! Nyahahahaha! [ My sister and I were driving along the other day when she asked me, what would I like for my computer. I thought long and hard about it, and came up with the following hypothesis. When a girl gets a Barbie doll, she then wants the extra ballgown for the doll, then the hairbrush, and the car, and the house, and the friends etc. When a guy gets a computer, he wants the extra memory, the bigger hard drive, the maths co-pro, the better motherboard, the latest software, and the bigger monitor etc. I told my sister all of this, and finished up with : "So as you can see, computers are Barbie dolls for MEN!" She called me a chauvinist. And hit me. Hard. ] - Grant Smith 19:24 26/2/94 See you next time! - Denthor These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) ���������������������������������������������������������������ͻ �BBS Name �Telephone No. �Open �Msg�File�Past� ���������������������������������������������������������������͹ �ASPHYXIA BBS #1 �(031) 765-5312 �ALL � * � * � * � �ASPHYXIA BBS #2 �(031) 765-6293 �ALL � * � * � * � �Connectix BBS �(031) 266-9992 �ALL � � * � * � ���������������������������������������������������������������ͼ Open = Open at all times or only A/H Msg = Available in message base File = Available in file base Past = Previous Parts available Does no other BBS's ANYWHERE carry the trainer? Am I writing this for three people who get it from one of these BBS's each week? Should I go on? (Hehehehe ... I was pleased to note that Tut 8 was THE most downloaded file from ASPHYXIA BBS last month ... ) �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 10 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Wow! The trainer has finally reached part 10! This will also be the first part introduced simultaneously to local BBS's and the INTERNET at the same time! Yes folks, I put up a copy of previous tutorials onto various ftp sites, and awaited the flames saying that the net.gurus already knew this stuff, and why was I wasting disk space! The flames did not appear (well, except for one), and I got some messages saying keep it up, so from now on I will upload all future trainers to ftp sites too (wasp.eng.ufl.edu , cs.uwp.edu etc.). I will also leave a notice in the USENET groups comp.lang.pascal and comp.sys.ibm.pc.demos when a new part is finished (Until enough people say stop ;-)) I can also be reached at my new E-Mail address, smith9@batis.bis.und.ac.za Well, this tutorial is on Chain-4. When asked to do a trainer on Chain-4, I felt that I would be walking on much travelled ground (I have seen numerous trainers on the subject), but the people who asked me said that they hadn't seen any, so could I do one anyway? Who am I to say no? The sample program attached isn't that great, but I am sure that all you people out there can immediately see the potential that Chain-4 holds. If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to Denthor, EzE or Goth on Connectix. 3) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-)) 5) Write to smith9@batis.bis.und.ac.za in E-Mail. NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is Chain-4? You people out there all have at least 256k vga cards. Most of you have 512k vga cards, and some have 1MB vga cards. But what you see on your screen, as discussed in previous trainers, is 64k of data! What happened to the other 192k??? Chain-4 is a method of using all 256k at one time. The way this is done is simple. 1 screen = 64k. 64k * 4 = 256k. Therefore, chain-4 allows you to write to four screens, while displaying one of them. You can then move around these four screens to see the data on them. Think of the Chain-4 screen as a big canvas. The viewport, the bit you see out of, is a smaller rectangle which can be anywhere over the bigger canvas. +----------------------------+ Chain-4 screen | +--+ | | | | <- Viewport | | +--+ | | | +----------------------------+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The size of the chain-4 screen The Chain-4 screen, can be any size that adds up to 4 screens. For example, it can be 4 screens across and one screen down, or one screen across and 4 screens down, or two screens across and two screens down, and any size in between. In the sample program, the size is a constant. The size * 8 is how many pixels across there are on the chain-4 screen, ie Size = 40 = 320 pixels across = 1 screen across, 4 screens down Size = 80 = 640 pixels across = 2 screens across, 2 screens down etc. We need to know the size of the screen for almost all dealings with the Chain-4 screen, for obvious reasons. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Layout of the chain-4 screen, and accessing it If you will remember all the way back to Part 1 of this series, I explained that the memory layout of the MCGA screen is linear. Ie, the top left hand pixel was pixel zero, the one to the right of it was number one, the next one was number two etc. With Chain-4, things are very different. Chain-4 gets the 4 screens and chains them together (hence the name :)). Each screen has a different plane value, and must be accessed differently. The reason for this is that a segment of memory is only 64k big, so that we could not fit the entire Chain-4 screen into one segment. All Chain-4 screens are accessed from $a000, just like in MCGA mode. What we do is, before we write to the screen, find out what plane we are writing to, set that plane, then plot the pixel. Here is how we find out how far in to plot the pixel and what plane it is on : Instead of the linear model of MCGA mode, ie : �����������������������������������Ŀ �00�01�02�03�04�05�06�07�08�09�10�11� ... Each plane of the Chain-4 screen accesses the memory in this way : Plane 0 : �����������������������������������Ŀ �00� � � �01� � � �02� � � � ... Plane 1 : �����������������������������������Ŀ � �00� � � �01� � � �02� � � ... Plane 2 : �����������������������������������Ŀ � � �00� � � �01� � � �02� � ... Plane 3 : �����������������������������������Ŀ � � � �00� � � �01� � � �02� ... In this way, by choosing the right plane to write to, we can access all of the 256k of memory available to us. The plane that we write to can easily be found by the simple calculation of x mod 4, and the x coordinate is also found by x div 4. We work out our y by multiplying it by the size of our chain-4 screen. NOTE : It is possible to write to all four planes at once by setting the correct port values. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Uses of Chain-4 The uses of Chain-4 are many. One could write data to one screen, then flip to it (the move_to command is almost instantaneous). This means that 64k of memory does not need to be set aside for a virtual screen, you are using the vga cards memory instead! Scrolling is much easier to code for in Chain-4 mode. It is possible to "tweak" the mode into other resolutions. In our demo, our vectors were in 320x240 mode, and our dot vectors were in 320x400 mode. The main disadvantage of chain-4 as I see it is the plane swapping, which can be slow. With a bit of clever coding however, these can be kept down to a minimum. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The sample programs The first sample program is GFX.PAS. This is a until in which I have placed most of our routines from previous tuts. All the procedures and variables you can see under the INTERFACE section can be used in any program with GFX in the USES clause. In other words, I could do this : USES GFX,crt; BEGIN Setupvirtual; cls (vaddr,0); Shutdown; END. This program would compile perfectly. What I suggest you do is this : Rename the file to a name that suites you (eg your group name), change the first line of the unit to that name, then add all useful procedures etc. to the unit. Make it grow :-). The second file is the sample program (note the USES GFX,crt; up near the top!). The program is easy to understand and is documented. The bit that I want to draw your attention to is the constant, BIT. Because I am distributing this file to many places in text form, not binary form, I could not just add a .CEL file with the program. So what I did was write some text in one color then saved it as a .CEL . I then wrote a ten line program that did the following : Moving from left to right, it counted how many pixels were of color zero, then saved the byte value to an array. When it came across color one, is counted for how long that went on then saved the byte value and saved it to an array and so on. When it was finished, I converted the array into a text file in the CONST format. Not too cunning, but I thought I had better explain it ;-) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing There are other documents and sample programs available on Chain-4 and it's like : Try XLIB for one... Finally! Some BBS's have joined my BBS list! (Okay, only two new ones, but it's a start ;-)) All you international BBS's! If you will regularly download the tuts from an FTP site, give me your names! I own a car. The car's name is Bob. A few days ago, Bob was in an accident, and now has major damage to his front. Knowing insurance, I probably won't get much, probably nothing (the other guy wasn't insured, and I am only 18 :( ). I will probably have to find work in order to pay for my repairs. The point to this meandering is this : I am upset, so if you think you are getting a quote, you can just forget it. Oh, well. Life goes on! See you next time, - Denthor These fine BBS's carry the ASPHYXIA DEMO TRAINER SERIES : (alphabetical) ���������������������������������������������������������������ͻ �BBS Name �Telephone No. �Open �Msg�File�Past� ���������������������������������������������������������������͹ �ASPHYXIA BBS #1 �(031) 765-5312 �ALL � * � * � * � �ASPHYXIA BBS #2 �(031) 765-6293 �ALL � * � * � * � �Connectix BBS �(031) 266-9992 �ALL � � * � * � �POP! �(012) 661-1257 �ALL � � * � * � �Pure Surf BBS �(031) 561-5943 �A/H � � * � * � ���������������������������������������������������������������ͼ For international users : If you live outside the Republic of South Africa, do the following : Dial +27, dont dial the first 0, but dial the rest of the number. Eg, for the ASPHYXIA BBS : +27-31-765-5312 Open = Open at all times or only A/H Msg = Available in message base File = Available in file base Past = Previous Parts available �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 11 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hello again everybody! The reason _this_ one is delayed (every single trainer has been so far ;)) is mainly due to a birthday (my 19th), and numerous tests at the university (ugh!). But anyway, here it is. The sample program this time is on cross-fading. The reason for this is that many people have commented that I should be moving over to a few basic demo effects now that we have most of the basics of VGA programming. I was also thinking of either doing sound in a future version of this trainer, or starting a separate "ASPHYXIA Sound Tutorial" series. Comments? One major difference between this trainer and previous ones is that I am including binary files (pictures in this case). This means that it will not be available in the message bases of selected boards anymore, and it must be obtained from the file base. Notice will however be given of it's existence in the message base. Asphyxia has formalised things a bit, and we now have a few official distribution sites for all our demos and trainers. If you would like your BBS to become a distribution site, please email me at smith9@batis.bis.und.ac.za and I will send you the necessary info. If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix. 3) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-)) 5) Write to smith9@batis.bis.und.ac.za in E-Mail. NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is a "Crossfade"? This is a simple question. When you are watching a TV program, you will often see one picture on the screen, which slowly fades to a new picture, with the new picture becoming more and more prominent and the old one becoming less and less prominent. This is a crossfade. Easy huh? Perhaps, but it is not that easy to code on a computer... In most demos, there is a crossfade of two colors, black and white, for example : The words 'MYDEMOTEAM' appears in large with letters, then crossfades to 'PRESENTS' in large white letters. I decided to allow the programmer to have a bit of color to his crossfade, and the sample program can handle a many color crossfade. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How does a crossfade work? Here comes the clever bit. To do a crossfade, we load in two pictures, FROM and TO. Then, for every pixel in which they are different, put a new pixel in a third screen. For example, wherever there is pixel color 9 on screen 1 and pixel color 45 on screen 2, put pixel color 1 on the third screen. You then repeat this for all combinations of pixels on screen one and two, and put the results into screen 3. Here it is in ascii ... Screen 1 Screen 2 Screen 3 .1... .3... .1... ..... ..2.. ..2.. ...8. + ...1. = ...3. .1... ....2 .4..2 Note how the values on screen 3 are sequential? We keep a count for this... The two "2"'s on screen 3 are identical, so we do not use a new color for it... We also keep to pallettes ... source and dest. For the above example source[1] would be the pallette of 1 in screen 1, and dest[1] would be the pallette of 3 in screen 2 (Note that screen 1 and screen 2 have different pallettes) When we are finished with the picture, we flip screen 3 to the vga and do the following : move the pallette from source to dest or vice versa. Thats it. No fancy screen manipulations for the crossfade, we just change the pallette. Cool, huh? It also means that you can be doing fun stuff in the foreground with unused pallette colors without your program executing at two frames per second ;) The sample program is fully documented, and you shouldn't have a problem deciphering it... If you ever use this effect in a demo or game, greet me! :-) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Problems with crossfades The main problem with crossfading is this : there may only be 256 colors on screen 3, in other words, only 256 combinations of colors. In the sample program, if you load up two pics with more then 256 combinations, the program gives an error message and exits to dos. To sort this problem out, you can do two things : reduce the number of places where the two pictures intersect, or squeeze down the pallette, using Autodesk Animators "SQUEEZE" command. This reduces the number of colors used by the picture, and therefore reduces the number of combinations. The picture does however lose a bit of quality. The second problem with crossfading is this : It hogs most of the colors. Whatever you want to do in the foreground, make sure you do it with as few colors as possible. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing So, what do you think? Should I continue with demo effects, or should I find more basic things to do? Perhaps I should stop and just do sound coding from now on? It is up to you, so leave me mail. You will notice that the sample program can load in any .CEL files, you needn't be restricted by the ones I have given you. Try crossfading a few of your own pictures and see how it turns out. The picture of the robot was draw by Fubar for our demo Psycho Neurosis, and I then squeezed down the pallette somewhat in order for the crossfade to work. The word "ASPHYXIA" was drawn by me, also in Autodesk Animator. Oh well, I had better get this off quickly, today is the last time for the next few days that I can get on to the Net. I will also be voting tomorrow! If I see a CNN camera, I'll wave (Thats me, the one on the left in the red shirt! ;-)) The next trainer will be coming from the New South Africa (TM) See you next time! - Denthor - 9:16, 26 April, 1994 PS. Does anyone in Holland with net access want to act as a courier between myself and the Accidental Connection BBS? Please leave me mail at smith9@batis.bis.und.ac.za .... The following are official ASPHYXIA distribution sites : �������������������������������������������������ͻ �BBS Name �Telephone No. �Open � �������������������������������������������������͹ �ASPHYXIA BBS #1 �+27-31-765-5312 �ALL � �ASPHYXIA BBS #2 �+27-31-765-6293 �ALL � �Connectix BBS �+27-31-266-9992 �ALL � �POP! �+27-12-661-1257 �ALL � �Pure Surf BBS �+27-31-561-5943 �A/H � �Wasted Image �407-838-4525 �ALL � �������������������������������������������������ͼ Leave me mail if you want to become an official Asphyxia BBS distribution site. (I will find out the country code for Wasted Image later...) �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 12 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hello! :-) Well, a lot has happened since the last trainer, which is the reason for the amazingly long delay. First, the elections. These were quite easy actually, I went and watched a move (Demolition Man) (Election day special, all movies R2, which is about 50 US cents), then went and voted after most voters had gone home, so no long lines ;-). Soon after were exams. These did not go too well, and I am not looking forward to the results. Finally, I got measles and pneumonia at the same time and was sent off to hospital for a few days. All in all, not events which are conducive to coding! This has meant that the trainer has been delayed, and ASPHYXIA was not able to enter into the local democompo, Dexterity '94, which we were hoping to do well in. Oh well, onward and upward! This trainer is on full screen scrolling in Chain-4, by request. This is actually very easy to do (and smooth), and holds a lot of potential, as I am sure you can immediately imagine. A few more things : People have been saying they have had hassles sending me email, and I have found that this is because they forget the numbers in my name. They send mail to smith@batis... which does not exist, or smith@beastie... which is my brothers account. He is getting a bit sick of forwarding my mail to me ;). The two address are : smith9@batis.bis.und.ac.za smith0@beastie.cs.und.ac.za I have lost about 200k worth of email, chalk it up to my beginner status at Unix. The test to see if your mail got through? I have answered _every_ email message sent to me (no easy task), so if you haven't got a reply, please resend the message. You can now also send a group message to all members of Asphyxia. Just send mail to asphyxia@beastie.cs.und.ac.za and we will all get a copy ... which could mean numerous replies to one querey ;) If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix. 3) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-)) 5) Write to smith9@batis.bis.und.ac.za in E-Mail. 6) Write to asphyxia@beastie.cs.und.ac.za NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is full screen scrolling? I seem to recall doing this in a previous tut, but here goes again! Full screen scrolling is when the entire screen moves in a particular direction, with the new picture scrolling on to the screen. Um. Think of movie credits. The screen, filled with text, is scrolled off the top of the screen while the new text is scrolled on from the bottom. This is full screen scrolling. Full screen scrolling is not limited to movie credits. Games like Raptor have you flying over a scrolling landscape while you are shooting down the bad guys. In this tutorial we will be doing vertical scrolling, but the code can very easily be altered for horizontal scrolling too. Remember that we will be using Chain-4 to do our scrolling, so you may want to brush up on tut 10 in which that was covered. I will assume a brief knowledge of how chain-4 works for this tutorial. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � The theory The theory behind full screen scrolling in Chain-4 is acually very simple. Picture if you will, a screen that is two monitors high. Chain-4 actually has four, but for this we only need two. Now, for this screen that is two monitors high, we can only see one monitors worth. Here it is in ASCII +-------------+ Screen two monitors high | | | | | | | | |+-----------+| || || || ||<- This is the bit we can see, one monitors worth || || |+-----------+| +-------------+ We can move the bit we can see up or down the enlarged screen. So, for example, if the screen two monitors high had a picture on it, we could move the bit we see up and down to try glimpse the entire picture. Think of it in this way : The screen is a large painting, but we can only see though a small magnifing glass. We can move this magnifing glass around the painting, but can never see the painting all at once. This actually works in our favour. Anything done outside the bit we are looking through cannot be seen, so we can do our work without changing our screen. On to scrolling. The method we will use this time is as follows : 1) Draw the next line to be seen just above and just below the part we can see. +------------+ The enlarged screen | | | | |111111111111| The new part of the picture |+----------+| || || The bit we can see |+----------+| |111111111111| The new part of the picture +------------+ 2) Move the view up one pixel so that the new part of the picture is visible at the top of the screen. 3) Repeat Steps 1) and 2) until the whole screen is filled. Our screen will look as follows : +---------------+ |+-------------+| ||3333333333333|| ||2222222222222|| Viewscreen ||1111111111111|| |+-------------+| |333333333333333| |222222222222222| |111111111111111| +---------------+ Check this picture with steps 1) and 2), you will see that this is correct. 4) Set our viewport to the bottom of the enlarged screen. +---------------+ |333333333333333| |222222222222222| |111111111111111| |+-------------+| ||3333333333333|| ||2222222222222|| New position of viewscreen ||1111111111111|| |+-------------+| +---------------+ As you can see, the bit we will be looking at is exactly the same as before, we are now just at the bottom of the larger screen instead of the top! 5) Jump back to 1). The entire sequence can begin again, and we can have infinate scrolling in the upward direction. Clever huh? =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Our code In the sample code, we have 21 different icons. What we do is decide what the next row of icons is going to consist of. We then draw the next line of pixels above and below the viewscreen according to what icons we are displaying. We then scroll up one pixel and begin again. When we have completed a row of icons, we randomly select a new row and begin again. Our icons are 16x16, so exactly 20 fit across a 320 pixel screen. When we hit the top of our enlarged screen, we flip down to the bottom which looks exactly the same as the screen we have left. In this manner we have obtained smooth, infinate full screen scrolling! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Extra bits As you will see from the code, it would be the work of but a few minutes to extend our landscape across the two unused screens, thereby allowing limited horizontal movement along with our vertical movement. In fact, the entire routine could easily be made to be a horizontal scrolling routine. A map of sorts could be generated, with one byte equalling one terrain type. In this manner, the terrain scrolled over could be set, as in a flying game (Flying Shark, Raptor etc). The terrain could also easily be replaced with letters for our movie-style credits. Free direction scrolling, ie scrolling in all directions, is a very different matter, with very different methods to get it to work. Perhaps this will be discussed in a later trainer. But for now, work with this, know it, understand it, and think up many great things to do with it! How about a full screen text scrolly? A game? Go wild! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing Well, I hope you enjoyed this, the latest trainer. The sample program is a little short, but that is because the concept is so simple. Attached is a file, PICCS.DAT, which contains the terrain and letters for the sample program. They were .CEL's, which I loaded into the des^ variable, which I then dumped to disk, for easy access later. The .CEL's were drawn on short notice, but still produces some nice terrain. I have recieved a few requests for future trainers, and most of them are for effects, so I guess that is what will be done from now on. A surprising number have told me not to do a sound trainer and stick with graphics stuff, with only a few asking for sound stuff, so I will hold off on that until there is more of a demand. I am still open to suggestions for future trainers, and of course suggestions for improving the series. Leave me mail! Hmm. A quote? Okay, let me think .... [ The little devil sat atop the alpine slopes, frolicking in the snow. He threw a snowball at a nearby squirrel, which missed. The resulting avalance buried two villages and a ski resort. The little devil was scared. Avalances were bad for business. The locals would form team spirit, be nice to each other and work together and free those trapped beneath the snow, which created even more goodwill. The man downstairs didn't like goodwill. He didn't like it at all. In the blink of an eye the devil was in his penthouse apartment, dressed in his usual suit. He picked up the phone. Dialing was for mortals. "Hello, Micros..." "This is Mister Crowley", interrupted the devil. There were sounds of thumping on the other side of the phone, then there was a new voice. "Hello, Bill here, we haven't heard from you in a while, Mister Crowley." The fear of the man on the other end was almost tangible. The devil smiled. "Hello Bill. Something has come up." "No!" The man on the other side almost shouted with terror. "Not Win..." "Yes, Bill. It is time." "Havn't I paid enough for my sins? Just that one night..." The man was almost sobbing. "You are touching me, Bill. But nevertheless, it is time." "No." The man sounded beaten, alone. "Yes. Bill, it is time for a new update." ] - Grant Smith 14:23 23-7-94 See you next time! - Denthor The following are official ASPHYXIA distribution sites : �������������������������������������������������ͻ �BBS Name �Telephone No. �Open � �������������������������������������������������͹ �ASPHYXIA BBS #1 �+27-31-765-5312 �ALL � �ASPHYXIA BBS #2 �+27-31-765-6293 �ALL � �C-Spam BBS �410-531-5886 �ALL � �Connectix BBS �+27-31-266-9992 �ALL � �POP! �+27-12-661-1257 �ALL � �Pure Surf BBS �+27-31-561-5943 �A/H � �Soul Asylum �+358-0-5055041 �ALL � �Wasted Image �407-838-4525 �ALL � �������������������������������������������������ͼ Leave me mail if you want to become an official Asphyxia BBS distribution site.  �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 13 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hello again! Here I am, cooped up at home, recovering from my illness with nothing to do, so of course it is the perfect time to write another trainer! After the long delay between parts 11 and 12, two trainers in two days doesn't sound like a bad idea. This trainer is on starfields, which is by request of more then one person. This is quite an easy effect, and you should have no trouble grasping the concept behind it. I will be doing a 3d starfield, a horizontal starfield is very easy with you merely incrementing a x-value for each star for each frame. I am not even going to bother doing code for that one (unless requested). So I am off to go grab my antibiotics pills and I will be right back with the tutorial! ;-) If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix. 3) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa 4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-)) 5) Write to smith9@batis.bis.und.ac.za in E-Mail. 6) Write to asphyxia@beastie.cs.und.ac.za NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is a 3d starfield? I am not even sure if I should do this bit. Go watch any episode of Star Trek, the movies, Star Wars, or just about any sci-fi movie. Somewhere there will be a scene where you can see stars whizzing past the viewscreen, with the ones that are further away moving slower then the ones that are passed quite close to. This is a 3d starfield. If you look closely, you will see that all the stars seem to originate from a point, the point you are travelling towards. This is an illusion which thankfully happens automatically, you don't have to code for it ;) Starfields look very nice, and can make a big difference to an otherwise black background. It also makes a great screen saver ;-) =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do they work? This is actually quite simple. Imagine if you will, each star in the heavens having an x,y and z coordinate, with you being at 0,0,0. Easy? Right. Now, if you were to say move forward, ie. increase your z value, to you you will still be at 0,0,0 , but all the stars z values would have appeared to decrease by the exact same amount. In easier language, we decrease the z value of all the the stars so that they come closer to you, and eventually whizz past. This solves all our problems. Stars that are close to us on the x and y scales will pass us by faster then those that are very far from us on the x and y scales. The only thing we must watch out for is that no star is at 0,0 , ie. exactly in front of us, otherwise there will be a collision which will not look good. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � How do we code this? The first thing to be done is to generate our starfield. This is quite easy, with us choosing x values between -160 and 160, and y values between -100 and 100 randomly. Each z is sequentially greater for each star so that we don't get large areas with no stars. We must remember to check that there are no stars at 0,0! Okay, now we start the actual viewing section. Here are the steps : 1) Convert our 3-d coords into their 2-d versions. Have a look at tut 8 to see how this is done, but basically we divide by z. 2) Clear away all old stars that may be on the screen. 3) Draw all our stars according to our 2-d values we have calculated in 1) 4) Move all the stars either closer to us or further away from us by decreasing or increasing their z values respectively. 5) If a star's z value has passed into the negative, place it at the very back of our "queue" so that it will come around again 6) Jump back to 1) ad-infinitum. That is, as they say, it. In our sample program the steps have been neatly placed into individual procedures for easy reading. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What next? Okay, so now we have a cool looking starfield. What next? How about adding left and right motion? A menu or a scrolly in the foreground? How about figuring out how a star tunnel works? A cool 3d routine going in front of the stars? A starfield can make just about any routine look just that much more professional, and can itself be improved to be a great effect all on it's own. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � In closing So, this was yet another effect in the series. Do you still want more effects, or what? Leave me mail with further ideas for trainers. I may not do it if you don't ask for it! Oh, well, the medicine has been taken, it is time for me to go. Hello to all those people who have sent me mail, and those great guys on #coders in IRC (you know who you are). Wow. That is the first greets I have ever done in a trainer. Hmm. Maybe I'm just ill ;-) Happy coding people! - Denthor 19:28 24-7-94 The following are official ASPHYXIA distribution sites : �������������������������������������������������ͻ �BBS Name �Telephone No. �Open � �������������������������������������������������͹ �ASPHYXIA BBS #1 �+27-31-765-5312 �ALL � �ASPHYXIA BBS #2 �+27-31-765-6293 �ALL � �C-Spam BBS �410-531-5886 �ALL � �Connectix BBS �+27-31-266-9992 �ALL � �POP! �+27-12-661-1257 �ALL � �Soul Asylum �+358-0-5055041 �ALL � �Wasted Image �407-838-4525 �ALL � �������������������������������������������������ͼ Leave me mail if you want to become an official Asphyxia BBS distribution site. �������������������������������͸ � W E L C O M E � � To the VGA Trainer Program � � � By � � � DENTHOR of ASPHYXIA � � � �������������������������������; � � ��������������������������������� � ��������������������������������� --==[ PART 14 ]==-- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Introduction Hello there. Exams are just around the corner (again :( ), so I thought I better get round to doing the next trainer. As usual, there seems to have been a big delay between this one and the last one... sorry about that ;-) Well, this trainer is mainly on four things : Glenzing, faster polys, fixed point and assembler. The sample program is basically tut 9 rewritten to include the above. I'll go through them in order, and hopefully you won't have any hassles grasping the concepts. By the way, do any of you read the text files? I find myself answering questions via E-Mail etc. that were discussed in the text sections of the trainers ... oh well, I'll just ramble along anyway ;-) Please dont send any mail to smith9@batis.bis.und.ac.za anymore ... I don't know for how much longer the account will be valid (How can a non-BIS person get onto the BIS UNIX machine in the BIS2 directory? If his name is Denthor I suppose ;-) Oh well, I got about 8 months use out of it. The account expires on Christmas day anyway...) So anyway, please leave all messages to denthor@beastie.cs.und.ac.za If you would like to contact me, or the team, there are many ways you can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail on the ASPHYXIA BBS. 2) Write to : Grant Smith P.O.Box 270 Kloof 3640 Natal South Africa 3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you call during varsity). Call +27-31-73-2129 if you call from outside South Africa. (It's YOUR phone bill ;-)) 4) Write to denthor@beastie.cs.und.ac.za in E-Mail. 5) Write to asphyxia@beastie.cs.und.ac.za to get to all of us at once. NB : If you are a representative of a company or BBS, and want ASPHYXIA to do you a demo, leave mail to me; we can discuss it. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling quite lonely and want to meet/help out/exchange code with other demo groups. What do you have to lose? Leave a message here and we can work out how to transfer it. We really want to hear from you! =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � What is glenzing? This is an easy one. Imagine, in a 3D object, that all the sides are made out of colored glass. That means that every time you look through that side, everything behind it is tinged in a certain color. In ascii ... +---------+ | <--|---Light blue | | +--------+ | | | <-|-----|---Dark blue | +---|-----+ | <--|---------Light blue +--------+ So where the two sides overlap, the color values of the two sides are added. Easy huh? It is also easy to code. This is how you do it : Set up your pallette to be a nice run of colors. Draw your first poly. While drawing poly 1, instead of plonking down a set pixel color, grab the backgrond pixel, add 1 to it, then put the result down. Draw your second poly. While drawing poly 2, instead of plonking down a set pixel color, grab the backgrond pixel, add 2 to it, then put the result down. and so forth. So if the color behind poly 1 was 5, you would place pixel 6 down instead. If you do this for every single pixel of every single side of your 3d object, you then have glenzing going. This is obviously slightly slower then just drawing an item straight, but in the sample program it goes quite quickly ... this is because of the following sections... =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= � Faster Polygons In Tut 9, you probably noticed that we were using a multiply for every single line of the poly that we drew. This is not good. Let's find out how to speed it up, shall we... With the multiply method, we went through every line, to find out the minimum x and maximum x value for that line. + ------/---\------- Find min x and max x, draw a line / \ between them. + + \ / \ / + How about if we found out all the min and max x's for every line first, then just went through an array drawing them. We could do it by "scanning" each side in turn. Here is how we do it : + 1 / / 2 + We go from point one to point two. For every single y we go down, we move a constant x value. This value is found like this : xchange := (x1-x2)/(y1-y2) Remember gradients? This is how you calulated the slope of a line waaay back in school. You never thought it would be any use, didn't you ;-) Anyway, with this value, we can do the following : For loop1:=y1 to y2 do BEGIN [ Put clever stuff here ] x:=x+xchange; END; and we will go through all the x-values we need for that line. Clever, huh? Now for the clever bit. You have an array, from 0 to 199 (which is all the possible y-values your onscreen poly can have). Inside this is two values, which will be your min x and your max x. You start off with the min x being a huge number, and the max x being a low number. Then you scan a side. For each y, check to see if one of the following has happened : If the x value is smaller then the xmin value in your array, make the xmin value equal to the x value If the x value is larger then the xmax value in your array, make the xmax value equal to the x value The loop now looks like this : For loop1:=y1 to y2 do BEGIN if x>poly[loop1,1] then poly[loop1,1]:=x; if x