From: cuz Date: Sat, 8 Sep 2001 15:24:54 +0000 (+0000) Subject: Added mouse module from C64 X-Git-Tag: V2.12.0~2709 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=e401636c28265a53e638ced6fe85ca8d07fb5f43;p=cc65 Added mouse module from C64 git-svn-id: svn://svn.cc65.org/cc65/trunk@870 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/libsrc/c128/Makefile b/libsrc/c128/Makefile index f54fd107d..05559bb3f 100644 --- a/libsrc/c128/Makefile +++ b/libsrc/c128/Makefile @@ -20,7 +20,8 @@ OBJS = _scrsize.o \ color.o \ cputc.o \ kbhit.o \ - readjoy.o + mouse.o \ + readjoy.o all: $(OBJS) diff --git a/libsrc/c128/mouse.s b/libsrc/c128/mouse.s new file mode 100644 index 000000000..921461bae --- /dev/null +++ b/libsrc/c128/mouse.s @@ -0,0 +1,461 @@ +; +; Ullrich von Bassewitz, 24.04.1999 +; +; Routines for the 1351 proportional mouse. Parts of the code are from +; the Commodore 1351 mouse users guide. +; + + .export _mouse_init, _mouse_done + .export _mouse_hide, _mouse_show + .export _mouse_box, _mouse_info + .export _mouse_move, _mouse_pos + .export _mouse_buttons, _mouse_info + + .import _readjoy + .import popa, popsreg, addysp1 + .importzp ptr1, sp, sreg + + .include "c128.inc" + + .macpack generic + +.code + +; -------------------------------------------------------------------------- +; +; unsigned char __fastcall__ mouse_init (unsigned char port, +; unsigned char sprite, +; unsigned char type); +; + +_mouse_init: + jsr popa ; Ignore the type, get sprite param + tax ; Save sprite number + jsr popa ; Get the port number + + ldy OldIRQ+1 ; Already initialized? + bne AlreadyInitialized ; Jump if yes + + stx MouseSprite ; Remember the sprite number + sta MousePort ; Remember the port number + +; Initialize variables + + ldx #0 + stx XPos + stx XPos+1 + stx YPos + stx YPos+1 + stx OldPotX + stx OldPotY + stx XMin + stx XMin+1 ; XMin = 0 + lda #29 + sta YMin + stx YMin+1 ; YMin = 29 + lda #250 + sta YMax + stx YMax+1 ; YMax = 250 + inx ; X = 1 + stx Visible ; Mouse *not* visible + lda #<344 + sta XMax + stx XMax+1 ; XMax = 344 + +; Remember the old IRQ vector + + lda IRQVec + sta OldIRQ + lda IRQVec+1 + sta OldIRQ+1 + +; Set our own IRQ vector. We cheat here to save a few bytes of code: +; The function is expected to return a value not equal to zero on success, +; and since we know that the high byte of the IRQ handler address is never +; zweo, we will return just this byte. + + ldx #MouseIRQ + bne SetIRQ ; Branch always + +AlreadyInitialized: + lda #0 ; Error + rts + +; -------------------------------------------------------------------------- +; +; void mouse_done (void); +; + +_mouse_done: + ldx OldIRQ ; Initialized? + lda OldIRQ+1 + beq Done ; Jump if no + ldy #0 + sty OldIRQ+1 ; Reset the initialized flag +SetIRQ: sei ; Disable interrupts + stx IRQVec ; Set the new/old vector + sta IRQVec+1 + cli ; Enable interrupts +Done: rts + +; -------------------------------------------------------------------------- +; +; void mouse_hide (void); +; + +_mouse_hide: + lda Visible ; Get the flag + bne @L1 ; Jump if already invisible + ldx MouseSprite ; Sprite defined? + beq @L1 ; Jump if no + + lda NotMask-1,x ; Get clean mask + + sei ; Disable interrupts + and VIC_SPR_ENA + sta VIC_SPR_ENA ; Disable sprite + cli ; Enable interrupts + +@L1: inc Visible ; Set the flag to invisible + rts + +; -------------------------------------------------------------------------- +; +; void mouse_show (void); +; + +_mouse_show: + lda Visible ; Mouse already visible? + beq @L1 ; Jump if yes + dec Visible ; Get the flag + bne @L1 ; Jump if still invisible + ldx MouseSprite ; Sprite defined? + beq @L1 ; Jump if no + + sei ; Disable interrupts + jsr MoveSprite1 ; Move the sprite to it's position + + ldx MouseSprite ; Get sprite number (again) + lda BitMask-1,x ; Get bit mask + ora VIC_SPR_ENA + sta VIC_SPR_ENA ; Enable sprite + + cli ; Enable interrupts + +@L1: rts + +; -------------------------------------------------------------------------- +; +; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy); +; + +_mouse_box: + ldy #0 ; Stack offset + + sei ; Disable interrupts + + sta YMax + stx YMax+1 ; maxy + + lda (sp),y + sta XMax + iny + lda (sp),y + sta XMax+1 ; maxx + + iny + lda (sp),y + sta YMin + iny + lda (sp),y + sta YMin+1 ; miny + + iny + lda (sp),y + sta XMin + iny + lda (sp),y + sta XMin+1 ; minx + + cli ; Enable interrupts + + jmp addysp1 ; Drop params, return + +; -------------------------------------------------------------------------- +; +; void __fastcall__ mouse_pos (struct mouse_pos* pos); +; /* Return the current mouse position */ +; + +_mouse_pos: + sta ptr1 + stx ptr1+1 ; Remember the argument pointer + + ldy #0 ; Structure offset + + sei ; Disable interrupts + + lda XPos ; Transfer the position + sta (ptr1),y + lda XPos+1 + iny + sta (ptr1),y + lda YPos + iny + sta (ptr1),y + lda YPos + iny + sta (ptr1),y + + cli ; Restore initial interrupt state + + rts ; Done + +; -------------------------------------------------------------------------- +; +; void __fastcall__ mouse_info (struct mouse_info* info); +; /* Return the state of the mouse buttons and the position of the mouse */ +; + +_mouse_info: + +; We're cheating here to keep the code smaller: The first fields of the +; mouse_info struct are identical to the mouse_pos struct, so we will just +; call _mouse_pos to initialize the struct pointer and fill the position +; fields. + + jsr _mouse_pos + +; Fill in the button state + + jsr _mouse_buttons ; Will not touch ptr1 + ldy #4 + sta (ptr1),y + + rts + +; -------------------------------------------------------------------------- +; +; void __fastcall__ mouse_move (int x, int y); +; + +_mouse_move: + jsr popsreg ; Get X + sei ; Disable interrupts + + sta YPos + stx YPos+1 + lda sreg + ldx sreg+1 + sta XPos + stx XPos+1 ; Set new position + + jsr MoveSprite ; Move the sprite to the mouse pos + +@L9: cli ; Enable interrupts + rts + + +; -------------------------------------------------------------------------- +; +; unsigned char mouse_buttons (void); +; + +_mouse_buttons: + lda MousePort ; Get the port + jmp _readjoy ; Same as joystick + +; -------------------------------------------------------------------------- +; +; Mouse interrupt handler +; + +MouseIRQ: + cld + lda SID_ADConv1 ; Get mouse X movement + ldy OldPotX + jsr MoveCheck ; Calculate movement vector + sty OldPotX + +; Calculate the new X coordinate (--> a/y) + + add XPos + tay ; Remember low byte + txa + adc XPos+1 + tax + +; Limit the X coordinate to the bounding box + + cpy XMin + sbc XMin+1 + bpl @L1 + ldy XMin + ldx XMin+1 + jmp @L2 +@L1: txa + + cpy XMax + sbc XMax+1 + bmi @L2 + ldy XMax + ldx XMax+1 +@L2: sty XPos + stx XPos+1 + +; Calculate the Y movement vector + + lda SID_ADConv2 ; Get mouse Y movement + ldy OldPotY + jsr MoveCheck ; Calculate movement + sty OldPotY + +; Calculate the new Y coordinate (--> a/y) + + sta OldValue + lda YPos + sub OldValue + tay + stx OldValue + lda YPos+1 + sbc OldValue + tax + + cpy YMin + sbc YMin+1 + bpl @L3 + ldy YMin + ldx YMin+1 + jmp @L4 +@L3: txa + + cpy YMax + sbc YMax+1 + bmi @L4 + ldy YMax + ldx YMax+1 +@L4: sty YPos + stx YPos+1 + +; Move the mouse sprite if it is enabled + + jsr MoveSprite ; Move the sprite + +; Jump to the next IRQ handler + + jmp (OldIRQ) + + +; -------------------------------------------------------------------------- +; +; Move check routine, called for both coordinates. +; +; Entry: y = old value of pot register +; a = current value of pot register +; Exit: y = value to use for old value +; x/a = delta value for position +; + +MoveCheck: + sty OldValue + sta NewValue + ldx #$00 + + sub OldValue ; a = mod64 (new - old) + and #%01111111 + cmp #%01000000 ; if (a > 0) + bcs @L1 ; + lsr a ; a /= 2; + beq @L2 ; if (a != 0) + ldy NewValue ; y = NewValue + rts ; return + +@L1: ora #%11000000 ; else or in high order bits + cmp #$FF ; if (a != -1) + beq @L2 + sec + ror a ; a /= 2 + dex ; high byte = -1 (X = $FF) + ldy NewValue + rts + +@L2: txa ; A = $00 + rts + +; -------------------------------------------------------------------------- +; +; Move the mouse sprite to the current mouse position. Must be called +; with interrupts off. MoveSprite1 is an entry without checking and +; loading X +; + +MoveSprite: + + lda Visible ; Mouse visible? + bne MoveSpriteDone ; Jump if no + ldx MouseSprite ; Sprite defined? + beq MoveSpriteDone ; Jump if no + +; Set the high X bit + +MoveSprite1: + lda VIC_SPR_HI_X ; Get high X bits of all sprites + and NotMask-1,x ; Mask out sprite bit + ldy XPos+1 ; Test Y position + beq @L1 + ora BitMask-1,x ; Set high X bit +@L1: sta VIC_SPR_HI_X ; Set hi X sprite values + +; Set the low X byte + + txa + asl a ; Index*2 + tax + lda XPos + sta VIC_SPR0_X-2,x ; Set low byte + +; Set the Y position + + ldy YPos+1 ; Negative or too large? + bne MoveSpriteDone ; Jump if yes + lda YPos + sta VIC_SPR0_Y-2,x ; Set Y position + +; Done + +MoveSpriteDone: + rts + +; -------------------------------------------------------------------------- +; Data + +.bss + +OldIRQ: .res 2 ; Old IRQ vector +MousePort: .res 1 ; Port used for the mouse +MouseSprite: .res 1 ; Number of sprite to control +OldValue: .res 1 ; Temp for MoveCheck routine +NewValue: .res 1 ; Temp for MoveCheck routine + +Visible: .res 1 ; Is the mouse visible? +OldPotX: .res 1 ; Old hw counter values +OldPotY: .res 1 + +XPos: .res 2 ; Current mouse position, X +YPos: .res 2 ; Current mouse position, Y + +XMin: .res 2 ; X1 value of bounding box +YMin: .res 2 ; Y1 value of bounding box +XMax: .res 2 ; X2 value of bounding box +YMax: .res 2 ; Y2 value of bounding box + +.data + +BitMask: .byte $01, $02, $04, $08, $10, $20, $40, $80 +NotMask: .byte $FE, $FD, $FB, $F7, $EF, $DF, $BF, $7F + + + + +