]> git.sur5r.net Git - cc65/blob - libsrc/tgi/tgi_clippedline.s
remove superfluous ".code" line
[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 ; Line coordinates. Must be set before calling tgi_clippedline
22 tgi_clip_x1:    .res    2
23 tgi_clip_y1:    .res    2
24 tgi_clip_x2:    .res    2
25 tgi_clip_y2:    .res    2
26
27 tgi_clip_o1:    .res    1
28 tgi_clip_o2:    .res    1
29
30 tgi_clip_d:     .res    1
31 tgi_clip_dx:    .res    2
32 tgi_clip_dy:    .res    2
33
34 tgi_clip_sign:  .res    1
35
36
37 ;----------------------------------------------------------------------------
38 ; outcode constants.
39
40 CLIP_NONE       = $00
41 CLIP_LEFT       = $01
42 CLIP_RIGHT      = $02
43 CLIP_BOTTOM     = $04
44 CLIP_TOP        = $08
45
46
47
48 ;----------------------------------------------------------------------------
49 ; Generate a Cohen Sutherland outcode
50 ;
51 ; void outcode ()
52 ; {
53 ;     unsigned char o = 0;
54 ;     if (Y < 0) {
55 ;         o = CLIP_BOTTOM;
56 ;     } else if (Y >= yres) {
57 ;         o = CLIP_TOP;
58 ;     }
59 ;     if (X < 0) {
60 ;         o |= CLIP_LEFT;
61 ;     } else if (X >= xres) {
62 ;         o |= CLIP_RIGHT;
63 ;     }
64 ;     return o;
65 ; }
66
67 .code
68 .proc   outcode
69
70         lda     #CLIP_NONE
71         sta     tmp1
72
73 ; Check Y coordinate
74
75         lda     tgi_clip_y1+1,y         ; High byte of Y1
76         bmi     L2                      ; Jump if bottom clip
77
78         ldx     tgi_clip_y1,y           ; Low byte of Y1
79         cpx     _tgi_yres
80         sbc     _tgi_yres+1
81         bvs     L1
82         eor     #$80
83 L1:     bpl     L4
84         lda     #CLIP_TOP               ; Top clipping necessary
85         bne     L3
86 L2:     lda     #CLIP_BOTTOM
87 L3:     sta     tmp1                    ; Save temp outcode
88
89
90 ; Check X coordinate
91
92 L4:     lda     tgi_clip_x1+1,y         ; High byte of X1
93         bmi     L7                      ; Jump if left clip
94
95         ldx     tgi_clip_x1,y           ; Low byte of X1
96         cpx     _tgi_xres
97         sbc     _tgi_xres+1
98         bvs     L5
99         eor     #$80
100 L5:     bmi     L6
101
102 ; No right or left clipping necessary
103
104         lda     tmp1
105         rts
106
107 ; Need right clipping
108
109 L6:     lda     #CLIP_RIGHT
110         ora     tmp1
111         rts
112
113 ; Need left clipping
114
115 L7:     lda     #CLIP_LEFT
116         ora     tmp1
117         rts
118
119 .endproc
120
121
122 ;----------------------------------------------------------------------------
123 ; Calculate outcodes for both ends of the line
124 ;
125
126 .code
127 .proc   outcode1
128
129         ldy     #0
130         jsr     outcode
131         sta     tgi_clip_o1
132         rts
133
134 .endproc
135
136 .code
137 .proc   outcode2
138
139         ldy     #(tgi_clip_y2 - tgi_clip_y1)
140         jsr     outcode
141         sta     tgi_clip_o2
142         rts
143
144 .endproc
145
146
147 ;----------------------------------------------------------------------------
148 ; Negate tgi_clip_dxy
149 ;
150
151 .code
152 .proc   negate
153
154         lda     tgi_clip_dx,y
155         eor     #$FF
156         clc
157         adc     #1
158         sta     tgi_clip_dx,y
159         lda     tgi_clip_dx+1,y
160         eor     #$FF
161         adc     #$00
162         sta     tgi_clip_dx+1,y
163         rts
164
165 .endproc
166
167
168 ;----------------------------------------------------------------------------
169 ; Calculate the absolute values of dx and dy and store the combined sign in
170 ; tgi_clip_sign
171 ;
172
173 .code
174 .proc   calcdeltas
175
176         lda     tgi_clip_x2
177         sec
178         sbc     tgi_clip_x1
179         sta     tgi_clip_dx
180         lda     tgi_clip_x2+1
181         sbc     tgi_clip_x1+1
182         sta     tgi_clip_dx+1
183         sta     tgi_clip_sign
184         bpl     @L1
185         ldy     #0
186         jsr     negate
187
188 @L1:    lda     tgi_clip_y2
189         sec
190         sbc     tgi_clip_y1
191         sta     tgi_clip_dy
192         lda     tgi_clip_y2+1
193         sbc     tgi_clip_y1+1
194         sta     tgi_clip_dy+1
195
196         eor     tgi_clip_sign
197         sta     tgi_clip_sign
198
199         bit     tgi_clip_dy+1
200         bpl     @L9
201
202         ldy     #(tgi_clip_dy - tgi_clip_dx)
203         jmp     negate
204
205 @L9:    rts
206
207 .endproc
208
209
210 ;----------------------------------------------------------------------------
211 ; Helper routine. Generate the absolute value of y/a and calculate the sign
212 ; of the final result
213 ;
214
215 .code
216 .proc   prepare_coord
217
218         tax                             ; Remember high byte
219         eor     tgi_clip_sign
220         sta     tmp1                    ; Sign of result
221         tya
222         cpx     #0                      ; Check sign
223         bpl     @L1
224         jsr     negax
225 @L1:    sta     ptr1
226         stx     ptr1+1
227         rts
228
229 .endproc
230
231
232 ;----------------------------------------------------------------------------
233 ; Helper routine. Move the value in eax to ptr1:ptr2
234 ;
235
236 .code
237 .proc   move_intermediate_result
238
239         sta     ptr1
240         stx     ptr1+1
241         ldy     sreg
242         sty     ptr2
243         ldy     sreg+1
244         sty     ptr2+1
245         rts
246
247 .endproc
248
249
250 ;----------------------------------------------------------------------------
251 ; Multiplicate value in y/a by dy, then divide by dx.
252 ;
253
254 .code
255 .proc   muldiv_dydx
256
257 ; Generate the absolute value of y/a and calculate the sign of the final
258 ; result
259                       
260         jsr     prepare_coord
261
262 ; All values are positive now (dx/dy have been made positive in calcdeltas)
263 ; and the sign of the final result is on tmp1, so we can use unsigned
264 ; operations and apply the final result later, after rounding.
265
266         lda     tgi_clip_dy
267         ldx     tgi_clip_dy+1           ; rhs
268         jsr     umul16x16r32            ; Multiplicate
269
270 ; Move the result of the multiplication into ptr1:ptr2
271
272         jsr     move_intermediate_result
273
274 ; Load divisor and divide
275
276         lda     tgi_clip_dx
277         ldx     tgi_clip_dx+1
278         jsr     udiv32by16r16
279
280 ; Check the sign of the final result and negate it if nessary
281
282 done:   bit     tmp1
283         jmi     negax
284         rts
285
286 .endproc
287
288
289
290 ;----------------------------------------------------------------------------
291 ; Multiplicate value in y/a by dx, then divide by dy.
292 ;
293
294 .code
295 .proc   muldiv_dxdy
296
297 ; Generate the absolute value of y/a and calculate the sign of the final
298 ; result
299
300         jsr     prepare_coord
301
302 ; All values are positive now (dx/dy have been made positive in calcdeltas)
303 ; and the sign of the final result is on tmp1, so we can use unsigned
304 ; operations and apply the final result later, after rounding.
305
306         lda     tgi_clip_dx
307         ldx     tgi_clip_dx+1           ; rhs
308         jsr     umul16x16r32            ; Multiplicate
309
310 ; Move the result of the multiplication into ptr1:ptr2
311
312         jsr     move_intermediate_result
313
314 ; Load divisor and divide
315
316         lda     tgi_clip_dy
317         ldx     tgi_clip_dy+1
318         jsr     udiv32by16r16
319
320 ; Check the sign of the final result and negate it if nessary
321
322         jmp     muldiv_dydx::done
323
324 .endproc
325
326
327
328 ;----------------------------------------------------------------------------
329 ; Clip a line using Cohen Sutherland
330 ;
331
332 .code
333 .proc   tgi_clippedline
334
335 ; Set a flag that we have no deltas calculated
336
337         lda     #0
338         sta     tgi_clip_d
339
340 ; Generate outcodes
341
342         jsr     outcode1
343         jsr     outcode2
344
345 ; if ((tgi_clip_o1 | tgi_clip_o2) == 0) {
346 ;     tgi_line (x1, y1, x2, y2);
347 ; }
348
349 Loop:   lda     tgi_clip_o1
350         ora     tgi_clip_o2
351         bne     L1
352
353 ; Copy the coordinates into ptr1-4 and draw the line
354
355         ldx     #7
356 L0:     lda     tgi_clip_x1,x
357         sta     ptr1,x
358         dex
359         bpl     L0
360         jmp     tgi_line
361
362 ; if ((tgi_clip_o1 & tgi_clip_o2) != 0) reject;
363
364 L1:     lda     tgi_clip_o1
365         and     tgi_clip_o2
366         beq     L2
367         rts                             ; Nothing to draw
368
369 ; We must clip. If we haven't already done so, calculate dx/dy.
370
371 L2:     lda     tgi_clip_d              ; Deltas alreay calculated?
372         bne     HaveDeltas              ; Jump if yes
373         inc     tgi_clip_d
374         jsr     calcdeltas
375
376 ; Check if X1/Y1 needs clipping
377
378 HaveDeltas:
379         lda     tgi_clip_o1
380         jeq     L10
381
382 ; Need to clip X1/Y1
383
384         lsr     a                       ; Check for CLIP_LEFT
385         bcc     L3
386
387 ; tgi_clip_y1 += (0 - tgi_clip_x1) * tgi_clip_dy / tgi_clip_dx;
388 ; tgi_clip_x1 = 0;
389
390         lda     #$00
391         tax
392         beq     L4
393
394 L3:     lsr     a                       ; Check for CLIP_RIGHT
395         bcc     L5
396
397 ; tgi_clip_y1 += (tgi_xmax - tgi_clip_x1) * tgi_clip_dy / tgi_clip_dx;
398 ; tgi_clip_x1 = tgi_xmax;
399
400         lda     _tgi_xmax
401         ldx     _tgi_xmax+1
402
403 L4:     tay
404         sec
405         sbc     tgi_clip_x1
406         sty     tgi_clip_x1
407         tay
408         txa
409         sbc     tgi_clip_x1+1
410         stx     tgi_clip_x1+1
411
412         jsr     muldiv_dydx
413
414         clc
415         adc     tgi_clip_y1
416         sta     tgi_clip_y1
417         txa
418         adc     tgi_clip_y1+1
419         sta     tgi_clip_y1+1
420
421 ;
422
423         lda     tgi_clip_o1
424         lsr     a
425         lsr     a
426 L5:     lsr     a                               ; Check for CLIP_BOTTOM
427         bcc     L6
428
429 ; tgi_clip_x1 = (0 - tgi_clip_y1) * tgi_clip_dx / tgi_clip_dy;
430 ; tgi_clip_y1 = 0;
431
432         lda     #$00
433         tax
434         beq     L7
435
436 L6:     lsr     a                               ; Check for CLIP_TOP
437         bcc     L8
438
439 ; tgi_clip_x1 += (tgi_ymax - tgi_clip_y1) * tgi_clip_dx / tgi_clip_dy;
440 ; tgi_clip_y1 = ymax;
441
442         lda     _tgi_ymax
443         ldx     _tgi_ymax+1
444
445 L7:     tay
446         sec
447         sbc     tgi_clip_y1
448         sty     tgi_clip_y1
449         tay
450         txa
451         sbc     tgi_clip_y1+1
452         stx     tgi_clip_y1+1
453
454         jsr     muldiv_dxdy
455
456         clc
457         adc     tgi_clip_x1
458         sta     tgi_clip_x1
459         txa
460         adc     tgi_clip_x1+1
461         sta     tgi_clip_x1+1
462
463 ; We need to recalculate outcode1 in this case
464
465 L8:     jsr     outcode1
466
467 ; Check if X2/Y2 needs clipping
468
469 L10:    lda     tgi_clip_o2
470         jeq     Loop
471
472 ; Need to clip X2/Y2
473
474         lsr     a                       ; Check for CLIP_LEFT
475         bcc     L11
476
477 ; tgi_clip_y2 += (0 - tgi_clip_x2) * tgi_clip_dy / tgi_clip_dx;
478 ; tgi_clip_x2 = 0;
479
480         lda     #$00
481         tax
482         beq     L12
483
484 L11:    lsr     a                       ; Check for CLIP_RIGHT
485         bcc     L13
486
487 ; tgi_clip_y2 += (tgi_xmax - tgi_clip_x2) * tgi_clip_dy / tgi_clip_dx;
488 ; tgi_clip_x2 = tgi_xmax;
489
490         lda     _tgi_xmax
491         ldx     _tgi_xmax+1
492
493 L12:    tay
494         sec
495         sbc     tgi_clip_x2
496         sty     tgi_clip_x2
497         tay
498         txa
499         sbc     tgi_clip_x2+1
500         stx     tgi_clip_x2+1
501
502         jsr     muldiv_dydx
503
504         clc
505         adc     tgi_clip_y2
506         sta     tgi_clip_y2
507         txa
508         adc     tgi_clip_y2+1
509         sta     tgi_clip_y2+1
510
511 ;
512
513         lda     tgi_clip_o2
514         lsr     a
515         lsr     a
516 L13:    lsr     a                       ; Check for CLIP_BOTTOM
517         bcc     L14
518
519 ; tgi_clip_x2 += (0 - tgi_clip_y2) * tgi_clip_dx / tgi_clip_dy;
520 ; tgi_clip_y2 = 0;
521
522         lda     #$00
523         tax
524         beq     L15
525
526 L14:    lsr     a                               ; Check for CLIP_TOP
527         bcc     L16
528
529 ; tgi_clip_x2 += (tgi_ymax - tgi_clip_y2) * tgi_clip_dx / tgi_clip_dy;
530 ; tgi_clip_y2 = tgi_ymax;
531
532         lda     _tgi_ymax
533         ldx     _tgi_ymax+1
534
535 L15:    tay
536         sec
537         sbc     tgi_clip_y2
538         sty     tgi_clip_y2
539         tay
540         txa
541         sbc     tgi_clip_y2+1
542         stx     tgi_clip_y2+1
543
544         jsr     muldiv_dxdy
545
546         clc
547         adc     tgi_clip_x2
548         sta     tgi_clip_x2
549         txa
550         adc     tgi_clip_x2+1
551         sta     tgi_clip_x2+1
552
553 ; We need to recalculate outcode2 in this case
554
555 L16:    jsr     outcode2
556
557 ; Try again
558
559         jmp     Loop
560
561 .endproc
562
563
564
565