diff --git a/include/ace/macros.h b/include/ace/macros.h index ef60c3b3..d4804131 100644 --- a/include/ace/macros.h +++ b/include/ace/macros.h @@ -25,6 +25,11 @@ #define MAX(x,y) ((x)>(y)? (x): (y)) #define CLAMP(x, min, max) ((x) < (min)? (min) : ((x) > (max) ? (max) : (x))) +/** + * Bit value macro - useful for setting & testing bits. + */ +#define BV(x) (1 << (x)) + /** * Checks if given x,y is in specified tRect. */ diff --git a/include/ace/managers/key.h b/include/ace/managers/key.h index 29795a97..cebf8c0f 100644 --- a/include/ace/managers/key.h +++ b/include/ace/managers/key.h @@ -3,13 +3,9 @@ #include #ifdef AMIGA -#include // IDCMP_RAWKEY etc +#include // struct Interrupt #endif // AMIGA -#include - -#include - /* ****************************************************************** DEFINES */ /** @@ -131,7 +127,7 @@ #define KEY_DEL 0x46 #define KEY_HELP 0x5F -// Key status flags +// Key state flags #define KEY_NACTIVE 0 #define KEY_USED 1 #define KEY_ACTIVE 2 @@ -140,6 +136,7 @@ /* ******************************************************************** TYPES */ typedef struct { + struct Interrupt *pInt; UBYTE pStates[103]; UBYTE ubLastKey; } tKeyManager; @@ -152,19 +149,63 @@ extern const UBYTE g_pToAscii[]; /* **************************************************************** FUNCTIONS */ -void keySetState( +/** + * Initializes mouse manager. + */ +void keyCreate(void); + +/** + * Cleans up after mouse manager. + */ +void keyDestroy(void); + +/** + * Processes key manager, updating keys' states. + * This function should be called once per frame. + */ +void keyProcess(void); + +/** + * Sets state of given key. + * @param ubKeyCode: Code of key, which state should be changed. + * @param ubKeyState: Key state (KEY_ACTIVE, KEY_NACTIVE or KEY_USED). + */ +static inline void keySetState( IN UBYTE ubKeyCode, IN UBYTE ubKeyState -); +) { + g_sKeyManager.pStates[ubKeyCode] = ubKeyState; + if(ubKeyState == KEY_ACTIVE) + g_sKeyManager.ubLastKey = ubKeyCode; +} -UBYTE keyCheck( +/** + * Polls state of key with given code. + * @param ubKeyCode: Code of key, which state should be polled. + * @return 1 if key is pressed, otherwise 0. + * @see keyUse() + */ +static inline UBYTE keyCheck( IN UBYTE ubKeyCode -); +) { + return g_sKeyManager.pStates[ubKeyCode] != KEY_NACTIVE; +} -UBYTE keyUse( +/** + * Checks if given key was recently pressed. + * If key's code is ACTIVE, fn returns 1 and changes key state to USED. + * @param ubKeyCode: Code of key, which state should be polled. + * @return 1 if key was recently pressed, otherwise 0. + * @see keyCheck() + */ +static inline UBYTE keyUse( IN UBYTE ubKeyCode -); - -void keyProcess(void); - -#endif \ No newline at end of file +) { + if (g_sKeyManager.pStates[ubKeyCode] == KEY_ACTIVE) { + g_sKeyManager.pStates[ubKeyCode] = KEY_USED; + return 1; + } + return 0; +} + +#endif diff --git a/include/ace/managers/mouse.h b/include/ace/managers/mouse.h index ecb58924..195c91a1 100644 --- a/include/ace/managers/mouse.h +++ b/include/ace/managers/mouse.h @@ -1,38 +1,41 @@ #ifndef GUARD_ACE_MANAGER_MOUSE_H #define GUARD_ACE_MANAGER_MOUSE_H -#ifdef AMIGA -#include // Amiga typedefs -#include // IDCMP_RAWKEY etc -#include -#include -#endif // AMIGA - #include +#include -#include - -/* Types */ -#ifdef AMIGA -#define MOUSE_LMB IECODE_LBUTTON -#define MOUSE_RMB IECODE_RBUTTON -#define MOUSE_MMB IECODE_MBUTTON -#else -#define MOUSE_LMB 1 -#define MOUSE_RMB 2 -#define MOUSE_MMB 4 -#endif // AMIGA +// Mouse button identifiers +#define MOUSE_LMB 0 +#define MOUSE_RMB 1 +#define MOUSE_MMB 2 +// Button state defines #define MOUSE_NACTIVE 0 #define MOUSE_USED 1 #define MOUSE_ACTIVE 2 -typedef struct { - UBYTE pStates[3]; +// Mouse ports +// #define MOUSE_PORT_0 0 // Unused mouse port for alignment +#define MOUSE_PORT_1 1 +#define MOUSE_PORT_2 2 + +/* Types */ +typedef struct _tMouse { + UWORD uwX; + UWORD uwY; + UBYTE pButtonStates[3]; + tUwAbsRect sBounds; ///< Min/max mouse position. #ifdef AMIGA - __chip UWORD pBlankCursor[6]; - struct MsgPort *pInputMP; - struct IOStdReq *pInputIO; + UBYTE ubPrevHwX; + UBYTE ubPrevHwY; +#endif +} tMouse; + +typedef struct _tMouseManager { + UBYTE ubPortFlags; + tMouse pMice[3]; ///< Zero is pad, faster than subtracting from port code. +#ifdef AMIGA + UWORD uwPrevPotGo; ///< Previous control port config. #endif // AMIGA } tMouseManager; @@ -40,62 +43,193 @@ typedef struct { extern tMouseManager g_sMouseManager; /* Functions */ -void mouseOpen(void); -void mouseSetState( - IN UBYTE ubMouseCode, - IN UBYTE ubMouseState +/** + * Initializes mouse management for given ports. + * @param ubPortFlags: Ports in which mouse should be processed. + * OR combination of MOUSE_PORT_* defines. + * @see mouseDestroy() + * @see mouseProcess() + */ +void mouseCreate( + IN UBYTE ubPortFlags ); -UBYTE mouseCheck( - IN UBYTE ubMouseCode -); +/** + * Cleans up after mouse maanger. + * @see mouseCreate() + */ +void mouseDestroy(void); -UBYTE mouseUse( - IN UBYTE ubMouseCode -); +/** + * Processes mouse manager, updating mice's position and button states. + * Should be called once per frame. + */ +void mouseProcess(void); -UBYTE mouseIsIntersects( - IN UWORD uwX, - IN UWORD uwY, - IN UWORD uwWidth, - IN UWORD uwHeight -); +/** + * Set on-screen constraints for cursor. + * @param ubMousePort: Mouse port to be constrained. + * @param uwLoX: Minimum cursor X position. + * @param uwLoX: Minimum cursor Y position. + * @param uwHiY: Maximum cursor X position. + * @param uwHiY: Maximum cursor Y position. + */ +static inline void mouseSetBounds( + IN UBYTE ubMousePort, + IN UWORD uwLoX, + IN UWORD uwLoY, + IN UWORD uwHiX, + IN UWORD uwHiY +) { + g_sMouseManager.pMice[ubMousePort].sBounds.uwX1 = uwLoX; + g_sMouseManager.pMice[ubMousePort].sBounds.uwY1 = uwLoY; + g_sMouseManager.pMice[ubMousePort].sBounds.uwX2 = uwHiX; + g_sMouseManager.pMice[ubMousePort].sBounds.uwY2 = uwHiY; +} -UWORD mouseGetX(void); -UWORD mouseGetY(void); +/** + * Returns given mouse's current X position. + * @param ubMousePort: Mouse to be polled. Use one of MOUSE_PORT_* values. + * @return Mouse's current X position relative to top-left screen pos. + */ +static inline UWORD mouseGetX( + IN UBYTE ubMousePort +) { + return g_sMouseManager.pMice[ubMousePort].uwX; +} -void mouseSetPointer( - IN UWORD *pCursor, - IN WORD wHeight, - IN WORD wWidth, - IN WORD wOffsetX, - IN WORD wOffsetY -); +/** + * Returns given mouse's current Y position. + * @param ubMousePort: Mouse to be polled. Use one of MOUSE_PORT_* values. + * @return Mouse's current X position relative to top-left screen pos. + */ +static inline UWORD mouseGetY( + IN UBYTE ubMousePort +) { + return g_sMouseManager.pMice[ubMousePort].uwY; +} + +/** + * Sets given mouse's button to desired state. + * @param ubMousePort: Mouse to be set. + * @param ubMouseCode: Mouse button, which state should be changed + * (MOUSE_LMB, MOUSE_RMB or MOUSE_MMB). + * @param ubMouseState: New button state + * (MOUSE_NACTIVE, MOUSE_USED, MOUSE_ACTIVE). + */ +static inline void mouseSetButton( + IN UBYTE ubMousePort, + IN UBYTE ubMouseCode, + IN UBYTE ubMouseState +) { + g_sMouseManager.pMice[ubMousePort].pButtonStates[ubMouseCode] = ubMouseState; +} -void mouseResetPointer(void); +/** + * Returns given mouse's button state. + * @param ubMousePort: Mouse to be polled. + * @param ubMouseCode: Button to be polled (MOUSE_LMB, MOUSE_RMB or MOUSE_MMB). + * @return 1 if button is pressed, otherwise 0. + */ +static inline UBYTE mouseCheck( + IN UBYTE ubMousePort, + IN UBYTE ubMouseCode +) { + UBYTE ubBtn = g_sMouseManager.pMice[ubMousePort].pButtonStates[ubMouseCode]; + return ubBtn != MOUSE_NACTIVE; +} + +/** + * Returns whether given button was recently pressed. + * If button was polled as ACTIVE, function returns 1 and sets button as USED. + * @param ubMousePort: Mouse to be polled. + * @param ubMouseCode: Button to be polled (MOUSE_LMB, MOUSE_RMB or MOUSE_MMB). + * @return 1 if button was recently pressed, otherwise 0. + */ +static inline UBYTE mouseUse( + IN UBYTE ubMousePort, + IN UBYTE ubMouseCode +) { + tMouse *pMouse = &g_sMouseManager.pMice[ubMousePort]; + if(pMouse->pButtonStates[ubMouseCode] == MOUSE_ACTIVE) { + pMouse->pButtonStates[ubMouseCode] = MOUSE_USED; + return 1; + } + return 0; +} + +/** + * Checks if given mouse has position contained within given rectangle. + * @param ubMousePort: Mouse to be polled. + * @param sRect: Rectangle to be checked. + * @return 1 if mouse position is within given rectangle, otherwise 0. + */ +static inline UBYTE mouseInRect( + IN UBYTE ubMousePort, + IN tUwRect sRect +) { + UWORD uwMouseX = g_sMouseManager.pMice[ubMousePort].uwX; + UWORD uwMouseY = g_sMouseManager.pMice[ubMousePort].uwY; + return ( + (sRect.uwX <= uwMouseX) && (uwMouseX < sRect.uwX + sRect.uwWidth) && + (sRect.uwY <= uwMouseY) && (uwMouseY < sRect.uwY + sRect.uwHeight) + ); +} /** * Sets mouse position to given absolute position. + * This function takes into account bounds specified by mouseSetBounds(). + * @param ubMousePort: Mouse of which position should be changed. + * @param uwNewX: new X position. + * @param uwNewY: new Y position. + * @see mouseSetBounds() + * @see mouseMoveBy() */ -void mouseSetPosition( +static inline void mouseSetPosition( + IN UBYTE ubMousePort, IN UWORD uwNewX, IN UWORD uwNewY -); +) { + tMouse *pMouse = &g_sMouseManager.pMice[ubMousePort]; + pMouse->uwX = CLAMP(uwNewX, pMouse->sBounds.uwX1, pMouse->sBounds.uwX2); + pMouse->uwY = CLAMP(uwNewY, pMouse->sBounds.uwY1, pMouse->sBounds.uwY2); +} /** * Moves mouse pointer from current position by relative offsets. + * This function takes into account bounds specified by mouseSetBounds(). + * @param ubMousePort: Mouse of which position should be changed. + * @param wDx: Positive value moves mouse right, negative moves left. + * @param wDy: Positive value moves mouse down, negative moves left. + * @see mouseSetBounds() + * @see mouseSetPosition() */ -void mouseMoveBy( +static inline void mouseMoveBy( + IN UBYTE ubMousePort, IN WORD wDx, IN WORD wDy -); - -void mouseClick( - IN UBYTE ubMouseCode -); +) { + tMouse *pMouse = &g_sMouseManager.pMice[ubMousePort]; + pMouse->uwX = CLAMP( + pMouse->uwX + wDx, pMouse->sBounds.uwX1, pMouse->sBounds.uwX2 + ); + pMouse->uwY = CLAMP( + pMouse->uwY + wDy, pMouse->sBounds.uwY1, pMouse->sBounds.uwY2 + ); +} -void mouseClose(void); +/** + * Resets mouse position to center of legal coordinate range. + * @param ubMousePort: Mouse of which position should be reset. + */ +static inline void mouseResetPos( + IN UBYTE ubMousePort +) { + const tUwAbsRect *pBounds = &g_sMouseManager.pMice[ubMousePort].sBounds; + g_sMouseManager.pMice[ubMousePort].uwX = (pBounds->uwX2 - pBounds->uwX1) >> 1; + g_sMouseManager.pMice[ubMousePort].uwY = (pBounds->uwY2 - pBounds->uwY1) >> 1; +} #endif diff --git a/include/ace/utils/custom.h b/include/ace/utils/custom.h index d97bcd03..ed9bd267 100644 --- a/include/ace/utils/custom.h +++ b/include/ace/utils/custom.h @@ -1,6 +1,8 @@ #ifndef GUARD_ACE_UTILS_CUSTOM_H #define GUARD_ACE_UTILS_CUSTOM_H +#include + #ifdef AMIGA /** @@ -41,5 +43,91 @@ extern volatile tCopperUlong * const pSprPtrs; extern volatile tCopperUlong * const pBplPtrs; extern volatile tCopperUlong * const pCopLc; +/** + * CIA registers. + * Borrowed from https://github.com/keirf/Amiga-Stuff + */ +typedef struct _tCia { + volatile UBYTE pra; + volatile UBYTE _0[0xff]; + volatile UBYTE prb; + volatile UBYTE _1[0xff]; + volatile UBYTE ddra; + volatile UBYTE _2[0xff]; + volatile UBYTE ddrb; + volatile UBYTE _3[0xff]; + volatile UBYTE talo; + volatile UBYTE _4[0xff]; + volatile UBYTE tahi; + volatile UBYTE _5[0xff]; + volatile UBYTE tblo; + volatile UBYTE _6[0xff]; + volatile UBYTE tbhi; + volatile UBYTE _7[0xff]; + volatile UBYTE todlow; + volatile UBYTE _8[0xff]; + volatile UBYTE todmid; + volatile UBYTE _9[0xff]; + volatile UBYTE todhi; + volatile UBYTE _a[0xff]; + volatile UBYTE b00; + volatile UBYTE _b[0xff]; + volatile UBYTE sdr; + volatile UBYTE _c[0xff]; + volatile UBYTE icr; + volatile UBYTE _d[0xff]; + volatile UBYTE cra; + volatile UBYTE _e[0xff]; + volatile UBYTE crb; + volatile UBYTE _f[0xff]; +} tCia; + +/** + * CIA defines. + */ +#define CIAAPRA_OVL BV(0) +#define CIAAPRA_LED BV(1) +#define CIAAPRA_CHNG BV(2) +#define CIAAPRA_WPRO BV(3) +#define CIAAPRA_TK0 BV(4) +#define CIAAPRA_RDY BV(5) +#define CIAAPRA_FIR0 BV(6) +#define CIAAPRA_FIR1 BV(7) + +#define CIABPRB_STEP BV(0) +#define CIABPRB_DIR BV(1) +#define CIABPRB_SIDE BV(2) +#define CIABPRB_SEL0 BV(3) +#define CIABPRB_SEL1 BV(4) +#define CIABPRB_SEL2 BV(5) +#define CIABPRB_SEL3 BV(6) +#define CIABPRB_MTR BV(7) + +#define CIAICR_TIMER_A BV(0) +#define CIAICR_TIMER_B BV(1) +#define CIAICR_TOD BV(2) +#define CIAICR_SERIAL BV(3) +#define CIAICR_FLAG BV(4) +#define CIAICR_SETCLR BV(7) + +#define CIACRA_START BV(0) +#define CIACRA_PBON BV(1) +#define CIACRA_OUTMODE BV(2) +#define CIACRA_RUNMODE BV(3) +#define CIACRA_LOAD BV(4) +#define CIACRA_INMODE BV(5) +#define CIACRA_SPMODE BV(6) + +#define CIACRB_START BV(0) +#define CIACRB_PBON BV(1) +#define CIACRB_OUTMODE BV(2) +#define CIACRB_RUNMODE BV(3) +#define CIACRB_LOAD BV(4) +#define CIACRB_INMODE (BV(5) | BV(6)) +#define CIACRB_ALARM BV(7) + +extern volatile tCia * const g_pCiaA; +extern volatile tCia * const g_pCiaB; + #endif // AMIGA #endif // GUARD_ACE_UTILS_CUSTOM_H diff --git a/src/ace/managers/key.c b/src/ace/managers/key.c index ba9d945e..bb137ce1 100644 --- a/src/ace/managers/key.c +++ b/src/ace/managers/key.c @@ -1,4 +1,34 @@ #include +#include +#include +#include // INTB_PORTS +#define KEY_RELEASED_BIT 1 + +/** + * Timer VBlank server + * Increments frame counter + */ +__amigainterrupt __saveds void keyIntServer(__reg("a1") tKeyManager *pManager) { + UBYTE ubKeyCode = ~g_pCiaA->sdr; + + // Start handshake + g_pCiaA->cra |= CIACRA_SPMODE; + UWORD uwStart = (g_pCiaA->tbhi << 8) | g_pCiaA->tblo; + + // Get keypress flag and shift keyCode + UBYTE ubKeyReleased = ubKeyCode & KEY_RELEASED_BIT; + ubKeyCode >>= 1; + + if(ubKeyReleased) + keySetState(ubKeyCode, KEY_NACTIVE); + else if (!keyCheck(ubKeyCode)) + keySetState(ubKeyCode, KEY_ACTIVE); + + // End handshake + while(uwStart - ((g_pCiaA->tbhi << 8) | g_pCiaA->tblo) < 65) + continue; + g_pCiaA->cra &= ~CIACRA_SPMODE; +} /* Globals */ tKeyManager g_sKeyManager; @@ -15,48 +45,28 @@ const UBYTE g_pToAscii[] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '(', ')', '/', '*', '+', '-', }; -/* Functions */ -void keyProcess() { - ULONG ulWindowSignal; - ULONG ulSignals; - struct IntuiMessage *pMsg; - - ulWindowSignal = 1L << g_sWindowManager.pWindow->UserPort->mp_SigBit; - ulSignals = SetSignal(0L, 0L); - - if (ulSignals & ulWindowSignal) { - while (pMsg = (struct IntuiMessage *) GetMsg(g_sWindowManager.pWindow->UserPort)) { - ReplyMsg((struct Message *) pMsg); - - switch (pMsg->Class) { - case IDCMP_RAWKEY: - if (pMsg->Code & IECODE_UP_PREFIX) { - pMsg->Code -= IECODE_UP_PREFIX; - keySetState(pMsg->Code, KEY_NACTIVE); - } - else if (!keyCheck(pMsg->Code)) { - keySetState(pMsg->Code, KEY_ACTIVE); - } - break; - } - } - } -} +void keyCreate(void) { +#ifdef AMIGA + g_sKeyManager.pInt = memAllocChipClear(sizeof(struct Interrupt)); // CHIP is PUBLIC. + + g_sKeyManager.pInt->is_Node.ln_Type = NT_INTERRUPT; + g_sKeyManager.pInt->is_Node.ln_Pri = -60; + g_sKeyManager.pInt->is_Node.ln_Name = "ACE_Keyboard_CIA"; + g_sKeyManager.pInt->is_Data = (APTR)&g_sKeyManager; + g_sKeyManager.pInt->is_Code = keyIntServer; -void keySetState(UBYTE ubKeyCode, UBYTE ubKeyState) { - g_sKeyManager.pStates[ubKeyCode] = ubKeyState; - if(ubKeyState == KEY_ACTIVE) - g_sKeyManager.ubLastKey = ubKeyCode; + AddIntServer(INTB_PORTS, g_sKeyManager.pInt); +#endif // AMIGA } -UBYTE keyCheck(UBYTE ubKeyCode) { - return g_sKeyManager.pStates[ubKeyCode] != KEY_NACTIVE; +void keyDestroy(void) { +#ifdef AMIGA + RemIntServer(INTB_PORTS, g_sKeyManager.pInt); + memFree(g_sKeyManager.pInt, sizeof(struct Interrupt)); +#endif // AMIGA } -UBYTE keyUse(UBYTE ubKeyCode) { - if (g_sKeyManager.pStates[ubKeyCode] == KEY_ACTIVE) { - g_sKeyManager.pStates[ubKeyCode] = KEY_USED; - return 1; - } - return 0; +void keyProcess(void) { + // This function is left out for other platforms - they will prob'ly not be + // interrupt-driven. } diff --git a/src/ace/managers/mouse.c b/src/ace/managers/mouse.c index 58992aa5..b276246a 100644 --- a/src/ace/managers/mouse.c +++ b/src/ace/managers/mouse.c @@ -1,126 +1,104 @@ #include +#include +#include +#include /* Globals */ tMouseManager g_sMouseManager; /* Functions */ -void mouseOpen() { -#ifdef AMIGA - g_sMouseManager.pInputMP = CreatePort(NULL, 0L); - g_sMouseManager.pInputIO = (struct IOStdReq *) CreateExtIO(g_sMouseManager.pInputMP, sizeof(struct IOStdReq)); - - OpenDevice("input.device", 0, (struct IORequest *) g_sMouseManager.pInputIO, 0); -#endif // AMIGA -} - -void mouseSetState(UBYTE ubMouseCode, UBYTE ubMouseState) { -#ifdef AMIGA - ubMouseCode -= IECODE_LBUTTON; -#endif // AMIGA - g_sMouseManager.pStates[ubMouseCode] = ubMouseState; -} +void mouseCreate(UBYTE ubPortFlags) { + memset(&g_sMouseManager, 0, sizeof(tMouseManager)); + g_sMouseManager.ubPortFlags = ubPortFlags; -UBYTE mouseCheck(UBYTE ubMouseCode) { #ifdef AMIGA - ubMouseCode -= IECODE_LBUTTON; + g_sMouseManager.uwPrevPotGo = custom.potinp; + UWORD uwPotMask = 0; + + // Enable RMB & MMB + if(ubPortFlags & MOUSE_PORT_1) + uwPotMask |= BV(11) | BV(10) | BV(9) | BV(8); + if(ubPortFlags & MOUSE_PORT_2) + uwPotMask |= BV(15) | BV(14) | BV(13) | BV(12); + custom.potgo = (custom.potinp & (0xFFFF ^ uwPotMask)) | uwPotMask; + + // Amiga Hardware Reference Manual suggests that pos should be polled every + // vblank, so there could be some interrupt init. #endif // AMIGA - return g_sMouseManager.pStates[ubMouseCode] != MOUSE_NACTIVE; -} -UBYTE mouseUse(UBYTE ubMouseCode) { -#ifdef AMIGA - ubMouseCode -= IECODE_LBUTTON; -#endif // AMIGA - if (g_sMouseManager.pStates[ubMouseCode] == MOUSE_ACTIVE) { - g_sMouseManager.pStates[ubMouseCode] = MOUSE_USED; - return 1; + if(ubPortFlags & MOUSE_PORT_1) { + mouseSetBounds(MOUSE_PORT_1, 0, 0, SCREEN_PAL_WIDTH, SCREEN_PAL_HEIGHT); + mouseResetPos(MOUSE_PORT_1); + } + if(ubPortFlags & MOUSE_PORT_2) { + mouseSetBounds(MOUSE_PORT_2, 0, 0, SCREEN_PAL_WIDTH, SCREEN_PAL_HEIGHT); + mouseResetPos(MOUSE_PORT_2); } - return 0; -} - -UBYTE mouseIsIntersects(UWORD uwX, UWORD uwY, UWORD uwWidth, UWORD uwHeight) { -#ifdef AMIGA - return (uwX <= g_sWindowManager.pWindow->MouseX) && (g_sWindowManager.pWindow->MouseX < uwX + uwWidth) && (uwY <= g_sWindowManager.pWindow->MouseY) && (g_sWindowManager.pWindow->MouseY < uwY + uwHeight); -#else - return 0; -#endif // AMIGA -} - -UWORD mouseGetX(void) { -#ifdef AMIGA - return g_sWindowManager.pWindow->MouseX; -#else - return 0; -#endif // AMIGA -} - -UWORD mouseGetY(void) { -#ifdef AMIGA - return g_sWindowManager.pWindow->MouseY; -#else - return 0; -#endif // AMIGA -} - -void mouseSetPointer(UWORD *pCursor, WORD wHeight, WORD wWidth, WORD wOffsetX, WORD wOffsetY) { - logBlockBegin("mouseSetPointer(pCursor: %p, wHeight: %d, wWidth, %d, wOffsetX: %d, wOffsetY: %d)", pCursor, wHeight, wWidth, wOffsetX, wOffsetY); -#ifdef AMIGA - SetPointer(g_sWindowManager.pWindow, pCursor, wHeight, wWidth, wOffsetX, wOffsetY); -#endif // AMIGA - logBlockEnd("mouseSetPointer"); } -void mouseResetPointer(void) { +void mouseDestroy(void) { #ifdef AMIGA - ClearPointer(g_sWindowManager.pWindow); + // Should mouse manager be interrupt driven, interrupt handler deletion will + // be here. + custom.potgo = g_sMouseManager.uwPrevPotGo; #endif // AMIGA } -#ifdef AMIGA -void _mouseDo(struct InputEvent *pEvent) { - g_sMouseManager.pInputIO->io_Data = (APTR) pEvent; - g_sMouseManager.pInputIO->io_Length = sizeof(struct InputEvent); - g_sMouseManager.pInputIO->io_Command = IND_WRITEEVENT; - - DoIO((struct IORequest *) g_sMouseManager.pInputIO); -} -#endif // AMIGA - -void mouseSetPosition(UWORD uwNewX, UWORD uwNewY) { - mouseMoveBy(uwNewX - mouseGetX(), uwNewY - mouseGetY()); +static void mouseProcessPort( + UBYTE ubPort, UWORD uwPosReg, + UBYTE ubStateLmb, UBYTE ubStateRmb, UBYTE ubStateMmb +) { + // Deltas are signed bytes even though underflows and overflows may occur. + // It is expected behavior since it is encouraged in Amiga HRM as means to + // determine mouse movement direction which takes into account joyxdat + // underflows and overflows. + + UBYTE ubPosX = uwPosReg & 0xFF; + UBYTE ubPosY = uwPosReg >> 8; + + BYTE bDx = ubPosX - g_sMouseManager.pMice[ubPort].ubPrevHwX; + BYTE bDy = ubPosY - g_sMouseManager.pMice[ubPort].ubPrevHwY; + mouseMoveBy(ubPort, bDx, bDy); + + g_sMouseManager.pMice[ubPort].ubPrevHwX = ubPosX; + g_sMouseManager.pMice[ubPort].ubPrevHwY = ubPosY; + + // Left button state + if(ubStateLmb) + mouseSetButton(ubPort, MOUSE_LMB, MOUSE_NACTIVE); + else if(!mouseCheck(ubPort, MOUSE_LMB)) + mouseSetButton(ubPort, MOUSE_LMB, MOUSE_ACTIVE); + + // Right button state + if(ubStateRmb) + mouseSetButton(ubPort, MOUSE_RMB, MOUSE_NACTIVE); + else if(!mouseCheck(ubPort, MOUSE_RMB)) + mouseSetButton(ubPort, MOUSE_RMB, MOUSE_ACTIVE); + + // Middle button state + if(ubStateMmb) + mouseSetButton(ubPort, MOUSE_MMB, MOUSE_NACTIVE); + else if(!mouseCheck(ubPort, MOUSE_MMB)) + mouseSetButton(ubPort, MOUSE_MMB, MOUSE_ACTIVE); } -void mouseMoveBy(WORD wDx, WORD wDy) { +void mouseProcess(void) { + // Even if whole Amiga process will be moved to vbl interrupt, other platforms + // will prob'ly use this fn anyway #ifdef AMIGA - struct InputEvent __chip sEvent; - - sEvent.ie_Class = IECLASS_POINTERPOS; - sEvent.ie_Code = IECODE_NOBUTTON; - sEvent.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE; - sEvent.ie_X = wDx; - sEvent.ie_Y = wDy; - _mouseDo(&sEvent); -#endif // AMIGA -} - -void mouseClick(UBYTE ubMouseCode) { -#ifdef AMIGA - struct InputEvent *pEvent = memAllocChipFlags(sizeof(struct InputEvent), MEMF_PUBLIC | MEMF_CLEAR); - - pEvent->ie_Class = IECLASS_RAWMOUSE; - pEvent->ie_Code = ubMouseCode; - - _mouseDo(pEvent); - - memFree(pEvent, sizeof(struct InputEvent)); -#endif // AMIGA -} + if(g_sMouseManager.ubPortFlags & MOUSE_PORT_1) { + mouseProcessPort( + MOUSE_PORT_1, custom.joy0dat, + g_pCiaA->pra & BV(6), custom.potinp & BV(10), custom.potinp & BV(8) + ); + } + if(g_sMouseManager.ubPortFlags & MOUSE_PORT_2) { + mouseProcessPort( + MOUSE_PORT_2, custom.joy1dat, + g_pCiaA->pra & BV(7), custom.potinp & BV(14), custom.potinp & BV(12) + ); + } -void mouseClose() { -#ifdef AMIGA - CloseDevice((struct IORequest *) g_sMouseManager.pInputIO); - DeleteExtIO((struct IORequest *) g_sMouseManager.pInputIO); - DeletePort(g_sMouseManager.pInputMP); #endif // AMIGA } diff --git a/src/ace/utils/custom.c b/src/ace/utils/custom.c index 374162dc..61aa736a 100644 --- a/src/ace/utils/custom.c +++ b/src/ace/utils/custom.c @@ -8,4 +8,7 @@ volatile tCopperUlong * const pBplPtrs = (APTR)&custom.bplpt; volatile tCopperUlong * const pSprPtrs = (APTR)&custom.sprpt; volatile tCopperUlong * const pCopLc = (APTR)&custom.cop1lc; +volatile tCia * const g_pCiaA = (tCia*)0x0bfe001; +volatile tCia * const g_pCiaB = (tCia*)0x0bfd000; + #endif // AMIGA