And drum beat please here's another issue of Commodore Hacking!! We've lasted longer and had more issues put out than some other magazines I won't discuss (wondering where issue 39 of that mag is).
Not many Commodore notes this time - things have gotten a little bit more montatenous(sp - it's late) on the Commodore front.
I was unable to get an article by Craig Bruce in time but I got the next best thing: An interview with him!! Users of his software may find this interview interesting in how he looks at programming.
Right now I'm entertaining the thought of dropping C= Hacking after I graduate which will be sometime around July 1st of this year. I'm interested in somebody who would "carry the reign" so to speak, and take over my job of nagging, bugging people etc :-) to write articles. I've got my system fairly automated in handling requests here - if that person has a VAX account then I could set them up with a mailserver, if a UNIX account then there's oodles of them floating on the net that could be used. PLEASE write to me and lemme know if you're interested. I'm going to try to get one more issue of Commodore Hacking out before July 1st.
Well, it is a new year, and I am sending up a new collection of the Commodore rivia for all to enjoy. If you haven't seen this already, the following is a collection of trivia questions that I post to various networks every month. I have collected Trivia Edition #8-13 in this article. As you may know, these questions form part of a contest in which the monthly winner gets a prize (Thanks to my various prize donators). The whole thing is mainly just for fun, so please enjoy.
As the new year rolls in, I am happy to report the following:
Jim.
The following article contains the answers to the July edition of trivia ($070 - $07F), the questions and answers for August ($080 - $08F), September ($090 - $09F), October ($0A0 - $0AF), November ($0B0 - $0BF), and the questions for the December edition ($0C0 - $0CF). Enjoy them!
We... are... VR Troopers! Okay Troopers, once again we need to make an excursion out of the three dimensional world and into our own little virtual world inside the C64. So sit back in your virtual chair, put on your virtual thinking helmet, maybe grab a virtual beer, and prepare for a virtually useful experience with another virtually humongous article.
Last time we laid down the foundations of 3D graphics: rotations and projections. In this article we will build upon this foundation with a look at hidden surfaces as well as filled surfaces. In addition we will snaz up the old program so that it is a little more efficient by for instance introducing a much faster multiplication routine and moving all variables into zero-page.
To get us in the mood let's review from last time. We are in a three-dimensional space; in particular, a right-handed three-dimensional space, so that the x-axis comes towards you, the y-axis increases to the right, and the z-axis increases "up". Now we have some object, centered at the origin.
To rotate the object we derived a 3x3 matrix for each axis which describes a rotation about that axis. After rotating we translate the object along the z-axis and then project it through the origin onto a plane z=constant.
As you recall the projection of a point is done by drawing a line from the point through the origin, and then figuring out where this line intersects our plane z=constant. You can think of this line as a ray of light bouncing off the object and through our little pinhole camera lens.
Clearly for any solid object some parts of the object will remain hidden, though, i.e. when you look at your monitor you can't see the back of it, and you probably can't see the sides. How do we capture this behavior mathematically?
No matter where you place your hand in space, the very last point at which it is visible is when it is exactly parallel to the light rays coming from it to your eyes; or, to put it another way, when the light rays are exactly perpendicular to a normal vector to the surface (in the above case this vector is either a rod or your finger). If the angle between the normal and a light ray is less than ninety degrees, then the surface is visible. If greater, then the surface is invisible.
At this point you may be wondering how to figure out the angle between two vectors. It turns out we really don't have to calculate it at all: instead we use a very important tool in our mathematical toolbox, the dot product.
If we have two vectors v1=(x1,y1,z1) and v2=(x2,y2,z2) then the dot product is defined to be
But we need to understand something about the dot-product. theta is the angle between two vectors joined at their base; mathematically the way we are going to draw the light ray is to draw a line FROM the origin TO a point on the surface. In our model above, we are going to draw a line from your eyes to the palm of your hand and then slide the normal vector down this line until the base of the normal vector touches your eye.
The whole point of this is that when we look at the dot product we need to keep in mind that if the dot product is negative, the face is visible.
All that remains is to write down an equation: let's say that we've rotated the surface and know a point P=(x,y,z) on the rotated surface, and we have a normal vector to the surface vn=(vx,vy,vz). First we need to translate down the z-axis so that P -> (x,y,z-z0) = P - (0,0,z0). If we then take the dot product we find that
We seem to have left something out here: how do we calculate the normal vector vn? One way to do it is by using another vector operator, the cross-product. The dot product of two vectors is just a scalar, but the cross product of two vectors is another vector, perpendicular to the first two.
The most common way to visualize the cross-product is by using your right hand: imagine two vectors in space, and place your right hand along one of them, with your thumb sticking out. Now curl your fingers towards the other vector. Your thumb points in the direction of the vector formed from the cross-product of the first two. You can easily convince yourself then that (A x B) = -(B x A), that is, if you reverse the order of the cross product, you get a vector pointing in the opposite direction.
Therefore, if we take any two vectors in the face (in particular, we know the edge of the face), and then take their cross-product, we have a normal vector.
But because we are dealing with a cube, we have an even easier method! We can use the fact that the faces on a cube are perpendicular to each other: if we take two points and subtract them we get a vector going between the two points. On a cube, this will give us a normal vector if we use two "opposite" points. Therefore all we need to do is rotate the cube, subtract two z-coordinates, add to K, and check if it is positive or negative.
This is how the program does it, and the specifics will be explained later. Right now I want to show you a second method of hidden surface detection. Instead of using the three-dimensional rotate vectors, what if we use the two-dimensional projected vectors? If we take the cross-product of two of these vectors we get a vector which either points into the screen or out of it, which corresponds to a positive or a negative result.
The cross-product is usually done by taking the determinant of a matrix. I am not going to explain that here -- you can look in any decent calculus book for the full cross-product. All we really care about is the z-coordinate of the vector, and the z-coordinate of v1 x v2 is:
What is this quantity anyways? Consider a parallelogram made up of our two vectors v1 and v2. The magnitude of the cross-product just happens to be
Note that the second method is quite general, while the first method only works for objects which have perpendicular surfaces (at least, in it's current form presented here). On the other hand, the first method is significantly faster.
Now that we've hidden the faces, it's time to fill them:
Q: How do you make a statue of an elephant? A: Start with a block of granite and carve away everything that doesn't look like elephant!The first method of filling faces is very simple in concept. Let's say we want a cube with white faces and black edges. Before, the program would make the buffer black and then draw in the white edges. The idea here is to make the entire buffer white, draw the edges in black, and then make everything outside of the edges black. Quite simply, we start with a solid block and then take away everything that doesn't look like a cube! You can also think of it like a cookie cutter: we press our cube-shaped cutter down and remove all the dough outside of the cutter.
This simplistic method actually has some advantages. If the object is very large, we spend very little time doing the actual un-filling. We don't care about how complicated the object is, because we just trace out the edge. Finally, this gives us an extremely easy way of implementing a rudimentary texture-mapping in multicolor mode. For instance, instead of coloring the block white, what if we used a changing pattern of colors? As long as the edge is a specific color, the pattern can be any combination of the other three colors. An example program which does just this is included -- note that the inititalization program needs to be changed slightly to run this program.
In other words, we roll the dough, draw a pattern into it, press our cutter down and remove the outside dough. We are left with a cube with patterns all over it.
On the downside it's not quite so easy to do things like have each face a separate color (but who wants wimpy separate colors when you can have evolving texture patterns, eh? :).
The program makes a few refinements to this technique. For instance, instead of coloring the entire buffer white, it calculates ahead of time the minimum and maximum values for y, and only colors that part of the drawing area white.
For the sake of completeness, here is another method of filling: exclusive-or. A clever way of filling faces is to use some EOR magic. Let's say we want to fill everything between two points A and B. We want to start filling at point A and stop at point B, and since EOR is a bit flipper this gives us a means of filling. Consider the following situation in memory:
Ah reckon y'all will just have to wait until next time tuh see :).
First, some bugs. There were two places in the line drawing routine where an SBC was performed with the carry clear when it should have been set, so we need to add some SECs in there. Somewhere there is a strange bug related to y-rotations, but I didn't track it down.
Although not a bug, there is something to think about. On the computer, x increases to the right, and y-increases downwards, with z coming out of the screen. But this is a left-handed coordinate system, and all our calculations were performed in a right-handed coordinate system. What this means is that one of our coordinates is actually a mirror-image of what it should be, while the other coordinate is where it is supposed to be. Remember that a projection generates a negative mirror-image of the object -- the computer coordinate system mirrors a single axis of the image again!
Because of the symmetry of a cube, this makes no difference. A smart way to fix this is to translate the object in front of the projection plane, i.e. to use the translation z=z+c instead of the currently used z=z-c, but still project through the origin and into the plane z=1. Since I am not particularly smart though, not to mention lazy and unmotivated, I didn't bother to fix this.
Before we start adding the new stuff like hidden surfaces into the code, why don't we think about doing some simple optimizations to the old code? One really easy thing to fix is in the projection routine. You will recall that the earlier program rotated z and then added 128 to it to use as an index. Why bother to add 128 at all? I dunno -- sometimes things seem like a good idea at the time. So that's something to fix. It's not that it's a big waste of time, it's just one of those annoying things that there's no reason for.
How about the variables? They're all just sitting at the end of the program -- why not move them all into zero page? Sounds good to me! We just need to make sure we don't use any sensitive locations in zero page that will hose the whole computer. So now that's fixed.
On the C64 an interrupt is performed every 60th of a second which scans the keyboard and things like that -- why in the world do we want that running in the middle of all our calculations? I dunno -- let's turn it off (but turn it back on before checking to see if F1 etc. was pressed!).
A footnote observation: when the rotation matrix is calculated, two macros are used (MUL2 and DIV2) which multiply and divide a signed number by two. It never ceases to amaze me what happens when you simply sit down and think about something, and in this case these two macros can be made much simpler:
There's the easy stuff to fix. What about the calculations themselves? The rotation is pretty straightforward -- nah, skip that. The line drawing routine takes up an awful lot of time -- maybe we can speed that up? That's for a future article :). Clearing the buffer takes a lot of time, but now that we're going to have filled faces there isn't too much we can do about that. In fact, so much more time is spent in those two areas than is spent in other parts of the code that any other optimizations we make really aren't going to make a very big difference... BUT...
How about multiplications?
Whoa there, wait a minute, all of our calculations are using signed numbers. Won't that make a difference? Well, the above calculation is completely general -- I never said what the sign of a and b are. The fact that we are using two's complement notation makes this even simpler!
Recall that our multiplication is
Well, that's easy to duplicate. From our first equation above, we see that
In other words, if we modify our table slightly, we get exactly the result we want. So here is the code to multiply two numbers together:
At the moment we don't do very many multiplications, but in the future, when we write a generalized routine to rotate and project an arbitrary object, this will give us a humongous time savings.
Astute readers may be thinking ahead here: in the program, for each projection we have two multiplications, x=x*c and y=y*c, where c is the same in both cases. So if we store c in ZP1 and ZP2, we can make the multiplication even more efficient, right? The answer is yes, but only by being extremely careful, for reasons that will be detailed in exactly two paragraphs.
BUT WAIT! We have to think about a few things here. What happens when we multiply, say, -1 * -1. In two's complement notation -1 is equal to 255. So our above algorithm adds 255 to 255 to get an index into the table and gets... oops! Our table needs to be larger than 256 bytes! In fact this is very easy to fix, because of the way two's complement works. All we need to do is put an exact copy of the 256 byte table on top of itself, and the table will work fine. (If you look at the initialization program you will notice that the statement is: q%=s*s:poke bm+j,q%:poke bm+j+256,q%).
BUT WAIT!!! What kinds of numbers are we multiplying together here? Our vertices start out at the points (+/-1,+/-1,+/-1). Our rotations correspond to moving these points around on a sphere, so it is easy to see that the largest rotated value we can have is sqr(3), the radius of this sphere. Since we are multiplying these numbers by 64, the largest value we can have for these numbers is 64*sqr(3) = 111. Okay, no big whoop, what are the values for d/(z0-z/64) anyways? Well, for z0=5 and d=150 say we get values like 28...
ACK! When we go to multiply we are going to add 111 to 28 and get 137, but in two's complement notation this is equal to -119.
Example:
We can see that we can get numbers larger than 127 when we add the two multiplicands together. What is the smallest number we will come up with? Certainly the smallest x is going to get is -111. Ahhh... d/(z0-z/64) is always positive, so when we add them together we will get something larger than -111, which in two's complement notation is 145. This means that we can treat the table entries between 127 and at least 145 as positive numbers instead of two's complement negative numbers, and everything will work out great.
Incidentally, fudging this table provides an easy way to add pretty cool special effects. The initialization program sets up the math table using the following line:
And this is why we can't store d/(z0-z) in the pointers ZP1 and ZP2 -- if we did, then for a given multiplication we could get numbers larger than 127 and smaller than -128, and our clever table would no longer work right. We can still get around this -- all we need is two clever tables, one for the positive d/(z0-z) and one for negative d/(z0-z). For the first table, we have the situation outlined above: no numbers smaller than -90 or so, and numbers possible larger than 127. For the second table we have the reverse situation: no numbers larger than 90 or so, but possible numbers less than -128. Since we are using two pointers anyways (ZP1 and ZP2), this is not difficult to implement.
The end result is that you can do the entire projection in around 36 cycles if you so desire. 36 cycles? Note that for the second table the code does something like EOR #$FF; CLC; ADC #$01. Well, if we set up the second table as f(x)=(x+1)^2/4 then we have included the CLC and ADC #$01 into the table, so the instructions can be removed. The entire projection routine is then:
You might be asking, what is the true minimum value for a given z0 and d? Well, I tried writing down a set of equations and minimizing according to some constraints, and I ended up with a sixth-order polynomial which I had to write little newton-iteration solver for. In other words, I don't think you can write down a simple function of d and z0 to give the table boundaries. I found 150 to be a perfectly reasonable number to use.
Incidentally, this is why the projection was not changed to z=z+c -- I didn't want to go fiddling around with it again. Maybe next time :).
ONE MORE THING!!! This is very important. The math table MUST be on an even boundary for the above algorithm to work correctly. This one is easy to get bit by.
First, dealing with signed numbers is much trickier -- the logarithm of a negative number is a complex (i.e. real+imaginary) number, complete with branch cuts. You can get around this by setting up the tables in a special way (for instance by letting log(-x)=-log(x)) and putting in some special handling, but it isn't as efficient as the algorithm used in the program.
Second, accuracy decreases significantly as x and y get large, so that for an eight-bit table of logarithms you will often get an answer that is off by one or more. You can in fact get around this problem by using some sneaky manipulation -- if you are interested in seeing this, contact us!
But it is worthwhile to keep this method in mind if you need a really fast multiplication and you aren't too worried about accuracy.
Christopher Jam (phillips@ee.uwa.edu.au) has come up with an interesting variation on this method. It calculates 64+64*x/z and uses a slightly different structure for the signed numbers, and runs almost as fast as the method used by the program -- contact him for more information if you're interested.
Here is something to consider: when one face is visible, the opposite face cannot be visible! Because of the way projections work, though, the converse is not true; it is entirely possible to have two opposite faces invisible. To prove this to yourself just look at your favorite box, like your monitor, straight-on, and notice that you can't see the sides!
All that the program does is subtract z-coordinates and add them to the constant K, and check the sign. Unfortunately we can have a positive overflow while adding stuff together (since these are signed numbers), and if we don't catch the positive overflow we will calculate a negative result when the result is actually positive! This will of course wreck the hidden surface removal.
Next, the cube is drawn. The background is black and the faces are white, i.e. our fill color is white. Clearly then we want to draw our lines in black. I could have reversed background and foreground colors and left the line routine as-is, but of course being the lazy programmer I am I decided instead to change the table BITP. You may recall that the earlier table had entries like %10000000 %01000000 etc. Now it has entries like %01111111 %10111111 etc., and instead of ORAing the values into the buffer, they are ANDed into the buffer. This then draws lines of zeroes into our buffer which is solid ones.
Finally, to un-fill the outside of the cube the program simply goes through the buffer from ymin to ymax, coloring everything black until it hits a zero, i.e. an edge. At this point it calculates the appropriate pattern to clear up to the edge, and then does the same thing starting from the right hand side of the buffer. In other words it runs along a specific y-value coloring everything black until it hits the edge of the cube, and does this for all the relevant y-values.
MAKE SURE that you change the value of D from 170 to 85 if you try this program! Pixels are doubled now, so that resolution is cut in half. This is located at line 240 in INIT3D2.0
Steve Judd George Taylor 12/2/95
This document is Copyright 1995 by Stephen Judd and George Taylor. Much like the previous one. It is also freely distributable.
And here is the source code:
3D is fun and interesting but in the end we must always display our work on a two-dimensional surface, the CRT. Not only are two-dimensional algorithms the foundation of three-dimensional drawings, they are of course useful for many other applications. This new series of articles is intended to complement (hah -- get it?) the 3D articles by George and myself. Between the two articles you should have at your disposal a powerful graphics toolbox for all of your applications.
The foundation of all of our drawings is a single point, and a logical next step would be a line. Algorithms for doing both of these things were discussed in depth in the first article of the 3D series, so you can look those up in a back-issue of C=Hacking. What is next after points and lines? Curves! So to start with, let's think about drawing a circle.
You can write the equation for a circle in many ways, depending on your coordinate system. In cartesian coordinates, the equation of a circle is:
But let's step back and consider: the above equations all give a "perfect" circle. Is there any way we can draw an "approximate" circle, with a large speed increase? The answer is of course yes, since this wouldn't be a very interesting article otherwise!
Let's say we are standing at a point on the circle, and want to take a step towards the next point. In what direction do we take this step? Consider a line tangent to the circle, touching the point where we are standing. If we take a little step in that direction, we ought to get close to the next point on the circle. The way to calculate the tangent line is to use the derivative, which will give us the slope of the tangent. Taking differentials of equation (1) above we have
Let's start at the point x=r,y=0 i.e. the right-endpoint of the circle. Since we are on a computer we want to take a step of length one in some direction (i.e. step one pixel), and at this point on the circle y is clearly increasing much faster than x. You may remember from the line drawing algorithm that we viewed the process as "keep taking steps in x until it is time to take a step in y". We are going to apply that same philosophy here: keep taking steps in y until it is time to take a step (backwards) in x. So our iteration is now:
How long do we do this for? In the same way that at x=r y increases much faster than x does, when y=r x increases much faster than y does. Somehwere in-between they have to be increasing at the same rate, which means the slope of the tangent line is equal to +/-1, i.e. at the point x=y. At this point we have drawn one-eighth of the circle. We can either draw all eight segments of the circle independentally, or else we can use the symmetry of a circle and do an 8-way plot.
TO SUMMARIZE: Here is the basic algorithm
"Yeah, but how well does it work?" Quite well, as a matter of fact. It will draw a perfect circle for circles with a radius greater than twelve or so. For circles with a smaller radius the sides start to flatten out, and the circle becomes squareish. Interestingly, the "discrete x" approximation improves the result over the straight floating-point calculation significantly!
So this is the best algorithm I was able to come up with for drawing a circle. If you have any suggestions for improvements or other ideas, please feel free to share them :). As always I must thank George Taylor and Christopher Jam for their suggestions and for helping me work out some ideas.
If you have any particular 2D algortihms/calculations that you would like to see, please feel free to suggest future topics for the 2D graphics toolbox.
Finally, here is a BASIC7.0 program which demonstrates the algorithm:
Advanged FLI is name I came up with during the time I coded the first version of AFLI editor. I have never claimed to be the one who discovered this new graphics mode for 64. I myself give the credit for COLORFUL/ORIGO but I am not sure if anyone did it before him (splits have been done but in my eyes they don't count).
In AFLI we can get 120 colors in theory (counted like this 16!/(2!*14!)=120). When we put red and blue hires pixels close to each other we get a vision of purple - thanks the television.
AFLI is just like FLI with $08-$0f (hires value) in $d016 and a couple of sprites over the first three marks. With $d018 we change the start of screen memory. And the good old $d011 for the main work.
AFLI is the same as FLI but we don't use the $d800-$dc00 area for the third color. Actually we can't. In normal hires pictures the colors on the picture is ordered in a normal screen (normal text screen is on $0400+). The upper 4 bits is the color for bit 0 in picture bitmap and the lower 4 bits is the color for bit 1 in picture bitmap (or the other way...but let us think that was the right way).
For example: a normal hires picture char (8x8 bits)
In FLI we have built the screen to have badlines on every scanline of the screen. This gives us the possibility to change the screenmemory the picture uses on everyline. Now... when AFLI (and FLI) uses screen memory for colors and we change the screenmemory start on everyline, we can have new colors on everyline.
The screens are usually ordered like this.
An example... Here we have cut from the memory showing the first bytes in every screen.
When we code a FLI routine we know that we have succeeded when we get a 3 marks wide area filled with value $ff on the screen. In FLI the thing is easily taken away; we just fill the three first bytes of a line with empty bytes ($00). In AFLI the value $ff is a color. If we try to clear the three first marks, we still have the gray area. WHY? The $ff value comes to the screen.. so... the $ff is a color and the upper four bits of the byte is the color for empty pixels. We can not clear the first three marks to wipe the thing off. We have a new lovely problem: we have to put black (or whatever) sprites over that area. This is just timing.
This may look very complicated and I think you will still be asking many questions from me - the text I have written surely ain't the best novel ever written. I'm great in jumping from a thing to another.
I really would like to start a thread on your favorite sequences of 6502 code. I hope much people will react so we can build up a library of the most beautiful 6502 code ever seen.
I would suggest little code fragments, probably not longer than 10 lines, doing some tiny function.
I propose the following standard:
I will hereby start with my all-time favourite code, I discovered it only recently and I will also show some examples of how to use it!
With these two beauties I want to give you an idea of what I mean, and please follow me up!.
BONUS. A little routine to clear the screen without erasing the sprite pointers.
This one only observes the VIC chip:
It's some time since I actually coded a routine of this kind, and I'm writing this off memory, so there might be some errors in the following code.
I hope this is what you were looking for. Sorry for not supplying a complete source, but as I said this is all from memory.
PS. My native lanuage is not english and I typed this in a hurry, so sorry for the lousy lanuage / source.
Furhermore, ways of getting an rnd.
Anything unclear? Mail me at s514@ii.uib.no
Bye...
- Rolf Wilhelm Rasmussen
Equal of Eternity
The following is an interview of Craig Bruce, author of numerous programs such as ZED, ACE etc for the Commodore 64/128.
What computer experience did you have before the Commodore computers?
Very little. I was 14 at the time, in grade nine, and it was December 1982. My Jr. High school had a few CBM 8032s, but I never actually got to touch one. I took a "mini course" on computers and learned a tiny little bit about what computers were like and about BASIC. To give you an idea of how little I learned, I was entirely incapable at the time of figuring out how to increment a variable (X=X+1).
What was your first Commodore computer and why?
My first computer was a VIC-20. I had the choice narrowed down to a VIC, a TI99-4A, or a Timex/Sinclair 1000(?). (I don't think I had heard of the Ataris or the Apple). I chose the VIC partly because it was related to the computers at school but mostly because it had the most impressive brochure and I had the most information about it. It was theoretically a Christmas present, but it didn't stay in the box very long. I paid half of the $400.00 price tag and my parents paid the other half.
How did you learn programming on the Commodore? Did experience from other PC's help?
Ahhh, those were the days. I learned programming from a few sources. The user's guide that came with the VIC was quite helpful, and I read the magazines of the day, mostly Compute!s. I also had a friend who went to high school and used the computers there who knew a thing or two, and two other friends who got VIC-20s soon after me, so we learned from each other.
I also took a relatively informal night course that was offered for programming VIC-20s. By the time I took it, though, I had already learned just about everything that the course tought: BASIC. Then, in the last class, the instuctor talked just a little bit about machine langauge, just enough for me to understand what was in the VIC-20 Programmer's Reference Guide. I learned 6502 machine language shortly after that.
Experience from other PCs didn't really factor into things, since I had no experience with any other PC. However, when the time came to learn about other computers and other programming languages (in high school and bachelor university), I had an enormous advantage over the other students, since I understood so thoroughly how computers worked because of my VIC-20 experience.
What other interests, besides hacking on the Commodore, do you have?
Not many. I don't get out much and I have only a handful of friends. I spend most of my time sleeping, watching TV, net surfing, doing school work, and/or hacking on Commodores. Hacking on Commodores is in my blood. While I'm doing these other things, I'm usually thinking about hacking on Commodores. You might say that I'm a sterotypical total computer geek. I do like biking, though. I bike to school every day. And music.
What is your feelings on the demise of Commodore?
Losing Commodore was a little sad, but as someone said on the newsgroup when Commodore went under, "What has Commodore done for you lately?". We 8-bitters lost all support from Commodore long before its demise. I certainly don't blame them; 8-bit computers are a thing of the past and there wasn't a big enough market to support a company the size of Commodore.
Do you see anything in the future that signals anything that will extend the useful lifetime of the Commodore 8-bits?
IMHO, there are only two things that 8-bit computers need to survive in the hands of hobbiests indefinitely: serious system software and modern hardware peripherals. Some serious system software has begun to surface recently :-), and Creative Micro Designs has been providing modern peripherals for us to use. New application programs are needed too, but I'm assuming that hobbiests + serious_system_software --> serious_new_application_programs. (Perhaps this is a bit self-serving).
Eight-bit computers have two big advantages over bigger PCs: a much lower price and a much higher understandability quotient. Both of these are very important to hobbiests.
Do you feel that with the addition of newer periphials that are gradually superceeding the CPU's job (REU, RamLink, SwiftLink etc...) that the Commodore 8-bit standard machine is no longer standard??
Indeed, there are lots of options. But I think that this is a good thing. The original Commodores are quite limited, and this modern hardware is needed to allow the Commodores to remain useful in the networked world. An important feature of all of these new products is that you can flip a switch or pull out a cartidge and you're back to your little old standard Commodore. Of course, who really wants to do this.
The reason that I have stayed with my little Commodore for all of these years is that I believe that it still has quite enough power (using modern peripherals and expanded memory) to do what I require of it. For example, it's quite possible to have a nice little 17K text editor that can edit huge files and be very useful. You don't need a multi-megabyte program with all kinds of snazzy features that requires a monsterous machine to run on to do this. These multi-megabyte programs are simply bloated and poorly designed.
Will there ever be an update to Zed? (a question asked on a lot of the commericial providers)
Yes. I've been promising this for a long time, but the right time to do this is finally near.
What is the process that you use for writing your programs?
I'll start this answer with a Unix-fortune quotation:
"Real programmers don't draw flowcharts. Flowcharts are, after all, the
illiterate's form of documentation. Cavemen drew flowcharts; look how
much good it did them."
For complicated algorithms, I'll sit down write some pseudo-code, and I
always plan and write out complicated data structures. But other than this,
I usually just sit down and write code, after kicking ideas around in my head
long enough for me to know what I have to do.
It's been noticed that you have a "fanatacism" about speed in your programs. Can you elaborate on this?
Guilty as charged. As I said above, I despise bloated software that needs a mega-machine to run on fast enough. I like software that is sleek and mean, and I have an axe to grind that little 8-bit Commodore computers offer quite enough computing power for most applications that most people would use them for. The exceptions are number-crunching, huge-data processing, and heavy computation. However, for most interactive programs, an 8-bit processor is quite enough. So, I grind my axe by producing fast programs. Arguably, that effort is sometimes misspent (like in the printing to the screen in ACE -- I still have a few more tricks up my sleeve though...), but I like to go a little too far sometimes to make people go, "Wow! I didn't know this little machine could do that so fast!!" I like to upset the notion that you need a huge machine to get adequate performance. (In fact, sometimes the opposite is true, since programmers assume that they can be extra sloppy when programming for huge machines).
As a user, I like crisp responsiveness. This is a feature of personal computers that can sometimes be absent on big multi-user virtual-memory machines.
I also have a big thing against backwards compatibility ("hysterical raisins"). This is a significant cause of software bloatedness. This is one reason that ACE, for example, was designed from scratch rather then with the pre-set limitation that all BASIC-compatible programs should run with it (a la CS-DOS).
Is there anything that you find particularly useful / handy about the Commodore's architecture?
Yeah, it's simple.
And the corallary: Is there anything particularly annoying?
Yeah, it's limited.
What is currently in the works / planned??
My Commodore job queue looks like the following:
Keep on Hackin'!
A discussion regarding Commodore 1541 disk drive alignment procedures, with suggestions.
An older version of a disk utility program, ("Disector" v3.0, as I remember it), had copy protection that would not let you load the disk up unless your disk alignment was perfect. While initially loading itself, it would search and search, never quitting, until it found what it was looking for, exactly where it was looking for it. It would stay in an endless loop, searching forever, never making it to so far as the first screen. This essentially "locked up" the computer, if the program thought the disk it was on was an illegal copy.
This quickly became the most hassle-free, no-worry alignment program I've ever seen. I have seen and used most of the others; this method beat them all, no contest, in my opinion.
The other programs, the ones made for aligning your drive, never consistently worked acceptably well, in my experience. Other technical users apparently feel the same way about them, as the "General FAQ, v2.1" on Commodores points out. They would work OK part of the time, or on part of the drives you tried, but not all, I found. Or they would say you now had a perfectly-aligned drive, but some difficult copy protection schemes would still not load and run on the newly tuned-up drive friend. A friend of mine, now deceased, once had a drive no alignment program could fix. We tried everything we could find. After aligning it with a given method or program, some programs would load that would not load before, but others would now no longer work, that used to work before. All in all, it was very frustrating, and the general feeling was that there has to be a better, easier, more reliable way to do this.
All an alignment program has to do, is to make sure that when the disk drive says it is precisely at a given track's physical location, that it is really there, centered on that track.
There are other Commodore adjustments, but alignment seems to be, by far, the most common problem. Disk drive rotational speed can be adjusted, but it usually is not the problem. In fact, I've seen more than one drive, that when adjusted to read a program-reported "perfect" 300 rpm rotation speed, they quit reading disks; requiring speed to be set at a reported 310 rpm, to work again. The end stop gap can also be adjusted, but I've never seen it be the real culprit with a non-working disk drive. Your experience may vary, of course, but I've always found that it is best to concentrate on alignment first, then fool around with the other adjustments ONLY after alignment is truly corrected, and only if it still refuses to work properly.
Once alignment is corrected, there are methods available to insure that it stays that way. For instance, you can have the stepper motor's pulley mechanically pinned to its shaft, instead of merely relying on the factory's interference fit to hold it. Commodore 1541 drives were made to be self- aligning, apparently, which would be fine if "head knocking" protection schemes were not around. Since they are, the pulley should, ideally, not be allowed to turn on its shaft, which is what causes misalignment problems.
Once you've done this, you set the drive up on one side, so that you can (carefully!) reach into the mechanism, to physically rotate the stepper motor, which would normally be on the bottom of the drive. You type in the program's loading instructions on the computer, and you then wait until the screen went black (copy protection searching for certain info on the diskette). This is where the program "locks up," with the unaligned drive.
Once the program is loading, but stuck and unable to find what it wants, you reach into the mechanism, very slowly and carefully, turning the stepper motor a slight bit in either direction, and stopping. Tiny adjustments are a lot; don't overdo it. Be patient; don't go too fast, or move it too much! You watch the screen carefully, and listen to the drive's sounds.
When you have rotated the stepper motor to the proper place, the sounds and the screen will act a little different, perhaps only slightly so. Wait a second, not moving the stepper motor at all. When you are right on, alignment-wise, the program will find what it is looking for, and the program's main menu will appear.
Once the main menu has come onto the screen, you have a perfectly aligned drive. Then you have to retighten the stepper mounting screws, being very careful not to accidentally move the motor in the process. Hold the motor firmly while retightening both screws in small steps, alternating back and forth between them until they are both tight. The rotational force of the screws turning, forces the motor to move some, so watch for it.
With this method, using a specially-prepared disk, I always got perfect results; everything would load, every time, from then on. (Assuming that the disk was formatted with a good drive to begin with; any disks you made recently, on your badly-aligned drive, may not load after the alignment procedure. Transfer the info on these disks, to a second, known-good drive, before you do this procedure. This is normal, however, no matter what method you use to align a bad drive.)
Ideally, the Commodore-compatible reading program would be short and simple enough to fit inside 8k of memory, so it could fit on a cartridge. This would allow it to work, even if a user's disk drive would not load programs anymore. It could still be stored on a diskette, too, with a little planning.
Theoretically, once you had the specially-formatted diskette, and the program on cartridge, you would only need a screwdriver to take the drive apart, and a Commodore microcomputer to run the program on. No other special tools would be needed, and very little technical knowledge would be required; just some general safety tips, because you are working around sensitive electronic parts, with wall current coming into the drive itself, at least on older 1541's.
Techies should appreciate it as a great, reliable and cheap way to align troublesome disk drives, and those people with a C64 in a closet would sure appreciate their technical buddies getting their dead systems going again!
If a person were to do this, I would suggest that they write an IBM program that would use a high density, 1.2 megabyte capacity, 5.25-inch type of disk drive to create the special diskettes, which the 1541 would later read.
Doing this would allow the creation of very thin tracks on the diskette's surface, spaced closely together. This would, within the limitations of the 1541's read head, allow the Commodore to "see" precisely where it currently was, to one side or the other of some "centered" position. The advantage of thin tracks, widthwise, is that the read head won't see them at all, reliably, unless you are exactly, perfectly right on top of them. Another advantage to this, again within the limitations of the 1541's read head (whatever that may be), is that left or right of center, the head would likely pick up the next track over, letting you know you were off by a certain amount automatically.
I hope I'm making myself clear, in my explanation of this. If I am not, Email me with your questions, and I'll try to answer them better, and/or update this file, to entice someone else to work on this. I really would like to see it done. (Current Email address, as of Sep 94: wardshrake@aol.com on the Internet, or just WardShrake on AOL. Will soon have a Compuserve Email address, too: I'll be user 75207,1005 there, or 75207.1005@compuserve.com on the Internet.)
Anyway, let's continue. With the IBM creating a specially-made disk just for this one purpose, you would not even have to worry about following any standard formatting procedures. No user-stored data would ever be written to the diskette, so standard sectoring could be safely ignored. You could create any signal or sectoring scheme you like, as long as the IBM could create it, and the Commodore could read it; and you'd be writing both programs, anyway, making this easier to insure, right?
I can hear some die-hard Commodore users saying, "I hate IBM's" or "I don't even have an IBM" or some such. Fine. Not a problem. If all the IBM-compatible program did was to create a special floppy disk, once, then quit, you would not even need to OWN an IBM, you'd just need to be able to USE one for a few minutes.
Even if you don't have access to one at work, and don't know of anyone who has one to lend you, I will stick with this suggestion, because I know that some businesses that make photocopies often also rent IBM's and Mac's on an hourly basis, for very little money. My local Kinko's copy center rents them both at $10.00 an hour. You would only need it for a few minutes or so.
The diskette-creation program would only need a few minutes to run, to make up a special disk, so you'd only be paying for a good quality, blank high density floppy, and ten or fifteen minutes of rental time, tops. The copy center person may even be able to start up the floppy-based IBM program for you, if you don't know how to do it yourself. That should come to $5.00 or less, even if you don't own or normally have access to an IBM compatible computer! You can't beat that, for a utility to align equipment!
OK. In overview, you'd need to use an IBM-compatible computer, just long enough to load an IBM-compatible program which would create one special, 5.25" diskette, perhaps on a high density floppy. You would then open up your Commodore drive's case, and start up a special program on your Commodore 64, to read the created diskette. (Again, an 8k Commodore program would fit very easily on a cartridge, for easiest loading and running.)
While the computer and drive were running, you would (very carefully, and observing safety precautions) loosen the stepper motor's screws, and slowly turn the motor clockwise and counter-clockwise, until the Commodore program's screen info told you that you were exactly where you should be, right over the proper track. Not to the left or right of it, but in perfect alignment.
Because the Commodore disk-reading program would be "on" constantly, and reporting any small changes to you via information on your screen, you would only have to take a few minutes of fiddling, doing a simple, non-technical turning of the stepper motor, to get the drive aligned. The two computer programs that would make up this package would be doing most of the work.
I imagine a drive could be perfectly aligned, and back in running order, in fifteen minutes or less. Five, if you paid attention to the process, and had some practice before. Remember, this is based on an alignment procedure I really used to do, using a heavily-protected diskette, so I am extrapolating from my personal experiences, even though I'm talking about a theory here.
I don't see where there would be any easier, simpler method of doing a disk alignment. The user wouldn't even have to know a thing about tracks and sectors; they would just loosen two screws, following some instructions, and turn the motor. What could be any easier?
The program could, if it was really creative and well-done, tell them to rotate the motor clockwise or counter-clockwise (as they face it), to dial the motor precisely in. Tracks to either side of an arbitrary (track 18?) center position would say to go one way, tracks on the other would say the reverse. When you turn it too far one way, it would reverse its instructions to you; you would know you were very close then. When you were "right on," the program would tell you so. You'd lock the screws down, carefully, and as long as you hadn't jiggled the motor when you tightened it back down, you would be all done!
Ward Shrake Covina, California