By Sane <sane@telia.com>
In this article we (or actually I) will talk about texture mapping.
I know I said I was gonna write about optimizing the poly routines, but that's really up to you, and texture mapping is a lot more interesting :)
But first, the gouraud shading poly routine had a bug in it which I said I'd give you a fix for if I figured out what was wrong, remember?
The bug is easily solved by changing
FOR x=x1 to x2
in the gLINE routine, to
FOR x=INT(x1) to x2
That way we make sure no numbers will be rounded so that a pixel is skipped or such.
For all the lazy people out there, there's a file called gpolyfix.bas with the downloadable version of this issue. In it, I also changed the PPS (polys per second) counter so that it's more accurate.
The texture mapping I'm writing about in this article doesn't give the best visual results, since it doesn't correct for perspective and such, but it's one of the fastest ones. When I decided to write an article about texture mapping instead of optimizing, I started to look around for information about it, since I didn't know how it was done at the time :) I didn't understand much, partially cause I wanted to learn it quickly, and didn't take the time to understand it, but also cause a lot of the tutorials made it seem a lot harder than it is. Today I tried an idea I came up with though, and it worked, so I finally started writing the article :)
Texture mapping is really a very simple thing to do, pretty similar to gouraud shading. You do exactly the same thing as you did when interpolating color values in gouraud shading, only that you do everything twice, since we're using two texture coordinates (U and V) instead of one color value (C). When changing the gPoly function into tPoly, I didn't do much but to replace c1,c2 and so on with u1,u2 and so on, and adding v1,v2 and so on (quite a lot of so on, I know, but I don't know how to write it in a better way :) Same thing could be done with gLINE, although I wrote tLINE from scratch, since that took less time :)
Here's the code from tPoly, also available from tpoly.bas in the downloadable version of QBCM:
'Made by Sane at the 1st of August 2001, for QBCM SUB tPoly (xx1, yy1, xx2, yy2, xx3, yy3, uu1, vv1, uu2, vv2, uu3, vv3) 'Declare an array for storing slopes DIM poly(199, 1) 'Declare arrays for texture coordinates DIM upos(199, 1) DIM vpos(199, 1) 'Point and texture coordinate sorting IF yy1 < yy2 AND yy1 < yy3 THEN x1 = xx1: y1 = yy1: u1 = uu1: v1 = vv1 IF yy2 < yy1 AND yy2 < yy3 THEN x1 = xx2: y1 = yy2: u1 = uu2: v1 = vv2 IF yy3 < yy1 AND yy3 < yy2 THEN x1 = xx3: y1 = yy3: u1 = uu3: v1 = vv3 IF yy1 > yy2 AND yy1 > yy3 THEN x3 = xx1: y3 = yy1: u2 = uu1: v2 = vv1 IF yy2 > yy1 AND yy2 > yy3 THEN x3 = xx2: y3 = yy2: u2 = uu2: v2 = vv2 IF yy3 > yy1 AND yy3 > yy2 THEN x3 = xx3: y3 = yy3: u2 = uu3: v2 = vv3 IF yy1 <> y1 AND yy1 <> y3 THEN x2 = xx1: y2 = yy1: u3 = uu1: v3 = vv1 IF yy2 <> y1 AND yy2 <> y3 THEN x2 = xx2: y2 = yy2: u3 = uu2: v3 = vv2 IF yy3 <> y1 AND yy3 <> y3 THEN x2 = xx3: y2 = yy3: u3 = uu3: v3 = vv3 'Calculating of the slope and texture coordinates from point 1 to point 2 x = 0 xm = 0 u = 0 um = 0 v = 0 vm = 0 IF x1 + x2 <> 0 AND y1 + y2 <> 0 THEN xm = (x1 - x2) / (y1 - y2) IF u1 + u2 <> 0 AND y1 + y2 <> 0 THEN um = (u1 - u2) / (y1 - y2) IF v1 + v2 <> 0 AND y1 + y2 <> 0 THEN vm = (v1 - v2) / (y1 - y2) FOR y = y1 TO y2 poly(y, 0) = x + x1 upos(y, 0) = u + u1 vpos(y, 0) = v + v1 x = x + xm u = u + um v = v + vm NEXT y 'Calculating of the slope and texture coordinates from point 2 to point 3 x = 0 xm = 0 u = 0 um = 0 v = 0 vm = 0 IF x2 + x3 <> 0 AND y2 + y3 <> 0 THEN xm = (x2 - x3) / (y2 - y3) IF u2 + u3 <> 0 AND y2 + y3 <> 0 THEN um = (u2 - u3) / (y2 - y3) IF v2 + v3 <> 0 AND y2 + y3 <> 0 THEN vm = (v2 - v3) / (y2 - y3) FOR y = y2 TO y3 poly(y, 0) = x + x2 upos(y, 0) = u + u2 vpos(y, 0) = v + v2 x = x + xm u = u + um v = v + vm NEXT y 'Calculating of the slope and texture coordinates from point 1 to point 3 m = 0 x = 0 u = 0 um = 0 v = 0 vm = 0 IF x1 + x3 <> 0 AND y1 + y3 <> 0 THEN m = (x1 - x3) / (y1 - y3) IF u1 + u3 <> 0 AND y1 + y3 <> 0 THEN um = (u1 - u3) / (y1 - y3) IF v1 + v3 <> 0 AND y1 + y3 <> 0 THEN vm = (v1 - v3) / (y1 - y3) FOR y = y1 TO y3 poly(y, 1) = x + x1 upos(y, 1) = u + u1 vpos(y, 1) = v + v1 x = x + m u = u + um v = v + vm NEXT y 'The easiest part, drawing FOR y = y1 TO y3 tLINE poly(y, 0), poly(y, 1), y, upos(y, 0), vpos(y, 0), upos(y, 1), vpos(y, 1) NEXT y END SUB
Code for tLINE:
'Made by Sane at the 1st of August 2001, for QBCM SUB tLINE (x1, x2, y, u1, v1, u2, v2) u = u1 um = 0 v = v1 vm = 0 IF u1 - u2 <> 0 AND x1 - x2 <> 0 THEN um = (u1 - u2) / (x1 - x2) IF v1 - v2 <> 0 AND x1 - x2 <> 0 THEN vm = (v1 - v2) / (x1 - x2) FOR x = INT(x1) TO x2 PSET (x, y), texture(u, v) u = u + um v = v + vm NEXT x END SUB
And the main testing code:
DECLARE SUB tPoly (xx1!, yy1!, xx2!, yy2!, xx3!, yy3!, uu1!, vv1!, uu2!, vv2!, uu3!, vv3!) DECLARE SUB tLINE (x1!, x2!, y!, u1!, v1!, u2!, v2!) 'Made by Sane at the 1st of August 2001, for QBCM SCREEN 13 'Declare a variable for holding the texture DIM SHARED texture(31, 31) AS INTEGER 'Fill the texture with random stuff FOR y = 0 TO 31 FOR x = 0 TO 31 texture(x, y) = INT(RND * 255) NEXT x NEXT y 'Setting color for PPS (Poly Per Second) rate text COLOR 15 oldtimer! = TIMER DO UNTIL INKEY$ = CHR$(27) x1 = INT(RND * 320) x2 = INT(RND * 320) x3 = INT(RND * 320) y1 = INT(RND * 200) y2 = INT(RND * 200) y3 = INT(RND * 200) tPoly x1, y1, x2, y2, x3, y3, INT(RND * 31), INT(RND * 31), INT(RND * 31), INT(RND * 31), INT(RND * 31), INT(RND * 31) polynum = polynum + 1 IF TIMER > oldtimer! + 1 THEN s = s + 1: LOCATE 1, 1: PRINT polynum / s: oldtimer! = TIMER LOOP
That's all for this time. As always, mail any comments/suggestions/questions to sane@telia.com. I still don't get more than 2-3 comments on my articles, which doesn't feel very nice, since I don't know if anyone reads them...
Next article will be an introduction into programming a 3D engine, that we'll do a few articles from now on.
See ya in next issue,
-Sane