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