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