#pragma once #include "olcPixelGameEngine.h" #include "SMX.h" using namespace olc; class PGEX_SMX : public PGEX{ public: PGEX_SMX():PGEX(true){ }; //UP is 0x2 //RIGHT is 0x20 //DOWN is 0x80 //LEFT is 0x08 //Add these bytes together to get the combination (all 4 held down is 0xAA HWButton GetPanel(Key k,int pad)const{ return panelState[k-UP]; }; void EnableLogMessages(bool enabled){ logMessages=enabled; } private: static bool logMessages; HWButton internal_panelState[4]; HWButton panelState[4]; //We store the 4 main panel states, similar to how PGE does. //SMX "screen" is 12x21 //Each panel is 4x7 static void SMXStateChangedCallback(int pad, SMXUpdateCallbackReason reason, void *pUser) { PGEX_SMX *pSelf = (PGEX_SMX*) pUser; pSelf->SMXStateChanged( pad, reason ); } static void SMXLogCallback(const char *log) { if(logMessages){ printf("-> %s\n", log); } } //The key enums are UP, DOWN, LEFT, RIGHT. void SMXStateChanged(int pad, SMXUpdateCallbackReason reason) { if(logMessages){ printf("Device %i state changed: %04x\n", pad, SMX_GetInputState(pad)); } int16_t state(SMX_GetInputState(pad)); if(state&0x2&&!internal_panelState[UP-UP].bPressed){ internal_panelState[UP-UP]={true,false,true}; }else if(!(state&0x2)&&!internal_panelState[UP-UP].bReleased){ internal_panelState[UP-UP]={false,true,false}; } if(state&0x20&&!internal_panelState[RIGHT-UP].bPressed){ internal_panelState[RIGHT-UP]={true,false,true}; }else if(!(state&0x20)&&!internal_panelState[RIGHT-UP].bReleased){ internal_panelState[RIGHT-UP]={false,true,false}; } if(state&0x80&&!internal_panelState[DOWN-UP].bPressed){ internal_panelState[DOWN-UP]={true,false,true}; }else if(!(state&0x80)&&!internal_panelState[DOWN-UP].bReleased){ internal_panelState[DOWN-UP]={false,true,false}; } if(state&0x8&&!internal_panelState[LEFT-UP].bPressed){ internal_panelState[LEFT-UP]={true,false,true}; }else if(!(state&0x8)&&!internal_panelState[LEFT-UP].bReleased){ internal_panelState[LEFT-UP]={false,true,false}; } } virtual void OnAfterUserCreate()override{ SMX_Start( SMXStateChangedCallback, this ); }; virtual bool OnBeforeUserUpdate(float& fElapsedTime){ //We don't want the panel states changing in the middle of a frame, since the input polling is on a separate thread. //Copy over the internal button states to the current panel state. for(int i=0;i<4;i++){ panelState[i]=internal_panelState[i]; internal_panelState[i].bPressed=false; internal_panelState[i].bReleased=false; } return false; } virtual void OnAfterUserUpdate(float fElapsedTime)override{ for(int i=0;i<4;i++){ panelState[i].bPressed=false; panelState[i].bReleased=false; } std::string lightData; //The light data for an SMX dance pad is outlined in the docs but the code used to transform the PGE's pixels to SMX pad's lights will be annotated here. //Both pads receive data sequentially, and for now we can mimic the data on both ends. for (int pad=0;pad<2;pad++){ for(int i=0;i<9;i++){ int row=0; for(int y=i/3*7;yGetDrawTarget()->GetPixel(x,y)); lightData.append(1,p.r); lightData.append(1,p.g); lightData.append(1,p.b); col++; } row+=2; } row=1; for(int y=i/3*7+1;yGetDrawTarget()->GetPixel(x,y)); lightData.append(1,p.r); lightData.append(1,p.g); lightData.append(1,p.b); col++; } row+=2; } } } SMX_SetLights2( lightData.data(), lightData.size() ); } }; bool PGEX_SMX::logMessages=false;