Advanced demo efx (a short tutorial about st c2p part 1)
introduction
does anyone expected this ? this millennium is nearly at the end and only a few days to y2k but well 1999 was a great year for st. dunno but i have the feeling that more demos were released for st than for falcon this year. can u believe this ?
inspired from some amiga or pc demos the coders started to leave oldschool stuff and created a new type of st demos.
sure the new demos are seldom done in one vbl. an exception here is evl with his great flicker blur stuff. but anyway to be honest i'm a bit tired of watching dots and bobs. so i also do only newschool stuff because who cares about if i can do 4 dots more than others.
i want to see some new stuff on st which is never/not that often done before on it.
this is why i've wrote this article to motivate ppl new and old ones to get active and to do some new stuff for st.
i take some stuff for granted...u should:
- can code 68k. well i can't explain all and i'm too lazy for this ;)
- be familiar with st gfx coding bit planes etc.
- be motivated ;)
oki lets start...
btw i don't say this is the best way of doing the stuff...its just a try to show u how it works... and i guess its of course not bug free ;)
what are u talking about?
this chapter will explain u some notions. i guess this is needed that u know what i'm talking about.
c2p
that's the key to the new demo effects nearly all newschool stuff depends on this technic.
its a shortcut for: chunky to planar chunky means here a byte oriented buffer where u set up your effect.
each byte represents one pixel ( or 2*2 ) on screen.
planar means the bit planes.
so c2p is only a technic to convert a chunky buffer to bitplane gfx.
but later more about this.
offset effects
some very well known efx are offset effects like tunnels or bumpmapping.
well its a technic which doesn't need much time and generates nice results...but what is an offset effects ?
normally if u copy a picture by pixel to a screen u read one pixel and write it to same position to the screen. so u do a excat copy to screen.
offset effects don't do this. its a kind of distortion.they copy for example the pixel from line 10 row 40 to screen position line 1 row 1. and so on. u generate an offset map before the efx that u know later which pixel from the gfx must be displayed at which position on screen.
bump mapping
this efx wonderful. it creates a illusion of a picture which is effected from a lightsource. after i've seen this efx for the first time i was absolutely impressed. this effect is that easy thats unbelieveable. it always consists of two pictures. one the picture which is bumpmapped and one picture of a light source.
this is an offset effect... but later more about this.
texture mapping
should be clear i guess. its just a poly with mapped grafix.
environment mapping
this effect creates a the illusion that your poly or object reflects the environnment. the polys looks like an mirror. if u use a special env map picture it can look like a spot lightsource which lights the object.
phong shading
means a poly texture mapper where each point of the poly has a special light source calcuation. this creates a realistic feeling of the object. but if u want to do real phong shading on st or falcon.
forget it ;) its too slow. most of all phong shadings are faked.
it consists mostly of a normal texturemapper and env mapping.
u use a special map for the envmapping which creates a light spot on the object and the envmapping controls the brightness of the texture...thats all ;)
why do i need c2p ?
did u ever tried to set a pixel bit plane mode ? its a real pain in the ass...
and its mostly that slow. it is faster to convert an entire buffer to screen.
the advantage of c2p is that u work with a byte oriented buffer where each byte is one pixel on screen. so its much easier to generate effects or manipulate that buffer.
but how can i convert a byte oriented buffer fast to bitplane gfx ?
hmm the key for this is "movep.l". i guess this instruction is the less used instruction in oldschool demos. well i never found out who used it for the first time . but even tat used it already in his fast tunnel effects intro for maggie.
but lets have a look what movep.l does:
for example:
lea $40000,a0
move.l #$11223344,d0
movep.l d0,(a0)
the result is:
$40000 = $11 (first byte of plane 1)
$40002 = $22 (first byte of plane 2)
$40004 = $33 (first byte of plane 3)
$40006 = $44 (first byte of plane 4)
as u can see movep.l splits up d0 into four bytes and writes the the $11 to $40000 ...and writes the $22 to $40002 and so on.
without movep.l it would look like this:
lea $40000,a0
move.l #$11223344,d0
move.b d0,6(a0)
lsr.l #8,d0
move.b d0,4(a0)
lsr.l #8,d0
move.b d0,2(a0)
lsr.l #8,d0
move.b d0,(a0)
so whats the advantage of movep.l ?
the advantage is that u can write with ONE instrution 8 pixel on screen in 4 bitplanes ! so movep.l writes one byte to each plane.
oki now we know a technic to set fast 8 pixels on screen in all bitplanes. but does it really help ?
yep for sure.
first of all we have to half the resolution. so we only want to set 4(2*2) pixel with one movep.l we just double the pixels. sure its possible to use 8 but its too slow for a normal st and the precalced buffers will be too big.;)
the next step is now to generate a long buffer that keeps all combinations of possible colors(16) in 4(2*2) pixel in bitplane format.
that long is later used to write it to screen via movep.l.
i will not say more about the generation of that buffer. have a look to the source
which is included in this issue of ucm. because its really basic stuff.
its more interesting to continue ;)
have a look to this source part.
lea screen,a0
lea buffer,a1 ; this is the generated buffer with all
; pixel/color combinations
moveq #$0,d0 move #$1234,d0 ; color information for the 4 pixel
lsl.l #2,d0
move.l (a0,d0.l),d0
movep.l d0,(a0)
hmm doesn't look that heavy ? but this is already a routine which displays 4(2*2) pixels on screen. with the colors 1 2 3 4. ok lets have a closer look what each instruction does:
lea screen,a0
lea buffer,a1 ; this is the generated buffer with all
; pixel/color combinations
this should be clear. this is to get the pointer so screen and our generated buffer.
moveq #$0,d0 move #$1234,d0
d0 keeps now the color informations for our 4 pixels so
- 1 = color of the first pixel
- 2 = color of the second pixel
- 3 = color of the third pixel
- 4 = color of the fourth pixel
the 1 2 3 4 means the real color numbers
lsl.l #2,d0
u know our generated buffer is long oriented. so we have to multiply it with 4.
move.l (a0,d0.l),d0
this gets the bitplane data from the generated buffer for movep.l.
this is the precalculated color combination for the colors 1 2 3 4.
movep.l d0,(a0)
and write it to screen. voila...
as u can see d0 keeps the colors for the 4 pixel. but well each color uses 4 bits in d0 but our chunky buffer is byte oriented. yes sure u can use a 4 bit oriented chunky buffer. but its not that handy like a byte oriented one. so we need to do a small trick.
the first c2p rout
ok lets continue with a small source part. this is the first byte oriented c2p.
lea screen,a0
lea c2pbuffer,a1
lea buffer,a2
moveq #0,d0
move.w (a1)+,d0
lsl #4,d0
or.w (a1)+,d0
lsl.l #2,d0 move.l (a2,d0),d0
movep.l d0,(a0)
c2pbuffer:
dc.w $01,$02,$03,$04
----------------------------
moveq #0,d0
move.w (a1)+,d0
this is to get the first 2 bytes (pixels) from the chunky buffer
d0 = $0102
lsl #4,d0
shift them up.
d0 = $1020
or.w (a1)+,d0
or the second 2 bytes(pixels) from the chunky buffer.
d0 = $1324
oh as u can see the order of the colors are not the same like in the example before $1234 and now $1324. this type of getting the data from the chunky buffer needs a small change in our generation routine for the buffer. but don't worry in that source is this already done.
thats the trick i meant. normally the color order is:
for a word
4 bits = color for pixel 1
4 bits = color for pixel 2
4 bits = color for pixel 3
4 bits = color for pixel 4
==16 bits
with this trick u have to swap the 2 and 3 so that the order is:
4 bits = color for pixel 1
4 bits = color for pixel 3
4 bits = color for pixel 2
4 bits = color for pixel 4
==16
thats it
ok now u know the basics of c2p. i will stop now. i guess this should be enough for the first part.
so play a bit with the source and if u have question just drop me a mail: candyman@atari.org
or visit our site at: cream.atari.org
in the next part we will have a look to:
- other kinds of c2p
- optimizing the c2p
- elemination of the chunky buffer
- offset effects
- bumpmapping
- tunnel efx
excuse my bad english ;)
regards
Ola
C2PTUT.S
;***********************************************************
;* sourcecode for the ucm c2p tutorial
;* code: candyman
;*
;* email: candyman@atari.org
;* www: cream.atari.org
;*
;* cream 1999
;***********************************************************
; i know this code is a bit unclean but it only should
; show how it works...
;
; this is a generic routine this means the generation
; function for the drawscreen rout
; generates an asm rout which displays the chunkybuffer
; depended on sizex and sizey
; the chunky buffer is byte oriented that means
; every byte is one point 2*2 pixel doubleing on screen
; the colors in the chunkybuffer have to be preshifed
; if u want to display a color 1 it with 4
; this is a optimisation to save the lsl #2 in the drawscreen rout
; hmm but i guess this is not really a problem because u can
; preshift your textures !...
; !!!!!! hmm SIZEX !!! have to mul with 4 to get the REAL
; x points in the chunky buffer !.
; u have to assemble this stuff with undepended symbols
; because i use some old routs and they are from turboass
; and u know it uppercases all letters sorry...
; because i do not want to change all ;-)
; enjoy it...cheers olaf...and have fun !
; i hope everything is clear !;-)
SIZEX EQU 36 ;x size*4 without pixeldouble 40 => 320
;on screen
SIZEY EQU 30 ;y size without pixeldouble 20 => 40
;on screen
*****************************************************************************
* und ab geht das ....
*****************************************************************************
MOVEM.L D0-A6,-(SP)
PEA PRG(PC)
MOVE.W #$26,-(SP)
TRAP #$0E
ADDA.L #6,SP
MOVEM.L (SP)+,D0-A6
CLR.W -(SP)
TRAP #1
RTS
*****************************************************************************
PRG:
MOVE.L $044E,OLD_SCREEN
MOVE.B #6,$0484
; set screen to new adress
LEA AKT,A0
MOVE.L A0,D0
AND.L #$FFFFFF00,D0
MOVE.L D0,AKT_SCR
MOVE.B #0,$FFFF8260
LSR.L #8,D0
MOVE.B D0,$FFFF8203.w
LSR.L #8,D0
MOVE.B D0,$FFFF8201.w
MOVE.W #$00,$FFFF8240.w
MOVE.W #$01,$FFFF8242.w
MOVE.W #$02,$FFFF8244.w
MOVE.W #$03,$FFFF8246.w
MOVE.W #$04,$FFFF8248.w
MOVE.W #$05,$FFFF824A.w
MOVE.W #$06,$FFFF824C.w
MOVE.W #$07,$FFFF824E.w
MOVE.W #$17,$FFFF8250.w
MOVE.W #$0127,$FFFF8252.w
MOVE.W #$0237,$FFFF8254.w
MOVE.W #$0347,$FFFF8256.w
MOVE.W #$0457,$FFFF8258.w
MOVE.W #$0567,$FFFF825A.w
MOVE.W #$0677,$FFFF825C.w
MOVE.W #$0777,$FFFF825E.w
MOVEA.L AKT_SCR,A0
MOVE.L #7999,D0
CLR:
CLR.L (A0)+
DBRA D0,CLR
; generate the textures
BSR GENTAB
;generate the main c2p converter function !
BSR GENERATEC2PDRAWSCREEN
; fill the chunky buffer with some bars
LEA CHUNKYBUFFER,A0
MOVE.W #SIZEX*SIZEY*4,D0
FILLCHUNKY:
MOVE.W D0,D1
AND.W #$0F,D1
LSL.W #2,D1 ; here u can see that u have to
; preshift every color !!!
MOVE.B D1,(A0)+
SUBQ.W #1,D0
BNE.S FILLCHUNKY
MOVE.L $70.w,OLD70
MOVE.L #VBL,$70.w
MAINLOOP:
;sync with vbl...this works only if
;the vbl runs...
; ticks is counted +1 in vbl !
MOVE.L TICKS,D0
WAIT:
CMP.L TICKS,D0
BEQ WAIT
;draw the chunky buffer
BSR DRAWIT
;scroll the chunky buffer
LEA CHUNKYBUFFER,A0
LEA CHUNKYBUFFER,A1
ADDA.L #1,A1
MOVE.W #(SIZEX-1)*SIZEY*4,D0
SCROLLCHUNKY:
MOVE.B (A1)+,(A0)+
SUBQ.W #1,D0
BNE.S SCROLLCHUNKY
MOVE.B $0FFFFC02,D0
CMPI.B #$39,D0
BEQ.S END_IT
BRA MAINLOOP
END_IT:
MOVE.L OLD70(PC),$70.w
MOVE.W #$0100,$FFFF8240
MOVE.W #$0555,$FFFF8242
MOVE.W #$0555,$FFFF8244
MOVE.W #$0555,$FFFF8246
MOVE.W #$01,-(SP)
MOVE.L OLD_SCREEN(PC),-(SP)
MOVE.L OLD_SCREEN(PC),-(SP)
MOVE.W #5,-(SP)
TRAP #14
ADDA.L #12,SP
RTS
*****************************************************************************
DRAWIT:
; function to draw the chunky buffer
; i calls the generated drawscreen function
LEA CHUNKYBUFFER,A0
LEA TEXTURETAB,A1
MOVEA.L AKT_SCR,A2
BSR DRAWSCREEN
RTS
*****************************************************************************
C2PTEMPLATE:
;this part is for the generation routine for
;the c2pdrawscree function.
;it is copied into the drawscreen memory
;%0000 0000 0011 1100 0011 1100
;%0000 0011 1100 0011 1100 0000
;%0000 0011 1111 1111 1111 1100
MOVEQ #0,D0
MOVE.W (A0)+,D0
LSL.L #4,D0
OR.W (A0)+,D0
MOVE.L 0(A1,D0.l),D0
C2PTEMP1: MOVEP.L D0,$4000(A2)
C2PTEMP2: MOVEP.L D0,$4000(A2)
C2PTEMPLATEEND:
*****************************************************************************
GENERATEC2PDRAWSCREEN:
; this routine generates the screendrawing function
; from the c2ptemplate
; the how often depends on the xsize and ysize
; count = xsize*ysize
LEA DRAWSCREEN,A0
LEA C2PTEMPLATE,A1
MOVE.W #SIZEY-1,D2
MOVEQ #0,D3
GENYLOOP:
MOVEQ #0,D0
GENXLOOP:
; yes i know there is a better way for this ...i am lazy
; anyway this function runs only once ...
; calculation of the screen adr
MOVE.W D0,D4
MOVE.W D4,D1 ;x
AND.W #1,D1
LSR.W #1,D4
LSL.W #3,D4
ADD.W D1,D4
ADD.W D3,D4 ;add y
; write screen pos to the template function
MOVEA.L A0,A2
LEA C2PTEMPLATE,A1
MOVE.W #((C2PTEMPLATEEND-C2PTEMPLATE)),D7
GENCOPYTEMPLATE:
MOVE.B (A1)+,(A0)+
SUBQ.W #1,D7
BNE.S GENCOPYTEMPLATE
MOVE.W D4,(C2PTEMP1-C2PTEMPLATE)+2(A2)
ADD.W #160,D4
MOVE.W D4,(C2PTEMP2-C2PTEMPLATE)+2(A2)
ADDQ.W #1,D0
CMP.W #SIZEX,D0
BNE.S GENXLOOP
ADD.W #320,D3 ;add to y 2 lines because of
; the pixel double...
DBRA D2,GENYLOOP
;our rout needs a last a rts !;-)
;without it this is not really funny...
MOVE.W #$4E75,(A0)+
RTS
*****************************************************************************
GENTAB:
LEA TEXTURETAB,A6
LEA TAB1,A0
LEA TAB2,A1
LEA TAB3,A2
LEA TAB4,A3
MOVE.W #0,D3
GENLOOP1:
MOVE.W #0,D4
GENLOOP2:
MOVE.W #0,D5
GENLOOP3:
MOVE.W #0,D6
GENLOOP4:
; 1324
MOVE.L 0(A0,D3.w),D2
OR.L 0(A1,D5.w),D2
OR.L 0(A2,D4.w),D2
OR.L 0(A3,D6.w),D2
MOVE.L D2,(A6)+
ADDQ.W #4,D6
CMP.B #$40,D6
BNE.S GENLOOP4
ADDQ.W #4,D5
CMP.B #$40,D5
BNE.S GENLOOP3
ADDQ.W #4,D4
CMP.B #$40,D4
BNE.S GENLOOP2
ADDQ.W #4,D3
CMP.B #$40,D3
BNE.S GENLOOP1
RTS
TAB1:
DC.B $00,$00,$00,$00
DC.B $C0,$00,$00,$00
DC.B $00,$C0,$00,$00
DC.B $C0,$C0,$00,$00
DC.B $00,$00,$C0,$00
DC.B $C0,$00,$C0,$00
DC.B $00,$C0,$C0,$00
DC.B $C0,$C0,$C0,$00
DC.B $00,$00,$00,$C0
DC.B $C0,$00,$00,$C0
DC.B $00,$C0,$00,$C0
DC.B $C0,$C0,$00,$C0
DC.B $00,$00,$C0,$C0
DC.B $C0,$00,$C0,$C0
DC.B $00,$C0,$C0,$C0
DC.B $C0,$C0,$C0,$C0
TAB2:
DC.B $00,$00,$00,$00
DC.B $30,$00,$00,$00
DC.B $00,$30,$00,$00
DC.B $30,$30,$00,$00
DC.B $00,$00,$30,$00
DC.B $30,$00,$30,$00
DC.B $00,$30,$30,$00
DC.B $30,$30,$30,$00
DC.B $00,$00,$00,$30
DC.B $30,$00,$00,$30
DC.B $00,$30,$00,$30
DC.B $30,$30,$00,$30
DC.B $00,$00,$30,$30
DC.B $30,$00,$30,$30
DC.B $00,$30,$30,$30
DC.B $30,$30,$30,$30
TAB3:
DC.B $00,$00,$00,$00
DC.B $0C,$00,$00,$00
DC.B $00,$0C,$00,$00
DC.B $0C,$0C,$00,$00
DC.B $00,$00,$0C,$00
DC.B $0C,$00,$0C,$00
DC.B $00,$0C,$0C,$00
DC.B $0C,$0C,$0C,$00
DC.B $00,$00,$00,$0C
DC.B $0C,$00,$00,$0C
DC.B $00,$0C,$00,$0C
DC.B $0C,$0C,$00,$0C
DC.B $00,$00,$0C,$0C
DC.B $0C,$00,$0C,$0C
DC.B $00,$0C,$0C,$0C
DC.B $0C,$0C,$0C,$0C
TAB4:
DC.B $00,$00,$00,$00
DC.B $03,$00,$00,$00
DC.B $00,$03,$00,$00
DC.B $03,$03,$00,$00
DC.B $00,$00,$03,$00
DC.B $03,$00,$03,$00
DC.B $00,$03,$03,$00
DC.B $03,$03,$03,$00
DC.B $00,$00,$00,$03
DC.B $03,$00,$00,$03
DC.B $00,$03,$00,$03
DC.B $03,$03,$00,$03
DC.B $00,$00,$03,$03
DC.B $03,$00,$03,$03
DC.B $00,$03,$03,$03
DC.B $03,$03,$03,$03
VBL:
MOVEM.L D0-A6,-(SP)
ADDI.L #1,TICKS
MOVEM.L (SP)+,D0-A6
RTE
;-----------------------------------------------------------
OLD70: DC.L 0
EVEN
;------------------------------------------------------------------------
TICKS: DC.L 0
;------------------------------------------------------------------------
AKT_SCR: DC.L 0
OLD_SCREEN: DC.L 0
CHUNKYBUFSIZE EQU SIZEX*SIZEY*4
C2PTEMPSIZE EQU (C2PTEMPLATEEND-C2PTEMPLATE)
DRAWSCRSIZE EQU C2PTEMPSIZE*SIZEX*SIZEY
; this is the chunky buffer for every pixel 1 byte
; u have to mul all colors with 4 or preshift your
; texture !.
DS.B SIZEX ; savety area
CHUNKYBUFFER: DS.B CHUNKYBUFSIZE
DS.B SIZEX ; savety area
EVEN
; this is the c2p draw function it is generated by the
; function generatec2pdrawscreen
; the length of the function depend on the size to display
; the is is calculated at the top
DRAWSCREEN: DS.B DRAWSCRSIZE
DC.W 0 ; the space for the rts command
DS.L 64
AKT: DS.L 8000
TEXTURETAB:
DS.L 16*16*16*16
END