;
; Ullrich von Bassewitz, 2009-11-05
;
-; Helper function for functions using sine/cosine: Multiply two values, one
-; being an 8.8 fixed point one, and return the rounded and scaled result.
+; Helper function for graphics functions: Multiply two values, one being
+; an 8.8 fixed point one, and return the rounded and scaled result.
+;
+; The module has two entry points: One is C callable and expects the
+; parameters in ax and the stack, the second is assembler callable and
+; expects the parameters in ax and ptr1
;
- .export _tgi_imulround
+ .export _tgi_imulround, tgi_imulround
.import popax, imul16x16r32
.include "zeropage.inc"
;
.code
-.proc _tgi_imulround
+
+; C callable entry point
+_tgi_imulround:
; Get arguments
stx ptr1+1 ; Save lhs
jsr popax ; Get rhs
+; ASM callable entry point
+tgi_imulround:
+
; Multiplicate
jsr imul16x16r32
tya
rts
-.endproc
+
.bss
-; Clipping coordinates.
+; Clipping coordinates. They must be in this order!
tgi_clip_x1: .res 2
tgi_clip_y1: .res 2
tgi_clip_x2: .res 2
;
.code
-.proc tgi_outcode
+.proc tgi_outcode
lda #TGI_CLIP_NONE
sta tmp1
.include "tgi-vectorfont.inc"
.include "zeropage.inc"
+ .import _toascii
.import popax, negax
; Data
text := regbank
+font := regbank ; Same as text
+widths := regbank+2
;----------------------------------------------------------------------------
;
tax
pla ; Restore s
jsr _tgi_textwidth ; Get width of text string
+
+; Move the graphics cursor by the amount in a/x
+
+MoveCursor:
ldy _tgi_textdir ; Horizontal or vertical text?
beq @L1 ; Jump if horizontal
txa
adc _tgi_curx+1,y
sta _tgi_curx+1,y
- rts
+Done: rts
-; Handle vector font output
+; Handle vector font output. First, check if we really have a registered
+; vector font. Bail out if this is not the case.
VectorFont:
tay
ora _tgi_vectorfont+1
beq Done ; Bail out if not
- lda text ; Save zero page variable on stack
+; Check if the font in the given size is partially out of the screen. We
+; do this in vertical direction here, and in horizontal direction before
+; outputting a character.
+
+ ; (todo)
+
+; Save zero page variable on stack and save
+
+ lda text
pha
lda text+1
pha
+ lda widths
+ pha
+ lda widths+1
+ pha
sty text
stx text+1 ; Store pointer to string
+ lda _tgi_vectorfont
+ clc
+ adc #<(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
+ sta widths
+ lda _tgi_vectorfont+1
+ adc #>(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
+ sta widths+1
+
; Output the text string
@L1: ldy #0
lda (text),y ; Get next character from string
beq EndOfText
+ jsr _toascii ; Convert to ascii
+ pha ; Save char in A
jsr _tgi_vectorchar ; Output it
+ pla
+
+; Move the graphics cursor by the width of the char
+
+ tay
+ lda (widths),y ; Get width of this char
+ sta ptr1
+ lda #0
+ sta ptr1+1
+ lda _tgi_textscalew
+ ldx _tgi_textscalew+1 ; Get scale factor
+ jsr tgi_imulround ; Multiplcate and round
+ jsr MoveCursor ; Move the graphics cursor
+
+; Next char in string
+
inc text
bne @L1
inc text+1
; Done. Restore registers and return
EndOfText:
+ pla
+ sta widths+1
+ pla
+ sta widths
pla
sta text+1
pla
sta text
-Done: rts
+ rts
.endproc
.include "tgi-kernel.inc"
+ .include "tgi-vectorfont.inc"
+ .include "zeropage.inc"
;-----------------------------------------------------------------------------
; unsigned __fastcall__ tgi_textheight (const char* s);
-; /* Calculate the width of the text in pixels according to the current text
+; /* Calculate the height of the text in pixels according to the current text
; * style.
; */
;
.proc _tgi_textheight
+ ldy _tgi_font
+ bne @L2 ; Jump if vector font
+
+; Return the height for the bitmap font
+
lda _tgi_charheight
ldx #0
- rts
+@L1: rts
+
+; Return the height for the vector font
+
+@L2: lda _tgi_vectorfont
+ tax
+ ora _tgi_vectorfont+1
+ beq @L1 ; Return zero if no font
+
+ stx ptr1
+ lda _tgi_vectorfont+1
+ sta ptr1+1
+ ldy #TGI_VECTORFONT::TOP
+ lda (ptr1),y
+ ldy #TGI_VECTORFONT::BOTTOM
+ clc
+ adc (ptr1),y ; Total font height is top + bottom
+
+ sta ptr1
+ lda #0
+ sta ptr1+1 ; Save base height in ptr1
+
+ lda _tgi_textscaleh
+ ldx _tgi_textscaleh+1 ; Get scale factor ...
+ jmp tgi_imulround ; ... and return scaled result
.endproc
.include "tgi-kernel.inc"
+ .include "tgi-vectorfont.inc"
+ .include "zeropage.inc"
+
+ .import _strlen, _toascii
+ .import umul16x16r32
+
+;-----------------------------------------------------------------------------
+; Aliases for zero page locations
+
+Width := ptr1
+WTab := ptr2
+Text := ptr3
+
- .import _strlen, pushax, tosumula0
;-----------------------------------------------------------------------------
; unsigned __fastcall__ tgi_textwidth (const char* s);
; Result is strlen (s) * tgi_textmagw * tgi_fontsizex
;
+.code
.proc _tgi_textwidth
+ ldy _tgi_font
+ bne @L1 ; Jump if vector font
+
+; Return the width of the string for the bitmap font
+
jsr _strlen
- jsr pushax
+ sta ptr1
+ stx ptr1+1
lda _tgi_charwidth
- jmp tosumula0
+ ldx #0
+ jmp umul16x16r32
+
+; Return the width of the string for the vector font. To save some code, we
+; will add up all the character widths and then multiply by the scale factor.
+; Since the output routine will scale each single character, the result may
+; be slightly different.
+
+@L1: sta Text
+ stx Text+1 ; Save pointer to string
+
+ lda _tgi_vectorfont+1
+ tax
+ ora _tgi_vectorfont
+ beq @L9 ; Return zero if no font
+
+ lda _tgi_vectorfont
+ clc
+ adc #<(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
+ sta WTab
+ txa
+ adc #>(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
+ sta WTab+1
+
+ ldy #0
+ sty Width
+ sty Width+1 ; Zero the total width
+
+; Sum up the widths of the single characters
+
+@L2: ldy #0
+ lda (Text),y ; Get next char
+ beq @L4 ; Bail out if end of text reached
+ jsr _toascii ; Convert to ascii
+ tay
+ lda (WTab),y ; Get width of this char
+ clc
+ adc Width
+ sta Width
+ bcc @L3
+ inc Width+1
+@L3: inc Text
+ bne @L2
+ inc Text+1
+ bne @L2
+
+; We have the total width now, scale and return it
+
+@L4: lda _tgi_textscalew
+ ldx _tgi_textscalew+1
+ jmp tgi_imulround
+
+; Exit point if no font installed
+
+@L9: rts
.endproc
+
+
; */
;
- .import _toascii, imul16x16r32, umul16x16r32, negax, negeax
+ .import imul16x16r32, umul16x16r32, negax, negeax
.include "tgi-kernel.inc"
.include "tgi-vectorfont.inc"
Y1: .res 2
X2: .res 2
Y2: .res 2
-BaseX: .res 2
-BaseY: .res 2
-Char: .res 1
;----------------------------------------------------------------------------
; Get the next operation from the Ops pointer, remove the flag bit and sign
-; extend the 8 bit value. On return, the flags are set for the value in A.
+; extend the 8 bit value to 16 bits.
.code
.proc GetOp
bne :+
inc Ops+1
-; Move bit 7 into Flag, then sign extend the value in A
+; Move bit 7 into Flag, then sign extend the value in A and extend the sign
+; into X.
: asl a ; Flag into carry
ror Flag
+ ldx #0
cmp #$80 ; Sign bit into carry
ror a ; Sign extend the value
+ bpl :+
+ dex ; Value is negative
; Done
- rts
+: rts
.endproc
-;----------------------------------------------------------------------------
-; Round a 16.8 fixed point value in eax
-
-.code
-.proc RoundFix
-
- cmp #$80 ; frac(val) >= 0.5?
- txa
- ldx sreg
- adc #$00
- bcc @L1
- inx
-@L1: rts
-
-.endproc
-
;----------------------------------------------------------------------------
; Get and process one coordinate value. The scale factor is passed in a/x
.code
-.proc GetProcessedCoord
+GetProcessedYCoord:
+ lda _tgi_textscaleh+0
+ ldx _tgi_textscaleh+1
+
+GetProcessedCoord:
; Save scale factor as left operand for multiplication
sta ptr1
stx ptr1+1
-; Load next operation value. This will set the flags for the value in A.
+; Load next operation value.
jsr GetOp
-; Since we know that the scale factor is always positive, we will remember
-; the sign of the coordinate offset, make it positive, do an unsigned mul
-; and negate the result if the vector was negative. This is faster than
-; relying on the signed multiplication, which will do the same, but for
-; both operands.
+; Multiplicate with the scale factor.
- sta tmp1 ; Remember sign of vector offset
- bpl :+
- eor #$FF
- clc
- adc #$01 ; Negate
-: ldx #$00 ; High byte is always zero
+ jmp tgi_imulround ; Multiplicate, round and scale
-; Multiplicate with the scale factor.
+;----------------------------------------------------------------------------
+; Add the base coordinate with offset in Y to the value in A/X
+
+.code
+.proc AddBaseCoord
+
+ clc
+ adc _tgi_curx+0,y
+ pha
+ txa
+ adc _tgi_curx+1,y
+ tax
+ pla
+ rts
- jsr umul16x16r32 ; Multiplicate
+.endproc
-; The result is a 16.8 fixed point value. Round it.
+;----------------------------------------------------------------------------
+; Subtract the value in a/x from the base coordinate with offset in Y
+; This is
+;
+; ax = _tgi_cur[xy] - ax
+;
+; which can be transformed to
+;
+; ax = _tgi_cur[xy] + (~ax + 1);
- jsr RoundFix
-; Check the sign and negate if necessary
+.code
+.proc SubBaseCoord
- bit tmp1 ; Check sign
- bpl :+
- jmp negax ; Negate result if necessary
-: rts
+ eor #$FF
+ sec ; + 1
+ adc _tgi_curx+0,y
+ pha
+ txa
+ eor #$FF
+ adc _tgi_curx+1,y
+ tax
+ pla
+ rts
.endproc
.code
.proc _tgi_vectorchar
-; Convert the character to ASCII, multiplicate by two and save into Y
+; Multiplicate the char value by two and save into Y
- jsr _toascii
asl a
tay
lda Flag
pha
-; Get the width of the char in question
-
- lda _tgi_vectorfont
- clc
- adc #<(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
- sta Ops
- lda _tgi_vectorfont+1
- adc #>(TGI_VECTORFONT::WIDTHS - TGI_VF_FIRSTCHAR)
- sta Ops+1
- lda (Ops),y
-
-; Save the character
-
- sty Char
-
-; Calculate the width of the character by multiplying with the scale
-; factor for the width
-
- sta ptr1
- lda #0
- sta ptr1+1
-
- lda _tgi_textscalew
- ldx _tgi_textscalew+1
- jsr umul16x16r32
- jsr RoundFix
-
-; Store the current value of the graphics cursor into BaseX/BaseY, then
-; move it to the next character position
-
- pha
- ldy #3
-: lda _tgi_curx,y
- sta BaseX,y
- dey
- bpl :-
- pla
-
- ldy _tgi_textdir
- beq :+ ; Jump if horizontal text
-
- jsr negax
- ldy #2 ; Offset of tgi_cury
-
-; Advance graphics cursor
-
-: clc
- adc _tgi_curx,y
- sta _tgi_curx,y
- txa
- adc _tgi_curx+1,y
- sta _tgi_curx+1,y
-
; Calculate a pointer to the vector ops for the given char (now in Y). We
; definitely expect a font here, that has to be checked by the caller.
adc #>(TGI_VECTORFONT::CHARS - 2*TGI_VF_FIRSTCHAR)
sta Ops+1
- ldy Char
iny
lda (Ops),y
tax
ldx _tgi_textscalew+1
jsr GetProcessedCoord ; Get X vector
-; X2 = BaseX + XMag * XDelta.
+; Depending on the text direction, the X vector is either applied to X as
+;
+; X2 = _tgi_curx + XMag * XDelta
+;
+; or applied to Y as
+;
+; Y2 = _tgi_cury - XMag * XDelta
+;
+; which can be transformed to
+;
+; Y2 = _tgi_cury + (~(XMag * XDelta) + 1);
+;
+;
+; For the Y component we have
+;
+; Y2 = _tgi_cury - YMag * YDelta
+;
+; which can be transformed to
+;
+; Y2 = _tgi_cury + (~(YMag * YDelta) + 1);
+;
+; or applied to X as
+;
+; X2 = _tgi_curx - YMag * YDelta
+;
+; which can be transformed to
+;
+; X2 = _tgi_curx + (~(YMag * YDelta) + 1);
+;
+
+ ldy _tgi_textdir ; Horizontal or vertical text?
+ bne @Vertical ; Jump if vertical
- clc
- adc BaseX+0
- sta X2+0
- txa
- adc BaseX+1
- sta X2+1
+; Process horizontal text
-; Process the Y value
+ ldy #0
+ jsr AddBaseCoord
+ sta X2
+ stx X2+1
- lda _tgi_textscaleh+0
- ldx _tgi_textscaleh+1
- jsr GetProcessedCoord
+; Get Y vector
-; Y2 = BaseY - YMag * YDelta;
-; Y2 = BaseY + (~(YMag * YDelta) + 1);
+ jsr GetProcessedYCoord
- eor #$FF
- sec ; + 1
- adc BaseY+0
- sta Y2+0
- txa
- eor #$FF
- adc BaseY+1
- sta Y2+1
+; Apply to Y
+
+ ldy #2
+ jsr SubBaseCoord
+ sta Y2
+ stx Y2+1
+ jmp @DrawMove
+
+; Process vertical text
+
+@Vertical:
+ ldy #2
+ jsr SubBaseCoord
+ sta Y2
+ stx Y2+1
+
+; Get Y vector
+
+ jsr GetProcessedYCoord
+
+; Apply to X
+
+ ldy #0
+ jsr SubBaseCoord
+ sta X2
+ stx X2+1
; Draw, then move - or just move
+@DrawMove:
bit Flag
bpl @Move ; Jump if move only
+.if 0
ldy #7 ; Copy start coords into zp
: lda X1,y
sta ptr1,y
bpl :-
jsr tgi_line ; Call the driver
+.else
+ ldy #7 ; Copy start coords
+: lda X1,y
+ sta tgi_clip_x1,y
+ dey
+ bpl :-
+
+ jsr tgi_clippedline ; Call line clipper
+.endif
; Move the start position
; Done. Restore zp and return.
-Done: pla
+ pla
sta Flag
pla
sta Ops+1