Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Input - Module.c
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* == Input ============================================================================================================================================================= */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions and Data                                                                                                                                         */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static ETgMODULE_STATE                      s_enInput_State = ETgMODULE_STATE__FREED;

#if TgCOMPILE_THREAD
static TgUINT32                             tgIN_Update_Producers_Thread( C_TgUINTPTR );

static TgBOOL                               s_bRun_Producer_Thread;
static TgBOOL                               s_bEnd_Producer_Thread;
static TgTHREAD_ID                          s_uiProducer_Thread;

/*# TgCOMPILE_THREAD */
#endif

#if TgS_STAT_INPUT
static CPC_TgCHAR                           s_aszStat_Controller_Name[] = {
                                                TgT("Game Pad 0"),
                                                TgT("Game Pad 1"),
                                                TgT("Game Pad 2"),
                                                TgT("Game Pad 3"),
                                                TgT("Keyboard"),
                                                TgT("GUI Keyboard"),
                                                TgT("Mouse"),
                                                TgT("GUI Mouse"),
                                                TgT("Net 0"),
                                                TgT("Net 1"),
                                                TgT("Net 2"),
                                                TgT("Net 3") };
#endif




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Public Functions                                                                                                                                                      */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgIN_Module_Init ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgIN_Module_Init( TgVOID )
{
    TgUINT32                            uiIndex;

    /* Verify the state of the system */
    TgERROR( ETgMODULE_STATE__FREED == s_enInput_State );
    s_enInput_State = ETgMODULE_STATE__INITIALIZING;

    memset( g_asController_Active, 0x00, sizeof( g_asController_Active ) );
    memset( g_asController_Rumble, 0x00, sizeof( g_asController_Rumble ) );
    memset( g_abController_Paused, 0x00, sizeof( g_abController_Paused ) );
    memset( g_asConsumer, 0x00, sizeof( g_asConsumer ) );
    for (uiIndex = 0; uiIndex < TgARRAY_COUNT( g_asConsumer ); ++uiIndex)
    {
        g_asConsumer[uiIndex].m_enController = ETgCONTROLLER_MAX;
        g_asConsumer[uiIndex].m_tiConsumer = KTgIN_CONSUMER_ID__INVALID;
    };

    tgCM_UTM_AM_ST_Init( &g_sConsumer_Insert );

    g_fDefault_Mouse_X_Dead_Zone = 0.0F;
    g_fDefault_Mouse_Y_Dead_Zone = 0.0F;
    g_fDefault_Mouse_Z_Dead_Zone = 0.0F;

    g_fDefault_GamePad_Stick_0_X_Dead_Zone = 0.0F;
    g_fDefault_GamePad_Stick_0_Y_Dead_Zone = 0.0F;
    g_fDefault_GamePad_Stick_1_X_Dead_Zone = 0.0F;
    g_fDefault_GamePad_Stick_1_Y_Dead_Zone = 0.0F;

#if TgS_STAT_INPUT
    memset( g_nuiStat_Insert, 0x00, sizeof( g_nuiStat_Insert ) );
    memset( g_nuiStat_Remove, 0x00, sizeof( g_nuiStat_Remove ) );
#endif

#if !defined(TgCOMPILE_FORCE_ANSI)
    tgIN_PM_Module_Init();
#endif

    s_enInput_State = ETgMODULE_STATE__INITIALIZED;
    return (KTgS_OK);
}


/* ---- tgIN_Module_Boot ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgIN_Module_Boot( TgVOID )
{
    /* Verify the state of the system */
    TgERROR( ETgMODULE_STATE__INITIALIZED == s_enInput_State );
    s_enInput_State = ETgMODULE_STATE__BOOTING;

    tgCN_PrintF( KTgCN_CHANEL_INITIALIZE_MEMORY, TgT( "%-16.16s(%-32.32s): %-48.48s % 14d\n" ), TgT("Input"), TgT("Boot_Module"), TgT("Static Memory Size"),
                 tgIN_Query_Fixed_Memory() );

#if !defined(TgCOMPILE_FORCE_ANSI)
    tgIN_PM_Module_Boot();
#endif

