Tech-tech - more resolution to vertical shift. by Pasi 'Albert' Ojala (po87553@cs.tut.fi _or_ albert@cc.tut.fi) (All timings are in PAL, principles will apply to NTSC too) One time half of the demos had pictures waving horizontally on the width of the whole screen. This effect is named tech-tech, and the audience was puzzled. You can move the screen only eight pixels using the horizontal scroll register. This effect was done using character graphics. How exactly and is the same possible with sprites ? Horizontal scroll register can move the screen by eight pixels. This isn't even nearly enough to produce a really stunning effect. You have to move the graphics itself, fortunately with a resolution of one character position (one byte) only, the rest can be done with the scroll register. During one scan line there is no time to move the actual data, you can only move a pointer. Changing the video matrix pointer won't help, because VIC (video interface controller) will fetch the character codes only at certain times, called bad lines. You can change the character set pointer instead, because VIC reads the data it displays directly from the character set memory. Character set-implementation has its restrictions Because horizontal movement is done by changing the character sets, the picture or text must be pure graphic and the character codes in the video matrix must be in a numerical order. The normal picture is in the first character memory and in the next one it is shifted one character position to the right. One video bank can hold only seven full character memories besides the video matrix. This limits the movement of the picture to 56 pixels. It is possible to get more movement if you use smaller picture or another video bank. The shift is done so that on each scan line we update the horizontal scroll register ($D016) with the three lowest bits of the shift value. We use the other bits to select the right character set ($D018). In a tech-tech the shift value changes during the display of the whole picture, and the values are stored in a table. In addition to that, the shift values should be put into two tables, one for the horizontal scroll register and another for the character set select. This is necessary, because there is no time for extra calculations on a bad line. Because we have to change the character set and x-scroll dynamically, we also need a raster routine to show a tech-tech. A raster routine is a routine which is synchronized to the electron beam. This eats up the processor time: the bigger the picture, the less time is left over for other activities. On other than bad lines you can do other funny things, like change the color of the background or border. An example program The demo program uses video bank 2, memory addesses $4000-7fff. The video matrix is in the beginning of the bank. Only inverted chars are used for the graphics, this way we have all eight character memories available and the maximum shift is 64 pixels. The area for the tech-tech in the video matrix is eight character rows high, but it has identical graphics on every line. This is why we use only 320 bytes from each character set. You can use a joystick to control the movement of the tech-tech. The stick decreases or increases the shift add value in a resolution of a half pixel. When the shift reaches its highest/lowest value, the direction of the add is reversed. Just experiment with it. You can do it on the screen, how about borders ? Because you cannot get characters to the border, you might think that it is impossible to make a tech-tech effect in the borders. It takes so much time to change sprite x-coordinates, that you can change only some of them. There is time for five sprite moves, if you do not need to change the most significant (9th) bit of the x-coordinate. On the other hand, you could design the movements directly to the sprites and then just change the images, but then the movements would be constant. However, there is one trick you can use to get all of the sprites on the screen, with variable movements and color bars etc. You do not change the x-coordinates, but the data itself on each scan line. In fact you change the sprite image pointers. There is multiple sprite pictures, where the graphics is shifted horizontally, just like the normal tech-tech charsets. Because of this, the sprites have to be placed side by side. No gaps are allowed. By changing the image pointers you can get the graphics to move horizontally on each line as you wish. With multicolor sprites you have to remember that one pixel corresponds to two bits - the movement is not so smooth. Wait ! How come there is enough time to change the sprite pointers, when there is not time to change the coordinates ? This is another pointer trick. VIC reads the sprite image pointers from the end of the current video matrix, normally $07f8. You just have to change the video matrix pointer ($D018) to change all of the image pointers. This takes only eight cycles and there is plenty of time left for other effects on each scan line. If you use only one video bank, you can get the sprite picture to 16 different places. This allows also another kind of effects, just use your imagination. -------------------------------------------------------------------------- Tech-tech demo program (PAL) BANK= $96 ; The value of the video bank register (CIA2) in the tech-area ZP= $FB ; Zero page for indirect addressing START= $4400 ; Start of the charsets (we use inverted chars) SCREEN= $4000 ; Position of the video matrix SHIFTL= $CF00 ; x-shift, lowest 3 bits SHIFTH= $CE00 ; x-shift, highest 3 bittid (multiplied with two) POINTER= $033C ; Pointer to shift-table VALUE= $033D ; Shift now SPEED= $033E ; Shift change *= $C000 ; Start address.. INIT SEI ; Disable interrupts LDA #$7F STA $DC0D ; Disable timer interrupt LDA #$81 STA $D01A ; Enable raster interrupt LDA #IRQ STA $0315 LDA #49 ; The interrupt to the line before the first bad line STA $D012 LDA #$1B STA $D011 ; 9th bit of the raster compare LDY #0 LDX #$40 STX ZP+1 STY ZP TYA LOOP0 STA (ZP),Y ; Clear the whole video bank ($4000-7FFF) INY BNE LOOP0 INC ZP+1 BPL LOOP0 LDA #>START STA ZP+1 LDA #$32 ; Character ROM to address space ($D000-) STA $01 LOOP1 TYA ; (Y-register is zero initially) LSR LSR LSR TAX LDA TEXT,X ; Which char to plot ? ASL ; Source ASL ASL TAX ; low byte to X LDA #$D0 ADC #0 ; high byte (one bit) taken into account STA LOOP2+2 ; Self-modifying again.. LOOP2 LDA $D000,X STA (ZP),Y INX INY TXA AND #7 BNE LOOP2 ; Copy one char CPY #0 BNE LOOP1 ; Copy 32 chars (256 bytes) LDA #$37 ; Memory configuration back to normal STA $01 LOOP3 LDA START,Y ; Copy the data to each charset, shifted by one STA START+2056,Y ; position to the right STA START+4112,Y STA START+6168,Y STA START+8224,Y STA START+10280,Y STA START+12336,Y STA START+14392,Y INY BNE LOOP3 LDA #0 ; Clear the pointer, value and speed STA POINTER STA VALUE STA SPEED LOOP4 TYA ; (Y was zero) ORA #$80 ; Use the inverted chars STA SCREEN,Y ; Set the character codes to video matrix STA SCREEN+40,Y STA SCREEN+80,Y STA SCREEN+120,Y STA SCREEN+160,Y STA SCREEN+200,Y STA SCREEN+240,Y STA SCREEN+280,Y LDA #239 ; leave the last line empty STA SCREEN+320,Y INY CPY #40 BNE LOOP4 ; Loop until the whole area is filled CLI ; Enable interrupts RTS IRQ LDA #BANK ; Change the video bank, some timing STA $DD00 NOP NOP LDY POINTER ; Y-register will point to x-shift JMP BAD ; next line is a bad line LOOP5 NOP LOOP6 LDA SHIFTL,Y ; Do the shift STA $D016 ; 3 lowest bits LDA SHIFTH,Y STA $D018 ; another 3 bits NOP : NOP : NOP : NOP : NOP : NOP ; waste some time NOP : NOP : NOP : NOP : NOP : NOP NOP : NOP : NOP LDA $D012 ; check if it is time to stop CMP #$78 BPL OVER INY ; next position in table DEX BNE LOOP5 ; No bad line, loop BAD LDA SHIFTL,Y ; This is a bad line, a bit more hurry STA $D016 LDA SHIFTH,Y STA $D018 INY LDX #7 ; New bad line coming up JMP LOOP6 OVER LDA #$97 ; Video bank to 'normal' STA $DD00 LDA #22 ; Same with the charset STA $D018 LDA #8 ; and the horizontal scroll register STA $D016 LDA $DC00 ; Let's check the joysticks AND $DC01 TAX LDY SPEED AND #8 ; Turned right, add speed BNE EIP INY CPY #4 ; Don't store, too much speed BPL EIP STY SPEED EIP TXA AND #4 ; Turned left BNE ULOS DEY CPY #$FC ; Too much ? BMI ULOS STY SPEED ULOS LDA VALUE ; Add speed to value (signed) CLC ADC SPEED BPL OK LDA SPEED ; Banged to the side ? EOR #$FF CLC ADC #1 STA SPEED LDA VALUE OK STA VALUE LSR ; Value is twice the shift TAX ; Remember the shift AND #7 ; lowest 3 bits ORA #8 ; (screen 40 chars wide) LDY POINTER STA SHIFTL,Y TXA LSR LSR LSR ; highest 3 bits too ASL ; multiplicated by two STA SHIFTH,Y DEC POINTER LDA #1 ; Ack the interrupt STA $D019 JMP $EA31 ; The normal interrupt routine TEXT SCR "THIS IS TECH-TECH FOR C=64 BY ME" ; Test text ; SCR converts to screen codes