diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 01b51fad71..799179e797 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -34,6 +34,7 @@ set(RUNTIME_SOURCE system/IOP_Kernel.cpp system/iop_thread.cpp system/Deci2Server.cpp + system/newpad.cpp sce/libcdvd_ee.cpp sce/libscf.cpp sce/libdma.cpp diff --git a/game/graphics/display.cpp b/game/graphics/display.cpp index a737485381..1d0b50274d 100644 --- a/game/graphics/display.cpp +++ b/game/graphics/display.cpp @@ -8,9 +8,11 @@ #include "common/log/log.h" -/* ****************************** */ -/* Internal functions */ -/* ****************************** */ +/* +******************************** +* Internal functions +******************************** +*/ namespace { @@ -28,9 +30,11 @@ void set_main_display(std::shared_ptr display) { } // namespace -/* ****************************** */ -/* GfxDisplay */ -/* ****************************** */ +/* +******************************** +* GfxDisplay +******************************** +*/ GfxDisplay::GfxDisplay(GLFWwindow* a_window) { set_renderer(GfxPipeline::OpenGL); @@ -81,9 +85,11 @@ void GfxDisplay::render_graphics() { m_renderer->render_display(this); } -/* ****************************** */ -/* DISPLAY */ -/* ****************************** */ +/* +******************************** +* DISPLAY +******************************** +*/ namespace Display { diff --git a/game/graphics/gfx.cpp b/game/graphics/gfx.cpp index 0c9c830ecb..53bc0d58a0 100644 --- a/game/graphics/gfx.cpp +++ b/game/graphics/gfx.cpp @@ -6,11 +6,12 @@ #include #include "gfx.h" +#include "display.h" +#include "pipelines/opengl.h" + #include "common/log/log.h" #include "game/runtime.h" -#include "display.h" - -#include "pipelines/opengl.h" +#include "game/system/newpad.h" namespace { @@ -29,7 +30,14 @@ void InitSettings(GfxSettings& settings) { // debug for now settings.debug = true; - return; + // we're not setting controller info + settings.pad_mapping_info.input_mode = false; + // use buffered input mode + settings.pad_mapping_info.buffer_mode = true; + // debug input settings + settings.pad_mapping_info.debug = true; + // use a default mapping + Pad::DefaultMapping(settings.pad_mapping_info); } } // namespace @@ -57,6 +65,8 @@ u32 Init() { lg::info("GFX Init"); // initialize settings InitSettings(g_settings); + // guarantee we have no keys detected by pad + Pad::ForceClearKeys(); if (g_settings.renderer->init(g_settings)) { lg::error("Gfx::Init error"); @@ -75,6 +85,9 @@ u32 Init() { void Loop(std::function f) { lg::info("GFX Loop"); while (f()) { + // clean the inputs + Pad::ClearKeys(); + // check if we have a display if (Display::GetMainDisplay()) { // lg::debug("run display"); @@ -116,4 +129,8 @@ void texture_relocate(u32 destination, u32 source, u32 format) { } } +int PadIsPressed(Pad::Button button, int port) { + return Pad::IsPressed(g_settings.pad_mapping_info, button, port); +} + } // namespace Gfx diff --git a/game/graphics/gfx.h b/game/graphics/gfx.h index 54e2e7c077..aa81b4ed93 100644 --- a/game/graphics/gfx.h +++ b/game/graphics/gfx.h @@ -7,8 +7,10 @@ #include #include + #include "common/common_types.h" #include "game/kernel/kboot.h" +#include "game/system/newpad.h" // forward declarations struct GfxSettings; @@ -39,12 +41,15 @@ struct GfxRendererModule { struct GfxSettings { // current version of the settings. this should be set up so that newer versions are always higher // than older versions - static constexpr u64 CURRENT_VERSION = 0x0000'0000'00001'0001; + static constexpr u64 CURRENT_VERSION = 0x0000'0000'0002'0001; u64 version; // the version of this settings struct const GfxRendererModule* renderer; // which rendering pipeline to use. int vsync; // (temp) number of screen update per frame bool debug; // graphics debugging + + Pad::MappingInfo pad_mapping_info; // button mapping + Pad::MappingInfo pad_mapping_info_backup; // button mapping backup (see newpad.h) }; namespace Gfx { @@ -64,4 +69,6 @@ void send_chain(const void* data, u32 offset); void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr); void texture_relocate(u32 destination, u32 source, u32 format); +int PadIsPressed(Pad::Button button, int port); + } // namespace Gfx diff --git a/game/graphics/pipelines/opengl.cpp b/game/graphics/pipelines/opengl.cpp index 0c5d81dcc6..e91b050698 100644 --- a/game/graphics/pipelines/opengl.cpp +++ b/game/graphics/pipelines/opengl.cpp @@ -14,6 +14,7 @@ #include "game/graphics/opengl_renderer/OpenGLRenderer.h" #include "game/graphics/texture/TexturePool.h" #include "game/graphics/dma/dma_copy.h" +#include "game/system/newpad.h" #include "common/log/log.h" #include "common/goal_constants.h" #include "game/runtime.h" @@ -50,8 +51,10 @@ void SetDisplayCallbacks(GLFWwindow* d) { glfwSetKeyCallback(d, [](GLFWwindow* /*window*/, int key, int scancode, int action, int mods) { if (action == GlfwKeyAction::Press) { lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods); + Pad::OnKeyPress(key); } else if (action == GlfwKeyAction::Release) { lg::debug("KEY RELEASE: key: {} scancode: {} mods: {:X}", key, scancode, mods); + Pad::OnKeyRelease(key); } }); } diff --git a/game/kernel/kmachine.cpp b/game/kernel/kmachine.cpp index 7743d90e5e..08147155ad 100644 --- a/game/kernel/kmachine.cpp +++ b/game/kernel/kmachine.cpp @@ -409,27 +409,128 @@ void CacheFlush(void* mem, int size) { * Prints an error if it fails to open. */ u64 CPadOpen(u64 cpad_info, s32 pad_number) { - auto info = Ptr(cpad_info).c(); - if (info->cpad_file == 0) { + auto cpad = Ptr(cpad_info).c(); + if (cpad->cpad_file == 0) { // not open, so we will open it - info->cpad_file = + cpad->cpad_file = ee::scePadPortOpen(pad_number, 0, pad_dma_buf + pad_number * SCE_PAD_DMA_BUFFER_SIZE); - if (info->cpad_file < 1) { - MsgErr("dkernel: !open cpad #%d (%d)\n", pad_number, info->cpad_file); + if (cpad->cpad_file < 1) { + MsgErr("dkernel: !open cpad #%d (%d)\n", pad_number, cpad->cpad_file); } - info->new_pad = 1; - info->state = 0; + cpad->new_pad = 1; + cpad->state = 0; } return cpad_info; } // TODO CPadGetData -void CPadGetData() { - static bool warned = false; - if (!warned) { - lg::warn("ignoring calls to CPadGetData"); - warned = true; +Ptr CPadGetData(u64 cpad_info) { + auto cpad = Ptr(cpad_info).c(); + auto pad_state = scePadGetState(cpad->number, 0); + if (pad_state == scePadStateDiscon) { + cpad->state = 0; } + cpad->valid = pad_state | 0x80; + switch (cpad->state) { + // case 99: // functional + default: // controller is functioning as normal + if (pad_state == scePadStateStable || pad_state == scePadStateFindCTP1) { + scePadRead(cpad->number, 0, (u8*)cpad); + // ps2 controllers would send an enabled bit if the button was NOT pressed, but we don't do + // that here. removed code that flipped the bits. + + if (cpad->change_time != 0) { + scePadSetActDirect(cpad->number, 0, cpad->direct); + } + cpad->valid = pad_state; + } + break; + case 0: // unavailable + if (pad_state == scePadStateStable || pad_state == scePadStateFindCTP1) { + auto pad_mode = scePadInfoMode(cpad->number, 0, InfoModeCurID, 0); + if (pad_mode != 0) { + auto vibration_mode = scePadInfoMode(cpad->number, 0, InfoModeCurExID, 0); + if (vibration_mode > 0) { + // vibration supported + pad_mode = vibration_mode; + } + if (pad_mode == 4) { + // controller mode + cpad->state = 40; + } else if (pad_mode == 7) { + // dualshock mode + cpad->state = 70; + } else { + // who knows mode + cpad->state = 90; + } + } + } + break; + case 40: // controller mode - check for extra modes + cpad->change_time = 0; + if (scePadInfoMode(cpad->number, 0, InfoModeIdTable, -1) == 0) { + // no controller modes + cpad->state = 90; + return make_ptr(cpad); + } + cpad->state = 41; + case 41: // controller mode - change to dualshock mode! + // try to enter the 2nd controller mode (dualshock for ds2's) + if (scePadSetMainMode(cpad->number, 0, 1, 3) == 1) { + cpad->state = 42; + } + break; + case 42: // controller mode change check + if (scePadGetReqState(cpad->number, 0) == scePadReqStateFailed) { + // failed to change to DS2 + cpad->state = 41; + } + if (scePadGetReqState(cpad->number, 0) == scePadReqStateComplete) { + // change successful. go back to the beginning. + cpad->state = 0; + } + break; + case 70: // dualshock mode - check vibration + // get number of actuators (2 for DS2) + if (scePadInfoAct(cpad->number, 0, -1, 0) < 1) { + // no actuators means no vibration. skip to end! + cpad->change_time = 0; + cpad->state = 99; + } else { + // we have actuators to use. + cpad->change_time = 1; // remember to update vibration. + cpad->state = 75; + } + break; + case 75: // set actuator vib param info + if (scePadSetActAlign(cpad->number, 0, cpad->align) != 0) { + if (scePadInfoPressMode(cpad->number, 0) == 1) { + // pressure buttons supported + cpad->state = 76; + } else { + // no pressure buttons, done with controller setup + cpad->state = 99; + } + } + break; + case 76: // enter pressure mode + if (scePadEnterPressMode(cpad->number, 0) == 1) { + cpad->state = 78; + } + break; + case 78: // pressure mode request check + if (scePadGetReqState(cpad->number, 0) == 1) { + cpad->state = 76; + } + if (scePadGetReqState(cpad->number, 0) == 0) { + cpad->state = 99; + } + break; + case 90: + break; // unsupported controller. too bad! + } + return make_ptr(cpad); } // TODO InstallHandler diff --git a/game/kernel/kmachine.h b/game/kernel/kmachine.h index 6056c95e1f..092f8696b3 100644 --- a/game/kernel/kmachine.h +++ b/game/kernel/kmachine.h @@ -89,21 +89,33 @@ void CacheFlush(void* mem, int size); void InitMachineScheme(); //! Mirror of cpad-info -struct CpadInfo { +struct CPadInfo { u8 valid; u8 status; - s16 button0; - u8 rx; - u8 ry; - u8 lx; - u8 ly; + u16 button0; + u8 rightx; + u8 righty; + u8 leftx; + u8 lefty; u8 abutton[12]; u8 dummy[12]; s32 number; s32 cpad_file; - u8 _pad0[36]; + u32 button0_abs[3]; + u32 button0_shadow_abs[1]; + u32 button0_rel[3]; + float stick0_dir; + float stick0_speed; s32 new_pad; s32 state; + u8 align[6]; + u8 direct[6]; + u8 buzz_val[2]; + u8 __pad[2]; + u64 buzz_time[2]; + u32 buzz; + s32 buzz_act; + s32 change_time; // actually u64 in goal! }; struct FileStream { diff --git a/game/sce/libcdvd_ee.h b/game/sce/libcdvd_ee.h index 1fea511f7c..21b03278d1 100644 --- a/game/sce/libcdvd_ee.h +++ b/game/sce/libcdvd_ee.h @@ -5,9 +5,6 @@ * Stub implementation of the EE CD/DVD library */ -#ifndef JAK1_LIBCDVD_EE_H -#define JAK1_LIBCDVD_EE_H - // for sceCdInit #define SCECdINIT 0x00 @@ -34,5 +31,3 @@ int sceCdMmode(int media); int sceCdDiskReady(int mode); int sceCdGetDiskType(); } // namespace ee - -#endif // JAK1_LIBCDVD_EE_H diff --git a/game/sce/libpad.cpp b/game/sce/libpad.cpp index a263bb7028..5a8fee20a2 100644 --- a/game/sce/libpad.cpp +++ b/game/sce/libpad.cpp @@ -1,7 +1,16 @@ #include "common/util/assert.h" #include "libpad.h" +#include "game/kernel/kmachine.h" +#include "game/graphics/gfx.h" + +/*! + * @file libpad.h + * Stub implementation of the EE pad (controller) library + */ + namespace ee { + int scePadPortOpen(int port, int slot, void*) { // we are expected to return a non-zero file descriptor. // we return the port + 1 and succeed always. @@ -9,4 +18,114 @@ int scePadPortOpen(int port, int slot, void*) { assert(slot == 0); return port + 1; } + +int scePadGetState(int port, int slot) { + // pretend we always have a controller connected + return scePadStateStable; +} + +// controller mode array for DS2s +// the game will try very hard to force into dualshock mode so let's not even try +static const int libpad_DualShock2_ModeIDs[2] = { + (int)PadMode::Controller, // no vibration or pressure sensitive buttons + (int)PadMode::DualShock2 // vibration + pressure sensitive buttons +}; +int scePadInfoMode(int port, int slot, int term, int offs) { + if (term == InfoModeCurExID) { + // return vibration mode ID. that's just dualshock mode. + return libpad_DualShock2_ModeIDs[1]; + + } else if (term == InfoModeCurID) { + // return mode ID. just dualshock. + return libpad_DualShock2_ModeIDs[1]; + + } else if (term == InfoModeCurExOffs) { + // offset of current mode ID + return 1; + + } else if (term == InfoModeIdTable) { + if (offs == -1) + return 2; + + return libpad_DualShock2_ModeIDs[offs]; // ? + } + + // invalid controller or some other error + return 0; +} + +// order of pressure sensitive buttons in memory (not the same as their bit order...). +static const Pad::Button libpad_PadPressureButtons[] = { + Pad::Button::Right, Pad::Button::Left, Pad::Button::Up, Pad::Button::Down, + Pad::Button::Triangle, Pad::Button::Circle, Pad::Button::X, Pad::Button::Square, + Pad::Button::L1, Pad::Button::R1, Pad::Button::L2, Pad::Button::R2}; +// reads controller data and writes it to a buffer in rdata (must be at least 32 bytes large). +// returns buffer size (32) or 0 on error. +int scePadRead(int port, int slot, u8* rdata) { + auto cpad = (CPadInfo*)(rdata); + + cpad->valid = 0; // success + cpad->status = 0x70 /* (dualshock2) */ | (20 / 2); /* (dualshock2 data size) */ + + cpad->rightx = 0; + cpad->righty = 0; + cpad->leftx = 0; + cpad->lefty = 0; + + // pressure sensitivity. ignore for now. + for (int i = 0; i < 12; ++i) { + cpad->abutton[i] = Gfx::PadIsPressed(libpad_PadPressureButtons[i], port) * 255; + } + + cpad->button0 = 0; + for (int i = 0; i < 16; ++i) { + cpad->button0 |= Gfx::PadIsPressed((Pad::Button)i, port) << i; + } + + return 32; +} + +// buzzer control. We don't care right now, return success. +int scePadSetActDirect(int port, int slot, const u8* data) { + return 1; +} +int scePadSetActAlign(int port, int slot, const u8* data) { + return 1; +} + +// we also don't care +int scePadSetMainMode(int port, int slot, int offs, int lock) { + return 1; +} + +// async pad functions are gonna be synchronous so this always succeeds +int scePadGetReqState(int port, int slot) { + return scePadReqStateComplete; +} + +int scePadInfoAct(int port, int slot, int actno, int term) { + if (actno == -1) + return 2; // i think? + if (actno < 2) { + if (term == InfoActSub) { + return 1; // whatever + } else if (term == InfoActFunc) { + return 1; // whatever + } else if (term == InfoActSize) { + return 0; // whatever + } else if (term == InfoActCurr) { + return 1; // whatever + } + } + return 0; +} + +int scePadInfoPressMode(int port, int slot) { + return 0; // we do NOT support pressure sensitive buttons right now +} + +int scePadEnterPressMode(int port, int slot) { + return 1; // we dont support pressure button, but if we did this would work straight away +} + } // namespace ee diff --git a/game/sce/libpad.h b/game/sce/libpad.h index a2c80f60b7..04fa75dd01 100644 --- a/game/sce/libpad.h +++ b/game/sce/libpad.h @@ -1,7 +1,62 @@ #pragma once +/*! + * @file libpad.h + * Stub implementation of the EE pad (controller) library + */ + +#include "common/common_types.h" + #define SCE_PAD_DMA_BUFFER_SIZE 0x100 +// pad status +#define scePadStateDiscon 0 +#define scePadStateFindPad 1 +#define scePadStateFindCTP1 2 +#define scePadStateExecCmd 5 +#define scePadStateStable 6 +#define scePadStateError 7 +#define scePadStateClosed 99 + +// pad mode info checks +#define InfoModeCurID 1 +#define InfoModeCurExID 2 +#define InfoModeCurExOffs 3 +#define InfoModeIdTable 4 + +// pad async request states +#define scePadReqStateComplete 0 +#define scePadReqStateFaild 1 // lol +#define scePadReqStateFailed 1 +#define scePadReqStateBusy 2 + +// pad actuator info checks +#define InfoActFunc 1 +#define InfoActSub 2 +#define InfoActSize 3 +#define InfoActCurr 4 + namespace ee { + +// controller modes (not in the lib) +enum PadMode { + Controller = 4, + DualShock = 7, + DualShock2 = DualShock, + NeGcon = 2, + Joystick = 5, + NamcoGun = 6 +}; + int scePadPortOpen(int port, int slot, void* data); -} \ No newline at end of file +int scePadGetState(int port, int slot); +int scePadInfoMode(int port, int slot, int term, int offs); +int scePadRead(int port, int slot, u8* rdata); +int scePadSetActDirect(int port, int slot, const u8* data); +int scePadSetActAlign(int port, int slot, const u8* data); +int scePadSetMainMode(int port, int slot, int offs, int lock); +int scePadGetReqState(int port, int slot); +int scePadInfoAct(int port, int slot, int actno, int term); +int scePadInfoPressMode(int port, int slot); +int scePadEnterPressMode(int port, int slot); +} diff --git a/game/system/newpad.cpp b/game/system/newpad.cpp new file mode 100644 index 0000000000..834b962b20 --- /dev/null +++ b/game/system/newpad.cpp @@ -0,0 +1,114 @@ +/*! + * @file newpad.cpp + * PC-port specific cpad implementation on the C kernel. Monitors button inputs. + * Actual input detection is done through window events and is gfx pipeline-dependent. + */ + +#include "newpad.h" +#include "common/log/log.h" + +#include "game/graphics/pipelines/opengl.h" // for GLFW macros + +namespace Pad { + +/* +******************************** +* Key checking +******************************** +*/ + +std::unordered_map g_key_status; +std::unordered_map g_buffered_key_status; + +void ForceClearKeys() { + g_key_status.clear(); + g_buffered_key_status.clear(); +} + +void ClearKeys() { + for (auto& key : g_key_status) { + key.second = false; + } + for (auto& key : g_buffered_key_status) { + key.second = false; + } +} + +void OnKeyPress(int key) { + // set absolute key status + if (g_key_status.find(key) == g_key_status.end()) { + g_key_status.insert(std::make_pair(key, 1)); + } else { + g_key_status.at(key) = 1; + } + + // set buffered key status + if (g_buffered_key_status.find(key) == g_buffered_key_status.end()) { + g_buffered_key_status.insert(std::make_pair(key, 1)); + } else { + g_buffered_key_status.at(key) = 1; + } +} + +void OnKeyRelease(int key) { + // set absolute key status + // no bounds checking for now in order to catch bugs + g_key_status.at(key) = 0; +} + +/* +******************************** +* Pad checking +******************************** +*/ + +static int CheckPadIdx(int pad) { + if (pad < 0 || pad > CONTROLLER_COUNT) { + lg::error("Invalid pad {}, returning pad 0", pad); + } + return 0; +} + +// returns 1 if button is pressed. returns 0 if invalid or not pressed. +int IsPressed(MappingInfo& mapping, Button button, int pad = 0) { + auto key = mapping.pad_mapping[CheckPadIdx(pad)][(int)button]; + if (key == -1) + return 0; + auto& keymap = mapping.buffer_mode ? g_buffered_key_status : g_key_status; + if (keymap.find(key) == keymap.end()) + return 0; + return keymap.at(key); +} + +// map a button on a pad to a key +void MapButton(MappingInfo& mapping, Button button, int pad, int key) { + // check if pad is valid. dont map buttons with invalid pads. + if (CheckPadIdx(pad) != pad) + return; + + mapping.pad_mapping[pad][(int)button] = key; +} + +// reset button mappings +void DefaultMapping(MappingInfo& mapping) { + // make every button invalid + for (int p = 0; p < CONTROLLER_COUNT; ++p) { + for (int i = 0; i < (int)Button::Max; ++i) { + MapButton(mapping, (Button)i, p, -1); + } + } + + // face buttons + MapButton(mapping, Button::Ecks, 0, GLFW_KEY_Z); + MapButton(mapping, Button::Square, 0, GLFW_KEY_X); + MapButton(mapping, Button::Triangle, 0, GLFW_KEY_S); + MapButton(mapping, Button::Circle, 0, GLFW_KEY_A); + + // dpad + MapButton(mapping, Button::Up, 0, GLFW_KEY_UP); + MapButton(mapping, Button::Right, 0, GLFW_KEY_RIGHT); + MapButton(mapping, Button::Down, 0, GLFW_KEY_DOWN); + MapButton(mapping, Button::Left, 0, GLFW_KEY_LEFT); +} + +}; // namespace Pad diff --git a/game/system/newpad.h b/game/system/newpad.h new file mode 100644 index 0000000000..7d0d9b7e9a --- /dev/null +++ b/game/system/newpad.h @@ -0,0 +1,74 @@ +#pragma once + +/*! + * @file newpad.h + * PC-port specific cpad implementation on the C kernel. Monitors button inputs. + * Actual input detection is done through window events and is gfx pipeline-dependent. + */ + +/* NOTE ABOUT KEY VALUES! + * I am using the renderer-dependent key value macros here (at least for now). This means that the + * button mapping may be renderer-dependent. When changing renderers, make sure to backup the + * original button mapping or something so that the user can reset it afterwards. Eventually we + * should fix this (or maybe it's not even a problem). + */ + +#include + +namespace Pad { + +static constexpr int CONTROLLER_COUNT = 2; // support 2 controllers. + +// mirrors goal enum pad-buttons. used as indices to an array! +enum class Button { + Select = 0, + L3 = 1, + R3 = 2, + Start = 3, + + Up = 4, + Right = 5, + Down = 6, + Left = 7, + + L2 = 8, + R2 = 9, + L1 = 10, + R1 = 11, + + Triangle = 12, + Circle = 13, + X = 14, + Square = 15, + + Max = 16, + + // aliases + Ecks = X, + Cross = X, + O = Circle +}; + +struct MappingInfo { + bool debug = true; // debug mode + bool input_mode = false; // input mode for controller mapping + bool buffer_mode = true; // use buffered inputs + int pad_mapping[CONTROLLER_COUNT][(int)Pad::Button::Max]; // controller button mapping + // TODO complex button mapping & key macros (e.g. shift+x for l2+r2 press etc.) +}; + +// key-down status of any detected key. +extern std::unordered_map g_key_status; +// key-down status of any detected key. this is buffered for the remainder of a frame. +extern std::unordered_map g_buffered_key_status; + +void OnKeyPress(int key); +void OnKeyRelease(int key); +void ForceClearKeys(); +void ClearKeys(); + +void DefaultMapping(MappingInfo& mapping); +int IsPressed(MappingInfo& mapping, Button button, int pad); +void MapButton(MappingInfo& mapping, Button button, int pad, int key); + +} // namespace Pad diff --git a/goal_src/engine/load/loader.gc b/goal_src/engine/load/loader.gc index 857453dbc6..9b119d6374 100644 --- a/goal_src/engine/load/loader.gc +++ b/goal_src/engine/load/loader.gc @@ -214,7 +214,6 @@ (defmethod link-art! art-group ((obj art-group)) "Links the elements of this art-group." - ;; this check seems superfluous (when obj (countdown (s5-0 (-> obj length)) (let* ((art-elt (-> obj data s5-0)) diff --git a/goal_src/engine/ps2/pad.gc b/goal_src/engine/ps2/pad.gc index e8f9d93d65..d7ec50a5ac 100644 --- a/goal_src/engine/ps2/pad.gc +++ b/goal_src/engine/ps2/pad.gc @@ -30,7 +30,15 @@ (x 14) (square 15) ) - + +(defenum pad-type + (normal 4) + (analog 5) + (dualshock 7) + (negcon 2) + (namco-gun 6) + ) + ;; these forward declarations should probably go somewhere else... (define-extern get-current-time (function uint)) (define-extern get-integral-current-time (function uint)) @@ -38,16 +46,25 @@ ;; this gets set to #f later on. (define *cheat-mode* #t) -;; data that comes directly from hardware. +;; data that comes directly from hardware. it's 32 bytes + type tag (ignored in C kernel). (deftype hw-cpad (basic) - ((valid uint8 :offset-assert 4) - (status uint8 :offset-assert 5) - (button0 uint16 :offset-assert 6) - (rightx uint8 :offset-assert 8) - (righty uint8 :offset-assert 9) - (leftx uint8 :offset-assert 10) - (lefty uint8 :offset-assert 11) - (abutton uint8 12 :offset-assert 12) + (;; BASIC CONTROLLER data + ;; status = 0x40 | (data length / 2) + (valid uint8 :offset-assert 4) ;; 0 if success, 255 if fail + (status uint8 :offset-assert 5) ;; depends on controller + (button0 uint16 :offset-assert 6) ;; binary button states! + ;; DUALSHOCK or JOYSTICK data + ;; status (dualshock) = 0x70 | (data length / 2) + ;; status (joystick) = 0x50 | (data length / 2) + (rightx uint8 :offset-assert 8) ;; right stick xdir + (righty uint8 :offset-assert 9) ;; right stick ydir + (leftx uint8 :offset-assert 10) ;; left stick xdir + (lefty uint8 :offset-assert 11) ;; left stick ydir + ;; DUALSHOCK 2 data + ;; status = 0x70 | (data length / 2) + (abutton uint8 12 :offset-assert 12) ;; pressure sensitivity information + + ;; pad buffer needs to be 32 bytes large. (dummy uint8 12 :offset-assert 24) ) :method-count-assert 9 @@ -57,7 +74,7 @@ ;; data from hardware + additional info calculated here. (deftype cpad-info (hw-cpad) - ((number int32 :offset-assert 36) + ((number int32 :offset-assert 36) ;; controller port number (cpad-file int32 :offset-assert 40) (button0-abs pad-buttons 3 :offset-assert 44) ;; bitmask of buttons, pressed or not, with history (button0-shadow-abs pad-buttons 1 :offset-assert 56) ;; modify this to change button history in the future. @@ -66,7 +83,7 @@ (stick0-speed float :offset-assert 76) (new-pad int32 :offset-assert 80) (state int32 :offset-assert 84) - (align uint8 6 :offset-assert 88) + (align uint8 6 :offset-assert 88) ;; hardware control of buzzing. (direct uint8 6 :offset-assert 94) ;; hardware control of buzzing. (buzz-val uint8 2 :offset-assert 100) ;; intensity for buzzing (buzz-time uint64 2 :offset-assert 104) ;; when to stop buzzing @@ -82,6 +99,10 @@ :flag-assert #x900000088 ) +(defmacro cpad-type? (type) + `(= (shr (-> pad status) 4) (cpad-type ,type)) + ) + (defun cpad-invalid! ((pad cpad-info)) "Reset all data in a cpad-info" (logior! (-> pad valid) 128)