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