#if TgCOMPILE_THREAD
    s_bEnd_Producer_Thread = TgFALSE;
    s_bRun_Producer_Thread = TgTRUE;
    tgAM_WRITE_FENCE();
    s_uiProducer_Thread = tgTR_Create( tgIN_Update_Producers_Thread, 0, 0, ETgTHREAD_PRIORITY__CRITICAL, TgT("IN Producer") );
/*# TgCOMPILE_THREAD */
#endif

    s_enInput_State = ETgMODULE_STATE__BOOTED;
    return (KTgS_OK);
}


/* ---- tgIN_Module_Stop ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgIN_Module_Stop( TgVOID )
{
#if TgCOMPILE_THREAD
    ETgCONTROLLER                       enController;
#endif

    if ((ETgMODULE_STATE__FREED == s_enInput_State) || (ETgMODULE_STATE__INITIALIZED == s_enInput_State))
    {
        return;
    };

    /* Verify the state of the system */
    TgERROR( ETgMODULE_STATE__BOOTED == s_enInput_State );
    s_enInput_State = ETgMODULE_STATE__STOPPING;

    TgERROR_MSGF( tgCM_UTM_AM_ST_Is_Empty( &g_sConsumer_Insert ), TgT( "%-16.16s(%-32.32s): Orphaned Consumer Insertion.\n" ), TgT("Input"), TgT("Stop_Module") );

#if TgCOMPILE_THREAD
    /* Stop the production thread */
    s_bRun_Producer_Thread = TgFALSE;
    tgAM_WRITE_FENCE();

    while (TgFALSE == s_bEnd_Producer_Thread)
    {
        for (enController = 0; enController < ETgCONTROLLER_MAX; ++enController)
        {
            while (0 != tgCM_UTM_LA_RB_SRSW__Query_Used_Size( &g_asController_Active[enController].m_sLA_RB_SRSW ))
            {
                tgCM_UTM_LA_RB_SRSW__Pop_Next_Index( &g_asController_Active[enController].m_sLA_RB_SRSW );
                tgCM_UTM_LA_RB_SRSW__Pop_Commit( &g_asController_Active[enController].m_sLA_RB_SRSW );
            };
        };
    };

    tgTR_Close( s_uiProducer_Thread );
    s_uiProducer_Thread = KTgTHREAD_ID__INVALID;
/*# TgCOMPILE_THREAD */
#endif

#if !defined(TgCOMPILE_FORCE_ANSI)
    tgIN_PM_Module_Stop();
#endif

    s_enInput_State = ETgMODULE_STATE__STOPPED;
}


/* ---- tgIN_Module_Free ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgIN_Module_Free( TgVOID )
{
    if (ETgMODULE_STATE__FREED == s_enInput_State)
    {
        return;
    };

    /* Verify the state of the system */
    TgERROR( ETgMODULE_STATE__STOPPED == s_enInput_State || ETgMODULE_STATE__INITIALIZED == s_enInput_State );
    s_enInput_State = ETgMODULE_STATE__FREEING;

#if !defined(TgCOMPILE_FORCE_ANSI)
    tgIN_PM_Module_Free();
#endif

    s_enInput_State = ETgMODULE_STATE__FREED;
}


