Kiyote Wolf's amazing cheap Texturemapping.
It's cheap cause it's SLOOOOOOOOOOOOOOOOOOW...
This routine works with a few givens, it uses a standard array, used for PUT/GET sprite graphics, the index of the sprite, and a chain style entry of data for the 4 corners and the amount of repeating of the texture.
You will notice, it takes the first 8 entries and applies it to where the corners of the polygon are. It uses the same standard polygon definition, where it goes from the upperleft corner, clockwise, to the bottom left corner. Then, it see's if there was a command "SCALE" in the chain and takes the next two entries as the values to repeat the texture within the area plotting, in both X and Y directions.
How does it work? Well, one day awhile ago.. last year?? I had one of those genius, Einstein moments, and it had something to do with a problem i was upset about with Google Sketchup, not "Google's Ketchup..", but anyway, I decided to make a SVGA texture mapping routine.
Well, that was fun for awhile, but what do I do most? Work with sprites. So I worked at it for a week and condensed the entire program down into a single SUB, which lets me take my ordinary sprites, and make them extrodinary textures.
The code self checks itself, and modifies it's way of rendering to adjust for redundancy, speed, scale, and size, and makes minor adjustments based on a radius method of checking your proposed work. I'm sure that making each of these modes of drawing would make for another copy of this routine, letting me manually choose the scale and quality based on individual results, but I am obviously quite lazy and am going to let the computer choose the quality as per it's measuring.
What happens in this code is a giant binary tree search, which does a sliver of the mapped polygon in one direction, as a binary tree, grabbing pixels from the source to the destination by measuring each point in the tree as it goes along. Why is this important? Because, when we go into details of how the polygon stretches, by going at it in a binary fashion, where the pixels are originally and where they ultimately should go, the computer is able to faithfully recreate the texture in a real stretched reproduction because it measures half of half of half of this distance between the actual and the model.
I have even tested this routine to do a floor mapping technique, which it lacks the checking ability to control the pixels to make them large enough for floor mapping, but that can be changed of course eventually, which means,..
You can plot your texture mapped polygon on the screen, or have every point off the screen without having to worry about clipping. The math is still going to work even with negative numbers and far off positive numbers that do not appear on the screen, and your texture is going to appear on the screen as it should, only what is visible appearing, because the code will do so faithfully.
It is slow as 8088 GWBasic, or worse, but for those of us who wanna grasp the idea of 3D math without having as much headache, and those of us who cheat and pre-render.. (hee hee.. me..), this is a golden opportunity to test out something random in the name of 3D math, and get away with it.
I am very very proud of the insane but actually doable nature of this code, because that has always been my way of doing anything anyway.
Kudos 3D programmers, and 3D n00bs like myself.
'******* WORKING EXAMPLE OF CODE,.. FINISHED AND READY TO USE.. ASSUMING THE GRID MULTI
' CODE IS PRESENT AS WELL AS PER MY PREVIOUS COLUMN ENTRY.
' YOU WILL ONLY NEED THE VERT AND THE GRID MULTI ROUTINES TO USE THIS EXAMPLE.
' I USED THE CHAIN DATA ENTRY METHOD CAUSE I HATE USING TWENTY MILLION VARIABLES JUST FOR X/Y DATA
SUB TextureSpr (Sprite(), image, DataStrg2$)
DataStrg$ = DataStrg2$
REDIM CornerX(20), CornerY(20)
ImageWidth = Sprite(0) / 8 'get the image width
ImageHeight = Sprite(1) 'and height
WWidth = ImageWidth
WHeight = ImageHeight
ElmPerImg = (4 + INT((ImageWidth * 8 + 7) / 8) * ImageHeight + 1) \ 2
'without going into a LONGINTEGER format, we can check an overflow
'by subtracting the ADDEND from the .....you get the point...
wbuf = 0
FOR w = 1 TO image
wbuf = wbuf + ElmPerImg
IF (32768 - wbuf) < ElmPerImg THEN EXIT SUB
NEXT w
StartElm = ElmPerImg * image 'element # in the
IF UBOUND(Sprite) < StartElm THEN EXIT SUB
SourceSeg = VARSEG(Sprite(StartElm)) 'source image
SourceOfs& = VARPTR(Sprite(StartElm)) + 4 'skip size info
CornerX(4) = GridMulti(DataStrg$, 0)
CornerY(4) = GridMulti(DataStrg$, 1)
CornerX(5) = GridMulti(DataStrg$, 2)
CornerY(5) = GridMulti(DataStrg$, 3)
CornerX(6) = GridMulti(DataStrg$, 4)
CornerY(6) = GridMulti(DataStrg$, 5)
CornerX(7) = GridMulti(DataStrg$, 6)
CornerY(7) = GridMulti(DataStrg$, 7)
'
Scale2 = 7
ScaleX = 1
ScaleY = 1
ScalePtr = GridIF(DataStrg$, "SCALE")
IF ScalePtr > 0 THEN
ScaleX = GridMulti(DataStrg$, ScalePtr + 1)
ScaleY = GridMulti(DataStrg$, ScalePtr + 2)
END IF
CornerX(0) = 0
CornerY(0) = 0
CornerX(1) = ImageWidth * ScaleX
CornerY(1) = 0
CornerX(2) = ImageWidth * ScaleX
CornerY(2) = ImageHeight * ScaleY
CornerX(3) = 0
CornerY(3) = ImageHeight * ScaleY
FOR w = 4 TO 7
IF w = 4 THEN
CornerAvgX = CornerX(w)
CornerAvgY = CornerY(w)
ELSE
CornerAvgX = (CornerAvgX + CornerX(w)) \ 2
CornerAvgY = (CornerAvgY + CornerY(w)) \ 2
END IF
NEXT w
CornerDist! = 0
CornerMax! = 0
FOR w = 4 TO 7
CornerDist! = SQR((CornerAvgX - CornerX(w)) ^ 2 + (CornerAvgY - CornerY(w)) ^ 2)
IF CornerDist! > CornerMax! THEN CornerMax! = CornerDist!
NEXT w
Scale = 0
'<> Does the max size go beyond 15 pels? If so,.. work large,.. if not.. small
IF CornerDist! < 15 THEN Scale = -1
Scale3 = 0
IF CornerDist! > 30 THEN Scale3 = -1
Scale4 = 0
IF CornerDist! > 50 THEN Scale4 = -1
'IF Scale2 > 1 THEN Scale = -1
' 0 1
'
' 3 2
' We render our simple texture mapped polygon similar to standard
' methods
FOR w = 0 TO 7
CornerX(w + 8) = CornerX(w)
CornerY(w + 8) = CornerY(w)
NEXT w
REDIM pgn(10, 10, 10)
'4095 = 12 bits
FOR BigCnt = 0 TO (63 + 48 * Scale * (-1 * (Scale2 = 1)))
FOR BigCnt2 = 0 TO (63 + 48 * Scale * (-1 * (Scale2 = 1)))
FOR w = 0 TO 7
CornerX(w) = CornerX(w + 8)
CornerY(w) = CornerY(w + 8)
NEXT w
FOR t = 0 TO (7 + 4 * Scale * (-1 * (Scale2 = 1)))
Flag = SGN(BigCnt AND 2 ^ t)
Flag2 = SGN(BigCnt2 AND 2 ^ t)
pgn(1, 1, 1) = CornerX(0)
pgn(2, 1, 1) = (CornerX(0) + CornerX(1)) \ 2
pgn(3, 1, 1) = CornerX(1)
pgn(1, 2, 1) = (CornerX(0) + CornerX(3)) \ 2
pgn(2, 2, 1) = (CornerX(0) + CornerX(1) + CornerX(2) + CornerX(3)) \ 4
pgn(3, 2, 1) = (CornerX(1) + CornerX(2)) \ 2
pgn(1, 3, 1) = CornerX(3)
pgn(2, 3, 1) = (CornerX(3) + CornerX(2)) \ 2
pgn(3, 3, 1) = CornerX(2)
pgn(1, 1, 2) = CornerY(0)
pgn(2, 1, 2) = (CornerY(0) + CornerY(1)) \ 2
pgn(3, 1, 2) = CornerY(1)
pgn(1, 2, 2) = (CornerY(0) + CornerY(3)) \ 2
pgn(2, 2, 2) = (CornerY(0) + CornerY(1) + CornerY(2) + CornerY(3)) \ 4
pgn(3, 2, 2) = (CornerY(1) + CornerY(2)) \ 2
pgn(1, 3, 2) = CornerY(3)
pgn(2, 3, 2) = (CornerY(3) + CornerY(2)) \ 2
pgn(3, 3, 2) = CornerY(2)
pgn(1, 1, 3) = CornerX(0 + 4)
pgn(2, 1, 3) = (CornerX(0 + 4) + CornerX(1 + 4)) \ 2
pgn(3, 1, 3) = CornerX(1 + 4)
pgn(1, 2, 3) = (CornerX(0 + 4) + CornerX(3 + 4)) \ 2
pgn(2, 2, 3) = (CornerX(0 + 4) + CornerX(1 + 4) + CornerX(2 + 4) + CornerX(3 + 4)) \ 4
pgn(3, 2, 3) = (CornerX(1 + 4) + CornerX(2 + 4)) \ 2
pgn(1, 3, 3) = CornerX(3 + 4)
pgn(2, 3, 3) = (CornerX(3 + 4) + CornerX(2 + 4)) \ 2
pgn(3, 3, 3) = CornerX(2 + 4)
pgn(1, 1, 4) = CornerY(0 + 4)
pgn(2, 1, 4) = (CornerY(0 + 4) + CornerY(1 + 4)) \ 2
pgn(3, 1, 4) = CornerY(1 + 4)
pgn(1, 2, 4) = (CornerY(0 + 4) + CornerY(3 + 4)) \ 2
pgn(2, 2, 4) = (CornerY(0 + 4) + CornerY(1 + 4) + CornerY(2 + 4) + CornerY(3 + 4)) \ 4
pgn(3, 2, 4) = (CornerY(1 + 4) + CornerY(2 + 4)) \ 2
pgn(1, 3, 4) = CornerY(3 + 4)
pgn(2, 3, 4) = (CornerY(3 + 4) + CornerY(2 + 4)) \ 2
pgn(3, 3, 4) = CornerY(2 + 4)
CornerX(0) = pgn(1 + Flag, 1 + Flag2, 1)
CornerY(0) = pgn(1 + Flag, 1 + Flag2, 2)
CornerX(1) = pgn(2 + Flag, 1 + Flag2, 1)
CornerY(1) = pgn(2 + Flag, 1 + Flag2, 2)
CornerX(2) = pgn(2 + Flag, 2 + Flag2, 1)
CornerY(2) = pgn(2 + Flag, 2 + Flag2, 2)
CornerX(3) = pgn(1 + Flag, 2 + Flag2, 1)
CornerY(3) = pgn(1 + Flag, 2 + Flag2, 2)
CornerX(4) = pgn(1 + Flag, 1 + Flag2, 3)
CornerY(4) = pgn(1 + Flag, 1 + Flag2, 4)
CornerX(5) = pgn(2 + Flag, 1 + Flag2, 3)
CornerY(5) = pgn(2 + Flag, 1 + Flag2, 4)
CornerX(6) = pgn(2 + Flag, 2 + Flag2, 3)
CornerY(6) = pgn(2 + Flag, 2 + Flag2, 4)
CornerX(7) = pgn(1 + Flag, 2 + Flag2, 3)
CornerY(7) = pgn(1 + Flag, 2 + Flag2, 4)
NEXT t
FOR m = 1 TO 3
FOR n = 1 TO 3
IF Scale = 0 THEN
FOR o = -1 TO 1
FOR p = -1 TO 1
px = ABS(pgn(m, n, 1) - (o * (Scale2 > 1)) * (-1 * (Scale <> 0))) MOD ImageWidth '+ o
py = ABS(pgn(m, n, 2) - (p * (Scale2 > 1)) * (-1 * (Scale <> 0))) MOD ImageHeight'+ p
IF Scale3 THEN
px = (pgn(m, n, 1) MOD ImageWidth) '+ o
py = (pgn(m, n, 2) MOD ImageHeight)' + p
ELSE
px = (pgn(m, n, 1) MOD ImageWidth) + o
py = (pgn(m, n, 2) MOD ImageHeight) + p
END IF
BLoc = py
IF BLoc > ImageHeight THEN BLoc = ImageHeight
IF BLoc < 0 THEN BLoc = 0
CLoc = px
IF CLoc > ImageWidth THEN CLoc = ImageWidth
IF CLoc < 0 THEN CLoc = 0
ALoc = (BLoc) * ImageWidth + CLoc
DEF SEG = SourceSeg
sc = PEEK(SourceOfs& + CLNG(ALoc)) 'check source
IF Scale3 THEN
IF ((ABS(SGN(o)) = 1) AND (ABS(SGN(p)) = 1) AND (Scale4 = 0)) THEN
REM
ELSE
IF VGAFlag THEN
PSET (pgn(m, n, 3) + o, pgn(m, n, 4) + p), sc
ELSEIF SVGAFlag THEN
PutPRGB sc
Pset24 pgn(m, n, 3) + o, pgn(m, n, 4) + p
END IF
END IF
ELSE
IF (o >= 0) AND (p >= 0) THEN
IF VGAFlag THEN
PSET (pgn(m, n, 3) + o, pgn(m, n, 4) + p), sc
ELSEIF SVGAFlag THEN
PutPRGB sc
Pset24 pgn(m, n, 3) + o, pgn(m, n, 4) + p
END IF
END IF
END IF
NEXT p
NEXT o
ELSE
px = pgn(m, n, 1) MOD ImageWidth
py = pgn(m, n, 2) MOD ImageHeight
BLoc = py
IF BLoc > ImageHeight THEN BLoc = ImageHeight
IF BLoc < 0 THEN BLoc = 0
CLoc = px
IF CLoc > ImageWidth THEN CLoc = ImageWidth
IF CLoc < 0 THEN CLoc = 0
ALoc = (BLoc) * ImageHeight + CLoc
DEF SEG = SourceSeg
sc = PEEK(SourceOfs& + CLNG(ALoc)) 'check source
IF VGAFlag THEN
PSET (pgn(m, n, 3), pgn(m, n, 4)), sc
ELSEIF SVGAFlag THEN
PutPRGB sc
Pset24 pgn(m, n, 3), pgn(m, n, 4)
END IF
END IF
NEXT n
NEXT m
NEXT BigCnt2
NEXT BigCnt
END SUB
'**************** END OF CODE EXAMPLE