diff --git a/.travis.yml b/.travis.yml index eecc593..a4eca52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,3 +14,4 @@ matrix: apt: packages: - libgtk-3-dev + - libasound2-dev diff --git a/3rd-party b/3rd-party index 04a806d..1ff2bf5 160000 --- a/3rd-party +++ b/3rd-party @@ -1 +1 @@ -Subproject commit 04a806d1e670de80e60ef4bc43a9bf9ffe5529ce +Subproject commit 1ff2bf5d723072b26d87a7f50c0b73a3604f4584 diff --git a/CMakeLists.txt b/CMakeLists.txt index ec3092a..4ec6a58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,10 @@ target_include_directories(tic80core PRIVATE 3rd-party/fennel) add_dependencies(tic80core lua lpeg wren squirrel giflib) target_link_libraries(tic80core lua lpeg wren squirrel giflib) +if(LINUX) + target_link_libraries(tic80core m) +endif() + ################################ # SDL2 ################################ @@ -239,7 +243,7 @@ endif() if(NOT EMSCRIPTEN) set(EXAMPLE_DIR examples) set(EXAMPLE_SRC - ${EXAMPLE_DIR}/sdl-renderer.c + ${EXAMPLE_DIR}/sdl/main.c ) if(WIN32) @@ -260,6 +264,77 @@ if(NOT EMSCRIPTEN) target_link_libraries(sdl-renderer tic80core SDL2-static SDL2main) endif() +################################ +# Sokol +################################ + +set(SOKOL_LIB_SRC src/system/sokol_gfx.c) + +if(APPLE) + set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} src/system/sokol_impl.m) +else() + set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} src/system/sokol_impl.c) +endif() + +add_library(sokol ${SOKOL_LIB_SRC}) + +if(APPLE) + target_compile_definitions(sokol PRIVATE SOKOL_METAL) +elseif(WIN32) + target_compile_definitions(sokol PRIVATE SOKOL_D3D11 SOKOL_D3D11_SHADER_COMPILER) +elseif(LINUX) + target_compile_definitions(sokol PRIVATE SOKOL_GLCORE33) +endif() + +if(APPLE) + set_property (TARGET sokol APPEND_STRING PROPERTY + COMPILE_FLAGS "-fobjc-arc") + + target_link_libraries(sokol + "-framework Cocoa" + "-framework QuartzCore" + "-framework Metal" + "-framework MetalKit" + "-framework AudioToolbox" + ) +elseif(WIN32) + target_link_libraries(sokol D3D11) + + if(MINGW) + target_link_libraries(sokol D3dcompiler_47) + endif() +elseif(LINUX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") + target_link_libraries(sokol X11 GL m dl asound) +endif() + +target_include_directories(sokol PRIVATE 3rd-party/sokol) + +################################ +# Sokol renderer example +################################ + +set(SOKOL_SRC + ${EXAMPLE_DIR}/sokol/main.c +) + +if(WIN32) + add_executable(sokol-renderer WIN32 ${SOKOL_SRC}) +else() + add_executable(sokol-renderer ${SOKOL_SRC}) +endif() + +if(MINGW) + target_link_libraries(sokol-renderer mingw32) +endif() + +target_include_directories(sokol-renderer PRIVATE include) +target_include_directories(sokol-renderer PRIVATE 3rd-party/sokol) +target_include_directories(sokol-renderer PRIVATE src) + +add_dependencies(sokol-renderer tic80core sokol) +target_link_libraries(sokol-renderer tic80core sokol) + ################################ # SDL GPU ################################ @@ -445,22 +520,24 @@ target_compile_definitions(tic80prolib PRIVATE TIC80_PRO) # TIC-80 app ################################ -set(TIC80_DIR src) -set(TIC80_SRC - ${TIC80_DIR}/net.c - ${TIC80_DIR}/system.c - ${TIC80_DIR}/ext/file_dialog.c -) - -if(APPLE) - set(TIC80_SRC ${TIC80_SRC} ${TIC80_DIR}/ext/file_dialog.m) -endif() - foreach(TIC80_OUTPUT ${TIC80_OUTPUTS}) + set(TIC80_SRC src/ext/file_dialog.c) + + if(APPLE) + set(TIC80_SRC ${TIC80_SRC} src/ext/file_dialog.m) + endif() + + set(TIC80_SRC ${TIC80_SRC} src/net.c src/system/sdlgpu.c) + if(WIN32) set(TIC80_SRC ${TIC80_SRC} build/windows/tic80.rc) - add_executable(${TIC80_OUTPUT} WIN32 ${TIC80_SRC}) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + else() + set(SYSTEM_TYPE WIN32) + endif() + + add_executable(${TIC80_OUTPUT} ${SYSTEM_TYPE} ${TIC80_SRC}) elseif(APPLE) add_executable(${TIC80_OUTPUT} MACOSX_BUNDLE ${TIC80_SRC} build/macosx/tic80.icns) set_source_files_properties(build/macosx/tic80.icns PROPERTIES MACOSX_PACKAGE_LOCATION RESOURCES) @@ -470,9 +547,11 @@ foreach(TIC80_OUTPUT ${TIC80_OUTPUTS}) endif() target_include_directories(${TIC80_OUTPUT} PRIVATE include) - target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/SDL2-2.0.8/include) - target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/sdl-gpu/include) + target_include_directories(${TIC80_OUTPUT} PRIVATE src) target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/SDL2_net-2.0.1) + target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/SDL2-2.0.8/include) + + target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/sdl-gpu/include) if(MINGW) target_link_libraries(${TIC80_OUTPUT} mingw32) @@ -498,4 +577,63 @@ foreach(TIC80_OUTPUT ${TIC80_OUTPUTS}) target_link_libraries(${TIC80_OUTPUT} ${GTK_LIBRARIES}) endif() -endforeach() \ No newline at end of file +endforeach() + + +################################ +# TIC-80 app (Sokol) +################################ + +foreach(TIC80_OUTPUT ${TIC80_OUTPUTS}) + + set(TIC80_SRC src/ext/file_dialog.c) + + if(APPLE) + set(TIC80_SRC ${TIC80_SRC} src/ext/file_dialog.m) + endif() + + set(TIC80_SRC ${TIC80_SRC} src/system/sokol.c) + + if(WIN32) + set(TIC80_SRC ${TIC80_SRC} build/windows/tic80.rc) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + else() + set(SYSTEM_TYPE WIN32) + endif() + + add_executable(${TIC80_OUTPUT}-sokol ${SYSTEM_TYPE} ${TIC80_SRC}) + elseif(APPLE) + add_executable(${TIC80_OUTPUT}-sokol MACOSX_BUNDLE ${TIC80_SRC} build/macosx/tic80.icns) + set_source_files_properties(build/macosx/tic80.icns PROPERTIES MACOSX_PACKAGE_LOCATION RESOURCES) + set_target_properties(${TIC80_OUTPUT}-sokol PROPERTIES MACOSX_BUNDLE_INFO_PLIST build/macosx/${TIC80_OUTPUT}-sokol.plist) + else() + add_executable(${TIC80_OUTPUT}-sokol ${TIC80_SRC}) + endif() + + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE include) + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE src) + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/SDL2_net-2.0.1) + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/SDL2-2.0.8/include) + + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/sokol) + + if(MINGW) + target_link_libraries(${TIC80_OUTPUT}-sokol mingw32) + endif() + + add_dependencies(${TIC80_OUTPUT}-sokol ${TIC80_OUTPUT}lib sokol) + target_link_libraries(${TIC80_OUTPUT}-sokol ${TIC80_OUTPUT}lib sokol) + + if(LINUX) + include(FindPkgConfig) + if(NOT PKG_CONFIG_FOUND) + message(FATAL_ERROR "We need pkg-config to compile this project") + endif() + + pkg_check_modules(GTK REQUIRED gtk+-3.0) + + target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE ${GTK_INCLUDE_DIRS}) + target_link_libraries(${TIC80_OUTPUT}-sokol ${GTK_LIBRARIES}) + endif() + +endforeach() diff --git a/appveyor.yml b/appveyor.yml index 070e3c6..b3afa11 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,22 +1,18 @@ version: '{build}' -image: Visual Studio 2017 - -configuration: -- Release - -platform: -- x64 +image: Visual Studio 2015 environment: matrix: - - arch: Win64 + - COMPILER: MSVC + - COMPILER: MSVC64 + - COMPILER: MinGW-w64 -install: git submodule update --init --recursive +install: + - git submodule update --init --recursive + - if [%COMPILER%]==[MinGW-w64] set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH% -before_build: - cmd: cmake -G "Visual Studio 15 2017 Win64" - -build: - project: c:\projects\tic-80\TIC-80.sln - verbosity: minimal - parallel: true +build_script: + - if [%COMPILER%]==[MinGW-w64] cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_SH=CMAKE_SH-NOTFOUND . + - if [%COMPILER%]==[MSVC] cmake -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=MinSizeRel . + - if [%COMPILER%]==[MSVC64] cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=MinSizeRel . + - cmake --build . diff --git a/build/macosx/tic80-sokol.plist b/build/macosx/tic80-sokol.plist new file mode 100644 index 0000000..509183f --- /dev/null +++ b/build/macosx/tic80-sokol.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + TIC-80 Sokol + CFBundleExecutable + tic80-sokol + CFBundleIconFile + tic80.icns + CFBundleIdentifier + com.nesbox.tic + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TIC-80 Sokol + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.70.6 + CFBundleVersion + 0.70.6 + NSHumanReadableCopyright + http://tic.computer © 2017 + NSHighResolutionCapable + + + diff --git a/build/macosx/tic80pro-sokol.plist b/build/macosx/tic80pro-sokol.plist new file mode 100644 index 0000000..d617494 --- /dev/null +++ b/build/macosx/tic80pro-sokol.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + TIC-80 Pro Sokol + CFBundleExecutable + tic80pro-sokol + CFBundleIconFile + tic80.icns + CFBundleIdentifier + com.nesbox.tic + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TIC-80 Pro Sokol + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.70.6 + CFBundleVersion + 0.70.6 + NSHumanReadableCopyright + http://tic.computer © 2017 + NSHighResolutionCapable + + + diff --git a/examples/makefile b/examples/makefile deleted file mode 100644 index 17b4405..0000000 --- a/examples/makefile +++ /dev/null @@ -1,23 +0,0 @@ -CC=gcc -OPT=-O3 -Wall -std=c99 -INCLUDES= \ - -I../include \ - -I../include/sdl2 \ - -I../include/tic80 - -LINKER_FLAGS= \ - -L../lib/mingw \ - -L../bin \ - -ltic80 \ - -lmingw32 -lSDL2main -lSDL2.dll \ - -mwindows - -SOURCES=\ - sdl-renderer.c - -SDL_RENDERER = ../bin/sdl-renderer.exe - -all: $(SDL_RENDERER) - -$(SDL_RENDERER): $(SOURCES) - $(CC) $(INCLUDES) $< $(OPT) $(LINKER_FLAGS) -o $@ diff --git a/examples/sdl-renderer.c b/examples/sdl/main.c similarity index 100% rename from examples/sdl-renderer.c rename to examples/sdl/main.c diff --git a/examples/sokol/main.c b/examples/sokol/main.c new file mode 100644 index 0000000..4700cb8 --- /dev/null +++ b/examples/sokol/main.c @@ -0,0 +1,119 @@ +#include "system/sokol.h" + +#include +#include +#include +#include + +#include + +static tic80* tic = NULL; + +static void app_init(void) +{ + saudio_desc desc = {0}; + desc.num_channels = 2; + saudio_setup(&desc); + + FILE* file = fopen("cart.tic", "rb"); + + if(file) + { + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, 0, SEEK_SET); + + void* cart = malloc(size); + if(cart) fread(cart, size, 1, file); + fclose(file); + + if(cart) + { + printf("%s\n", "cart loaded"); + tic = tic80_create(saudio_sample_rate()); + + if(tic) + { + printf("%s\n", "tic created"); + tic80_load(tic, cart, size); + } + } + } + + sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1, false, false); +} + +static tic80_input tic_input; + +static void app_frame(void) +{ + if(tic) + tic80_tick(tic, tic_input); + + sokol_gfx_draw(tic->screen); + + static float floatSamples[44100 / 60 * 2]; + + for(s32 i = 0; i < tic->sound.count; i++) + floatSamples[i] = (float)tic->sound.samples[i] / SHRT_MAX; + + saudio_push(floatSamples, tic->sound.count / 2); +} + +static void app_input(const sapp_event* event) +{ + static const sapp_keycode Keys[] = + { + SAPP_KEYCODE_UP, + SAPP_KEYCODE_DOWN, + SAPP_KEYCODE_LEFT, + SAPP_KEYCODE_RIGHT, + + SAPP_KEYCODE_Z, + SAPP_KEYCODE_X, + SAPP_KEYCODE_A, + SAPP_KEYCODE_S, + }; + + switch (event->type) + { + case SAPP_EVENTTYPE_KEY_DOWN: + case SAPP_EVENTTYPE_KEY_UP: + + for (int i = 0; i < sizeof Keys / sizeof Keys[0]; i++) + { + if (event->key_code == Keys[i]) + { + if(event->type == SAPP_EVENTTYPE_KEY_DOWN) + tic_input.gamepads.first.data |= (1 << i); + else + tic_input.gamepads.first.data &= ~(1 << i); + } + } + break; + default: + break; + } +} + +static void app_cleanup(void) +{ + if(tic) + tic80_delete(tic); + + sg_shutdown(); +} + +sapp_desc sokol_main(int argc, char* argv[]) { + // args_init(argc, argv); + return (sapp_desc) { + .init_cb = app_init, + .frame_cb = app_frame, + .event_cb = app_input, + .cleanup_cb = app_cleanup, + .width = 3 * TIC80_FULLWIDTH, + .height = 3 * TIC80_FULLHEIGHT, + .window_title = "TIC-80 with Sokol renderer", + .ios_keyboard_resizes_canvas = true + }; +} diff --git a/include/tic80_config.h b/include/tic80_config.h index b64c721..8794620 100644 --- a/include/tic80_config.h +++ b/include/tic80_config.h @@ -22,6 +22,12 @@ #pragma once +#if !defined(TIC_BUILD_WITH_LUA) && \ + !defined(TIC_BUILD_WITH_MOON) && \ + !defined(TIC_BUILD_WITH_FENNEL) && \ + !defined(TIC_BUILD_WITH_JS) && \ + !defined(TIC_BUILD_WITH_WREN) + #define TIC_BUILD_WITH_LUA 1 #define TIC_BUILD_WITH_MOON 1 #define TIC_BUILD_WITH_FENNEL 1 @@ -29,6 +35,8 @@ #define TIC_BUILD_WITH_WREN 1 #define TIC_BUILD_WITH_SQUIRREL 1 +#endif + #if defined(__APPLE__) // TODO: this disables macos config # include "AvailabilityMacros.h" diff --git a/src/ext/file_dialog.c b/src/ext/file_dialog.c index ed13edc..68842bf 100644 --- a/src/ext/file_dialog.c +++ b/src/ext/file_dialog.c @@ -22,9 +22,9 @@ #include "file_dialog.h" -#include +#include -#if defined(__WINDOWS__) +#if defined(__TIC_WINDOWS__) #include #include @@ -36,7 +36,7 @@ wchar_t* wcscpy(wchar_t *, const wchar_t *); void file_dialog_load(file_dialog_load_callback callback, void* data) { OPENFILENAMEW ofn; - SDL_zero(ofn); + memset(&ofn, 0, sizeof ofn); wchar_t filename[MAX_PATH]; memset(filename, 0, sizeof(filename)); @@ -83,7 +83,7 @@ void file_dialog_load(file_dialog_load_callback callback, void* data) void file_dialog_save(file_dialog_save_callback callback, const char* name, const u8* buffer, size_t size, void* data, u32 mode) { OPENFILENAMEW ofn; - SDL_zero(ofn); + memset(&ofn, 0, sizeof ofn); wchar_t filename[MAX_PATH]; mbstowcs(filename, name, MAX_PATH); @@ -102,7 +102,7 @@ void file_dialog_save(file_dialog_save_callback callback, const char* name, cons fwrite(buffer, 1, size, file); fclose(file); -#if !defined(__WINDOWS__) +#if !defined(__TIC_WINDOWS__) chmod(filename, mode); #endif callback(true, data); @@ -157,7 +157,7 @@ void file_dialog_save(file_dialog_save_callback callback, const char* name, cons callback(true, data); } -#elif defined(__LINUX__) +#elif defined(__TIC_LINUX__) #include #include @@ -267,7 +267,7 @@ void file_dialog_save(file_dialog_save_callback callback, const char* name, cons callback(false, data); } -#elif defined(__MACOSX__) +#elif defined(__TIC_MACOSX__) #include #include @@ -345,7 +345,7 @@ void file_dialog_save(file_dialog_save_callback callback, const char* name, cons callback(false, data); } -#elif defined(__ANDROID__) +#elif defined(__TIC_ANDROID__) #include #include diff --git a/src/system.h b/src/system.h index 7473064..ad718ba 100644 --- a/src/system.h +++ b/src/system.h @@ -3,6 +3,9 @@ #include "ticapi.h" #include "ext/file_dialog.h" +#define TIC80_OFFSET_LEFT ((TIC80_FULLWIDTH-TIC80_WIDTH)/2) +#define TIC80_OFFSET_TOP ((TIC80_FULLHEIGHT-TIC80_HEIGHT)/2) + typedef struct { void (*setClipboardText)(const char* text); diff --git a/src/system/chip.c b/src/system/chip.c deleted file mode 100644 index e961d40..0000000 --- a/src/system/chip.c +++ /dev/null @@ -1,683 +0,0 @@ -#include "../system.h" -#include "../net.h" -#include "../tools.h" - -#include -#include -#include -#include - -#define STUDIO_UI_SCALE 2 -#define STUDIO_PIXEL_FORMAT SDL_PIXELFORMAT_ABGR8888 -#define TEXTURE_SIZE (TIC80_FULLWIDTH) -#define OFFSET_LEFT ((TIC80_FULLWIDTH-TIC80_WIDTH)/2) -#define OFFSET_TOP ((TIC80_FULLHEIGHT-TIC80_HEIGHT)/2) - -static struct -{ - Studio* studio; - - - SDL_Window* window; - SDL_Renderer* renderer; - SDL_Texture* texture; - - struct - { - SDL_Joystick* ports[TIC_GAMEPADS]; - tic80_gamepads joystick; - } gamepad; - - struct - { - SDL_Texture* texture; - const u8* src; - } mouse; - - Net* net; - - struct - { - SDL_AudioSpec spec; - SDL_AudioDeviceID device; - SDL_AudioCVT cvt; - } audio; -} platform; - -static void initSound() -{ - SDL_AudioSpec want = - { - .freq = 44100, - .format = AUDIO_S16, - .channels = 1, - .userdata = NULL, - }; - - platform.audio.device = SDL_OpenAudioDevice(NULL, 0, &want, &platform.audio.spec, SDL_AUDIO_ALLOW_ANY_CHANGE); - - SDL_BuildAudioCVT(&platform.audio.cvt, want.format, want.channels, platform.audio.spec.freq, platform.audio.spec.format, platform.audio.spec.channels, platform.audio.spec.freq); - - if(platform.audio.cvt.needed) - { - platform.audio.cvt.len = platform.audio.spec.freq * sizeof(s16) / TIC_FRAMERATE; - platform.audio.cvt.buf = SDL_malloc(platform.audio.cvt.len * platform.audio.cvt.len_mult); - } -} - -static u8* getSpritePtr(tic_tile* tiles, s32 x, s32 y) -{ - enum { SheetCols = (TIC_SPRITESHEET_SIZE / TIC_SPRITESIZE) }; - return tiles[x / TIC_SPRITESIZE + y / TIC_SPRITESIZE * SheetCols].data; -} - -static u8 getSpritePixel(tic_tile* tiles, s32 x, s32 y) -{ - return tic_tool_peek4(getSpritePtr(tiles, x, y), (x % TIC_SPRITESIZE) + (y % TIC_SPRITESIZE) * TIC_SPRITESIZE); -} - -static void calcTextureRect(SDL_Rect* rect) -{ - SDL_GetWindowSize(platform.window, &rect->w, &rect->h); - - { - enum{Width = TIC80_WIDTH, Height = TIC80_HEIGHT}; - - s32 discreteHeight = rect->h - rect->h % Height; - s32 discreteWidth = Width * discreteHeight / Height; - - rect->x = (rect->w - discreteWidth) / 2; - rect->y = (rect->h - discreteHeight) / 2; - - rect->w = discreteWidth; - rect->h = discreteHeight; - } -} - -static void processMouse() -{ - s32 mx = 0, my = 0; - s32 mb = SDL_GetMouseState(&mx, &my); - - tic80_input* input = &platform.studio->tic->ram.input; - - { - input->mouse.x = input->mouse.y = 0; - - SDL_Rect rect = {0, 0, 0, 0}; - calcTextureRect(&rect); - - if(rect.w) input->mouse.x = (mx - rect.x) * TIC80_WIDTH / rect.w; - if(rect.h) input->mouse.y = (my - rect.y) * TIC80_HEIGHT / rect.h; - } - - { - input->mouse.left = mb & SDL_BUTTON_LMASK ? 1 : 0; - input->mouse.middle = mb & SDL_BUTTON_MMASK ? 1 : 0; - input->mouse.right = mb & SDL_BUTTON_RMASK ? 1 : 0; - } -} - -static void processKeyboard() -{ - static const u8 KeyboardCodes[] = - { - #include "../keycodes.c" - }; - - tic80_input* input = &platform.studio->tic->ram.input; - input->keyboard.data = 0; - - const u8* keyboard = SDL_GetKeyboardState(NULL); - - for(s32 i = 0, c = 0; i < COUNT_OF(KeyboardCodes) && c < COUNT_OF(input->keyboard.keys); i++) - if(keyboard[i] && KeyboardCodes[i] > tic_key_unknown) - input->keyboard.keys[c++] = KeyboardCodes[i]; -} - -static s32 getAxisMask(SDL_Joystick* joystick) -{ - s32 mask = 0; - - s32 axesCount = SDL_JoystickNumAxes(joystick); - - for (s32 a = 0; a < axesCount; a++) - { - s32 axe = SDL_JoystickGetAxis(joystick, a); - - if (axe) - { - if (a == 0) - { - if (axe > 16384) mask |= SDL_HAT_RIGHT; - else if(axe < -16384) mask |= SDL_HAT_LEFT; - } - else if (a == 1) - { - if (axe > 16384) mask |= SDL_HAT_DOWN; - else if (axe < -16384) mask |= SDL_HAT_UP; - } - } - } - - return mask; -} - -static s32 getJoystickHatMask(s32 hat) -{ - tic80_gamepads gamepad; - gamepad.data = 0; - - gamepad.first.up = hat & SDL_HAT_UP; - gamepad.first.down = hat & SDL_HAT_DOWN; - gamepad.first.left = hat & SDL_HAT_LEFT; - gamepad.first.right = hat & SDL_HAT_RIGHT; - - return gamepad.data; -} - -static void processJoysticks() -{ - platform.gamepad.joystick.data = 0; - s32 index = 0; - - for(s32 i = 0; i < COUNT_OF(platform.gamepad.ports); i++) - { - SDL_Joystick* joystick = platform.gamepad.ports[i]; - - if(joystick && SDL_JoystickGetAttached(joystick)) - { - tic80_gamepad* gamepad = NULL; - - switch(index) - { - case 0: gamepad = &platform.gamepad.joystick.first; break; - case 1: gamepad = &platform.gamepad.joystick.second; break; - case 2: gamepad = &platform.gamepad.joystick.third; break; - case 3: gamepad = &platform.gamepad.joystick.fourth; break; - } - - if(gamepad) - { - gamepad->data |= getJoystickHatMask(getAxisMask(joystick)); - - for (s32 h = 0; h < SDL_JoystickNumHats(joystick); h++) - gamepad->data |= getJoystickHatMask(SDL_JoystickGetHat(joystick, h)); - - s32 numButtons = SDL_JoystickNumButtons(joystick); - if(numButtons >= 2) - { - gamepad->a = SDL_JoystickGetButton(joystick, 0); - gamepad->b = SDL_JoystickGetButton(joystick, 1); - - if(numButtons >= 4) - { - gamepad->x = SDL_JoystickGetButton(joystick, 2); - gamepad->y = SDL_JoystickGetButton(joystick, 3); - - for(s32 i = 5; i < numButtons; i++) - { - s32 back = SDL_JoystickGetButton(joystick, i); - - if(back) - { - tic_mem* tic = platform.studio->tic; - - for(s32 i = 0; i < TIC80_KEY_BUFFER; i++) - { - if(!tic->ram.input.keyboard.keys[i]) - { - tic->ram.input.keyboard.keys[i] = tic_key_escape; - break; - } - } - } - } - } - } - - index++; - } - } - } -} - -static void processGamepad() -{ - processJoysticks(); - - { - platform.studio->tic->ram.input.gamepads.data = 0; - platform.studio->tic->ram.input.gamepads.data |= platform.gamepad.joystick.data; - } -} - -static void pollEvent() -{ - tic80_input* input = &platform.studio->tic->ram.input; - - { - input->mouse.btns = 0; - } - - SDL_Event event; - - while(SDL_PollEvent(&event)) - { - switch(event.type) - { - case SDL_MOUSEWHEEL: - { - input->mouse.scrollx = event.wheel.x; - input->mouse.scrolly = event.wheel.y; - } - break; - case SDL_JOYDEVICEADDED: - { - s32 id = event.jdevice.which; - - if (id < TIC_GAMEPADS) - { - if(platform.gamepad.ports[id]) - SDL_JoystickClose(platform.gamepad.ports[id]); - - platform.gamepad.ports[id] = SDL_JoystickOpen(id); - } - } - break; - - case SDL_JOYDEVICEREMOVED: - { - s32 id = event.jdevice.which; - - if (id < TIC_GAMEPADS && platform.gamepad.ports[id]) - { - SDL_JoystickClose(platform.gamepad.ports[id]); - platform.gamepad.ports[id] = NULL; - } - } - break; - case SDL_WINDOWEVENT: - switch(event.window.event) - { - case SDL_WINDOWEVENT_FOCUS_GAINED: platform.studio->updateProject(); break; - } - break; - case SDL_QUIT: - platform.studio->exit(); - break; - default: - break; - } - } - - processMouse(); - processKeyboard(); - processGamepad(); -} - -static void blitTexture() -{ - tic_mem* tic = platform.studio->tic; - - SDL_Rect rect = {0, 0, 0, 0}; - calcTextureRect(&rect); - - void* pixels = NULL; - s32 pitch = 0; - SDL_LockTexture(platform.texture, NULL, &pixels, &pitch); - - platform.studio->tick(); - - memcpy(pixels, tic->screen, sizeof tic->screen); - - SDL_UnlockTexture(platform.texture); - - { - enum {Top = OFFSET_TOP}; - enum {Left = OFFSET_LEFT}; - - SDL_Rect srcRect = {Left, Top, TIC80_WIDTH, TIC80_HEIGHT}; - - SDL_RenderCopy(platform.renderer, platform.texture, &srcRect, &rect); - } -} - -static void blitSound() -{ - tic_mem* tic = platform.studio->tic; - - SDL_PauseAudioDevice(platform.audio.device, 0); - - if(platform.audio.cvt.needed) - { - SDL_memcpy(platform.audio.cvt.buf, tic->samples.buffer, tic->samples.size); - SDL_ConvertAudio(&platform.audio.cvt); - SDL_QueueAudio(platform.audio.device, platform.audio.cvt.buf, platform.audio.cvt.len_cvt); - } - else SDL_QueueAudio(platform.audio.device, tic->samples.buffer, tic->samples.size); -} - -static void blitCursor(const u8* in) -{ - if(!platform.mouse.texture) - { - platform.mouse.texture = SDL_CreateTexture(platform.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, TIC_SPRITESIZE, TIC_SPRITESIZE); - SDL_SetTextureBlendMode(platform.mouse.texture, SDL_BLENDMODE_BLEND); - } - - if(platform.mouse.src != in) - { - platform.mouse.src = in; - - void* pixels = NULL; - s32 pitch = 0; - SDL_LockTexture(platform.mouse.texture, NULL, &pixels, &pitch); - - { - const u8* end = in + sizeof(tic_tile); - const u32* pal = tic_palette_blit(&platform.studio->tic->ram.vram.palette); - u32* out = pixels; - - while(in != end) - { - u8 low = *in & 0x0f; - u8 hi = (*in & 0xf0) >> TIC_PALETTE_BPP; - *out++ = low ? (*(pal + low) | 0xff000000) : 0; - *out++ = hi ? (*(pal + hi) | 0xff000000) : 0; - - in++; - } - } - - SDL_UnlockTexture(platform.mouse.texture); - } - - SDL_Rect rect = {0, 0, 0, 0}; - calcTextureRect(&rect); - s32 scale = rect.w / TIC80_WIDTH; - - SDL_Rect src = {0, 0, TIC_SPRITESIZE, TIC_SPRITESIZE}; - SDL_Rect dst = {0, 0, TIC_SPRITESIZE * scale, TIC_SPRITESIZE * scale}; - - SDL_GetMouseState(&dst.x, &dst.y); - - if(platform.studio->config()->theme.cursor.pixelPerfect) - { - dst.x -= (dst.x - rect.x) % scale; - dst.y -= (dst.y - rect.y) % scale; - } - - if(SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MOUSE_FOCUS) - SDL_RenderCopy(platform.renderer, platform.mouse.texture, &src, &dst); -} - -static void renderCursor() -{ - if(platform.studio->tic->ram.vram.vars.cursor.system) - { - switch(platform.studio->tic->ram.vram.vars.cursor.sprite) - { - case tic_cursor_hand: - { - if(platform.studio->config()->theme.cursor.hand >= 0) - { - SDL_ShowCursor(SDL_DISABLE); - blitCursor(platform.studio->config()->cart->bank0.tiles.data[platform.studio->config()->theme.cursor.hand].data); - } - else - { - SDL_ShowCursor(SDL_ENABLE); - SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND)); - } - } - break; - case tic_cursor_ibeam: - { - if(platform.studio->config()->theme.cursor.ibeam >= 0) - { - SDL_ShowCursor(SDL_DISABLE); - blitCursor(platform.studio->config()->cart->bank0.tiles.data[platform.studio->config()->theme.cursor.ibeam].data); - } - else - { - SDL_ShowCursor(SDL_ENABLE); - SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM)); - } - } - break; - default: - { - if(platform.studio->config()->theme.cursor.arrow >= 0) - { - SDL_ShowCursor(SDL_DISABLE); - blitCursor(platform.studio->config()->cart->bank0.tiles.data[platform.studio->config()->theme.cursor.arrow].data); - } - else - { - SDL_ShowCursor(SDL_ENABLE); - SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW)); - } - } - } - } - else - { - SDL_ShowCursor(SDL_DISABLE); - blitCursor(platform.studio->tic->ram.sprites.data[platform.studio->tic->ram.vram.vars.cursor.sprite].data); - } - -// if(platform.mode == TIC_RUN_MODE && !platform.studio.tic->input.mouse) -// { -// SDL_ShowCursor(SDL_DISABLE); -// return; -// } -} - -static void tick() -{ - pollEvent(); - - if(platform.studio->quit) - return; - - SDL_RenderClear(platform.renderer); - - blitTexture(); - renderCursor(); - - SDL_RenderPresent(platform.renderer); - - blitSound(); -} - -static const char* getAppFolder() -{ - static char appFolder[FILENAME_MAX]; - - char* path = SDL_GetPrefPath(TIC_PACKAGE, TIC_NAME); - strcpy(appFolder, path); - SDL_free(path); - - return appFolder; -} - -static void setClipboardText(const char* text) -{ - SDL_SetClipboardText(text); -} - -static bool hasClipboardText() -{ - return SDL_HasClipboardText(); -} - -static char* getClipboardText() -{ - return SDL_GetClipboardText(); -} - -static void freeClipboardText(const char* text) -{ - SDL_free((void*)text); -} - -static u64 getPerformanceCounter() -{ - return SDL_GetPerformanceCounter(); -} - -static u64 getPerformanceFrequency() -{ - return SDL_GetPerformanceFrequency(); -} - -static void goFullscreen() -{ - SDL_SetWindowFullscreen(platform.window, SDL_GetWindowFlags(platform.window) & SDL_WINDOW_FULLSCREEN_DESKTOP ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); -} - -static void showMessageBox(const char* title, const char* message) -{ - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, title, message, NULL); -} - -static void setWindowTitle(const char* title) -{ - SDL_SetWindowTitle(platform.window, title); -} - -#if defined(__WINDOWS__) || defined(__LINUX__) || defined(__MACOSX__) - -static void openSystemPath(const char* path) -{ - char command[FILENAME_MAX]; - -#if defined(__WINDOWS__) - - sprintf(command, "explorer \"%s\"", path); - - wchar_t wcommand[FILENAME_MAX]; - mbstowcs(wcommand, command, FILENAME_MAX); - - _wsystem(wcommand); - -#elif defined(__LINUX__) - - sprintf(command, "xdg-open \"%s\"", path); - system(command); - -#elif defined(__MACOSX__) - - sprintf(command, "open \"%s\"", path); - system(command); - -#endif -} - -#else - -static void openSystemPath(const char* path) {} - -#endif - -static void* getUrlRequest(const char* url, s32* size) -{ - return netGetRequest(platform.net, url, size); -} - -static void preseed() -{ -#if defined(__MACOSX__) - srandom(time(NULL)); - random(); -#else - srand(time(NULL)); - rand(); -#endif -} - -static void updateConfig() {} - -static System systemInterface = -{ - .setClipboardText = setClipboardText, - .hasClipboardText = hasClipboardText, - .getClipboardText = getClipboardText, - .freeClipboardText = freeClipboardText, - - .getPerformanceCounter = getPerformanceCounter, - .getPerformanceFrequency = getPerformanceFrequency, - - .getUrlRequest = getUrlRequest, - - .fileDialogLoad = file_dialog_load, - .fileDialogSave = file_dialog_save, - - .goFullscreen = goFullscreen, - .showMessageBox = showMessageBox, - .setWindowTitle = setWindowTitle, - - .openSystemPath = openSystemPath, - .preseed = preseed, - .poll = pollEvent, - .updateConfig = updateConfig, -}; - -s32 main(s32 argc, char **argv) -{ - const char* folder = getAppFolder(); - - SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK); - - initSound(); - - platform.net = createNet(); - - platform.window = SDL_CreateWindow( TIC_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - (TIC80_FULLWIDTH) * STUDIO_UI_SCALE, - (TIC80_FULLHEIGHT) * STUDIO_UI_SCALE, - SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN_DESKTOP); - - platform.studio = studioInit(argc, argv, platform.audio.spec.freq, folder, &systemInterface); - - platform.renderer = SDL_CreateRenderer(platform.window, -1, SDL_RENDERER_SOFTWARE); - platform.texture = SDL_CreateTexture(platform.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, TEXTURE_SIZE, TEXTURE_SIZE); - - { - u64 nextTick = SDL_GetPerformanceCounter(); - const u64 Delta = SDL_GetPerformanceFrequency() / TIC_FRAMERATE; - - while (!platform.studio->quit) - { - nextTick += Delta; - - tick(); - - { - s64 delay = nextTick - SDL_GetPerformanceCounter(); - - if(delay < 0) nextTick -= delay; - else SDL_Delay((u32)(delay * 1000 / SDL_GetPerformanceFrequency())); - } - } - } - - platform.studio->close(); - - closeNet(platform.net); - - if(platform.audio.cvt.buf) - SDL_free(platform.audio.cvt.buf); - - if(platform.mouse.texture) - SDL_DestroyTexture(platform.mouse.texture); - - SDL_DestroyTexture(platform.texture); - SDL_DestroyRenderer(platform.renderer); - SDL_DestroyWindow(platform.window); - - SDL_CloseAudioDevice(platform.audio.device); - - return 0; -} diff --git a/src/system.c b/src/system/sdlgpu.c similarity index 95% rename from src/system.c rename to src/system/sdlgpu.c index 40e2d07..4420504 100644 --- a/src/system.c +++ b/src/system/sdlgpu.c @@ -1,3 +1,25 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + #include "system.h" #include "net.h" #include "tools.h" @@ -14,8 +36,6 @@ #define STUDIO_PIXEL_FORMAT GPU_FORMAT_RGBA #define TEXTURE_SIZE (TIC80_FULLWIDTH) -#define OFFSET_LEFT ((TIC80_FULLWIDTH-TIC80_WIDTH)/2) -#define OFFSET_TOP ((TIC80_FULLHEIGHT-TIC80_HEIGHT)/2) #define KBD_COLS 22 #define KBD_ROWS 17 @@ -345,7 +365,7 @@ static void calcTextureRect(SDL_Rect* rect) rect->y = rect->w > rect->h ? (rect->h - discreteHeight) / 2 - : OFFSET_TOP*discreteWidth/Width; + : TIC80_OFFSET_TOP*discreteWidth/Width; rect->w = discreteWidth; rect->h = discreteHeight; @@ -381,8 +401,8 @@ static void processMouse() s32 x = -1, y = -1; if(crtMonitorEnabled()) { - if(rect.w) x = (mx - rect.x) * TIC80_FULLWIDTH / rect.w - OFFSET_LEFT; - if(rect.h) y = (my - rect.y) * TIC80_FULLHEIGHT / rect.h - OFFSET_TOP; + if(rect.w) x = (mx - rect.x) * TIC80_FULLWIDTH / rect.w - TIC80_OFFSET_LEFT; + if(rect.h) y = (my - rect.y) * TIC80_FULLHEIGHT / rect.h - TIC80_OFFSET_TOP; } else { @@ -833,7 +853,7 @@ static void blitGpuTexture(GPU_Target* screen, GPU_Image* texture) SDL_Rect rect = {0, 0, 0, 0}; calcTextureRect(&rect); - enum {Header = OFFSET_TOP, Top = OFFSET_TOP, Left = OFFSET_LEFT}; + enum {Header = TIC80_OFFSET_TOP, Top = TIC80_OFFSET_TOP, Left = TIC80_OFFSET_LEFT}; s32 width = 0; SDL_GetWindowSize(platform.window, &width, NULL); @@ -887,7 +907,7 @@ static void renderKeyboard() SDL_Rect rect; SDL_GetWindowSize(platform.window, &rect.w, &rect.h); - GPU_Rect src = {OFFSET_LEFT, OFFSET_TOP, KBD_COLS*TIC_SPRITESIZE, KBD_ROWS*TIC_SPRITESIZE}; + GPU_Rect src = {TIC80_OFFSET_LEFT, TIC80_OFFSET_TOP, KBD_COLS*TIC_SPRITESIZE, KBD_ROWS*TIC_SPRITESIZE}; float scale = rect.w/src.w; GPU_Rect dst = (GPU_Rect){0, rect.h - KBD_ROWS*TIC_SPRITESIZE*scale, scale, scale}; @@ -911,11 +931,11 @@ static void renderKeyboard() { if(key == KbdLayout[k]) { - GPU_Rect src = {(k % Cols)*TIC_SPRITESIZE + OFFSET_LEFT, (k / Cols)*TIC_SPRITESIZE + OFFSET_TOP, + GPU_Rect src = {(k % Cols)*TIC_SPRITESIZE + TIC80_OFFSET_LEFT, (k / Cols)*TIC_SPRITESIZE + TIC80_OFFSET_TOP, TIC_SPRITESIZE, TIC_SPRITESIZE}; GPU_BlitScale(platform.keyboard.texture.down, &src, platform.gpu.screen, - (src.x - OFFSET_LEFT) * dst.w, (src.y - OFFSET_TOP) * dst.h + dst.y, dst.w, dst.h); + (src.x - TIC80_OFFSET_LEFT) * dst.w, (src.y - TIC80_OFFSET_TOP) * dst.h + dst.y, dst.w, dst.h); } } } diff --git a/src/system/sokol.c b/src/system/sokol.c new file mode 100644 index 0000000..d1d4b16 --- /dev/null +++ b/src/system/sokol.c @@ -0,0 +1,421 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include + +#include "system.h" +#include "system/sokol.h" + +static struct +{ + Studio* studio; + + struct + { + bool state[tic_keys_count]; + } keyboard; + + struct + { + saudio_desc desc; + float* samples; + } audio; + + char* clipboard; + +} platform; + +static void setClipboardText(const char* text) +{ + if(platform.clipboard) + { + free(platform.clipboard); + platform.clipboard = NULL; + } + + platform.clipboard = strdup(text); +} + +static bool hasClipboardText() +{ + return platform.clipboard != NULL; +} + +static char* getClipboardText() +{ + return platform.clipboard ? strdup(platform.clipboard) : NULL; +} + +static void freeClipboardText(const char* text) +{ + free((void*)text); +} + +static u64 getPerformanceCounter() +{ + return 0; +} + +static u64 getPerformanceFrequency() +{ + return 1000; +} + +static void* getUrlRequest(const char* url, s32* size) +{ + return NULL; +} + +static void goFullscreen() +{ +} + +static void showMessageBox(const char* title, const char* message) +{ +} + +static void setWindowTitle(const char* title) +{ +} + +static void openSystemPath(const char* path) +{ + +} + +static void preseed() +{ +#if defined(__TIC_MACOSX__) + srandom(time(NULL)); + random(); +#else + srand(time(NULL)); + rand(); +#endif +} + +static void pollEvent() +{ + +} + +static void updateConfig() +{ + +} + +static System systemInterface = +{ + .setClipboardText = setClipboardText, + .hasClipboardText = hasClipboardText, + .getClipboardText = getClipboardText, + .freeClipboardText = freeClipboardText, + + .getPerformanceCounter = getPerformanceCounter, + .getPerformanceFrequency = getPerformanceFrequency, + + .getUrlRequest = getUrlRequest, + + .fileDialogLoad = file_dialog_load, + .fileDialogSave = file_dialog_save, + + .goFullscreen = goFullscreen, + .showMessageBox = showMessageBox, + .setWindowTitle = setWindowTitle, + + .openSystemPath = openSystemPath, + .preseed = preseed, + .poll = pollEvent, + .updateConfig = updateConfig, +}; + +static void app_init(void) +{ + sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1, false, true); + + platform.audio.samples = calloc(sizeof platform.audio.samples[0], saudio_sample_rate() / TIC_FRAMERATE * TIC_STEREO_CHANNLES); +} + +static void handleKeyboard() +{ + tic_mem* tic = platform.studio->tic; + + tic80_input* input = &tic->ram.input; + input->keyboard.data = 0; + + enum{BufSize = COUNT_OF(input->keyboard.keys)}; + + for(s32 i = 0, c = 0; i < COUNT_OF(platform.keyboard.state) && c < BufSize; i++) + if(platform.keyboard.state[i]) + input->keyboard.keys[c++] = i; +} + +static void app_frame(void) +{ + tic_mem* tic = platform.studio->tic; + + if(platform.studio->quit) exit(0); + + tic80_input* input = &tic->ram.input; + + input->gamepads.data = 0; + handleKeyboard(); + platform.studio->tick(); + + sokol_gfx_draw(platform.studio->tic->screen); + + s32 count = tic->samples.size / sizeof tic->samples.buffer[0]; + for(s32 i = 0; i < count; i++) + platform.audio.samples[i] = (float)tic->samples.buffer[i] / SHRT_MAX; + + saudio_push(platform.audio.samples, count / 2); + + input->mouse.scrollx = input->mouse.scrolly = 0; +} + +static void handleKeydown(sapp_keycode keycode, bool down) +{ + static const tic_keycode KeyboardCodes[] = + { + [SAPP_KEYCODE_INVALID] = tic_key_unknown, + [SAPP_KEYCODE_SPACE] = tic_key_space, + [SAPP_KEYCODE_APOSTROPHE] = tic_key_apostrophe, + [SAPP_KEYCODE_COMMA] = tic_key_comma, + [SAPP_KEYCODE_MINUS] = tic_key_minus, + [SAPP_KEYCODE_PERIOD] = tic_key_period, + [SAPP_KEYCODE_SLASH] = tic_key_slash, + [SAPP_KEYCODE_0] = tic_key_0, + [SAPP_KEYCODE_1] = tic_key_1, + [SAPP_KEYCODE_2] = tic_key_2, + [SAPP_KEYCODE_3] = tic_key_3, + [SAPP_KEYCODE_4] = tic_key_4, + [SAPP_KEYCODE_5] = tic_key_5, + [SAPP_KEYCODE_6] = tic_key_6, + [SAPP_KEYCODE_7] = tic_key_7, + [SAPP_KEYCODE_8] = tic_key_8, + [SAPP_KEYCODE_9] = tic_key_9, + [SAPP_KEYCODE_SEMICOLON] = tic_key_semicolon, + [SAPP_KEYCODE_EQUAL] = tic_key_equals, + [SAPP_KEYCODE_A] = tic_key_a, + [SAPP_KEYCODE_B] = tic_key_b, + [SAPP_KEYCODE_C] = tic_key_c, + [SAPP_KEYCODE_D] = tic_key_d, + [SAPP_KEYCODE_E] = tic_key_e, + [SAPP_KEYCODE_F] = tic_key_f, + [SAPP_KEYCODE_G] = tic_key_g, + [SAPP_KEYCODE_H] = tic_key_h, + [SAPP_KEYCODE_I] = tic_key_i, + [SAPP_KEYCODE_J] = tic_key_j, + [SAPP_KEYCODE_K] = tic_key_k, + [SAPP_KEYCODE_L] = tic_key_l, + [SAPP_KEYCODE_M] = tic_key_m, + [SAPP_KEYCODE_N] = tic_key_n, + [SAPP_KEYCODE_O] = tic_key_o, + [SAPP_KEYCODE_P] = tic_key_p, + [SAPP_KEYCODE_Q] = tic_key_q, + [SAPP_KEYCODE_R] = tic_key_r, + [SAPP_KEYCODE_S] = tic_key_s, + [SAPP_KEYCODE_T] = tic_key_t, + [SAPP_KEYCODE_U] = tic_key_u, + [SAPP_KEYCODE_V] = tic_key_v, + [SAPP_KEYCODE_W] = tic_key_w, + [SAPP_KEYCODE_X] = tic_key_x, + [SAPP_KEYCODE_Y] = tic_key_y, + [SAPP_KEYCODE_Z] = tic_key_z, + [SAPP_KEYCODE_LEFT_BRACKET] = tic_key_leftbracket, + [SAPP_KEYCODE_BACKSLASH] = tic_key_backslash, + [SAPP_KEYCODE_RIGHT_BRACKET] = tic_key_rightbracket, + [SAPP_KEYCODE_GRAVE_ACCENT] = tic_key_grave, + [SAPP_KEYCODE_WORLD_1] = tic_key_unknown, + [SAPP_KEYCODE_WORLD_2] = tic_key_unknown, + [SAPP_KEYCODE_ESCAPE] = tic_key_escape, + [SAPP_KEYCODE_ENTER] = tic_key_return, + [SAPP_KEYCODE_TAB] = tic_key_tab, + [SAPP_KEYCODE_BACKSPACE] = tic_key_backspace, + [SAPP_KEYCODE_INSERT] = tic_key_insert, + [SAPP_KEYCODE_DELETE] = tic_key_delete, + [SAPP_KEYCODE_RIGHT] = tic_key_right, + [SAPP_KEYCODE_LEFT] = tic_key_left, + [SAPP_KEYCODE_DOWN] = tic_key_down, + [SAPP_KEYCODE_UP] = tic_key_up, + [SAPP_KEYCODE_PAGE_UP] = tic_key_pageup, + [SAPP_KEYCODE_PAGE_DOWN] = tic_key_pagedown, + [SAPP_KEYCODE_HOME] = tic_key_home, + [SAPP_KEYCODE_END] = tic_key_end, + [SAPP_KEYCODE_CAPS_LOCK] = tic_key_capslock, + [SAPP_KEYCODE_SCROLL_LOCK] = tic_key_unknown, + [SAPP_KEYCODE_NUM_LOCK] = tic_key_unknown, + [SAPP_KEYCODE_PRINT_SCREEN] = tic_key_unknown, + [SAPP_KEYCODE_PAUSE] = tic_key_unknown, + [SAPP_KEYCODE_F1] = tic_key_f1, + [SAPP_KEYCODE_F2] = tic_key_f2, + [SAPP_KEYCODE_F3] = tic_key_f3, + [SAPP_KEYCODE_F4] = tic_key_f4, + [SAPP_KEYCODE_F5] = tic_key_f5, + [SAPP_KEYCODE_F6] = tic_key_f6, + [SAPP_KEYCODE_F7] = tic_key_f7, + [SAPP_KEYCODE_F8] = tic_key_f8, + [SAPP_KEYCODE_F9] = tic_key_f9, + [SAPP_KEYCODE_F10] = tic_key_f10, + [SAPP_KEYCODE_F11] = tic_key_f11, + [SAPP_KEYCODE_F12] = tic_key_f12, + [SAPP_KEYCODE_F13] = tic_key_unknown, + [SAPP_KEYCODE_F14] = tic_key_unknown, + [SAPP_KEYCODE_F15] = tic_key_unknown, + [SAPP_KEYCODE_F16] = tic_key_unknown, + [SAPP_KEYCODE_F17] = tic_key_unknown, + [SAPP_KEYCODE_F18] = tic_key_unknown, + [SAPP_KEYCODE_F19] = tic_key_unknown, + [SAPP_KEYCODE_F20] = tic_key_unknown, + [SAPP_KEYCODE_F21] = tic_key_unknown, + [SAPP_KEYCODE_F22] = tic_key_unknown, + [SAPP_KEYCODE_F23] = tic_key_unknown, + [SAPP_KEYCODE_F24] = tic_key_unknown, + [SAPP_KEYCODE_F25] = tic_key_unknown, + [SAPP_KEYCODE_KP_0] = tic_key_0, + [SAPP_KEYCODE_KP_1] = tic_key_1, + [SAPP_KEYCODE_KP_2] = tic_key_2, + [SAPP_KEYCODE_KP_3] = tic_key_3, + [SAPP_KEYCODE_KP_4] = tic_key_4, + [SAPP_KEYCODE_KP_5] = tic_key_5, + [SAPP_KEYCODE_KP_6] = tic_key_6, + [SAPP_KEYCODE_KP_7] = tic_key_7, + [SAPP_KEYCODE_KP_8] = tic_key_8, + [SAPP_KEYCODE_KP_9] = tic_key_9, + [SAPP_KEYCODE_KP_DECIMAL] = tic_key_unknown, + [SAPP_KEYCODE_KP_DIVIDE] = tic_key_unknown, + [SAPP_KEYCODE_KP_MULTIPLY] = tic_key_unknown, + [SAPP_KEYCODE_KP_SUBTRACT] = tic_key_unknown, + [SAPP_KEYCODE_KP_ADD] = tic_key_unknown, + [SAPP_KEYCODE_KP_ENTER] = tic_key_return, + [SAPP_KEYCODE_KP_EQUAL] = tic_key_equals, + [SAPP_KEYCODE_LEFT_SHIFT] = tic_key_shift, + [SAPP_KEYCODE_LEFT_CONTROL] = tic_key_ctrl, + [SAPP_KEYCODE_LEFT_ALT] = tic_key_alt, + [SAPP_KEYCODE_LEFT_SUPER] = tic_key_unknown, + [SAPP_KEYCODE_RIGHT_SHIFT] = tic_key_shift, + [SAPP_KEYCODE_RIGHT_CONTROL] = tic_key_ctrl, + [SAPP_KEYCODE_RIGHT_ALT] = tic_key_alt, + [SAPP_KEYCODE_RIGHT_SUPER] = tic_key_unknown, + [SAPP_KEYCODE_MENU] = tic_key_unknown, + + }; + + tic_key key = KeyboardCodes[keycode]; + + if(key > tic_key_unknown) + { + // ALT+TAB fix + if(key == tic_key_tab && platform.keyboard.state[tic_key_alt]) + platform.keyboard.state[tic_key_alt] = false; + + platform.keyboard.state[key] = down; + } +} + +static void processMouse(sapp_mousebutton btn, s32 down) +{ + tic80_input* input = &platform.studio->tic->ram.input; + + switch(btn) + { + case SAPP_MOUSEBUTTON_LEFT: input->mouse.left = down; break; + case SAPP_MOUSEBUTTON_MIDDLE: input->mouse.middle = down; break; + case SAPP_MOUSEBUTTON_RIGHT: input->mouse.right = down; break; + default: break; + } +} + +static void app_input(const sapp_event* event) +{ + tic80_input* input = &platform.studio->tic->ram.input; + + switch(event->type) + { + case SAPP_EVENTTYPE_KEY_DOWN: + handleKeydown(event->key_code, true); + break; + case SAPP_EVENTTYPE_KEY_UP: + handleKeydown(event->key_code, false); + break; + case SAPP_EVENTTYPE_MOUSE_MOVE: + { + struct {s32 x, y, w, h;}rect; + sokol_calc_viewport(&rect.x, &rect.y, &rect.w, &rect.h); + + s32 mx = -1, my = -1; + if(rect.w) mx = ((s32)event->mouse_x - rect.x) * TIC80_FULLWIDTH / rect.w - TIC80_OFFSET_LEFT; + if(rect.h) my = ((s32)event->mouse_y - rect.y) * TIC80_FULLHEIGHT / rect.h - TIC80_OFFSET_TOP; + + input->mouse.x = mx >= 0 && mx < 0xff ? mx : 0xff; + input->mouse.y = my >= 0 && my < 0xff ? my : 0xff; + } + break; + case SAPP_EVENTTYPE_MOUSE_DOWN: + processMouse(event->mouse_button, 1); break; + break; + case SAPP_EVENTTYPE_MOUSE_UP: + processMouse(event->mouse_button, 0); break; + break; + case SAPP_EVENTTYPE_MOUSE_SCROLL: + input->mouse.scrollx = event->scroll_x; + input->mouse.scrolly = event->scroll_y; + break; + default: + break; + } +} + +static void app_cleanup(void) +{ + platform.studio->close(); + free(platform.audio.samples); +} + +sapp_desc sokol_main(s32 argc, char* argv[]) +{ + memset(&platform, 0, sizeof platform); + + platform.audio.desc.num_channels = TIC_STEREO_CHANNLES; + saudio_setup(&platform.audio.desc); + + platform.studio = studioInit(argc, argv, saudio_sample_rate(), "./", &systemInterface); + + const s32 Width = TIC80_FULLWIDTH * platform.studio->config()->uiScale; + const s32 Height = TIC80_FULLHEIGHT * platform.studio->config()->uiScale; + + return(sapp_desc) + { + .init_cb = app_init, + .frame_cb = app_frame, + .event_cb = app_input, + .cleanup_cb = app_cleanup, + .width = Width, + .height = Height, + .window_title = TIC_TITLE, + .ios_keyboard_resizes_canvas = true, + .high_dpi = true, + }; +} diff --git a/src/system/sokol.h b/src/system/sokol.h new file mode 100644 index 0000000..4d6de17 --- /dev/null +++ b/src/system/sokol.h @@ -0,0 +1,34 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "sokol_app.h" +#include "sokol_gfx.h" +#include "sokol_time.h" +#include "sokol_audio.h" + +#include + +void sokol_calc_viewport(int* x, int* y, int* w, int* h); +void sokol_gfx_init(int w, int h, int sx, int sy, bool integer_scale, bool portrait_top_align); +void sokol_gfx_draw(const uint32_t* ptr); diff --git a/src/system/sokol_gfx.c b/src/system/sokol_gfx.c new file mode 100644 index 0000000..3d90328 --- /dev/null +++ b/src/system/sokol_gfx.c @@ -0,0 +1,268 @@ +#include "sokol.h" + +static struct +{ + sg_draw_state upscale_draw_state; + sg_pass upscale_pass; + sg_draw_state draw_state; + int fb_width; + int fb_height; + int fb_aspect_scale_x; + int fb_aspect_scale_y; + + bool integer_scale; + bool portrait_top_align; +} sokol_gfx; + +#if defined(SOKOL_GLCORE33) +static const char* gfx_vs_src = + "#version 330\n" + "in vec2 in_pos;\n" + "in vec2 in_uv;\n" + "out vec2 uv;\n" + "void main() {\n" + " gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n" + " uv = in_uv;\n" + "}\n"; +static const char* gfx_fs_src = + "#version 330\n" + "uniform sampler2D tex;\n" + "in vec2 uv;\n" + "out vec4 frag_color;\n" + "void main() {\n" + " frag_color = texture(tex, uv);\n" + "}\n"; +#elif defined(SOKOL_GLES2) +static const char* gfx_vs_src = + "attribute vec2 in_pos;\n" + "attribute vec2 in_uv;\n" + "varying vec2 uv;\n" + "void main() {\n" + " gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n" + " uv = in_uv;\n" + "}\n"; +static const char* gfx_fs_src = + "precision mediump float;\n" + "uniform sampler2D tex;" + "varying vec2 uv;\n" + "void main() {\n" + " gl_FragColor = texture2D(tex, uv);\n" + "}\n"; +#elif defined(SOKOL_METAL) +static const char* gfx_vs_src = + "#include \n" + "using namespace metal;\n" + "struct vs_in {\n" + " float2 pos [[attribute(0)]];\n" + " float2 uv [[attribute(1)]];\n" + "};\n" + "struct vs_out {\n" + " float4 pos [[position]];\n" + " float2 uv;\n" + "};\n" + "vertex vs_out _main(vs_in in [[stage_in]]) {\n" + " vs_out out;\n" + " out.pos = float4(in.pos*2.0-1.0, 0.5, 1.0);\n" + " out.uv = in.uv;\n" + " return out;\n" + "}\n"; +static const char* gfx_fs_src = + "#include \n" + "using namespace metal;\n" + "struct fs_in {\n" + " float2 uv;\n" + "};\n" + "fragment float4 _main(fs_in in [[stage_in]], texture2d tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n" + " return tex.sample(smp, in.uv);\n" + "}\n"; +#elif defined(SOKOL_D3D11) +static const char* gfx_vs_src = + "struct vs_in {\n" + " float2 pos: POS;\n" + " float2 uv: UV;\n" + "};\n" + "struct vs_out {\n" + " float2 uv: TEXCOORD0;\n" + " float4 pos: SV_Position;\n" + "};\n" + "vs_out main(vs_in inp) {\n" + " vs_out outp;\n" + " outp.pos = float4(inp.pos*2.0-1.0, 0.5, 1.0);\n" + " outp.uv = inp.uv;\n" + " return outp;\n" + "}\n"; +static const char* gfx_fs_src = + "Texture2D tex: register(t0);\n" + "sampler smp: register(s0);\n" + "float4 main(float2 uv: TEXCOORD0): SV_Target0 {\n" + " return tex.Sample(smp, uv);\n" + "}\n"; +#endif + +void sokol_gfx_init(int w, int h, int sx, int sy, bool integer_scale, bool portrait_top_align) { + sokol_gfx.fb_width = w; + sokol_gfx.fb_height = h; + sokol_gfx.fb_aspect_scale_x = sx; + sokol_gfx.fb_aspect_scale_y = sy; + sokol_gfx.integer_scale = integer_scale; + sokol_gfx.portrait_top_align = portrait_top_align; + + sg_setup(&(sg_desc){ + .mtl_device = sapp_metal_get_device(), + .mtl_renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor, + .mtl_drawable_cb = sapp_metal_get_drawable, + .d3d11_device = sapp_d3d11_get_device(), + .d3d11_device_context = sapp_d3d11_get_device_context(), + .d3d11_render_target_view_cb = sapp_d3d11_get_render_target_view, + .d3d11_depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view + }); + + /* quad vertex buffers with and without flipped UVs */ + float verts[] = { + 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + float verts_flipped[] = { + 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f + }; + sokol_gfx.upscale_draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ + .size = sizeof(verts), + .content = verts, + }); + sokol_gfx.draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){ + .size = sizeof(verts), + .content = sg_query_feature(SG_FEATURE_ORIGIN_TOP_LEFT) ? verts : verts_flipped + }); + + /* a shader to render a textured quad */ + sg_shader fsq_shd = sg_make_shader(&(sg_shader_desc){ + .fs.images = { + [0] = { .name="tex", .type=SG_IMAGETYPE_2D }, + }, + .vs.source = gfx_vs_src, + .fs.source = gfx_fs_src, + }); + + /* 2 pipeline-state-objects, one for upscaling, one for rendering */ + sg_pipeline_desc pip_desc = { + .layout = { + .attrs[0] = { .name="in_pos", .sem_name="POS", .format=SG_VERTEXFORMAT_FLOAT2 }, + .attrs[1] = { .name="in_uv", .sem_name="UV", .format=SG_VERTEXFORMAT_FLOAT2 } + }, + .shader = fsq_shd, + .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP + }; + sokol_gfx.draw_state.pipeline = sg_make_pipeline(&pip_desc); + pip_desc.blend.depth_format = SG_PIXELFORMAT_NONE; + sokol_gfx.upscale_draw_state.pipeline = sg_make_pipeline(&pip_desc); + + /* a texture with the emulator's raw pixel data */ + sokol_gfx.upscale_draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){ + .width = sokol_gfx.fb_width, + .height = sokol_gfx.fb_height, + .pixel_format = SG_PIXELFORMAT_RGBA8, + .usage = SG_USAGE_STREAM, + .min_filter = SG_FILTER_NEAREST, + .mag_filter = SG_FILTER_NEAREST, + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, + .wrap_v = SG_WRAP_CLAMP_TO_EDGE + }); + /* a 2x upscaled render-target-texture */ + sokol_gfx.draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){ + .render_target = true, + .width = 2*sokol_gfx.fb_width, + .height = 2*sokol_gfx.fb_height, + .pixel_format = SG_PIXELFORMAT_RGBA8, + .min_filter = SG_FILTER_LINEAR, + .mag_filter = SG_FILTER_LINEAR, + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, + .wrap_v = SG_WRAP_CLAMP_TO_EDGE + }); + + /* a render pass for the 2x upscaling */ + sokol_gfx.upscale_pass = sg_make_pass(&(sg_pass_desc){ + .color_attachments[0].image = sokol_gfx.draw_state.fs_images[0] + }); +} + +static const sg_pass_action gfx_upscale_pass_action = { + .colors[0] = { .action = SG_ACTION_DONTCARE } +}; + +static const sg_pass_action gfx_draw_pass_action = { + .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.05f, 0.05f, 0.05f, 1.0f } } +}; + +void sokol_calc_viewport(int* x, int* y, int* w, int* h) +{ + int vp_x = 0, vp_y = 0, vp_w = sapp_width(), vp_h = sapp_height(); + + if (vp_w * sokol_gfx.fb_height < vp_h * sokol_gfx.fb_width) + { + int discreteWidth = vp_w - (sokol_gfx.integer_scale ? vp_w % sokol_gfx.fb_width : 0); + int discreteHeight = sokol_gfx.fb_height * discreteWidth / sokol_gfx.fb_width; + + vp_x = (vp_w - discreteWidth) / 2; + vp_y = sokol_gfx.portrait_top_align && vp_w < vp_h + ? 0 + : (vp_h - discreteHeight) / 2; + + vp_w = discreteWidth; + vp_h = discreteHeight; + } + else + { + int discreteHeight = vp_h - (sokol_gfx.integer_scale ? vp_h % sokol_gfx.fb_height : 0); + int discreteWidth = sokol_gfx.fb_width * discreteHeight / sokol_gfx.fb_height; + + vp_x = (vp_w - discreteWidth) / 2; + vp_y = (vp_h - discreteHeight) / 2; + + vp_w = discreteWidth; + vp_h = discreteHeight; + } + + *x = vp_x; + *y = vp_y; + *w = vp_w; + *h = vp_h; +} + + +static void apply_viewport(void) { + + int vp_x, vp_y, vp_w, vp_h; + sokol_calc_viewport(&vp_x, &vp_y, &vp_w, &vp_h); + + sg_apply_viewport(vp_x, vp_y, vp_w, vp_h, true); +} + +void sokol_gfx_draw(const uint32_t* ptr) { + + /* copy emulator pixel data into upscaling source texture */ + sg_update_image(sokol_gfx.upscale_draw_state.fs_images[0], &(sg_image_content){ + .subimage[0][0] = { + .ptr = ptr, + .size = sokol_gfx.fb_width*sokol_gfx.fb_height*sizeof ptr[0] + } + }); + + /* upscale the original framebuffer 2x with nearest filtering */ + sg_begin_pass(sokol_gfx.upscale_pass, &gfx_upscale_pass_action); + sg_apply_draw_state(&sokol_gfx.upscale_draw_state); + sg_draw(0, 4, 1); + sg_end_pass(); + + /* draw the final pass with linear filtering */ + sg_begin_default_pass(&gfx_draw_pass_action, sapp_width(), sapp_height()); + apply_viewport(); + sg_apply_draw_state(&sokol_gfx.draw_state); + sg_draw(0, 4, 1); + sg_end_pass(); + sg_commit(); +} diff --git a/src/system/sokol_impl.c b/src/system/sokol_impl.c new file mode 100644 index 0000000..0e83e81 --- /dev/null +++ b/src/system/sokol_impl.c @@ -0,0 +1,36 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#define SOKOL_IMPL + +#if defined(WIN32) + +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif + +#endif + +#include "sokol_app.h" +#include "sokol_gfx.h" +#include "sokol_time.h" +#include "sokol_audio.h" diff --git a/src/system/sokol_impl.m b/src/system/sokol_impl.m new file mode 100644 index 0000000..ba868ca --- /dev/null +++ b/src/system/sokol_impl.m @@ -0,0 +1,28 @@ +// MIT License + +// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#define SOKOL_IMPL + +#include "sokol_app.h" +#include "sokol_gfx.h" +#include "sokol_time.h" +#include "sokol_audio.h"