/* ---- tgIN_Module_Update ---------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgIN_Module_Update( C_TgFLOAT32 fDT )
{
    ETgCONTROLLER                       enController;
    TgUINT32                            uiEvent;
    P_STg2_Input_Consumer               psConsumer, psNew_Consumer, psInput_Consumer, psInput_Prev_Consumer, psInput_Next_Consumer;
    TgUINT32                            uiIndex = 0;

#if !TgCOMPILE_THREAD
    tgIN_Update_Producers();
/*# !TgCOMPILE_THREAD */
#endif

    while (1)
    {
        /* Insert Consumers from the Producers Attached List */
        psNew_Consumer = (P_STg2_Input_Consumer)tgCM_UTM_AM_ST_Pop( &g_sConsumer_Insert );

        if (0 == psNew_Consumer)
        {
            break;
        };

        for (uiIndex = 0; uiIndex < KTgMAX_CONSUMER; ++uiIndex)
        {
            TgERROR( psNew_Consumer != g_asConsumer[uiIndex].m_sMP_Element.m_pNext_Node );
            TgERROR( g_asConsumer + uiIndex != g_asConsumer[uiIndex].m_sMP_Element.m_pNext_Node );
        };

        psNew_Consumer->m_sMP_Element.m_pNext_Node = nullptr;

    #if TgS_STAT_INPUT
        ++g_nuiStat_Insert[psNew_Consumer->m_enController];
        ++g_nuiStat_Insert[ETgCONTROLLER_MAX];
    /*# TgS_STAT_INPUT */
    #endif

        if (nullptr == g_asController_Active[psNew_Consumer->m_enController].m_psConsumer)
        {
            g_asController_Active[psNew_Consumer->m_enController].m_psConsumer = psNew_Consumer;
            continue;
        };

        psConsumer = g_asController_Active[psNew_Consumer->m_enController].m_psConsumer;
        psInput_Next_Consumer = (P_STg2_Input_Consumer)(psConsumer->m_sMP_Element.m_pNext_Node);

        while (nullptr != psInput_Next_Consumer && psNew_Consumer->m_uiPriority < psInput_Next_Consumer->m_uiPriority)
        {
            psConsumer = psInput_Next_Consumer;
            psInput_Next_Consumer = (P_STg2_Input_Consumer)(psConsumer->m_sMP_Element.m_pNext_Node);
        };

        TgERROR( psConsumer->m_sMP_Element.m_pNext_Node != psNew_Consumer );
        psNew_Consumer->m_sMP_Element.m_pNext_Node = psConsumer->m_sMP_Element.m_pNext_Node;
        psConsumer->m_sMP_Element.m_pNext_Node = (TgATOMIC_PVOID)psNew_Consumer;
    };

    /* Remove Consumers from the Producers Attached List */
    for (enController = 0; enController < ETgCONTROLLER_MAX; ++enController)
    {
        /* Loop through all of the consumers for the controller */
        psInput_Consumer = g_asController_Active[enController].m_psConsumer;
        psInput_Prev_Consumer = nullptr;
        while (nullptr != psInput_Consumer)
        {
            PC_STg2_Input_Consumer              psRemove_Consumer = psInput_Consumer;

            TgERROR( psInput_Consumer->m_enController == enController );

            if (TgTRUE != psInput_Consumer->m_bRemove)
            {
                psInput_Prev_Consumer = psInput_Consumer;
                psInput_Consumer = (P_STg2_Input_Consumer)psInput_Consumer->m_sMP_Element.m_pNext_Node;
                continue;
            }

            TgERROR( psInput_Consumer->m_sMP_Element.m_pNext_Node != psRemove_Consumer );
            if (nullptr == psInput_Prev_Consumer)
            {
                g_asController_Active[enController].m_psConsumer = (P_STg2_Input_Consumer)psInput_Consumer->m_sMP_Element.m_pNext_Node;
            }
            else
            {
                psInput_Prev_Consumer->m_sMP_Element.m_pNext_Node = psInput_Consumer->m_sMP_Element.m_pNext_Node;
            };

            psInput_Consumer = (P_STg2_Input_Consumer)psInput_Consumer->m_sMP_Element.m_pNext_Node;

        #if TgS_STAT_INPUT
            ++g_nuiStat_Remove[psRemove_Consumer->m_enController];
            ++g_nuiStat_Remove[ETgCONTROLLER_MAX];
        #endif

            psRemove_Consumer->m_pfnConsume = nullptr;
            psRemove_Consumer->m_sMP_Element.m_pNext_Node = 0;
            psRemove_Consumer->m_enController = ETgCONTROLLER_MAX;
            psRemove_Consumer->m_uiParam = 0;
            psRemove_Consumer->m_uiPriority = KTgMAX_U32;
            psRemove_Consumer->m_bRemove = TgFALSE;

            psRemove_Consumer->m_tiConsumer = KTgIN_CONSUMER_ID__INVALID;
            tgAM_WRITE_FENCE();

            for (uiIndex = 0; uiIndex < KTgMAX_CONSUMER; ++uiIndex)
            {
                TgERROR( psRemove_Consumer != g_asConsumer[uiIndex].m_sMP_Element.m_pNext_Node );
                TgERROR( g_asConsumer + uiIndex != g_asConsumer[uiIndex].m_sMP_Element.m_pNext_Node );
            };
        };
    };

    /* Loop through all of the controllers */
    for (enController = 0; enController < ETgCONTROLLER_MAX; ++enController)
    {
        while (0 != tgCM_UTM_LA_RB_SRSW__Query_Used_Size( &g_asController_Active[enController].m_sLA_RB_SRSW ))
        {
            uiEvent = (TgUINT32)tgCM_UTM_LA_RB_SRSW__Pop_Next_Index( &g_asController_Active[enController].m_sLA_RB_SRSW );

            /* Loop through all of the consumers for the controller */
            psConsumer = g_asController_Active[enController].m_psConsumer;
            while (nullptr != psConsumer && !g_abController_Paused[enController])
            {
                TgIN_FCN_CONSUMER                pfnConsume;

                /* Stop processing if the event has been consumed */
                pfnConsume = (TgIN_FCN_CONSUMER)(psConsumer->m_pfnConsume);
                if (TgTRUE == pfnConsume( psConsumer->m_uiParam, fDT, g_asController_Active[enController].m_asEvent + uiEvent ))
                {
                    break;
                };

                psConsumer = (P_STg2_Input_Consumer)psConsumer->m_sMP_Element.m_pNext_Node;
            };

            tgCM_UTM_LA_RB_SRSW__Pop_Commit( &g_asController_Active[enController].m_sLA_RB_SRSW );
        };
    };

    return (KTgS_OK);
}


