]> git.sur5r.net Git - cc65/blob - libsrc/tgi/tgi_clippedline.s
Fixed _textcolor definition.
[cc65] / libsrc / tgi / tgi_clippedline.s
1 ;
2 ; Ullrich von Bassewitz, 2009-10-25
3 ;
4 ; Clips line coordinates to the screen coordinates and calls tgi_line
5 ;
6
7
8         .import umul16x16r32, udiv32by16r16
9         .import negax
10
11         .include "tgi-kernel.inc"
12         .include "zeropage.inc"
13
14         .macpack longbranch
15
16 ;----------------------------------------------------------------------------
17 ; Data
18
19 .bss
20
21 ; Outcodes for both ends
22 tgi_clip_o1:    .res    1
23 tgi_clip_o2:    .res    1
24
25 ; Line deltas
26 tgi_clip_d:     .res    1
27 tgi_clip_dx:    .res    2
28 tgi_clip_dy:    .res    2
29
30 tgi_clip_sign:  .res    1
31
32
33 ;----------------------------------------------------------------------------
34 ; Calculate outcodes for both ends of the line
35 ;
36
37 .code
38 .proc   outcode1
39
40         ldy     #0
41         jsr     tgi_outcode
42         sta     tgi_clip_o1
43         rts
44
45 .endproc
46
47 .code
48 .proc   outcode2
49
50         ldy     #<(tgi_clip_y2 - tgi_clip_y1)
51         jsr     tgi_outcode
52         sta     tgi_clip_o2
53         rts
54
55 .endproc
56
57
58 ;----------------------------------------------------------------------------
59 ; Negate tgi_clip_dxy
60 ;
61
62 .code
63 .proc   negate
64
65         lda     tgi_clip_dx,y
66         eor     #$FF
67         clc
68         adc     #1
69         sta     tgi_clip_dx,y
70         lda     tgi_clip_dx+1,y
71         eor     #$FF
72         adc     #$00
73         sta     tgi_clip_dx+1,y
74         rts
75
76 .endproc
77
78
79 ;----------------------------------------------------------------------------
80 ; Calculate the absolute values of dx and dy and store the combined sign in
81 ; tgi_clip_sign
82 ;
83
84 .code
85 .proc   calcdeltas
86
87         lda     tgi_clip_x2
88         sec
89         sbc     tgi_clip_x1
90         sta     tgi_clip_dx
91         lda     tgi_clip_x2+1
92         sbc     tgi_clip_x1+1
93         sta     tgi_clip_dx+1
94         sta     tgi_clip_sign
95         bpl     @L1
96         ldy     #0
97         jsr     negate
98
99 @L1:    lda     tgi_clip_y2
100         sec
101         sbc     tgi_clip_y1
102         sta     tgi_clip_dy
103         lda     tgi_clip_y2+1
104         sbc     tgi_clip_y1+1
105         sta     tgi_clip_dy+1
106
107         eor     tgi_clip_sign
108         sta     tgi_clip_sign
109
110         bit     tgi_clip_dy+1
111         bpl     @L9
112
113         ldy     #(tgi_clip_dy - tgi_clip_dx)
114         jmp     negate
115
116 @L9:    rts
117
118 .endproc
119
120
121 ;----------------------------------------------------------------------------
122 ; Helper routine. Generate the absolute value of y/a and calculate the sign
123 ; of the final result
124 ;
125
126 .code
127 .proc   prepare_coord
128
129         tax                             ; Remember high byte
130         eor     tgi_clip_sign
131         sta     tmp1                    ; Sign of result
132         tya
133         cpx     #0                      ; Check sign
134         bpl     @L1
135         jsr     negax
136 @L1:    sta     ptr1
137         stx     ptr1+1
138         rts
139
140 .endproc
141
142
143 ;----------------------------------------------------------------------------
144 ; Helper routine. Move the value in eax to ptr1:ptr2
145 ;
146
147 .code
148 .proc   move_intermediate_result
149
150         sta     ptr1
151         stx     ptr1+1
152         ldy     sreg
153         sty     ptr2
154         ldy     sreg+1
155         sty     ptr2+1
156         rts
157
158 .endproc
159
160
161 ;----------------------------------------------------------------------------
162 ; Multiplicate value in y/a by dy, then divide by dx.
163 ;
164
165 .code
166 .proc   muldiv_dydx
167
168 ; Generate the absolute value of y/a and calculate the sign of the final
169 ; result
170
171         jsr     prepare_coord
172
173 ; All values are positive now (dx/dy have been made positive in calcdeltas)
174 ; and the sign of the final result is on tmp1, so we can use unsigned
175 ; operations and apply the final result later, after rounding.
176
177         lda     tgi_clip_dy
178         ldx     tgi_clip_dy+1           ; rhs
179         jsr     umul16x16r32            ; Multiplicate
180
181 ; Move the result of the multiplication into ptr1:ptr2
182
183         jsr     move_intermediate_result
184
185 ; Load divisor and divide
186
187         lda     tgi_clip_dx
188         ldx     tgi_clip_dx+1
189         jsr     udiv32by16r16
190
191 ; Check the sign of the final result and negate it if nessary
192
193 done:   bit     tmp1
194         jmi     negax
195         rts
196
197 .endproc
198
199
200
201 ;----------------------------------------------------------------------------
202 ; Multiplicate value in y/a by dx, then divide by dy.
203 ;
204
205 .code
206 .proc   muldiv_dxdy
207
208 ; Generate the absolute value of y/a and calculate the sign of the final
209 ; result
210
211         jsr     prepare_coord
212
213 ; All values are positive now (dx/dy have been made positive in calcdeltas)
214 ; and the sign of the final result is on tmp1, so we can use unsigned
215 ; operations and apply the final result later, after rounding.
216
217         lda     tgi_clip_dx
218         ldx     tgi_clip_dx+1           ; rhs
219         jsr     umul16x16r32            ; Multiplicate
220
221 ; Move the result of the multiplication into ptr1:ptr2
222
223         jsr     move_intermediate_result
224
225 ; Load divisor and divide
226
227         lda     tgi_clip_dy
228         ldx     tgi_clip_dy+1
229         jsr     udiv32by16r16
230
231 ; Check the sign of the final result and negate it if nessary
232
233         jmp     muldiv_dydx::done
234
235 .endproc
236
237
238
239 ;----------------------------------------------------------------------------
240 ; Clip a line using Cohen Sutherland
241 ;
242
243 .code
244 .proc   tgi_clippedline
245
246 ; Set a flag that we have no deltas calculated
247
248         lda     #0
249         sta     tgi_clip_d
250
251 ; Generate outcodes
252
253         jsr     outcode1
254         jsr     outcode2
255
256 ; if ((tgi_clip_o1 | tgi_clip_o2) == 0) {
257 ;     tgi_line (x1, y1, x2, y2);
258 ; }
259
260 Loop:   lda     tgi_clip_o1
261         ora     tgi_clip_o2
262         bne     L1
263
264 ; Copy the coordinates into ptr1-4 and draw the line
265
266         ldx     #7
267 L0:     lda     tgi_clip_x1,x
268         sta     ptr1,x
269         dex
270         bpl     L0
271         jmp     tgi_line
272
273 ; if ((tgi_clip_o1 & tgi_clip_o2) != 0) reject;
274
275 L1:     lda     tgi_clip_o1
276         and     tgi_clip_o2
277         beq     L2
278         rts                             ; Nothing to draw
279
280 ; We must clip. If we haven't already done so, calculate dx/dy.
281
282 L2:     lda     tgi_clip_d              ; Deltas alreay calculated?
283         bne     HaveDeltas              ; Jump if yes
284         inc     tgi_clip_d
285         jsr     calcdeltas
286
287 ; Check if X1/Y1 needs clipping
288
289 HaveDeltas:
290         lda     tgi_clip_o1
291         jeq     L10
292
293 ; Need to clip X1/Y1
294
295         lsr     a                       ; Check for TGI_CLIP_LEFT
296         bcc     L3
297
298 ; tgi_clip_y1 += (0 - tgi_clip_x1) * tgi_clip_dy / tgi_clip_dx;
299 ; tgi_clip_x1 = 0;
300
301         lda     #$00
302         tax
303         beq     L4
304
305 L3:     lsr     a                       ; Check for TGI_CLIP_RIGHT
306         bcc     L5
307
308 ; tgi_clip_y1 += (tgi_xmax - tgi_clip_x1) * tgi_clip_dy / tgi_clip_dx;
309 ; tgi_clip_x1 = tgi_xmax;
310
311         lda     _tgi_xmax
312         ldx     _tgi_xmax+1
313
314 L4:     tay
315         sec
316         sbc     tgi_clip_x1
317         sty     tgi_clip_x1
318         tay
319         txa
320         sbc     tgi_clip_x1+1
321         stx     tgi_clip_x1+1
322
323         jsr     muldiv_dydx
324
325         clc
326         adc     tgi_clip_y1
327         sta     tgi_clip_y1
328         txa
329         adc     tgi_clip_y1+1
330         sta     tgi_clip_y1+1
331
332 ;
333
334         lda     tgi_clip_o1
335         lsr     a
336         lsr     a
337 L5:     lsr     a                               ; Check for TGI_CLIP_BOTTOM
338         bcc     L6
339
340 ; tgi_clip_x1 = (0 - tgi_clip_y1) * tgi_clip_dx / tgi_clip_dy;
341 ; tgi_clip_y1 = 0;
342
343         lda     #$00
344         tax
345         beq     L7
346
347 L6:     lsr     a                               ; Check for TGI_CLIP_TOP
348         bcc     L8
349
350 ; tgi_clip_x1 += (tgi_ymax - tgi_clip_y1) * tgi_clip_dx / tgi_clip_dy;
351 ; tgi_clip_y1 = ymax;
352
353         lda     _tgi_ymax
354         ldx     _tgi_ymax+1
355
356 L7:     tay
357         sec
358         sbc     tgi_clip_y1
359         sty     tgi_clip_y1
360         tay
361         txa
362         sbc     tgi_clip_y1+1
363         stx     tgi_clip_y1+1
364
365         jsr     muldiv_dxdy
366
367         clc
368         adc     tgi_clip_x1
369         sta     tgi_clip_x1
370         txa
371         adc     tgi_clip_x1+1
372         sta     tgi_clip_x1+1
373
374 ; We need to recalculate outcode1 in this case
375
376 L8:     jsr     outcode1
377
378 ; Check if X2/Y2 needs clipping
379
380 L10:    lda     tgi_clip_o2
381         jeq     Loop
382
383 ; Need to clip X2/Y2
384
385         lsr     a                       ; Check for TGI_CLIP_LEFT
386         bcc     L11
387
388 ; tgi_clip_y2 += (0 - tgi_clip_x2) * tgi_clip_dy / tgi_clip_dx;
389 ; tgi_clip_x2 = 0;
390
391         lda     #$00
392         tax
393         beq     L12
394
395 L11:    lsr     a                       ; Check for TGI_CLIP_RIGHT
396         bcc     L13
397
398 ; tgi_clip_y2 += (tgi_xmax - tgi_clip_x2) * tgi_clip_dy / tgi_clip_dx;
399 ; tgi_clip_x2 = tgi_xmax;
400
401         lda     _tgi_xmax
402         ldx     _tgi_xmax+1
403
404 L12:    tay
405         sec
406         sbc     tgi_clip_x2
407         sty     tgi_clip_x2
408         tay
409         txa
410         sbc     tgi_clip_x2+1
411         stx     tgi_clip_x2+1
412
413         jsr     muldiv_dydx
414
415         clc
416         adc     tgi_clip_y2
417         sta     tgi_clip_y2
418         txa
419         adc     tgi_clip_y2+1
420         sta     tgi_clip_y2+1
421
422 ;
423
424         lda     tgi_clip_o2
425         lsr     a
426         lsr     a
427 L13:    lsr     a                       ; Check for TGI_CLIP_BOTTOM
428         bcc     L14
429
430 ; tgi_clip_x2 += (0 - tgi_clip_y2) * tgi_clip_dx / tgi_clip_dy;
431 ; tgi_clip_y2 = 0;
432
433         lda     #$00
434         tax
435         beq     L15
436
437 L14:    lsr     a                       ; Check for TGI_CLIP_TOP
438         bcc     L16
439
440 ; tgi_clip_x2 += (tgi_ymax - tgi_clip_y2) * tgi_clip_dx / tgi_clip_dy;
441 ; tgi_clip_y2 = tgi_ymax;
442
443         lda     _tgi_ymax
444         ldx     _tgi_ymax+1
445
446 L15:    tay
447         sec
448         sbc     tgi_clip_y2
449         sty     tgi_clip_y2
450         tay
451         txa
452         sbc     tgi_clip_y2+1
453         stx     tgi_clip_y2+1
454
455         jsr     muldiv_dxdy
456
457         clc
458         adc     tgi_clip_x2
459         sta     tgi_clip_x2
460         txa
461         adc     tgi_clip_x2+1
462         sta     tgi_clip_x2+1
463
464 ; We need to recalculate outcode2 in this case
465
466 L16:    jsr     outcode2
467
468 ; Try again
469
470         jmp     Loop
471
472 .endproc
473
474
475
476