From 946b1fe53d3cef10b1db7bf827f3d21b4d787e32 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sun, 22 Jan 2023 11:01:03 +0100 Subject: [PATCH] Add mouse library --- README.md | 7 ++ include/c64/cia.c | 4 + include/c64/cia.h | 2 + include/c64/keyboard.c | 2 +- include/c64/mouse.c | 52 +++++++++ include/c64/mouse.h | 26 +++++ oscar64/CompilerTypes.h | 5 +- oscar64/NativeCodeGenerator.cpp | 2 +- oscar64/oscar64.cpp | 6 +- oscar64/oscar64.rc | 8 +- oscar64setup/oscar64setup.vdproj | 110 ++++++++++++++++++- samples/hiresmc/build.sh | 1 + samples/hiresmc/make.bat | 1 + samples/hiresmc/paint.c | 180 +++++++++++++++++++++++++++++++ samples/resources/mouse.spd | Bin 0 -> 1044 bytes 15 files changed, 394 insertions(+), 12 deletions(-) create mode 100644 include/c64/mouse.c create mode 100644 include/c64/mouse.h create mode 100644 samples/hiresmc/paint.c create mode 100644 samples/resources/mouse.spd diff --git a/README.md b/README.md index 6b9573c..daa21c9 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ The compiler is command line driven, and creates an executable .prg file. * -O2: more aggressive speed optimizations including auto inline of small functions * -O3: aggressive optimization for speed * -Os: optimize for size +* -Oi: enable auto inline of small functions (part of O2/O3) +* -Oa: optimize inline assembler (part of O2/O3) * -tf: target format, may be prg, crt or bin * -d64 : create a d64 disk image * -f : add a binary file to the disk image @@ -688,6 +690,11 @@ Similar to its hires counterpart but using different colors and patterns. Draws filled random circles and fills the space using flood fill. +#### Painting with mouse or joystick "paint.c" + +Paint on the screen with mouse or joystick. Keyboard 0..9 for color selection, HOME to clear the screen. + + #### 3D Function plotter "func3d.c" Similar to its hires counterpart but using four shades of grey. diff --git a/include/c64/cia.c b/include/c64/cia.c index a13c158..4ac9312 100644 --- a/include/c64/cia.c +++ b/include/c64/cia.c @@ -1,5 +1,7 @@ #include "cia.h" +byte ciaa_pra_def; + void cia_init(void) { cia1.icr = 0x7f; @@ -19,4 +21,6 @@ void cia_init(void) char i0 = cia1.icr; char i1 = cia2.icr; + + ciaa_pra_def = 0x7f; } diff --git a/include/c64/cia.h b/include/c64/cia.h index 5c18bdc..aebb71e 100644 --- a/include/c64/cia.h +++ b/include/c64/cia.h @@ -17,6 +17,8 @@ struct CIA #define cia1 (*((struct CIA *)0xdc00)) #define cia2 (*((struct CIA *)0xdd00)) +extern byte ciaa_pra_def; + void cia_init(void); #pragma compile("cia.c") diff --git a/include/c64/keyboard.c b/include/c64/keyboard.c index 062c0b8..d9a302f 100644 --- a/include/c64/keyboard.c +++ b/include/c64/keyboard.c @@ -96,5 +96,5 @@ void keyb_poll(void) } } - cia1.pra = 0xff; + cia1.pra = ciaa_pra_def; } diff --git a/include/c64/mouse.c b/include/c64/mouse.c new file mode 100644 index 0000000..5fcf93a --- /dev/null +++ b/include/c64/mouse.c @@ -0,0 +1,52 @@ +#include "mouse.h" +#include "sid.h" +#include "cia.h" + +sbyte mouse_dx, mouse_dy; +bool mouse_lb, mouse_rb; +static char mouse_px, mouse_py; +static char mouse_port; + +inline signed char dpos(char * old, char new) +{ + new = (new & 0x7f) >> 1; + + char diff = (new - *old) & 0x3f; + + if (diff >= 0x20) + { + *old = new; + return diff | 0xe0; + } + else if (diff) + { + *old = new; + return diff; + } + + return 0; +} + +void mouse_poll(void) +{ + char b = ((volatile char *)0xdc00)[mouse_port]; + mouse_rb = (b & 0x01) == 0; + mouse_lb = (b & 0x10) == 0; + + char x = sid.potx, y = sid.poty; + + mouse_dx = dpos(&mouse_px, x); + mouse_dy = dpos(&mouse_py, y); +} + +void mouse_arm(char n) +{ + mouse_port = n; + cia1.pra = ciaa_pra_def = n ? 0x7f : 0xbf; +} + +void mouse_init(void) +{ + mouse_arm(1); + mouse_poll(); +} diff --git a/include/c64/mouse.h b/include/c64/mouse.h new file mode 100644 index 0000000..144761b --- /dev/null +++ b/include/c64/mouse.h @@ -0,0 +1,26 @@ +#ifndef C64_MOUSE_H +#define C64_MOUSE_H + +#include "types.h" + +extern sbyte mouse_dx, mouse_dy; +extern bool mouse_lb, mouse_rb; + + +void mouse_init(void); + +// arm the potentiometer input for the selected mouse input +// needs ~4ms to stabilize + +void mouse_arm(char n); + +// poll mouse input for selected mouse, but the relative +// movement into mouse_dx/dy and the button state into +// mouse_lb/mouse_rb + +void mouse_poll(void); + +#pragma compile("mouse.c") + +#endif + diff --git a/oscar64/CompilerTypes.h b/oscar64/CompilerTypes.h index a293995..54fadfe 100644 --- a/oscar64/CompilerTypes.h +++ b/oscar64/CompilerTypes.h @@ -4,6 +4,7 @@ static const uint64 COPT_OPTIMIZE_BASIC = 0x00000001; static const uint64 COPT_OPTIMIZE_INLINE = 0x00000002; +static const uint64 COPT_OPTIMIZE_ASSEMBLER = 0x00000004; static const uint64 COPT_OPTIMIZE_AUTO_INLINE = 0x00000010; static const uint64 COPT_OPTIMIZE_AUTO_INLINE_ALL = 0x00000020; @@ -32,9 +33,9 @@ static const uint64 COPT_OPTIMIZE_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_ static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE; -static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS; +static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER; -static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS; +static const uint64 COPT_OPTIMIZE_ALL = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_INLINE_ALL | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER; struct CompilerSettings { diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index f37bdac..4133544 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -11533,7 +11533,7 @@ void NativeCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, NativeCodePro assert(ins->mSrc[0].mLinkerObject); - if (ins->mCode == IC_ASSEMBLER) + if (ins->mCode == IC_ASSEMBLER && (proc->mModule->mCompilerOptions & COPT_OPTIMIZE_ASSEMBLER)) { GrowingArray tains(NativeCodeInstruction(ASMIT_INV, ASMIM_IMPLIED)); diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp index dc6561c..81e1e9c 100644 --- a/oscar64/oscar64.cpp +++ b/oscar64/oscar64.cpp @@ -74,7 +74,7 @@ int main2(int argc, const char** argv) #else strcpy(strProductName, "oscar64"); - strcpy(strProductVersion, "1.14.181"); + strcpy(strProductVersion, "1.15.182"); #ifdef __APPLE__ uint32_t length = sizeof(basePath); @@ -178,6 +178,10 @@ int main2(int argc, const char** argv) compiler->mCompilerOptions |= COPT_OPTIMIZE_ALL; else if (arg[2] == 's') compiler->mCompilerOptions |= COPT_OPTIMIZE_SIZE; + else if (arg[2] == 'a') + compiler->mCompilerOptions |= COPT_OPTIMIZE_ASSEMBLER; + else if (arg[2] == 'i') + compiler->mCompilerOptions |= COPT_OPTIMIZE_AUTO_INLINE; } else if (arg[1] == 'e') { diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc index 0ab31f2..5c563a2 100644 --- a/oscar64/oscar64.rc +++ b/oscar64/oscar64.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,14,181,0 - PRODUCTVERSION 1,14,181,0 + FILEVERSION 1,15,182,0 + PRODUCTVERSION 1,15,182,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,12 +43,12 @@ BEGIN BEGIN VALUE "CompanyName", "oscar64" VALUE "FileDescription", "oscar64 compiler" - VALUE "FileVersion", "1.14.181.0" + VALUE "FileVersion", "1.15.182.0" VALUE "InternalName", "oscar64.exe" VALUE "LegalCopyright", "Copyright (C) 2021" VALUE "OriginalFilename", "oscar64.exe" VALUE "ProductName", "oscar64" - VALUE "ProductVersion", "1.14.181.0" + VALUE "ProductVersion", "1.15.182.0" END END BLOCK "VarFileInfo" diff --git a/oscar64setup/oscar64setup.vdproj b/oscar64setup/oscar64setup.vdproj index 9e8cd3f..f19991a 100644 --- a/oscar64setup/oscar64setup.vdproj +++ b/oscar64setup/oscar64setup.vdproj @@ -46,6 +46,12 @@ } "Entry" { + "MsmKey" = "8:_06971480436546E1B12DDC7EC9F704FD" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_0819C3D33D0942EF9E319C754E6C43D8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -496,6 +502,12 @@ } "Entry" { + "MsmKey" = "8:_8E57961EDF0840A7A08877E8ED4826BC" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_8EBEED55D3F142769DE0A0014758447D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -790,6 +802,12 @@ } "Entry" { + "MsmKey" = "8:_D52B954DFBCE4EB0932433DE7FCE9090" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_D76DA8C7D3964C93ABE193A7B53A0A9B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -808,6 +826,12 @@ } "Entry" { + "MsmKey" = "8:_D9089340F2BF445B85880C886B30D7B7" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { "MsmKey" = "8:_DA28A07E7836459C99161100D7C102B8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" @@ -1143,6 +1167,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_06971480436546E1B12DDC7EC9F704FD" + { + "SourcePath" = "8:..\\samples\\resources\\mouse.spd" + "TargetName" = "8:mouse.spd" + "Tag" = "8:" + "Folder" = "8:_758C6547998745659548D0656D380FEA" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0819C3D33D0942EF9E319C754E6C43D8" { "SourcePath" = "8:..\\include\\gfx\\bitmap.h" @@ -2643,6 +2687,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E57961EDF0840A7A08877E8ED4826BC" + { + "SourcePath" = "8:..\\include\\c64\\mouse.h" + "TargetName" = "8:mouse.h" + "Tag" = "8:" + "Folder" = "8:_247D4CAD3CB843B3A8A4DC2D90F47C28" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8EBEED55D3F142769DE0A0014758447D" { "SourcePath" = "8:..\\samples\\particles\\fireworks_hires.c" @@ -3623,6 +3687,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D52B954DFBCE4EB0932433DE7FCE9090" + { + "SourcePath" = "8:..\\samples\\hiresmc\\paint.c" + "TargetName" = "8:paint.c" + "Tag" = "8:" + "Folder" = "8:_3E74C69B2EF64E938EA60950128C5A74" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D76DA8C7D3964C93ABE193A7B53A0A9B" { "SourcePath" = "8:..\\samples\\stdio\\make.bat" @@ -3683,6 +3767,26 @@ "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D9089340F2BF445B85880C886B30D7B7" + { + "SourcePath" = "8:..\\include\\c64\\mouse.c" + "TargetName" = "8:mouse.c" + "Tag" = "8:" + "Folder" = "8:_247D4CAD3CB843B3A8A4DC2D90F47C28" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DA28A07E7836459C99161100D7C102B8" { "SourcePath" = "8:..\\include\\c64\\memmap.h" @@ -4450,15 +4554,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:oscar64" - "ProductCode" = "8:{F041F169-30F1-469E-BB7C-E316C7A562B5}" - "PackageCode" = "8:{B0EC0EC4-A9FC-496F-B024-6515FEB53CC0}" + "ProductCode" = "8:{D9D7E97A-B793-4546-B204-9518010E2DB9}" + "PackageCode" = "8:{40E0B5C5-53B2-4285-802B-FBA08B4E661D}" "UpgradeCode" = "8:{9AB61EFF-ACAC-4079-9950-8D96615CD4EF}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.14.181" + "ProductVersion" = "8:1.15.182" "Manufacturer" = "8:oscar64" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" diff --git a/samples/hiresmc/build.sh b/samples/hiresmc/build.sh index cb79ae9..f4fe227 100644 --- a/samples/hiresmc/build.sh +++ b/samples/hiresmc/build.sh @@ -2,3 +2,4 @@ ../../bin/oscar64 func3d.c -n ../../bin/oscar64 polygon.c -n ../../bin/oscar64 floodfill.c -n +../../bin/oscar64 paint.c -n diff --git a/samples/hiresmc/make.bat b/samples/hiresmc/make.bat index d146567..1ddc9f3 100644 --- a/samples/hiresmc/make.bat +++ b/samples/hiresmc/make.bat @@ -1,3 +1,4 @@ call ..\..\bin\oscar64 floodfill.c -n call ..\..\bin\oscar64 polygon.c -n call ..\..\bin\oscar64 func3d.c -n +call ..\..\bin\oscar64 paint.c -n diff --git a/samples/hiresmc/paint.c b/samples/hiresmc/paint.c new file mode 100644 index 0000000..921d66a --- /dev/null +++ b/samples/hiresmc/paint.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma region(main, 0x0880, 0xd000, , , {code, data, bss, heap, stack} ) + +static char * const Color1 = (char *)0xd000; +static char * const Color2 = (char *)0xd800; +static char * const Hires = (char *)0xe000; +static char * const Sprites = (char *)0xd800; + +const char MouseSpriteData[] = { + #embed spd_sprites lzo "../resources/mouse.spd" +}; + +Bitmap sbm; +ClipRect scr = { 0, 0, 320, 200 }; + +void init(void) +{ + // Install IRQ trampoline + mmap_trampoline(); + + // All RAM + mmap_set(MMAP_RAM); + + // Init hires mem, and resources + memset(Color1, 0x67, 1000); + memset(Hires, 0, 8000); + oscar_expand_lzo(Sprites, MouseSpriteData); + + // Sprite image for cursor + Color1[0x3f8] = 97; + Color1[0x3f9] = 96; + + // Enable IO space + mmap_set(MMAP_NO_ROM); + + // Clear color RAM + memset(Color2, 0x02, 1000); + + // Set screen + vic.color_back = VCOL_BLACK; + vic.color_border = VCOL_BLACK; + vic_setmode(VICM_HIRES_MC, Color1, Hires); + + // Init mouse cursor + spr_show(0, true); + spr_show(1, true); + spr_color(0, VCOL_BLACK); + spr_color(1, VCOL_WHITE); + spr_move(0, 24, 50); + spr_move(1, 24, 50); + + // Disable system interrupt and init mouse + cia_init(); + mouse_init(); + + bm_init(&sbm, Hires, 40, 25); +} + +int mouse_x, mouse_y; + +bool mouse_move(void) +{ + // Poll mouse and joystick for backup + joy_poll(0); + mouse_poll(); + + // New mouse cursor position + int mx = mouse_x + (signed char)(joyx[0] + mouse_dx); + int my = mouse_y + (signed char)(joyy[0] - mouse_dy); + + // Clip to screen + if (mx < 0) + mx = 0; + else if (mx > 319) + mx = 319; + if (my < 0) + my = 0; + else if (my > 199) + my = 199; + + // Check if moved + if (mx != mouse_x || my != mouse_y) + { + mouse_x = mx; + mouse_y = my; + + // Update cursor sprite + spr_move(0, mx + 24, my + 50); + spr_move(1, mx + 24, my + 50); + + return true; + } + + return false; +} + +int main(void) +{ + init(); + + char c0 = 1, c1 = 1; + + for(;;) + { + // Check if mouse moved + if (mouse_move()) + { + // Paint a circle at the mouse position, if mouse was moved + + if (mouse_lb || joyb[0]) + bmmc_circle_fill(&sbm, &scr, mouse_x, mouse_y, 5, MixedColors[c0][c1]); + else if (mouse_rb) + bmmc_circle_fill(&sbm, &scr, mouse_x, mouse_y, 5, MixedColors[0][0]); + } + + // Poll the keyboard + keyb_poll(); + + switch (keyb_key) + { + // Clear screen + case KSCAN_HOME + KSCAN_QUAL_DOWN: + bmmcu_rect_fill(&sbm, 0, 0, 320, 200, 0); + break; + + // Select color with 0..9 + case KSCAN_0 + KSCAN_QUAL_DOWN: + c0 = 0; c1 = 0; + break; + case KSCAN_1 + KSCAN_QUAL_DOWN: + c0 = 1; c1 = 1; + break; + case KSCAN_2 + KSCAN_QUAL_DOWN: + c0 = 2; c1 = 2; + break; + case KSCAN_3 + KSCAN_QUAL_DOWN: + c0 = 3; c1 = 3; + break; + + case KSCAN_4 + KSCAN_QUAL_DOWN: + c0 = 1; c1 = 0; + break; + case KSCAN_5 + KSCAN_QUAL_DOWN: + c0 = 1; c1 = 2; + break; + case KSCAN_6 + KSCAN_QUAL_DOWN: + c0 = 1; c1 = 3; + break; + case KSCAN_7 + KSCAN_QUAL_DOWN: + c0 = 2; c1 = 0; + break; + case KSCAN_8 + KSCAN_QUAL_DOWN: + c0 = 2; c1 = 3; + break; + case KSCAN_9 + KSCAN_QUAL_DOWN: + c0 = 3; c1 = 0; + break; + + // Flood fill + case KSCAN_F + KSCAN_QUAL_DOWN: + bmmc_flood_fill(&sbm, &scr, mouse_x, mouse_y, c0); + break; + } + + // Wait one frame + vic_waitFrame(); + } + + return 0; +} diff --git a/samples/resources/mouse.spd b/samples/resources/mouse.spd new file mode 100644 index 0000000000000000000000000000000000000000..d301b307c50d8d68865e2a7295852f4dc9fca4af GIT binary patch literal 1044 zcmWFzaA9Q-V1NKl21Z5(MiBc01H&H%2Kxi3=mP`)2L|R33=9XL8nA+?4;UEcFfcSX zFdQgga4=wSNMJ~CU{FwCP!M1+<6w}NV36FvAn<^J!2zpwia{%dCXDK*42*^!WnjR= F4*>Of8|eT5 literal 0 HcmV?d00001