]> git.sur5r.net Git - cc65/blob - libsrc/c128/mouse.s
removed objects shared with common conio
[cc65] / libsrc / c128 / mouse.s
1 ;
2 ; Ullrich von Bassewitz, 24.04.1999
3 ;
4 ; Routines for the 1351 proportional mouse. Parts of the code are from
5 ; the Commodore 1351 mouse users guide.
6 ;
7
8         .export         _mouse_init, _mouse_done
9         .export         _mouse_hide, _mouse_show
10         .export         _mouse_box, _mouse_info
11         .export         _mouse_move, _mouse_pos
12         .export         _mouse_buttons, _mouse_info
13         .condes         MouseIRQ, 2
14
15         .import         popax, addysp1
16         .importzp       ptr1, sp
17
18         .include        "c128.inc"
19
20         .macpack        generic
21
22
23 .code
24
25 ; --------------------------------------------------------------------------
26 ;
27 ; Constants
28 ;
29
30 SPRITE_HEIGHT   = 21
31 SPRITE_WIDTH    = 24
32 SCREEN_HEIGHT   = 200
33 SCREEN_WIDTH    = 320
34 XCORR           = SPRITE_WIDTH
35
36 ; --------------------------------------------------------------------------
37 ;
38 ; unsigned char __fastcall__ mouse_init (unsigned char type);
39 ;
40
41 .proc   _mouse_init
42         lda     Initialized             ; Already initialized?
43         bne     AlreadyInitialized      ; Jump if yes
44
45 ; Initialize variables
46
47         ldx     #0
48         lda     #XCORR
49         sta     XPos
50         stx     XPos+1
51         stx     YPos
52         stx     YPos+1
53         stx     OldPotX
54         stx     OldPotY
55         stx     XMin
56         stx     XMin+1                  ; XMin = 0
57         lda     #50                     ; ## FIXME: This is the PAL value
58         sta     YCorr
59         sta     YPos
60         stx     YPos+1
61         sec
62         sbc     #SPRITE_HEIGHT          ; Sprite height in pixels
63         sta     YMin
64         stx     YMin+1                  ; YMin = 29
65         lda     #SCREEN_HEIGHT          ; Vertical screen res
66         add     YCorr                   ; Add correction factor
67         sta     YMax
68         stx     YMax+1
69         inx                             ; X = 1
70         stx     Invisible               ; Mouse *not* visible
71         lda     #<(SCREEN_WIDTH + SPRITE_WIDTH)
72         sta     XMax
73         stx     XMax+1                  ; XMax = 320 + sprite width
74
75 ; Save the old init status and reset bit 0. This will disable the BASIC
76 ; IRQ handler which will otherwise try to manage the mouse sprite on its
77 ; own
78
79         lda     INIT_STATUS
80         sta     OldInitStatus
81         and     #$FE
82         sta     INIT_STATUS
83
84 ; Mouse successfully initialized
85
86         lda     #1
87         sta     Initialized
88         rts
89
90 AlreadyInitialized:
91         lda     #0                      ; Error
92         rts
93
94 .endproc
95
96 ; --------------------------------------------------------------------------
97 ;
98 ; void mouse_done (void);
99 ;
100
101 _mouse_done:
102         lda     Initialized             ; Initialized?
103         beq     mddone                  ; Jump if no
104         lda     #0
105         sta     Initialized             ; Reset the initialized flag
106         lda     OldInitStatus           ; Load the old BASIC int bit
107         and     #$01                    ; Mask it
108         ora     INIT_STATUS             ; Restore the old state
109         sta     INIT_STATUS
110
111 ; Disable the mouse sprite
112
113 DisableSprite:
114         lda     #$FE                    ; Clear bit for sprite #0
115         sei                             ; Disable interrupts
116         and     VIC_SPR_ENA
117         sta     VIC_SPR_ENA             ; Disable sprite
118         cli                             ; Enable interrupts
119 mddone: rts
120
121
122 ; --------------------------------------------------------------------------
123 ;
124 ; void mouse_hide (void);
125 ;
126
127 .proc   _mouse_hide
128
129         lda     Invisible               ; Get the flag
130         bne     @L1                     ; Jump if already invisible
131         jsr     DisableSprite           ; Disable the mouse sprite
132 @L1:    inc     Invisible               ; Set the flag to invisible
133         rts
134
135 .endproc
136
137 ; --------------------------------------------------------------------------
138 ;
139 ; void mouse_show (void);
140 ;
141
142 .proc   _mouse_show
143
144         lda     Invisible               ; Mouse invisible?
145         beq     @L1                     ; Jump if no
146         dec     Invisible               ; Set the flag
147         bne     @L1                     ; Jump if still invisible
148
149         sei                             ; Disable interrupts
150         jsr     MoveSprite1             ; Move the sprite to it's position
151         lda     VIC_SPR_ENA             ; Get sprite enable register
152         ora     #$01                    ; Enable sprite #0
153         sta     VIC_SPR_ENA             ; Write back
154         cli                             ; Enable interrupts
155
156 @L1:    rts
157
158 .endproc
159
160 ; --------------------------------------------------------------------------
161 ;
162 ; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
163 ;
164
165 .proc   _mouse_box
166
167         ldy     #0                      ; Stack offset
168
169         add     YCorr                   ; Adjust the Y value
170         bcc     @L1
171         inx
172         clc
173 @L1:    sei                             ; Disable interrupts
174
175         sta     YMax
176         stx     YMax+1                  ; maxy
177
178         lda     (sp),y
179         adc     #XCORR
180         sta     XMax
181         iny
182         lda     (sp),y
183         adc     #$00
184         sta     XMax+1                  ; maxx
185
186         iny
187         lda     (sp),y
188         add     YCorr
189         sta     YMin
190         iny
191         lda     (sp),y
192         adc     #$00
193         sta     YMin+1                  ; miny
194
195         iny
196         lda     (sp),y
197         add     #XCORR
198         sta     XMin
199         iny
200         lda     (sp),y
201         adc     #$00
202         sta     XMin+1                  ; minx
203
204         cli                             ; Enable interrupts
205
206         jmp     addysp1                 ; Drop params, return
207
208 .endproc
209
210 ; --------------------------------------------------------------------------
211 ;
212 ; void __fastcall__ mouse_pos (struct mouse_pos* pos);
213 ; /* Return the current mouse position */
214 ;
215
216 .proc   _mouse_pos
217
218         sta     ptr1
219         stx     ptr1+1                  ; Remember the argument pointer
220
221         ldy     #0                      ; Structure offset
222         sec                             ; Needed for the SBC later
223
224         sei                             ; Disable interrupts
225         lda     XPos                    ; Transfer the position
226         sbc     #XCORR
227         sta     (ptr1),y
228         lda     XPos+1
229         sbc     #$00
230         iny
231         sta     (ptr1),y
232         lda     YPos
233         ldx     YPos+1
234         cli                             ; Restore initial interrupt state
235
236         sub     YCorr                   ; Apply the Y correction value
237         bcs     @L1
238         dex
239 @L1:    iny
240         sta     (ptr1),y                ; Store YPos
241         txa
242         iny
243         sta     (ptr1),y
244
245         rts                             ; Done
246
247 .endproc
248
249 ; --------------------------------------------------------------------------
250 ;
251 ; void __fastcall__ mouse_info (struct mouse_info* info);
252 ; /* Return the state of the mouse buttons and the position of the mouse */
253 ;
254
255 .proc   _mouse_info
256
257 ; We're cheating here to keep the code smaller: The first fields of the
258 ; mouse_info struct are identical to the mouse_pos struct, so we will just
259 ; call _mouse_pos to initialize the struct pointer and fill the position
260 ; fields.
261
262         jsr     _mouse_pos
263
264 ; Fill in the button state
265
266         jsr     _mouse_buttons          ; Will not touch ptr1
267         ldy     #4
268         sta     (ptr1),y
269
270         rts
271
272 .endproc
273
274 ; --------------------------------------------------------------------------
275 ;
276 ; void __fastcall__ mouse_move (int x, int y);
277 ;
278
279 .proc   _mouse_move
280
281         add     YCorr                   ; Add Y coordinate correction
282         bcc     @L1
283         inx
284         clc
285 @L1:    sei
286         sta     YPos
287         stx     YPos+1
288         cli
289
290         jsr     popax                   ; Get X
291         adc     #XCORR                  ; Adjust X coordinate
292         bcc     @L2
293         inx
294 @L2:    sei
295         sta     XPos
296         stx     XPos+1                  ; Set new position
297         jsr     MoveSprite              ; Move the sprite to the mouse pos
298         cli                             ; Enable interrupts
299
300         rts
301
302 .endproc
303
304 ; --------------------------------------------------------------------------
305 ;
306 ; unsigned char mouse_buttons (void);
307 ;
308
309 .proc   _mouse_buttons
310
311         lda     #$7F
312         sei
313         sta     CIA1_PRA
314         lda     CIA1_PRB                ; Read joystick #0
315         cli
316         ldx     #0
317         and     #$1F
318         eor     #$1F
319         rts
320
321 .endproc
322
323 ; --------------------------------------------------------------------------
324 ;
325 ; Mouse interrupt handler
326 ;
327
328 IRQDone:rts
329
330 MouseIRQ:
331
332         lda     Initialized             ; Mouse initialized?
333         beq     IRQDone                 ; Jump if no
334         lda     SID_ADConv1             ; Get mouse X movement
335         ldy     OldPotX
336         jsr     MoveCheck               ; Calculate movement vector
337         sty     OldPotX
338
339 ; Calculate the new X coordinate (--> a/y)
340
341         add     XPos
342         tay                             ; Remember low byte
343         txa
344         adc     XPos+1
345         tax
346
347 ; Limit the X coordinate to the bounding box
348
349         cpy     XMin
350         sbc     XMin+1
351         bpl     @L1
352         ldy     XMin
353         ldx     XMin+1
354         jmp     @L2
355 @L1:    txa
356
357         cpy     XMax
358         sbc     XMax+1
359         bmi     @L2
360         ldy     XMax
361         ldx     XMax+1
362 @L2:    sty     XPos
363         stx     XPos+1
364
365 ; Calculate the Y movement vector
366
367         lda     SID_ADConv2             ; Get mouse Y movement
368         ldy     OldPotY
369         jsr     MoveCheck               ; Calculate movement
370         sty     OldPotY
371
372 ; Calculate the new Y coordinate (--> a/y)
373
374         sta     OldValue
375         lda     YPos
376         sub     OldValue
377         tay
378         stx     OldValue
379         lda     YPos+1
380         sbc     OldValue
381         tax
382
383         cpy     YMin
384         sbc     YMin+1
385         bpl     @L3
386         ldy     YMin
387         ldx     YMin+1
388         jmp     @L4
389 @L3:    txa
390
391         cpy     YMax
392         sbc     YMax+1
393         bmi     @L4
394         ldy     YMax
395         ldx     YMax+1
396 @L4:    sty     YPos
397         stx     YPos+1
398
399 ; Move the mouse sprite to the current mouse position. Must be called
400 ; with interrupts off. MoveSprite1 is an entry without checking.
401
402 MoveSprite:
403
404         lda     Invisible               ; Mouse visible?
405         bne     Done                    ; Jump if no
406
407 ; Set the high X bit
408
409 MoveSprite1:
410         lda     VIC_SPR_HI_X            ; Get high X bits of all sprites
411         and     #$FE                    ; Clear bit for sprite #0
412         ldy     XPos+1                  ; Test Y position
413         beq     @L5
414         ora     #$01                    ; Set high X bit
415 @L5:    sta     VIC_SPR_HI_X            ; Set hi X sprite values
416
417 ; Set the low X byte
418
419         lda     XPos
420         sta     VIC_SPR0_X              ; Set low byte
421
422 ; Set the Y position
423
424         ldy     YPos+1                  ; Negative or too large?
425         bne     Done                    ; Jump if yes
426         lda     YPos
427         sta     VIC_SPR0_Y              ; Set Y position
428
429 ; Done
430
431 Done:   rts
432
433 ; --------------------------------------------------------------------------
434 ;
435 ; Move check routine, called for both coordinates.
436 ;
437 ; Entry:        y = old value of pot register
438 ;               a = current value of pot register
439 ; Exit:         y = value to use for old value
440 ;               x/a = delta value for position
441 ;
442
443 .proc   MoveCheck
444
445         sty     OldValue
446         sta     NewValue
447         ldx     #$00
448
449         sub     OldValue                ; a = mod64 (new - old)
450         and     #%01111111
451         cmp     #%01000000              ; if (a > 0)
452         bcs     @L1                     ;
453         lsr     a                       ;   a /= 2;
454         beq     @L2                     ;   if (a != 0)
455         ldy     NewValue                ;     y = NewValue
456         rts                             ;   return
457
458 @L1:    ora     #%11000000              ; else or in high order bits
459         cmp     #$FF                    ; if (a != -1)
460         beq     @L2
461         sec
462         ror     a                       ;   a /= 2
463         dex                             ;   high byte = -1 (X = $FF)
464         ldy     NewValue
465         rts
466
467 @L2:    txa                             ; A = $00
468         rts
469
470 .endproc
471
472 ; --------------------------------------------------------------------------
473 ; Data
474
475 .bss
476
477 Initialized:    .res    1               ; True if mouse initialized
478 OldInitStatus:  .res    1               ; Old IRQ flag value
479 OldValue:       .res    1               ; Temp for MoveCheck routine
480 NewValue:       .res    1               ; Temp for MoveCheck routine
481 YCorr:          .res    1               ; Correction for Y coordinate
482
483 Invisible:      .res    1               ; Is the mouse invisible?
484 OldPotX:        .res    1               ; Old hw counter values
485 OldPotY:        .res    1
486
487 XPos:           .res    2               ; Current mouse position, X
488 YPos:           .res    2               ; Current mouse position, Y
489
490 XMin:           .res    2               ; X1 value of bounding box
491 YMin:           .res    2               ; Y1 value of bounding box
492 XMax:           .res    2               ; X2 value of bounding box
493 YMax:           .res    2               ; Y2 value of bounding box
494
495