/* ---- tgIN_Load_Config ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgIN_Load_Config( TgVOID )
{

}


/* ---- tgIN_Save_Config ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgIN_Save_Config( TgVOID )
{

}


/* ---- tgIN_Query_Init ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgIN_Query_Init( TgVOID )
{
    return (ETgMODULE_STATE__INITIALIZED <= s_enInput_State && s_enInput_State <= ETgMODULE_STATE__STOPPED);
}


/* ---- tgIN_Query_Boot ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgBOOL tgIN_Query_Boot( TgVOID )
{
    return (ETgMODULE_STATE__BOOTED == s_enInput_State);
}


/* ---- tgIN_Stats ------------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#if TgS_STAT_INPUT
TgVOID tgIN_Stats( P_STg2_Output UNUSED_PARAM psOUT )
{
    TgUINT32                            uiIndex;

    TgMSGF( 0, TgT( "\n%-16.16s(%-32.32s): %-48.48s % 14d\n" ), TgT("Input"), TgT("Stop_Module"), TgT("Total Consumer Insert"), g_nuiStat_Insert[ETgCONTROLLER_MAX] );

    for (uiIndex = 0; uiIndex < ETgCONTROLLER_MAX; ++uiIndex)
    {
        TgMSGF( 0xD, TgT( "%-16.16s(%-32.32s):    -%-44.44s % 14d\n" ), TgT("Input"), TgT("Stop_Module"), s_aszStat_Controller_Name[uiIndex], g_nuiStat_Insert[uiIndex] );
    };

    TgMSGF( 0x0, TgT( "\n%-16.16s(%-32.32s): %-48.48s % 14d\n" ), TgT("Input"), TgT("Stop_Module"), TgT("Total Consumer Remove"), g_nuiStat_Remove[ETgCONTROLLER_MAX] );

    for (uiIndex = 0; uiIndex < ETgCONTROLLER_MAX; ++uiIndex)
    {
        TgMSGF( 0xD, TgT( "%-16.16s(%-32.32s):    -%-44.44s % 14d\n" ), TgT("Input"), TgT("Stop_Module"), s_aszStat_Controller_Name[uiIndex], g_nuiStat_Remove[uiIndex] );
    };
}
/*# TgS_STAT_INPUT */
#endif




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgIN_Update_Producers_Thread -------------------------------------------------------------------------------------------------------------------------------------*/
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
#if TgCOMPILE_THREAD
static TgUINT32 tgIN_Update_Producers_Thread( C_TgUINTPTR UNUSED_PARAM uiUnused )
{
    s_bEnd_Producer_Thread = TgFALSE;
    while (s_bRun_Producer_Thread)
    {
        tgTR_Sleep( 16 ); /* Needs to be changed to an event call so that vblank can trigger */
        tgIN_Update_Producers();
    };
    s_bEnd_Producer_Thread = TgTRUE;

    return (0);
}
/*# TgCOMPILE_THREAD */
#endif