Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: Shockwave on August 31, 2006
-
Here's the version with inline assembly language as promised (it's a bit quicker too).
[Edit, code removed because it didn't work properly, new listing added below... ~ SW.]
-
Excellent! Shockie writing asm!
One thing - you can do
asm
cld
end asm
once at the start of your program. Nothing will ever change it. In fact I'd be surprised if it didn't default the direction flag to 0 anyway.
Another thing is this shows how shit the code optimisation is in freebasic. The thing you did with *p, p=p+1 should have been only a small amount slower than rep stosd. I've been pretty disappointed with the speed of the freebasic demos - sure, it's 10x faster than Blitz, but it's not competing with a decent C compiler. I should try writing some comparisons.
Jim
-
Nice work Shockie!
But I think there's something wrong with the asm version (or maybe my FB version), because it isn't working like the original version. If I replace the first function 'DBFTRI' (1st example code) with the DBFTRI asm version it just crash  :(
-
Sweet. didn't know about that rep stosd thingy. Just looked it up. Might come in handy that... Thanks for posting Shockwave, that learning curve keeps getting steeper and steeper. Better buy some climbing gear I think....
-
Excellent! Shockie writing asm!
One thing - you can do
asm
 cld
end asm
once at the start of your program. Nothing will ever change it. In fact I'd be surprised if it didn't default the direction flag to 0 anyway.
Another thing is this shows how shit the code optimisation is in freebasic. The thing you did with *p, p=p+1 should have been only a small amount slower than rep stosd. I've been pretty disappointed with the speed of the freebasic demos - sure, it's 10x faster than Blitz, but it's not competing with a decent C compiler. I should try writing some comparisons.
Jim
Don't forget that since .13b or so any emmiter based optimizatons has been ditched in preparation for the GCC backend move.
The GCC move would enable FB with:
1. GCC speed
2. OO(classes etc)
3. Portability to any architecture GCC is ported to.
-
I didn't know that, thanks! I hope that doesn't spell bad news for Windows people. GCC is poorly supported there.
Sorry - OT - get back to talking 'bout triangles dammit!
Jim
-
Lol, actually the triangle ratsriser above is broken :(
Most of the asm works though so at least you'll see a triangle, when you try and move it around bad things can happen. I'll need to fix it and put the working one up :)
Glad you liked it.
-
Ok, that version was horribly buggy, I have now re-coded it and it's very stable now. I've implimented some 2D clipping so this is pretty safe for anyone to use if they need a fast flatshader for their project. In fact this is probably about 40 % faster than my old flatshader so the speed increase is really significant.
You will need to have these variables;
XRES
YRES
And a screen buffer and you need to initialise a very small bit of asm before your main loop but that's all.
You can call the sub with;
FLAT_TRIANGLE( X1,Y1 , X2,Y2 , X3,Y3 , RGBCOLOUR )
The renderer will clip to the variables you define as your screen resolution.
Hope that you find it useful. :)
' Brand New Assembly Language Flatshaded Triangle Renderer
' Coded by Shockwave / DBF / S!P 2006 Use freely but credit Plz!
' Thanks to Stonemonkey and Jim Shaw for help with this technique.
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OPTION STATIC
OPTION EXPLICIT
CONST XRES = 800
CONST YRES = 600
CONST HALFX = XRES/2
CONST HALFY = YRES/2
DIM SHARED BUFFER ( XRES * YRES ) AS UINTEGER
DIM SHARED AS DOUBLE OLDTIME,GADD
DIM SHARED AS UINTEGER TICKS,NEWTIME
#define PTC_WIN
#Include Once "tinyptc.bi"
DECLARE SUB DELTA()
DECLARE SUB FLAT_TRIANGLE( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' Open Screen.
'-------------------------------------------------------------------------
If( ptc_open( "TRIANGLE ROUTINE WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE^S!P^DBF", XRES, YRES ) = 0 ) Then
End -1
End If
'-------------------------------------------------------------------------
' YOU NEED TO DO THIS ONCE BEFORE THE MAIN LOOP OF THE PROGRAM;
'-------------------------------------------------------------------------
asm
cld
end asm
OLDTIME = TIMER
DO
GADD=GADD+.005
DELTA()
FLAT_TRIANGLE(HALFX+500*SIN(GADD),HALFY+400*COS(GADD),HALFX+150*SIN(GADD*2),HALFY+200*COS(GADD*3),HALFX+300*SIN(GADD/2),HALFY+100*COS(GADD*5),&H88FF55)
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
TICKS=TICKS+1
LOOP UNTIL INKEY$ = CHR$(27)
SUB FLAT_TRIANGLE(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(2) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT BOTTOMED TRIANGLE Y2 = Y3
'***
IF TFLAG=0 AND PY(2) = PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(3) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
'-------------------------------------------------------------------------
' TIMER MANAGEMENT;
'-------------------------------------------------------------------------
SUB DELTA()
DIM Z AS UINTEGER
IF TIMER-OLDTIME>=1 THEN
NEWTIME = TICKS
OLDTIME = TIMER
PRINT "FPS:"+STR$(NEWTIME)
TICKS =0
END IF
END SUB
-
Welldone dude :)
-
Thanks Clyde.. Here's how it looks with a vector routine attached to it, a new type of glenze effect..
' Brand New Assembly Language Flatshaded Triangle Renderer
' Coded by Shockwave / DBF / S!P 2006 Use freely but credit Plz!
' Thanks to Stonemonkey and Jim Shaw for help with this technique.
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OPTION STATIC
OPTION EXPLICIT
CONST XRES = 640
CONST YRES = 480
CONST HALFX = XRES/2
CONST HALFY = YRES/2
DIM SHARED BUFFER ( XRES * YRES ) AS UINTEGER
DIM SHARED BUFFER2( XRES * YRES ) AS UINTEGER
DIM SHARED AS DOUBLE OLDTIME,GADD
DIM SHARED AS UINTEGER TICKS,NEWTIME
'#define PTC_WIN
#Include Once "tinyptc.bi"
DECLARE SUB DELTA()
DECLARE SUB FLAT_TRIANGLE( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
DECLARE SUB FLAT_TRIANGLE2( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
DECLARE SUB CONSTRUCT()
DECLARE SUB ROTATE()
'---------------------------------------------------------
' Define the necessary variables;
'---------------------------------------------------------
DIM shared N AS DOUBLE
dim shared vx1 as double
dim shared vx2 as double
dim shared vy1 as double
dim shared vy2 as double
DIM SHARED SIZE AS DOUBLE
DIM SHARED POINTS AS INTEGER
DIM SHARED FACES AS INTEGER
DIM SHARED VXR as double
dim shared VYR as double
dim shared VZR AS double
size=30
points=14
faces=24
Dim SHARED Vx(points) AS DOUBLE
Dim SHARED Vy(points) AS DOUBLE
Dim SHARED Vz(points) AS DOUBLE
Dim SHARED Vtx(points) AS INTEGER
Dim SHARED Vty(points) AS INTEGER
Dim SHARED Vtz(points) AS INTEGER
Dim SHARED Vf1(faces) AS DOUBLE
Dim SHARED Vf2(faces) AS DOUBLE
Dim SHARED Vf3(faces) AS DOUBLE
Dim SHARED Vf4(faces) AS DOUBLE
Dim SHARED Vr(faces) AS DOUBLE
Dim SHARED Vg(faces) AS DOUBLE
Dim SHARED Vb(faces) AS DOUBLE
'---------------------------------------------------------
' Read in the Object's points;
'---------------------------------------------------------
dim A
For a=1 To points
Read Vx(a)
read Vy(a)
read Vz(a)
Next
For a=1 To faces
Read Vf1(a)
Read Vf2(a)
Read Vf3(a)
Read Vf4(a)
Read Vr(a)
READ Vg(a)
READ Vb(a)
Next
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'-------------------------------------------------------------------------
' Open Screen.
'-------------------------------------------------------------------------
If( ptc_open( "GLENZE EFFECT BY SHOCKWAVE 2006!", XRES, YRES ) = 0 ) Then
End -1
End If
'-------------------------------------------------------------------------
' YOU NEED TO DO THIS ONCE BEFORE THE MAIN LOOP OF THE PROGRAM;
'-------------------------------------------------------------------------
asm
cld
end asm
OLDTIME = TIMER
DIM AS INTEGER LLX,LLY ,MMUL
DO
DELTA()
ROTATE()
CONSTRUCT()
FOR LLY=HALFY-150 TO HALFY+150
MMUL=LLY*XRES
FOR LLX=HALFX-150 TO HALFX+150
BUFFER(MMUL+LLX)=BUFFER(MMUL+LLX)+BUFFER2(MMUL+LLX)
NEXT
NEXT
'FOR A=1 TO XRES*YRES : BUFFER(A)=BUFFER(A) + BUFFER2(A) : NEXT
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
ERASE BUFFER2
TICKS=TICKS+1
LOOP UNTIL INKEY$ = CHR$(27)
SUB FLAT_TRIANGLE(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(2) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT BOTTOMED TRIANGLE Y2 = Y3
'***
IF TFLAG=0 AND PY(2) = PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(3) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
SUB FLAT_TRIANGLE2(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(2) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT BOTTOMED TRIANGLE Y2 = Y3
'***
IF TFLAG=0 AND PY(2) = PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(3) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
'-------------------------------------------------------------------------
' TIMER MANAGEMENT;
'-------------------------------------------------------------------------
SUB DELTA()
DIM Z AS UINTEGER
IF TIMER-OLDTIME>=1 THEN
NEWTIME = TICKS
OLDTIME = TIMER
PRINT "FPS:"+STR$(NEWTIME)
TICKS =0
END IF
END SUB
'---------------------------------------------------------
' Draw The Object;
'---------------------------------------------------------
SUB construct()
DIM A
DIM AS DOUBLE N,RD,GR,BL
For a=1 To faces
'---------------------------------------------------------
' Draw A Face Of The Object;
'---------------------------------------------------------
vx1= Vtx(Vf1(a))-Vtx(Vf2(a))
vy1= Vty(Vf1(a))-Vty(Vf2(a))
vx2= Vtx(Vf3(a))-Vtx(Vf2(a))
vy2= Vty(Vf3(a))-Vty(Vf2(a))
n= vx1*vy2-vx2*vy1
If n>0 THEN
n=(n/7000)
rd=Vr(a)*n : If rd>50 THEN rd=50
gr=Vg(a)*n : If gr>50 THEN gr=50
bl=Vb(a)*n : If bl>50 THEN bl=50
FLAT_TRIANGLE2(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf2(a)),Vty(Vf2(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
FLAT_TRIANGLE2(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf4(a)),Vty(Vf4(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
End If
NEXT
For a=1 To faces
'---------------------------------------------------------
' Draw A Face Of The Object;
'---------------------------------------------------------
vx1= Vtx(Vf1(a))-Vtx(Vf2(a))
vy1= Vty(Vf1(a))-Vty(Vf2(a))
vx2= Vtx(Vf3(a))-Vtx(Vf2(a))
vy2= Vty(Vf3(a))-Vty(Vf2(a))
n= vx1*vy2-vx2*vy1
If n<0 THEN
n=-(n/2500)
rd=Vr(a)*n : If rd>200 THEN rd=200
gr=Vg(a)*n : If gr>200 THEN gr=200
bl=Vb(a)*n : If bl>200 THEN bl=200
FLAT_TRIANGLE(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf2(a)),Vty(Vf2(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
FLAT_TRIANGLE(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf4(a)),Vty(Vf4(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
End If
NEXT
END SUB
SUB ROTATE()
DIM A
DIM VX1 AS DOUBLE
dim VY1 AS DOUBLE
dim VZ1 AS DOUBLE
DIM VZZ AS DOUBLE
dim vxx as double
dim vyy as double
DIM VDV AS DOUBLE
'###############################################
'## Rotate And Scale Each Point! Store Result ##
'###############################################
For a=1 To points
VX1=Vx(a)
VY1=Vy(a)
VZ1=Vz(a)
'######################
'## X,Y,Z rotations! ##
'######################
Vxx=Vx1
Vyy=Vy1*cos(Vxr)+Vz1*sin(Vxr)
Vzz=Vz1*cos(Vxr)-Vy1*sin(Vxr)
Vy1=Vyy
Vx1=Vxx*cos(Vyr)-Vzz*sin(Vyr)
Vz1=Vxx*sin(Vyr)+Vzz*cos(Vyr)
Vzz=Vz1
Vxx=Vx1*cos(Vzr)-Vy1*sin(Vzr)
Vyy=Vx1*sin(Vzr)+Vy1*cos(Vzr)
'########################
'## Apply Perspective! ##
'########################
Vdv=(Vzz/40)+1
Vxx=(size*(Vxx/Vdv))+HALFX
Vyy=(size*(Vyy/Vdv))+HALFY
Vtx(a)=Int(Vxx)
Vty(a)=Int(Vyy)
Vtz(a)=Int(Vzz)
Next
Vxr=Vxr+0.008
Vyr=Vyr+0.007
Vzr=Vzr+0.006
END SUB
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
' The Object Description As Data!
' The Data Below Describes A Cube.
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'Points definition;
'~~~~~~~~~~~~~~~~~~
'Below are the points of the Object defined as x,y,z;
Data 5,-5,-5,5,5,-5,-5,5,-5,-5,-5,-5,0,0,-8,8,0,0,0
Data 8,0,-8,0,0,0,-8,0,5,-5,5,5,5,5,-5,5,5,-5,-5,5,0,0,8
'Connection definition;
'Below are the faces of the Object defined as vertice
'numbers, specified in clockwise order. These are followed
'by r,g,b values For the face And finally cell shaded
'parameter (0)=off (1)=on.
Data 10,9,13,13,5,2,2
Data 14,10,13,13,4,4,4
Data 14,13,12,12,2,5,2
Data 8,12,13,13,4,4,4
Data 4,8,13,13,2,2,5
Data 10,14,11,11,2,5,2
Data 10,11,6,6,4,4,4
Data 4,13,9,9,4,4,4
Data 1,4,9,9,5,2,2
Data 1,9,10,10,4,4,4
Data 6,1,10,10,5,1,5
Data 5,4,1,1,4,4,4
Data 8,4,3,3,4,4,4
Data 3,12,8,8,2,2,5
Data 3,4,5,5,1,5,5
Data 7,12,3,3,4,4,4
Data 14,12,11,11,4,4,4
Data 11,12,7,7,5,5,1
Data 6,11,2,2,5,1,5
Data 11,7,2,2,4,4,4
Data 1,6,2,2,4,4,4
Data 2,5,1,1,1,5,5
Data 2,7,3,3,5,5,1
Data 2,3,5,5,4,4,4
'===============================================================================
' ***END***
'===============================================================================
-
:o Fuc***g good dude, well done !
-
I've always liked your glenzes :)
You still have a problem though. There is cracking caused by the bottom half of a normal triangle not being set up right.  In two places where you move from drawing the top half of the tri to the bottom half you have
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
The problem with that is that it assumes that XP1 has reached PX(2) by interpolation, and it doesn't always do that. You should replace it with
XI1 = (PX(2)-PX(3)) / (PY(3) - PY(2))
XP1 = PX(2)
That makes sure you start the bottom half with the exact values. If you don't do that, the bottom half of this triangle doesn't match with the top half of the joining triangle as they had different start and/or end points.
Tiny top clipping problem too
IF LO>0 AND LO<YRES THENshould beIF LO>=0 AND LO<YRES THEN
I've done a bit of googling. You defintiely don't need the 'asm cld' code. Windows clears it at startup and expects it to be clear whenever it's called.
I have a question too. Basically a normal triangle is just a flat-bottomed triangle on top of a flat-topped triangle. Can't you take advantage of that and shrink about half of the code away?
Jim
-
Thank you for spotting that bug! I hadn't noticed it, I'll edit to include your suggestions, but in the meantime, here's the same code with another couple of effects thrown in for good measure and some delta timing..
This is actually going to be a S!P intro when it is finished.
'WORK IN PROGRESS..
' Coded by Shockwave / DBF / S!P 2006.
' Thanks to Stonemonkey and Jim Shaw for help with this technique.
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OPTION STATIC
OPTION EXPLICIT
CONST XRES = 640
CONST YRES = 480
CONST HALFX = XRES/2
CONST HALFY = YRES/2
CONST PCLIP = 18
DIM SHARED BUFFER ( XRES * YRES ) AS UINTEGER
DIM SHARED BUFFER2( XRES * YRES ) AS UINTEGER
DIM SHARED AS DOUBLE OLDTIME,GADD,DELTAVALUE
DIM SHARED AS UINTEGER TICKS,NEWTIME
DIM SHARED AS DOUBLE GRADD
DIM SHARED AS INTEGER GRID
GRID=20
DIM SHARED AS DOUBLE CHESS_GRIDX(GRID,GRID)
DIM SHARED AS DOUBLE CHESS_GRIDZ(GRID,GRID)
DIM SHARED CFM AS DOUBLE
CFM=0
'#define PTC_WIN
#Include Once "tinyptc.bi"
DECLARE SUB DELTA()
DECLARE SUB FLAT_TRIANGLE( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
DECLARE SUB FLAT_TRIANGLE2( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
DECLARE SUB CONSTRUCT()
DECLARE SUB ROTATE()
DECLARE SUB COPY_GLENZE()
DECLARE SUB CHESS_SETUP()
DECLARE SUB CHESS_FUNK()
CHESS_SETUP()
'---------------------------------------------------------
' Define the necessary variables;
'---------------------------------------------------------
DIM shared N AS DOUBLE
dim shared vx1 as double
dim shared vx2 as double
dim shared vy1 as double
dim shared vy2 as double
DIM SHARED SIZE AS DOUBLE
DIM SHARED POINTS AS INTEGER
DIM SHARED FACES AS INTEGER
DIM SHARED VXR as double
dim shared VYR as double
dim shared VZR AS double
size=24
points=14
faces=24
Dim SHARED Vx(points) AS DOUBLE
Dim SHARED Vy(points) AS DOUBLE
Dim SHARED Vz(points) AS DOUBLE
Dim SHARED Vtx(points) AS INTEGER
Dim SHARED Vty(points) AS INTEGER
Dim SHARED Vtz(points) AS INTEGER
Dim SHARED Vf1(faces) AS DOUBLE
Dim SHARED Vf2(faces) AS DOUBLE
Dim SHARED Vf3(faces) AS DOUBLE
Dim SHARED Vf4(faces) AS DOUBLE
Dim SHARED Vr(faces) AS DOUBLE
Dim SHARED Vg(faces) AS DOUBLE
Dim SHARED Vb(faces) AS DOUBLE
'---------------------------------------------------------
' Read in the Object's points;
'---------------------------------------------------------
dim A
For a=1 To points
Read Vx(a)
read Vy(a)
read Vz(a)
Next
For a=1 To faces
Read Vf1(a)
Read Vf2(a)
Read Vf3(a)
Read Vf4(a)
Read Vr(a)
READ Vg(a)
READ Vb(a)
Next
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'-------------------------------------------------------------------------
' Open Screen.
'-------------------------------------------------------------------------
If( ptc_open( "GLENZE EFFECT BY SHOCKWAVE 2006!", XRES, YRES ) = 0 ) Then
End -1
End If
'-------------------------------------------------------------------------
' YOU NEED TO DO THIS ONCE BEFORE THE MAIN LOOP OF THE PROGRAM;
'-------------------------------------------------------------------------
asm
cld
end asm
OLDTIME = TIMER
DELTAVALUE=100
TICKS=80
DO
DELTA()
ROTATE()
CHESS_FUNK()
CONSTRUCT()
COPY_GLENZE()
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
ERASE BUFFER2
TICKS=TICKS+1
LOOP UNTIL INKEY$ = CHR$(27)
SUB CHESS_FUNK()
DIM CHYP AS INTEGER
CHYP=350
DIM AS INTEGER ZC,LX,LZ,TX1,TY1,TX2,TY2,TX3,TY3,TX4,TY4,FP,TOG,ML1,ML2
TOG=0
FP=1
ZC=1
FOR LZ=1 TO GRID-1
FOR LX=FP TO GRID-1
TX1=(CHESS_GRIDX(LX,LZ) / (CHESS_GRIDZ(LX,LZ)+CFM) ) + HALFX
TY1=(CHYP / (CHESS_GRIDZ(LX,LZ)+CFM) ) + HALFY
TX2=(CHESS_GRIDX(LX+1,LZ) / (CHESS_GRIDZ(LX+1,LZ)+CFM) ) + HALFX
TY2=(CHYP / (CHESS_GRIDZ(LX+1,LZ)+CFM) ) + HALFY
TX3=(CHESS_GRIDX(LX+1,LZ+1) / (CHESS_GRIDZ(LX+1,LZ+1)+CFM) ) + HALFX
TY3=(CHYP / (CHESS_GRIDZ(LX+1,LZ+1)+CFM) ) + HALFY
TX4=(CHESS_GRIDX(LX,LZ+1) / (CHESS_GRIDZ(LX,LZ+1)+CFM) ) + HALFX
TY4=(CHYP / (CHESS_GRIDZ(LX,LZ+1)+CFM) ) + HALFY
ZC=TY3-305
ML1=RGB(ZC SHR 2,ZC SHR 2,ZC SHR 1)
ML2=RGB(ZC SHR 3,ZC SHR 3,ZC SHR 2)
IF TOG=0 THEN
FLAT_TRIANGLE(TX1,TY1,TX2,TY2,TX3,TY3,ML1)
FLAT_TRIANGLE(TX3,TY3,TX4,TY4,TX1,TY1,ML1)
ELSE
FLAT_TRIANGLE(TX1,TY1,TX2,TY2,TX3,TY3,ML2)
FLAT_TRIANGLE(TX3,TY3,TX4,TY4,TX1,TY1,ML2)
END IF
TOG=TOG+1
IF TOG>1 THEN TOG=0
NEXT
FP=FP+1
IF FP>2 THEN FP=1
TOG=FP
NEXT
CFM=CFM-1/DELTAVALUE
IF CFM<.4 THEN CFM=CFM+.4
END SUB
SUB CHESS_SETUP()
'
' THIS SUB INITIALISES A GRID FOR THE CHESSFUNK!
'
DIM AS DOUBLE CX,CZ,CSTX,CSTZ
DIM AS INTEGER LX,LZ
CSTX = (50 / GRID)*2
CSTZ = (1 / GRID)*2
CZ=.3
FOR LX = 1 TO GRID
CX=-50
FOR LZ = 1 TO GRID
CHESS_GRIDX(LX,LZ) = ( CX * 50)
CHESS_GRIDZ(LX,LZ) = ( CZ * 2)
CX=CX+CSTX
NEXT
CZ=CZ+CSTZ
NEXT
END SUB
SUB COPY_GLENZE()
DIM AS INTEGER LLX,LLY ,MMUL
GRADD=GRADD+250/DELTAVALUE
SIZE=15+8*SIN(GRADD / 150)
FOR LLY=HALFY-190 TO HALFY+190
MMUL=LLY*XRES
FOR LLX=HALFX-190 TO HALFX+190
BUFFER(MMUL+LLX)=BUFFER(MMUL+LLX)+BUFFER2(MMUL+LLX)
NEXT
NEXT
LLY=XRES-1
FOR LLX=0 TO XRES-1
MMUL = RGB(125+124*SIN((LLX+GRADD)/100),125+124*SIN((LLX+GRADD)/120),125+124*SIN((LLX+GRADD)/123))
BUFFER(LLX+(PCLIP*XRES)) = MMUL
BUFFER(LLY+((YRES-PCLIP)*XRES)) = MMUL
LLY=LLY-1
NEXT
END SUB
SUB FLAT_TRIANGLE(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(2) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT BOTTOMED TRIANGLE Y2 = Y3
'***
IF TFLAG=0 AND PY(2) = PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(3) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
SUB FLAT_TRIANGLE2(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (XP1-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(2) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT BOTTOMED TRIANGLE Y2 = Y3
'***
IF TFLAG=0 AND PY(2) = PY(3) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(3) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER2(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
'-------------------------------------------------------------------------
' TIMER MANAGEMENT;
'-------------------------------------------------------------------------
SUB DELTA()
DIM Z AS UINTEGER
IF TIMER-OLDTIME>=.1 THEN
DELTAVALUE=(3*(TICKS*1.5))+1
NEWTIME = TICKS
OLDTIME = TIMER
PRINT "FPS:"+STR$(NEWTIME*10)
TICKS =0
END IF
END SUB
'---------------------------------------------------------
' Draw The Object;
'---------------------------------------------------------
SUB construct()
DIM A
DIM AS DOUBLE N,RD,GR,BL
For a=1 To faces
'---------------------------------------------------------
' Draw A Face Of The Object;
'---------------------------------------------------------
vx1= Vtx(Vf1(a))-Vtx(Vf2(a))
vy1= Vty(Vf1(a))-Vty(Vf2(a))
vx2= Vtx(Vf3(a))-Vtx(Vf2(a))
vy2= Vty(Vf3(a))-Vty(Vf2(a))
n= vx1*vy2-vx2*vy1
If n>0 THEN
n=(n/8000)
rd=Vr(a)*n : If rd>85 THEN rd=85
gr=Vg(a)*n : If gr>85 THEN gr=85
bl=Vb(a)*n : If bl>85 THEN bl=85
FLAT_TRIANGLE2(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf2(a)),Vty(Vf2(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
FLAT_TRIANGLE2(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf4(a)),Vty(Vf4(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
End If
NEXT
For a=1 To faces
'---------------------------------------------------------
' Draw A Face Of The Object;
'---------------------------------------------------------
vx1= Vtx(Vf1(a))-Vtx(Vf2(a))
vy1= Vty(Vf1(a))-Vty(Vf2(a))
vx2= Vtx(Vf3(a))-Vtx(Vf2(a))
vy2= Vty(Vf3(a))-Vty(Vf2(a))
n= vx1*vy2-vx2*vy1
If n<0 THEN
n=-(n/2000)
rd=Vr(a)*n : If rd>150 THEN rd=170
gr=Vg(a)*n : If gr>150 THEN gr=170
bl=Vb(a)*n : If bl>150 THEN bl=170
FLAT_TRIANGLE(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf2(a)),Vty(Vf2(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
FLAT_TRIANGLE(Vtx(Vf1(a)),Vty(Vf1(a)),Vtx(Vf4(a)),Vty(Vf4(a)),Vtx(Vf3(a)),Vty(Vf3(a)),RGB(RD,GR,BL))
End If
NEXT
END SUB
SUB ROTATE()
DIM A
DIM XCUNT AS DOUBLE
XCUNT=5*SIN(GRADD/180)
DIM VX1 AS DOUBLE
dim VY1 AS DOUBLE
dim VZ1 AS DOUBLE
DIM VZZ AS DOUBLE
dim vxx as double
dim vyy as double
DIM VDV AS DOUBLE
'###############################################
'## Rotate And Scale Each Point! Store Result ##
'###############################################
For a=1 To points
VX1=Vx(a)+XCUNT
VY1=Vy(a)
VZ1=Vz(a)
'######################
'## X,Y,Z rotations! ##
'######################
Vxx=Vx1
Vyy=Vy1*cos(Vxr)+Vz1*sin(Vxr)
Vzz=Vz1*cos(Vxr)-Vy1*sin(Vxr)
Vy1=Vyy
Vx1=Vxx*cos(Vyr)-Vzz*sin(Vyr)
Vz1=Vxx*sin(Vyr)+Vzz*cos(Vyr)
Vzz=Vz1
Vxx=Vx1*cos(Vzr)-Vy1*sin(Vzr)
Vyy=Vx1*sin(Vzr)+Vy1*cos(Vzr)
'########################
'## Apply Perspective! ##
'########################
Vdv=(Vzz/40)+1
Vxx=(size*(Vxx/Vdv))+HALFX
Vyy=(size*(Vyy/Vdv))+HALFY
Vtx(a)=Int(Vxx)
Vty(a)=Int(Vyy)
Vtz(a)=Int(Vzz)
Next
Vxr=Vxr+1/DELTAVALUE
Vyr=Vyr+1/DELTAVALUE
Vzr=Vzr+1/DELTAVALUE
END SUB
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
' The Object Description As Data!
' The Data Below Describes A Cube.
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'Points definition;
'~~~~~~~~~~~~~~~~~~
'Below are the points of the Object defined as x,y,z;
Data 5,-5,-5,5,5,-5,-5,5,-5,-5,-5,-5,0,0,-8,8,0,0,0
Data 8,0,-8,0,0,0,-8,0,5,-5,5,5,5,5,-5,5,5,-5,-5,5,0,0,8
'Connection definition;
'Below are the faces of the Object defined as vertice
'numbers, specified in clockwise order. These are followed
'by r,g,b values For the face And finally cell shaded
'parameter (0)=off (1)=on.
Data 10,9,13,13,5,1,1
Data 14,10,13,13,4,4,4
Data 14,13,12,12,1,5,1
Data 8,12,13,13,4,4,4
Data 4,8,13,13,1,1,5
Data 10,14,11,11,1,5,1
Data 10,11,6,6,4,4,4
Data 4,13,9,9,4,4,4
Data 1,4,9,9,5,1,1
Data 1,9,10,10,4,4,4
Data 6,1,10,10,5,0,5
Data 5,4,1,1,4,4,4
Data 8,4,3,3,4,4,4
Data 3,12,8,8,2,2,5
Data 3,4,5,5,0,5,5
Data 7,12,3,3,4,4,4
Data 14,12,11,11,4,4,4
Data 11,12,7,7,5,5,0
Data 6,11,2,2,5,0,5
Data 11,7,2,2,4,4,4
Data 1,6,2,2,4,4,4
Data 2,5,1,1,0,5,5
Data 2,7,3,3,5,5,0
Data 2,3,5,5,4,4,4
'===============================================================================
' ***END***
'===============================================================================
-
That's completely awesome Shocky! Keep up the good work!
-
Cheers Phoenix :)
Hopefully when it's finished it will have a few more effects, as this is going to be my first intro for Surprise Productions I'd like to do a good job but I want to keep the oldschool feel too.
-
Great stuff, nice to see new ways of doing Triangle Rasteriser. O0
:||
-
Takes us back to before when we were all talking about triangle rasterisers and when you were learning how to make your first gourad routine eh Tetra? You've moved forward and I'm still coding flatshaders :) Heheh. Tbh, I am very happy with this flatshader esp after I've implimented Jims bug fixes.
-
Nice work Shockwave, I think there might be another slight problem with the clipping. The max values should be XRES-1 and YRES-1.
It's possible to take some things out of the loop too, in this:
FOR LO = PY(2) TO PY(3)
IF LO>PCLIP AND LO<YRES-PCLIP THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1>XRES THEN IL1=XRES
IF IL2<0 THEN IL2=0
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
You could try something like this although ive not tested it and you'd probably have to mess around a bit to get it working.
'clip top and bottom of tri
y_start=PY(2)
y_end=PY(3)
if y_start<PCLIP then y_start=PCLIP
if y_end>(YRES-PCLIP) then y_end=YRES-PCLIP
'swap the gradients of each side if they're the wrong way round so not having to do a swap for every scanline
if XI1>XI2 then
temp=XI1
XI1=XI2
XI2=temp
end if
'if top is clipped then find the start and end of the scanlines at the point of clipping
dy=y_start-PY(2)
XP1+=XI1*dy
XP2+=XI2*dy
FOR LO = ystart TO yend
'you can do away with 2 of the tests here as the "IF SLICE>0 THEN" line will take care of that
IF XL2>=XRES THEN IL2=XRES-1
' IF XL1>=XRES THEN IL1=XRES-1
' IF XL2<0 THEN XL2=0
IF XL1<0 THEN XL1=0
SLICE = XL2-XL1
IF SLICE>0 THEN
PP = @BUFFER(XL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
-
I think XRES is right. Since he draws R-L pixels, so if L=0 and R=640 then it's 640-0 pixels drawn. I checked it the other day and it looked OK.
I think YRES-1 is right though. The for loop goes for y=0 to 480 and in freebasic that's 481 iterations, 1 too many.
Jim
-
Thanks for the optimisations Stonemonkey :) and cheers for sorting the clipping bug both.
I'll be sure to post the fixed version for everyone who wants to use it as soon as I've fixed it.
-
I've implimented some (but not quite all) of the fixes. The code has been shrunk, some if thens have been ditched and a slight clipping bug fixed, also interpolation bug at the bottom of the triangle has been mended.
Thanks to Jim and Stonemonkey, here's the source with example. Feel free to use it;
' Brand New Assembly Language Flatshaded Triangle Renderer
' Coded by Shockwave / DBF / S!P 2006 Use freely but credit Plz!
' Thanks to Stonemonkey and Jim Shaw for help with this technique.
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OPTION STATIC
OPTION EXPLICIT
CONST XRES = 800
CONST YRES = 600
CONST HALFX = XRES/2
CONST HALFY = YRES/2
DIM SHARED BUFFER ( XRES * YRES ) AS UINTEGER
DIM SHARED AS DOUBLE OLDTIME,GADD
DIM SHARED AS UINTEGER TICKS,NEWTIME
'#define PTC_WIN
#Include Once "tinyptc.bi"
DECLARE SUB DELTA()
DECLARE SUB FLAT_TRIANGLE( BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' Open Screen.
'-------------------------------------------------------------------------
If( ptc_open( "TRIANGLE ROUTINE WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE^S!P^DBF", XRES, YRES ) = 0 ) Then
End -1
End If
OLDTIME = TIMER
DO
GADD=GADD+.002
DELTA()
FLAT_TRIANGLE(HALFX+500*SIN(GADD),HALFY+400*COS(GADD),HALFX+150*SIN(GADD*2),HALFY+200*COS(GADD*3),HALFX+300*SIN(GADD/2),HALFY+100*COS(GADD*5),&H88FF55)
GADD=GADD+10
FLAT_TRIANGLE(HALFX+500*SIN(GADD),HALFY+400*COS(GADD),HALFX+150*SIN(GADD*2),HALFY+200*COS(GADD*3),HALFX+300*SIN(GADD/2),HALFY+100*COS(GADD*5),&HFF88F55)
GADD=GADD-10
PTC_UPDATE@BUFFER(0)
ERASE BUFFER
TICKS=TICKS+1
LOOP UNTIL INKEY$ = CHR$(27)
SUB FLAT_TRIANGLE(BYVAL X1 AS INTEGER , BYVAL Y1 AS INTEGER, BYVAL X2 AS INTEGER , BYVAL Y2 AS INTEGER , BYVAL X3 AS INTEGER, BYVAL Y3 AS INTEGER , BYVAL TC AS INTEGER)
'-------------------------------------------------------------------------
' FLAT TRIANGLE RENDERER WITH ASSEMBLY LANGUAGE RASTERISING BY SHOCKWAVE ^ DBF ^ S!P 2006.
'-------------------------------------------------------------------------
'-------------------------------------------------------------------------
' WE NEED TO SORT THESE POINTS INTO ORDER FROM TOP TO BOTTOM, AN EXCHANGE SORT IS OK.
' AS WE ONLY HAVE GOT 3 POINTS TO ARRANGE.
'-------------------------------------------------------------------------
DIM AS INTEGER TEMPX,TEMPY,LO,LI
DIM AS INTEGER PX(3)
DIM AS INTEGER PY(3)
DIM TFLAG AS INTEGER
dim pp as uinteger PTR
DIM AS INTEGER IL1,IL2,SLICE
TFLAG=0
PX(1)= X1
PX(2)= X2
PX(3)= X3
PY(1)= Y1
PY(2)= Y2
PY(3)= Y3
FOR LO = 1 TO 2
FOR LI =1 TO 2
IF PY(LI+1) <= PY(LI) THEN
TEMPX = PX(LI) : TEMPY = PY(LI)
PX(LI) = PX(LI+1)
PY(LI) = PY(LI+1)
PX(LI+1) = TEMPX
PY(LI+1) = TEMPY
END IF
NEXT LI
NEXT LO
DIM AS DOUBLE XP1,XP2:' SCREEN POSITIONS.
DIM AS DOUBLE XI1,XI2:' INTERPOLATIONS.
'***
'*** REGULAR TRIANGLE (Y1<Y2 Y2<Y3)
'***
IF PY(1)<PY(2) AND PY(2)<PY(3) or (PY(2) = PY(3)) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(1)
XI1 = (PX(1)-PX(2)) / (PY(2) - PY(1))
XI2 = (PX(1)-PX(3)) / (PY(3) - PY(1))
FOR LO = PY(1) TO PY(2)-1
IF LO>=0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
XI1 = (PX(2)-PX(3)) / (PY(3) - PY(2))
XP1 = PX(2)
FOR LO = PY(2) TO PY(3)
IF LO>=0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
'***
'*** FLAT TOPPED TRIANGLE Y1=Y2
'***
IF TFLAG=0 AND PY(1) = PY(2) THEN
TFLAG=1
XP1 = PX(1)
XP2 = PX(2)
XI1 = (PX(1)-PX(3)) / (PY(3) - PY(1))
XI2 = (PX(2)-PX(3)) / (PY(3) - PY(2))
FOR LO = PY(1) TO PY(3)
IF LO>=0 AND LO<YRES THEN
IF XP1<=XP2 THEN
IL1=XP1
IL2=XP2
ELSE
IL1=XP2
IL2=XP1
END IF
IF IL2>XRES THEN IL2=XRES
IF IL1<0 THEN IL1=0
SLICE = IL2-IL1
IF SLICE>0 THEN
PP = @BUFFER(IL1+(LO*XRES))
asm
mov eax,dword ptr[TC]
mov ecx, [slice]
mov edi, [PP]
rep stosd
end asm
END IF
END IF
XP1=XP1-XI1
XP2=XP2-XI2
NEXT
END IF
END SUB
'-------------------------------------------------------------------------
' TIMER MANAGEMENT;
'-------------------------------------------------------------------------
SUB DELTA()
DIM Z AS UINTEGER
IF TIMER-OLDTIME>=1 THEN
NEWTIME = TICKS
OLDTIME = TIMER
PRINT "FPS:"+STR$(NEWTIME)
TICKS =0
END IF
END SUB