this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1122 from asiekierka/3ds-port

3DS port

authored by

Vadim Grigoruk and committed by
GitHub
4208ced1 a7a9949a

+1706 -5
+79 -3
CMakeLists.txt
··· 35 35 36 36 configure_file("${PROJECT_SOURCE_DIR}/version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/version.h") 37 37 38 - if(ANDROID OR EMSCRIPTEN) 38 + if(ANDROID OR EMSCRIPTEN OR N3DS) 39 39 set(BUILD_SOKOL_DEFAULT OFF) 40 40 set(BUILD_LIBRETRO_DEFAULT OFF) 41 41 set(BUILD_DEMO_CARTS_DEFAULT OFF) ··· 54 54 option(BUILD_PRO "Build PRO version" FALSE) 55 55 option(BUILD_PLAYER "Build standalone players" ${BUILD_PLAYER_DEFAULT}) 56 56 57 + if (N3DS) 58 + set(BUILD_SDL off) 59 + # disable CURL linking - use HTTPC instead 60 + set(DISABLE_NETWORKING TRUE) 61 + option(N3DS_BUILD_CIA "Build .cia variant - requires bannertool and makerom" FALSE) 62 + endif() 63 + 57 64 if (BAREMETALPI) 58 65 59 66 set(BUILD_SDL off) ··· 116 123 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDISABLE_NETWORKING") 117 124 endif() 118 125 119 - if(UNIX AND NOT APPLE AND NOT EMSCRIPTEN AND NOT ANDROID) 126 + if(UNIX AND NOT APPLE AND NOT EMSCRIPTEN AND NOT ANDROID AND NOT N3DS) 120 127 set(LINUX TRUE) 121 128 endif() 122 129 ··· 200 207 201 208 target_compile_definitions(lua PRIVATE LUA_COMPAT_5_2) 202 209 target_include_directories(lua INTERFACE ${THIRDPARTY_DIR}/lua) 210 + 211 + if(N3DS) 212 + target_compile_definitions(lua PUBLIC LUA_32BITS) 213 + endif() 203 214 204 215 ################################ 205 216 # LPEG ··· 499 510 ################################ 500 511 501 512 if (NOT DISABLE_NETWORKING) 513 + 514 + if (NOT N3DS) 515 + 502 516 set(BUILD_SHARED_LIBS OFF CACHE BOOL "") 503 517 504 518 if(WIN32) ··· 516 530 517 531 endif() 518 532 533 + endif() 534 + 519 535 ################################ 520 536 # ZLIB 521 537 ################################ 522 538 539 + if (NOT N3DS) 540 + 523 541 set(ZLIB_DIR ${THIRDPARTY_DIR}/zlib) 524 542 set(ZLIB_SRC 525 543 ${ZLIB_DIR}/adler32.c ··· 538 556 add_library(zlib STATIC ${ZLIB_SRC}) 539 557 target_include_directories(zlib INTERFACE ${THIRDPARTY_DIR}/zlib) 540 558 559 + else () 560 + 561 + add_library(zlib STATIC IMPORTED) 562 + set_target_properties( zlib PROPERTIES IMPORTED_LOCATION ${DEVKITPRO}/portlibs/3ds/lib/libz.a ) 563 + target_include_directories(zlib INTERFACE ${DEVKITPRO}/portlibs/3ds/include) 564 + 565 + endif () 566 + 541 567 ################################ 542 568 # ZIP 543 569 ################################ ··· 552 578 if(BUILD_DEMO_CARTS) 553 579 set(BIN2TXT_DIR ${CMAKE_SOURCE_DIR}/build/tools/bin2txt) 554 580 set(BIN2TXT_SRC 555 - ${BIN2TXT_DIR}/bin2txt.c 581 + ${BIN2TXT_DIR}/bin2txt.c 556 582 ) 557 583 558 584 add_executable(bin2txt ${BIN2TXT_SRC}) ··· 634 660 635 661 target_link_libraries(${TIC80_OUTPUT}lib tic80core zlib zip wave_writer) 636 662 663 + if(N3DS) 664 + target_include_directories(${TIC80_OUTPUT}lib PRIVATE ${DEVKITPRO}/portlibs/3ds/include) 665 + target_link_directories(${TIC80_OUTPUT}lib PUBLIC ${DEVKITPRO}/portlibs/3ds/lib) 666 + endif() 667 + 637 668 if(NOT DISABLE_NETWORKING) 669 + if(N3DS) 670 + target_link_libraries(${TIC80_OUTPUT}lib curl mbedtls mbedx509 mbedcrypto) 671 + else() 638 672 target_link_libraries(${TIC80_OUTPUT}lib libcurl) 673 + endif() 639 674 endif() 640 675 641 676 if(BUILD_PRO) ··· 832 867 endif() 833 868 834 869 endif() 870 + 871 + ################################ 872 + # TIC-80 app (N3DS) 873 + ################################ 874 + 875 + if(N3DS) 876 + set(TIC80_SRC ${TIC80_SRC} 877 + ${CMAKE_SOURCE_DIR}/src/system/n3ds/utils.c 878 + ${CMAKE_SOURCE_DIR}/src/system/n3ds/keyboard.c 879 + ${CMAKE_SOURCE_DIR}/src/system/n3ds/net_httpc.c 880 + ${CMAKE_SOURCE_DIR}/src/system/n3ds/main.c 881 + ) 882 + 883 + if (DISABLE_NETWORKING) 884 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_HTTPC") 885 + endif() 886 + 887 + add_executable(${TIC80_OUTPUT}_n3ds ${TIC80_SRC}) 888 + 889 + target_include_directories(${TIC80_OUTPUT}_n3ds PRIVATE 890 + ${DEVKITPRO}/portlibs/3ds/include 891 + ${CMAKE_SOURCE_DIR}/include 892 + ${CMAKE_SOURCE_DIR}/src) 893 + 894 + target_link_directories(${TIC80_OUTPUT}_n3ds PRIVATE ${DEVKITPRO}/libctru/lib) 895 + target_link_libraries(${TIC80_OUTPUT}_n3ds ${TIC80_OUTPUT}lib png citro3d) 896 + 897 + if (N3DS_BUILD_CIA) 898 + add_custom_command(TARGET tic80_n3ds 899 + POST_BUILD 900 + COMMAND ${CMAKE_SOURCE_DIR}/build/n3ds/elf_to_cia.sh 901 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/build 902 + ) 903 + endif() 904 + 905 + add_custom_command(TARGET tic80_n3ds 906 + POST_BUILD 907 + COMMAND ${CMAKE_SOURCE_DIR}/build/n3ds/elf_to_3dsx.sh 908 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/build 909 + ) 910 + endif()
+26
build/n3ds/README.md
··· 1 + # 3DS build 2 + 3 + ## Requirements 4 + 5 + * devkitARM (tested on release 54, please use latest) + the 3ds-dev meta package 6 + * the following additional packages: 7 + * devkitpro-pkgbuild-helpers 8 + * 3ds-libpng 9 + * 3ds-pkg-config 10 + * 3ds-zlib 11 + 12 + If you'd like to build a .CIA archive in addition to .3DSX, the following tools must be added to your PATH: 13 + 14 + * bannertool 15 + * makerom 16 + 17 + ## Building instructions 18 + 19 + ``` 20 + cd build 21 + cmake .. -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake -DN3DS=TRUE -DN3DS_BUILD_CIA=? 22 + cmake .. -DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/3ds.cmake -DN3DS=TRUE -DN3DS_BUILD_CIA=? # must be run twice due to bug 23 + make 24 + ``` 25 + 26 + You should now be able to find `tic80.3dsx` (and `tic80.cia`, if you enabled the CIA build option) in build/bin.
+5
build/n3ds/elf_to_3dsx.sh
··· 1 + #!/bin/sh 2 + echo "[3DSX] Building metadata" 3 + ${DEVKITPRO}/tools/bin/smdhtool --create "TIC-80 tiny computer" "free and open source fantasy computer" "tic.computer" "../src/system/n3ds/icon.png" tic80.smdh 4 + echo "[3DSX] Building binary" 5 + ${DEVKITPRO}/tools/bin/3dsxtool bin/tic80_n3ds bin/tic80.3dsx --smdh=tic80.smdh --romfs=../src/system/n3ds/romfs/
+6
build/n3ds/elf_to_cia.sh
··· 1 + #!/bin/sh 2 + ${DEVKITARM}/bin/arm-none-eabi-strip -o tic80_cia.elf bin/tic80_n3ds 3 + bannertool makebanner -i ../src/system/n3ds/cia/banner.png -a ../src/system/n3ds/cia/sound.wav -o tic80_cia.bnr 4 + bannertool makesmdh -s "TIC-80" -l "TIC-80 tiny computer" -p "nesbox" -i ../src/system/n3ds/icon.png -o tic80_cia.smdh -r regionfree 5 + echo "[CIA] Building binary" 6 + makerom -f cia -elf tic80_cia.elf -icon tic80_cia.smdh -banner tic80_cia.bnr -desc app:4 -v -o bin/tic80.cia -target t -exefslogo -rsf ../src/system/n3ds/cia/build.rsf
+2 -2
src/fs.c
··· 500 500 fwrite(buffer, 1, size, dest); 501 501 fclose(dest); 502 502 503 - #if !defined(__TIC_WINRT__) && !defined(__TIC_WINDOWS__) 503 + #if !defined(__TIC_WINRT__) && !defined(__TIC_WINDOWS__) && !defined(_3DS) 504 504 if(mode) 505 505 chmod(path, mode); 506 506 #endif ··· 893 893 894 894 static void fsFullname(const char *path, char *fullname) 895 895 { 896 - #if defined(BAREMETALPI) 896 + #if defined(BAREMETALPI) || defined(_3DS) 897 897 dbg("fsFullname %s", path); 898 898 // TODO BAREMETALPI 899 899 #else
src/system/n3ds/cia/banner.png

This is a binary file and will not be displayed.

+183
src/system/n3ds/cia/build.rsf
··· 1 + BasicInfo: 2 + Title : "TIC-80" 3 + ProductCode : "CTR-P-TC80" 4 + ContentType : Application 5 + Logo : Homebrew 6 + 7 + RomFs: 8 + RootPath : ../src/system/n3ds/romfs 9 + 10 + TitleInfo: 11 + Category : Application 12 + UniqueId : 0x71C80 13 + 14 + Option: 15 + UseOnSD : true # true if App is to be installed to SD 16 + FreeProductCode : true # Removes limitations on ProductCode 17 + MediaFootPadding : false # If true CCI files are created with padding 18 + EnableCrypt : false # Enables encryption for NCCH and CIA 19 + EnableCompress : true # Compresses exefs code 20 + 21 + SystemControlInfo: 22 + SaveDataSize: 0KB 23 + RemasterVersion: 0 24 + StackSize: 0x40000 25 + 26 + # DO NOT EDIT BELOW HERE OR PROGRAMS WILL NOT LAUNCH (most likely) 27 + 28 + AccessControlInfo: 29 + UseExtSaveData : false 30 + 31 + FileSystemAccess: 32 + - DirectSdmc 33 + - DirectSdmcWrite 34 + 35 + IdealProcessor : 0 36 + AffinityMask : 1 37 + 38 + Priority : 16 39 + 40 + MaxCpu : 0 41 + DisableDebug : true 42 + EnableForceDebug : false 43 + CanWriteSharedPage : false 44 + CanUsePrivilegedPriority : false 45 + CanUseNonAlphabetAndNumber : false 46 + PermitMainFunctionArgument : false 47 + CanShareDeviceMemory : false 48 + RunnableOnSleep : false 49 + SpecialMemoryArrange : false 50 + CoreVersion : 2 51 + DescVersion : 2 52 + 53 + ReleaseKernelMajor : "02" 54 + ReleaseKernelMinor : "33" 55 + MemoryType : Application 56 + HandleTableSize: 512 57 + 58 + SystemMode : 64MB 59 + SystemModeExt : 124MB # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode 60 + CpuSpeed : 804MHz # 268MHz(Default)/804MHz 61 + EnableL2Cache : true # false(default)/true 62 + CanAccessCore2 : true 63 + 64 + IORegisterMapping: 65 + - 1ff00000-1ff7ffff 66 + MemoryMapping: 67 + - 1f000000-1f5fffff:r 68 + SystemCallAccess: 69 + ArbitrateAddress: 34 70 + Break: 60 71 + CancelTimer: 28 72 + ClearEvent: 25 73 + ClearTimer: 29 74 + CloseHandle: 35 75 + ConnectToPort: 45 76 + ControlMemory: 1 77 + CreateAddressArbiter: 33 78 + CreateEvent: 23 79 + CreateMemoryBlock: 30 80 + CreateMutex: 19 81 + CreateSemaphore: 21 82 + CreateThread: 8 83 + CreateTimer: 26 84 + DuplicateHandle: 39 85 + ExitProcess: 3 86 + ExitThread: 9 87 + GetCurrentProcessorNumber: 17 88 + GetHandleInfo: 41 89 + GetProcessId: 53 90 + GetProcessIdOfThread: 54 91 + GetProcessIdealProcessor: 6 92 + GetProcessInfo: 43 93 + GetResourceLimit: 56 94 + GetResourceLimitCurrentValues: 58 95 + GetResourceLimitLimitValues: 57 96 + GetSystemInfo: 42 97 + GetSystemTick: 40 98 + GetThreadContext: 59 99 + GetThreadId: 55 100 + GetThreadIdealProcessor: 15 101 + GetThreadInfo: 44 102 + GetThreadPriority: 11 103 + MapMemoryBlock: 31 104 + OutputDebugString: 61 105 + QueryMemory: 2 106 + ReleaseMutex: 20 107 + ReleaseSemaphore: 22 108 + SendSyncRequest1: 46 109 + SendSyncRequest2: 47 110 + SendSyncRequest3: 48 111 + SendSyncRequest4: 49 112 + SendSyncRequest: 50 113 + SetThreadPriority: 12 114 + SetTimer: 27 115 + SignalEvent: 24 116 + SleepThread: 10 117 + UnmapMemoryBlock: 32 118 + WaitSynchronization1: 36 119 + WaitSynchronizationN: 37 120 + InterruptNumbers: 121 + ServiceAccessControl: 122 + - APT:U 123 + - $hioFIO 124 + - $hostio0 125 + - $hostio1 126 + - ac:u 127 + - boss:U 128 + - cam:u 129 + - ir:rst 130 + - cfg:u 131 + - dlp:FKCL 132 + - dlp:SRVR 133 + - dsp::DSP 134 + - ssl:C 135 + - fs:USER 136 + - gsp::Gpu 137 + - hid:USER 138 + - http:C 139 + - mic:u 140 + - ndm:u 141 + - news:s 142 + - nwm::UDS 143 + - ptm:u 144 + - pxi:dev 145 + - soc:U 146 + - gsp::Lcd 147 + - y2r:u 148 + - ldr:ro 149 + - ir:USER 150 + - ir:u 151 + 152 + SystemControlInfo: 153 + Dependency: 154 + ac: 0x0004013000002402L 155 + am: 0x0004013000001502L 156 + boss: 0x0004013000003402L 157 + camera: 0x0004013000001602L 158 + cecd: 0x0004013000002602L 159 + cfg: 0x0004013000001702L 160 + codec: 0x0004013000001802L 161 + csnd: 0x0004013000002702L 162 + dlp: 0x0004013000002802L 163 + dsp: 0x0004013000001a02L 164 + friends: 0x0004013000003202L 165 + gpio: 0x0004013000001b02L 166 + gsp: 0x0004013000001c02L 167 + hid: 0x0004013000001d02L 168 + http: 0x0004013000002902L 169 + i2c: 0x0004013000001e02L 170 + ir: 0x0004013000003302L 171 + mcu: 0x0004013000001f02L 172 + mic: 0x0004013000002002L 173 + ndm: 0x0004013000002b02L 174 + news: 0x0004013000003502L 175 + nim: 0x0004013000002c02L 176 + nwm: 0x0004013000002d02L 177 + pdn: 0x0004013000002102L 178 + ps: 0x0004013000003102L 179 + ptm: 0x0004013000002202L 180 + ro: 0x0004013000003702L 181 + socket: 0x0004013000002e02L 182 + spi: 0x0004013000002302L 183 + ssl: 0x0004013000002f02L
src/system/n3ds/cia/sound.wav

This is a binary file and will not be displayed.

src/system/n3ds/icon.png

This is a binary file and will not be displayed.

+355
src/system/n3ds/keyboard.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #include <stdlib.h> 24 + 25 + #include "system.h" 26 + #include "keyboard.h" 27 + #include "utils.h" 28 + 29 + typedef struct 30 + { 31 + u16 x, y, w, h; 32 + tic_keycode keycode; 33 + u8 flags; 34 + } touch_area_t; 35 + 36 + #define TOUCH_AREA_MODIFIER 1 37 + #define TOUCH_AREA_MOD_TOGGLE 2 38 + 39 + static const touch_area_t touch_areas[] = { 40 + { 2, 97, 22, 16, tic_key_escape, 0 }, 41 + { 23, 97, 22, 16, tic_key_f1, 0 }, 42 + { 44, 97, 22, 16, tic_key_f2, 0 }, 43 + { 65, 97, 22, 16, tic_key_f3, 0 }, 44 + { 86, 97, 22, 16, tic_key_f4, 0 }, 45 + { 107, 97, 22, 16, tic_key_f5, 0 }, 46 + { 128, 97, 22, 16, tic_key_f6, 0 }, 47 + { 149, 97, 22, 16, tic_key_f7, 0 }, 48 + { 170, 97, 22, 16, tic_key_f8, 0 }, 49 + { 191, 97, 22, 16, tic_key_f9, 0 }, 50 + { 212, 97, 22, 16, tic_key_f10, 0 }, 51 + { 233, 97, 22, 16, tic_key_f11, 0 }, 52 + { 254, 97, 22, 16, tic_key_f12, 0 }, 53 + { 275, 97, 22, 16, tic_key_insert, 0 }, 54 + { 296, 97, 22, 16, tic_key_delete, 0 }, 55 + 56 + { 2, 112, 22, 22, tic_key_grave, 0 }, 57 + { 23, 112, 22, 22, tic_key_1, 0 }, 58 + { 44, 112, 22, 22, tic_key_2, 0 }, 59 + { 65, 112, 22, 22, tic_key_3, 0 }, 60 + { 86, 112, 22, 22, tic_key_4, 0 }, 61 + { 107, 112, 22, 22, tic_key_5, 0 }, 62 + { 128, 112, 22, 22, tic_key_6, 0 }, 63 + { 149, 112, 22, 22, tic_key_7, 0 }, 64 + { 170, 112, 22, 22, tic_key_8, 0 }, 65 + { 191, 112, 22, 22, tic_key_9, 0 }, 66 + { 212, 112, 22, 22, tic_key_0, 0 }, 67 + { 233, 112, 22, 22, tic_key_minus, 0 }, 68 + { 254, 112, 22, 22, tic_key_equals, 0 }, 69 + { 275, 112, 43, 22, tic_key_backspace, 0 }, 70 + 71 + { 2, 133, 34, 22, tic_key_tab, 0 }, 72 + { 35, 133, 22, 22, tic_key_q, 0 }, 73 + { 56, 133, 22, 22, tic_key_w, 0 }, 74 + { 77, 133, 22, 22, tic_key_e, 0 }, 75 + { 98, 133, 22, 22, tic_key_r, 0 }, 76 + { 119, 133, 22, 22, tic_key_t, 0 }, 77 + { 140, 133, 22, 22, tic_key_y, 0 }, 78 + { 161, 133, 22, 22, tic_key_u, 0 }, 79 + { 182, 133, 22, 22, tic_key_i, 0 }, 80 + { 203, 133, 22, 22, tic_key_o, 0 }, 81 + { 224, 133, 22, 22, tic_key_p, 0 }, 82 + { 245, 133, 22, 22, tic_key_leftbracket, 0 }, 83 + { 266, 133, 22, 22, tic_key_rightbracket, 0 }, 84 + { 287, 133, 31, 22, tic_key_backslash, 0 }, 85 + 86 + { 2, 154, 41, 22, tic_key_ctrl, TOUCH_AREA_MODIFIER }, 87 + { 42, 154, 22, 22, tic_key_a, 0 }, 88 + { 63, 154, 22, 22, tic_key_s, 0 }, 89 + { 84, 154, 22, 22, tic_key_d, 0 }, 90 + { 105, 154, 22, 22, tic_key_f, 0 }, 91 + { 126, 154, 22, 22, tic_key_g, 0 }, 92 + { 147, 154, 22, 22, tic_key_h, 0 }, 93 + { 168, 154, 22, 22, tic_key_j, 0 }, 94 + { 189, 154, 22, 22, tic_key_k, 0 }, 95 + { 210, 154, 22, 22, tic_key_l, 0 }, 96 + { 231, 154, 22, 22, tic_key_semicolon, 0 }, 97 + { 252, 154, 22, 22, tic_key_apostrophe, 0 }, 98 + { 273, 154, 45, 22, tic_key_return, 0 }, 99 + 100 + { 2, 175, 54, 22, tic_key_shift, TOUCH_AREA_MODIFIER }, 101 + { 55, 175, 22, 22, tic_key_z, 0 }, 102 + { 76, 175, 22, 22, tic_key_x, 0 }, 103 + { 97, 175, 22, 22, tic_key_c, 0 }, 104 + { 118, 175, 22, 22, tic_key_v, 0 }, 105 + { 139, 175, 22, 22, tic_key_b, 0 }, 106 + { 160, 175, 22, 22, tic_key_n, 0 }, 107 + { 181, 175, 22, 22, tic_key_m, 0 }, 108 + { 202, 175, 22, 22, tic_key_comma, 0 }, 109 + { 223, 175, 22, 22, tic_key_period, 0 }, 110 + { 244, 175, 22, 22, tic_key_slash, 0 }, 111 + { 265, 175, 53, 22, tic_key_shift, TOUCH_AREA_MODIFIER }, 112 + 113 + { 2, 196, 28, 22, tic_key_capslock, TOUCH_AREA_MODIFIER | TOUCH_AREA_MOD_TOGGLE }, 114 + { 29, 196, 37, 22, tic_key_alt, TOUCH_AREA_MODIFIER }, 115 + { 65, 196, 142, 22, tic_key_space, 0 }, 116 + { 206, 196, 28, 22, tic_key_alt, TOUCH_AREA_MODIFIER }, 117 + { 233, 196, 22, 22, tic_key_home, 0 }, 118 + { 254, 196, 22, 22, tic_key_up, 0 }, 119 + { 275, 196, 22, 22, tic_key_end, 0 }, 120 + { 296, 196, 22, 22, tic_key_pageup, 0 }, 121 + 122 + { 233, 217, 22, 22, tic_key_left, 0 }, 123 + { 254, 217, 22, 22, tic_key_down, 0 }, 124 + { 275, 217, 22, 22, tic_key_right, 0 }, 125 + { 296, 217, 22, 22, tic_key_pagedown, 0 } 126 + }; 127 + 128 + #define touch_areas_len (sizeof(touch_areas) / sizeof(touch_area_t)) 129 + 130 + extern void n3ds_draw_texture(C3D_Tex* tex, int x, int y, int tx, int ty, int width, int height, int twidth, int theight, 131 + float cmul); 132 + 133 + void n3ds_keyboard_init(tic_n3ds_keyboard *kbd) { 134 + memset(kbd, 0, sizeof(tic_n3ds_keyboard)); 135 + if (!ctr_load_png(&kbd->tex, "romfs:/kbd_display.png", TEXTURE_TARGET_VRAM)) 136 + { 137 + consoleInit(GFX_BOTTOM, NULL); 138 + } 139 + kbd->render_dirty = true; 140 + } 141 + 142 + void n3ds_keyboard_free(tic_n3ds_keyboard *kbd) { 143 + C3D_TexDelete(&kbd->tex); 144 + } 145 + 146 + static void n3ds_keyboard_draw_pressed(tic_n3ds_keyboard *kbd, int pos) { 147 + const touch_area_t* area = &touch_areas[pos]; 148 + n3ds_draw_texture(&(kbd->tex), area->x, area->y, 149 + area->x, 16 + (area->y - 1), 150 + area->w, area->h - 1, 151 + area->w, area->h - 1, 0.5f); 152 + } 153 + 154 + void n3ds_keyboard_draw(tic_n3ds_keyboard *kbd) { 155 + if (kbd->tex.data != NULL) 156 + { 157 + n3ds_draw_texture(&(kbd->tex), 0, 0, 0, 16, 320, 240, 320, 240, 1.0f); 158 + for(int i = 0; i < kbd->kd_count; i++) 159 + { 160 + n3ds_keyboard_draw_pressed(kbd, kbd->kd[i]); 161 + } 162 + } 163 + } 164 + 165 + static inline 166 + bool n3ds_key_touched(touchPosition* pos, const touch_area_t* area) 167 + { 168 + return pos->px >= area->x && pos->py >= area->y 169 + && pos->px < (area->x + area->w) 170 + && pos->py < (area->y + area->h); 171 + } 172 + 173 + #define MAP_BUTTON_KEY(keymask, tickey) \ 174 + if ((key_held & (keymask)) && !state[(tickey)] && (buffer_pos < TIC80_KEY_BUFFER)) \ 175 + { \ 176 + tic_kbd->keys[buffer_pos++] = (tickey); \ 177 + state[(tickey)] = true; \ 178 + } 179 + 180 + void n3ds_keyboard_update(tic_n3ds_keyboard *kbd, tic_mem *tic, char *chcode) { 181 + u32 key_down, key_up, key_held; 182 + touchPosition touch; 183 + const touch_area_t* area; 184 + bool changed = false; 185 + bool state[tic_keys_count]; 186 + int i, j; 187 + 188 + tic80_keyboard *tic_kbd = &tic->ram.input.keyboard; 189 + 190 + memset(&state, 0, sizeof(state)); 191 + key_down = hidKeysDown(); 192 + key_held = hidKeysHeld(); 193 + key_up = hidKeysUp(); 194 + 195 + changed = false; 196 + if((key_down | key_up) & KEY_TOUCH) 197 + { 198 + hidTouchRead(&touch); 199 + 200 + if(key_down & KEY_TOUCH) 201 + { 202 + for(i = 0; i < touch_areas_len; i++) 203 + { 204 + area = &touch_areas[i]; 205 + if(n3ds_key_touched(&touch, area)) 206 + { 207 + int set = -1; 208 + for(j = 0; j < kbd->kd_count; j++) 209 + { 210 + if(kbd->kd[j] == i) 211 + { 212 + set = j; 213 + break; 214 + } 215 + } 216 + 217 + if(set < 0) 218 + { 219 + kbd->kd[kbd->kd_count++] = i; 220 + changed = true; 221 + } 222 + else if(area->flags & TOUCH_AREA_MODIFIER) 223 + { 224 + // allow de-pressing modifiers 225 + kbd->kd[set] = 0; 226 + for (j = set + 1; j < kbd->kd_count; j++) { 227 + kbd->kd[j - 1] = kbd->kd[j]; 228 + kbd->kd[j] = 0; 229 + } 230 + kbd->kd_count--; 231 + changed = true; 232 + } 233 + 234 + break; 235 + } 236 + } 237 + } 238 + else if(key_up & KEY_TOUCH) 239 + { 240 + if(kbd->kd_count > 0 && !(touch_areas[kbd->kd[kbd->kd_count - 1]].flags & TOUCH_AREA_MODIFIER)) { 241 + for(i = 0, j = 0; i < kbd->kd_count; i++) { 242 + if(touch_areas[kbd->kd[i]].flags & TOUCH_AREA_MOD_TOGGLE) { 243 + kbd->kd[j++] = kbd->kd[i]; 244 + } 245 + } 246 + kbd->kd_count = j; 247 + changed = true; 248 + } 249 + } 250 + } 251 + 252 + changed |= (key_down | key_up) & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_A | KEY_B | KEY_X | KEY_Y); 253 + 254 + if (changed) { 255 + // apply to TIC-80 256 + kbd->render_dirty = true; 257 + 258 + tic_kbd->data = 0; 259 + int buffer_pos = 0; 260 + for(i = 0; i < kbd->kd_count && buffer_pos < TIC80_KEY_BUFFER; i++) 261 + { 262 + tic_keycode curr_keycode = touch_areas[kbd->kd[i]].keycode; 263 + if(!state[curr_keycode]) 264 + { 265 + tic_kbd->keys[buffer_pos++] = curr_keycode; 266 + state[curr_keycode] = true; 267 + } 268 + } 269 + 270 + MAP_BUTTON_KEY(KEY_UP, tic_key_up); 271 + MAP_BUTTON_KEY(KEY_DOWN, tic_key_down); 272 + MAP_BUTTON_KEY(KEY_LEFT, tic_key_left); 273 + MAP_BUTTON_KEY(KEY_RIGHT, tic_key_right); 274 + MAP_BUTTON_KEY(KEY_A, tic_key_z); 275 + MAP_BUTTON_KEY(KEY_B, tic_key_x); 276 + MAP_BUTTON_KEY(KEY_X, tic_key_a); 277 + MAP_BUTTON_KEY(KEY_Y, tic_key_s); 278 + 279 + // TODO: merge with sdlgpu.c 280 + if (chcode != NULL) 281 + { 282 + *chcode = 0; 283 + if (buffer_pos > 0) 284 + { 285 + static const char Symbols[] = " abcdefghijklmnopqrstuvwxyz0123456789-=[]\\;'`,./ "; 286 + static const char Shift[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ)!@#$%^&*(_+{}|:\"~<>? "; 287 + 288 + enum{Count = sizeof Symbols}; 289 + 290 + for(s32 i = 0; i < buffer_pos; i++) 291 + { 292 + tic_key key = tic_kbd->keys[i]; 293 + 294 + if(key > 0 && key < Count && tic_api_keyp(tic, key, KEYBOARD_HOLD, KEYBOARD_PERIOD)) 295 + { 296 + bool caps = tic_api_key(tic, tic_key_capslock); 297 + bool shift = tic_api_key(tic, tic_key_shift); 298 + 299 + *chcode = caps 300 + ? key >= tic_key_a && key <= tic_key_z 301 + ? shift ? Symbols[key] : Shift[key] 302 + : shift ? Shift[key] : Symbols[key] 303 + : shift ? Shift[key] : Symbols[key]; 304 + 305 + break; 306 + } 307 + } 308 + } 309 + } 310 + } 311 + } 312 + 313 + void n3ds_gamepad_update(tic_n3ds_keyboard *kbd, tic_mem *tic) { 314 + tic80_gamepads *tic_pad = &tic->ram.input.gamepads; 315 + tic80_mouse *tic_mouse = &tic->ram.input.mouse; 316 + u32 key_held = hidKeysHeld(); 317 + u64 curr_clock = svcGetSystemTick(); 318 + circlePosition cstick; 319 + 320 + // gamepad 321 + tic_pad->first.data = 0; 322 + tic_pad->first.up = (key_held & KEY_UP) != 0; 323 + tic_pad->first.down = (key_held & KEY_DOWN) != 0; 324 + tic_pad->first.left = (key_held & KEY_LEFT) != 0; 325 + tic_pad->first.right = (key_held & KEY_RIGHT) != 0; 326 + tic_pad->first.a = (key_held & KEY_A) != 0; 327 + tic_pad->first.b = (key_held & KEY_B) != 0; 328 + tic_pad->first.x = (key_held & KEY_X) != 0; 329 + tic_pad->first.y = (key_held & KEY_Y) != 0; 330 + 331 + // mouse scroll 332 + tic_mouse->scrollx = 0; 333 + tic_mouse->scrolly = 0; 334 + 335 + if (curr_clock >= kbd->scroll_debounce) { 336 + if(key_held & KEY_CSTICK_UP) 337 + tic_mouse->scrolly = 1; 338 + else if(key_held & KEY_CSTICK_DOWN) 339 + tic_mouse->scrolly = -1; 340 + 341 + if(key_held & KEY_CSTICK_LEFT) 342 + tic_mouse->scrollx = -1; 343 + else if(key_held & KEY_CSTICK_RIGHT) 344 + tic_mouse->scrollx = 1; 345 + 346 + if(tic_mouse->scrollx != 0 || tic_mouse->scrolly != 0) 347 + { 348 + hidCstickRead(&cstick); 349 + int dmax = cstick.dx > cstick.dy ? cstick.dx : cstick.dy; 350 + float delay = 250.0f / (1 + (dmax / 22)); 351 + 352 + kbd->scroll_debounce = curr_clock + (u64) (delay * CPU_TICKS_PER_MSEC); 353 + } 354 + } 355 + }
+45
src/system/n3ds/keyboard.h
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #pragma once 24 + 25 + #include "tic.h" 26 + #include "ticapi.h" 27 + 28 + #include <3ds.h> 29 + #include <citro3d.h> 30 + 31 + typedef struct 32 + { 33 + C3D_Tex tex; 34 + u8 kd[8]; 35 + u32 kd_count; 36 + bool render_dirty; 37 + 38 + u64 scroll_debounce; 39 + } tic_n3ds_keyboard; 40 + 41 + void n3ds_keyboard_init(tic_n3ds_keyboard *kbd); 42 + void n3ds_keyboard_free(tic_n3ds_keyboard *kbd); 43 + void n3ds_keyboard_draw(tic_n3ds_keyboard *kbd); 44 + void n3ds_keyboard_update(tic_n3ds_keyboard *kbd, tic_mem *tic, char *chcode); 45 + void n3ds_gamepad_update(tic_n3ds_keyboard *kbd, tic_mem *tic);
+613
src/system/n3ds/main.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #include <stdio.h> 24 + #include <stdlib.h> 25 + #include <time.h> 26 + #include <limits.h> 27 + 28 + #include <sys/stat.h> 29 + 30 + #include <3ds.h> 31 + #include <citro3d.h> 32 + 33 + #include "system.h" 34 + #include "net.h" 35 + 36 + #include "keyboard.h" 37 + #include "utils.h" 38 + #include "net_httpc.h" 39 + 40 + // #define RENDER_CONSOLE_TOP 41 + #define AUDIO_FREQ 44100 42 + #define AUDIO_BLOCKS 4 43 + 44 + static struct 45 + { 46 + Studio* studio; 47 + char* clipboard; 48 + #ifndef DISABLE_NETWORKING 49 + Net* net; 50 + #endif 51 + 52 + struct 53 + { 54 + u32* tic_buf; 55 + C3D_Tex tic_tex; 56 + C3D_Mtx proj_top, proj_bottom; 57 + C3D_RenderTarget *target_top, *target_bottom; 58 + 59 + DVLB_s* shader_dvlb; 60 + shaderProgram_s shader_program; 61 + int shader_proj_mtx_loc; 62 + C3D_AttrInfo shader_attr; 63 + 64 + int scaled; 65 + bool on_bottom; 66 + } render; 67 + 68 + struct { 69 + int x, y; 70 + int width, height; 71 + } screen_size; 72 + 73 + struct 74 + { 75 + int samples, buffer_size, curr_block; 76 + u8* buffer; 77 + ndspWaveBuf ndspBuf[AUDIO_BLOCKS]; 78 + } audio; 79 + 80 + tic_n3ds_keyboard keyboard; 81 + #ifdef ENABLE_HTTPC 82 + tic_n3ds_net httpc; 83 + #endif 84 + LightLock tick_lock; 85 + } platform; 86 + 87 + static const char n3ds_shader_shbin[289] = { 88 + 0x44, 0x56, 0x4c, 0x42, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 89 + 0x00, 0x44, 0x56, 0x4c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 90 + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x08, 91 + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 + 0x4e, 0x01, 0xf0, 0x07, 0x4e, 0x02, 0x10, 0x20, 0x4e, 0x01, 0xf0, 94 + 0x27, 0x4e, 0x03, 0x08, 0x02, 0x08, 0x04, 0x18, 0x02, 0x08, 0x05, 95 + 0x28, 0x02, 0x08, 0x06, 0x38, 0x02, 0x08, 0x07, 0x10, 0x20, 0x4c, 96 + 0x07, 0x10, 0x41, 0x4c, 0x00, 0x00, 0x00, 0x88, 0x6e, 0x03, 0x00, 97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x0a, 0x00, 0x00, 0x00, 0x00, 98 + 0x00, 0x00, 0x4e, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 99 + 0xc3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xc3, 0x06, 0x00, 100 + 0x00, 0x00, 0x00, 0x00, 0x62, 0xc3, 0x06, 0x00, 0x00, 0x00, 0x00, 101 + 0x00, 0x61, 0xc3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x03, 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x56, 0x4c, 0x45, 0x02, 103 + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 104 + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 105 + 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 106 + 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6c, 107 + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 108 + 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 109 + 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 110 + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 111 + 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 112 + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x13, 113 + 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 114 + 0x00, 0x00, 0x00 115 + }; 116 + 117 + static const int n3ds_shader_shbin_length = 289; 118 + 119 + static void setClipboardText(const char* text) 120 + { 121 + if(platform.clipboard) 122 + { 123 + free(platform.clipboard); 124 + platform.clipboard = NULL; 125 + } 126 + } 127 + 128 + static bool hasClipboardText() 129 + { 130 + return platform.clipboard != NULL; 131 + } 132 + 133 + static char* getClipboardText() 134 + { 135 + return platform.clipboard ? strdup(platform.clipboard) : NULL; 136 + } 137 + 138 + static void freeClipboardText(const char* text) 139 + { 140 + free((void*) text); 141 + } 142 + 143 + static u64 getPerformanceCounter() 144 + { 145 + return svcGetSystemTick(); 146 + } 147 + 148 + static u64 getPerformanceFrequency() 149 + { 150 + return SYSCLOCK_ARM11; 151 + } 152 + 153 + static void* httpGetSync(const char* url, s32* size) 154 + { 155 + #ifndef DISABLE_NETWORKING 156 + return netGetSync(platform.net, url, size); 157 + #else 158 + #ifdef ENABLE_HTTPC 159 + return n3ds_net_get_sync(&platform.httpc, url, size); 160 + #endif 161 + #endif 162 + } 163 + 164 + static void httpGet(const char* url, HttpGetCallback callback, void* calldata) 165 + { 166 + #ifndef DISABLE_NETWORKING 167 + netGet(platform.net, url, callback, calldata); 168 + #else 169 + #ifdef ENABLE_HTTPC 170 + n3ds_net_get(&platform.httpc, url, callback, calldata); 171 + #endif 172 + #endif 173 + } 174 + 175 + static void n3ds_file_dialog_load(file_dialog_load_callback callback, void* data) 176 + { 177 + } 178 + 179 + static void n3ds_file_dialog_save(file_dialog_save_callback callback, const char* name, const u8* buffer, size_t size, void* data, u32 mode) 180 + { 181 + } 182 + 183 + 184 + static void goFullscreen() 185 + { 186 + } 187 + 188 + static void showMessageBox(const char* title, const char* message) 189 + { 190 + } 191 + 192 + static void setWindowTitle(const char* title) 193 + { 194 + } 195 + 196 + static void openSystemPath(const char* path) 197 + { 198 + } 199 + 200 + static void preseed() 201 + { 202 + srand(osGetTime()); 203 + rand(); 204 + } 205 + 206 + static void pollEvent() 207 + { 208 + 209 + } 210 + 211 + static void updateConfig() 212 + { 213 + 214 + } 215 + 216 + static void update_screen_size(void) { 217 + int scr_width = platform.render.on_bottom ? 320 : 400; 218 + 219 + if (platform.render.scaled > 0) { 220 + float sw = platform.render.on_bottom ? 316.0f : 400.0f; 221 + float sh = TIC80_FULLHEIGHT * sw / TIC80_FULLWIDTH; 222 + platform.screen_size.width = (int) (sw + 0.5f); 223 + platform.screen_size.height = (int) (sh + 0.5f); 224 + } else { 225 + platform.screen_size.width = TIC80_FULLWIDTH; 226 + platform.screen_size.height = TIC80_FULLHEIGHT; 227 + } 228 + 229 + platform.screen_size.x = (scr_width - platform.screen_size.width) >> 1; 230 + platform.screen_size.y = (240 - platform.screen_size.height) >> 1; 231 + } 232 + 233 + static void n3ds_draw_init(void) 234 + { 235 + C3D_TexEnv *texEnv; 236 + 237 + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); 238 + 239 + platform.render.target_top = C3D_RenderTargetCreate(240, 400, GPU_RB_RGB8, GPU_RB_DEPTH16); 240 + platform.render.target_bottom = C3D_RenderTargetCreate(240, 320, GPU_RB_RGB8, GPU_RB_DEPTH16); 241 + C3D_RenderTargetClear(platform.render.target_top, C3D_CLEAR_ALL, 0, 0); 242 + C3D_RenderTargetClear(platform.render.target_bottom, C3D_CLEAR_ALL, 0, 0); 243 + C3D_RenderTargetSetOutput(platform.render.target_top, GFX_TOP, GFX_LEFT, 244 + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); 245 + C3D_RenderTargetSetOutput(platform.render.target_bottom, GFX_BOTTOM, GFX_LEFT, 246 + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); 247 + 248 + C3D_TexInitVRAM(&platform.render.tic_tex, 256, 256, GPU_RGBA8); 249 + platform.render.tic_buf = linearAlloc(256 * 256 * 4); 250 + 251 + Mtx_OrthoTilt(&platform.render.proj_top, 0.0, 400.0, 0.0, 240.0, -1.0, 1.0, true); 252 + Mtx_OrthoTilt(&platform.render.proj_bottom, 0.0, 320.0, 0.0, 240.0, -1.0, 1.0, true); 253 + 254 + texEnv = C3D_GetTexEnv(0); 255 + C3D_TexEnvSrc(texEnv, C3D_Both, GPU_TEXTURE0, 0, 0); 256 + C3D_TexEnvOpRgb(texEnv, 0, 0, 0); 257 + C3D_TexEnvOpAlpha(texEnv, 0, 0, 0); 258 + C3D_TexEnvFunc(texEnv, C3D_Both, GPU_MODULATE); 259 + 260 + C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); 261 + C3D_CullFace(GPU_CULL_NONE); 262 + 263 + platform.render.shader_dvlb = DVLB_ParseFile((u32 *) n3ds_shader_shbin, n3ds_shader_shbin_length); 264 + shaderProgramInit(&(platform.render.shader_program)); 265 + shaderProgramSetVsh(&(platform.render.shader_program), &(platform.render.shader_dvlb->DVLE[0])); 266 + platform.render.shader_proj_mtx_loc = shaderInstanceGetUniformLocation(platform.render.shader_program.vertexShader, "projection"); 267 + AttrInfo_Init(&(platform.render.shader_attr)); 268 + 269 + AttrInfo_AddLoader(&(platform.render.shader_attr), 0, GPU_FLOAT, 3); // v0 = position 270 + AttrInfo_AddLoader(&(platform.render.shader_attr), 1, GPU_FLOAT, 3); // v1 = texcoord 271 + 272 + C3D_BindProgram(&(platform.render.shader_program)); 273 + C3D_SetAttrInfo(&(platform.render.shader_attr)); 274 + 275 + update_screen_size(); 276 + } 277 + 278 + static void n3ds_draw_exit(void) 279 + { 280 + linearFree(platform.render.tic_buf); 281 + C3D_TexDelete(&platform.render.tic_tex); 282 + 283 + C3D_RenderTargetDelete(platform.render.target_top); 284 + C3D_RenderTargetDelete(platform.render.target_bottom); 285 + 286 + C3D_Fini(); 287 + } 288 + 289 + void n3ds_draw_texture(C3D_Tex* tex, int x, int y, int tx, int ty, int width, int height, int twidth, int theight, 290 + float cmul) { 291 + float txmin, tymin, txmax, tymax; 292 + txmin = (float) tx / tex->width; 293 + tymax = (float) ty / tex->height; 294 + txmax = (float) (tx+twidth) / tex->width; 295 + tymin = (float) (ty+theight) / tex->height; 296 + 297 + C3D_TexBind(0, tex); 298 + C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); 299 + C3D_ImmSendAttrib((float) x, (float) 240 - y - height, 0.0f, 0.0f); 300 + C3D_ImmSendAttrib((float) txmin, (float) tymin, cmul, 0.0f); 301 + 302 + C3D_ImmSendAttrib((float) x + width, (float) 240 - y - height, 0.0f, 0.0f); 303 + C3D_ImmSendAttrib((float) txmax, (float) tymin, cmul, 0.0f); 304 + 305 + C3D_ImmSendAttrib((float) x, (float) 240 - y, 0.0f, 0.0f); 306 + C3D_ImmSendAttrib((float) txmin, (float) tymax, cmul, 0.0f); 307 + 308 + C3D_ImmSendAttrib((float) x + width, (float) 240 - y, 0.0f, 0.0f); 309 + C3D_ImmSendAttrib((float) txmax, (float) tymax, cmul, 0.0f); 310 + C3D_ImmDrawEnd(); 311 + } 312 + 313 + #define FRAME_PITCH (TIC80_FULLWIDTH * sizeof(u32)) 314 + 315 + static void n3ds_copy_frame(void) 316 + { 317 + u32 *in = platform.studio->tic->screen; 318 + 319 + /* for (int y = 0; y < TIC80_FULLHEIGHT; y++) { 320 + out = platform.render.tic_buf + (y * 256); 321 + for (int x = 0; x < TIC80_FULLWIDTH; x++, in++, out++) { 322 + *out = __builtin_bswap32(*in); 323 + } 324 + memcpy(out, in, sizeof(u32) * TIC80_FULLWIDTH); 325 + } */ 326 + 327 + if (platform.render.scaled == 2) { 328 + // pad border 1 pixel lower to minimize glitches in "linear" scaling mode 329 + memcpy( 330 + in + (FRAME_PITCH * TIC80_FULLHEIGHT), 331 + in + (FRAME_PITCH * (TIC80_FULLHEIGHT - 1)), 332 + FRAME_PITCH 333 + ); 334 + GSPGPU_FlushDataCache(in, (TIC80_FULLHEIGHT + 1) * FRAME_PITCH); 335 + } else { 336 + GSPGPU_FlushDataCache(in, TIC80_FULLHEIGHT * FRAME_PITCH); 337 + } 338 + 339 + C3D_SyncDisplayTransfer( 340 + in, GX_BUFFER_DIM(256, 256), 341 + platform.render.tic_tex.data, GX_BUFFER_DIM(256, 256), 342 + (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | 343 + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | 344 + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) 345 + ); 346 + GSPGPU_FlushDataCache(platform.render.tic_tex.data, 256 * 256 * 4); 347 + } 348 + 349 + static void n3ds_draw_frame(void) 350 + { 351 + if (platform.keyboard.render_dirty && !platform.render.on_bottom) { 352 + C3D_FrameDrawOn(platform.render.target_bottom); 353 + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, platform.render.shader_proj_mtx_loc, &platform.render.proj_bottom); 354 + 355 + n3ds_keyboard_draw(&platform.keyboard); 356 + platform.keyboard.render_dirty = false; 357 + } 358 + 359 + if (!platform.render.on_bottom) { 360 + #ifdef RENDER_CONSOLE_TOP 361 + return; 362 + #endif 363 + } else { 364 + // clear top screen 365 + C3D_FrameDrawOn(platform.render.target_top); 366 + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, platform.render.shader_proj_mtx_loc, &platform.render.proj_top); 367 + 368 + // fill with border color 369 + C3D_RenderTargetClear(platform.render.target_top, C3D_CLEAR_ALL, platform.studio->tic->screen[0] >> 8, 0); 370 + } 371 + 372 + if (platform.render.on_bottom) { 373 + C3D_FrameDrawOn(platform.render.target_bottom); 374 + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, platform.render.shader_proj_mtx_loc, &platform.render.proj_bottom); 375 + 376 + // fill with border color 377 + C3D_RenderTargetClear(platform.render.target_bottom, C3D_CLEAR_ALL, platform.studio->tic->screen[0] >> 8, 0); 378 + } else { 379 + C3D_FrameDrawOn(platform.render.target_top); 380 + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, platform.render.shader_proj_mtx_loc, &platform.render.proj_top); 381 + 382 + // fill with border color 383 + C3D_RenderTargetClear(platform.render.target_top, C3D_CLEAR_ALL, platform.studio->tic->screen[0] >> 8, 0); 384 + } 385 + 386 + n3ds_draw_texture(&platform.render.tic_tex, 387 + platform.screen_size.x, platform.screen_size.y, 388 + 0, 0, 389 + platform.screen_size.width, platform.screen_size.height, 390 + TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 391 + 1.0f); 392 + } 393 + 394 + void n3ds_sound_init(int sample_rate) 395 + { 396 + float mix[12]; 397 + int buffer_size; 398 + 399 + platform.audio.samples = platform.studio->tic->samples.size / (TIC_STEREO_CHANNELS * sizeof(u16)); 400 + buffer_size = platform.audio.samples * (TIC_STEREO_CHANNELS * sizeof(u16)); 401 + 402 + platform.audio.buffer = linearAlloc(buffer_size * AUDIO_BLOCKS); 403 + platform.audio.buffer_size = buffer_size; 404 + memset(platform.audio.buffer, 0, buffer_size * AUDIO_BLOCKS); 405 + 406 + ndspInit(); 407 + ndspSetOutputMode(NDSP_OUTPUT_STEREO); 408 + ndspChnSetInterp(0, NDSP_INTERP_LINEAR); 409 + ndspChnSetRate(0, sample_rate); 410 + ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); 411 + 412 + memset(mix, 0, sizeof(mix)); 413 + mix[0] = 1.0f; 414 + mix[1] = 1.0f; 415 + ndspChnSetMix(0, mix); 416 + 417 + for(int i = 0; i < AUDIO_BLOCKS; i++) 418 + { 419 + platform.audio.ndspBuf[i].data_vaddr = &platform.audio.buffer[buffer_size * i]; 420 + platform.audio.ndspBuf[i].nsamples = platform.audio.samples; 421 + 422 + ndspChnWaveBufAdd(0, &platform.audio.ndspBuf[i]); 423 + } 424 + 425 + platform.audio.curr_block = 0; 426 + } 427 + 428 + void n3ds_sound_exit(void) 429 + { 430 + ndspExit(); 431 + linearFree(platform.audio.buffer); 432 + } 433 + 434 + static System systemInterface = 435 + { 436 + .setClipboardText = setClipboardText, 437 + .hasClipboardText = hasClipboardText, 438 + .getClipboardText = getClipboardText, 439 + .freeClipboardText = freeClipboardText, 440 + 441 + .getPerformanceCounter = getPerformanceCounter, 442 + .getPerformanceFrequency = getPerformanceFrequency, 443 + 444 + .httpGetSync = httpGetSync, 445 + .httpGet = httpGet, 446 + 447 + .fileDialogLoad = n3ds_file_dialog_load, 448 + .fileDialogSave = n3ds_file_dialog_save, 449 + 450 + .goFullscreen = goFullscreen, 451 + .showMessageBox = showMessageBox, 452 + .setWindowTitle = setWindowTitle, 453 + 454 + .openSystemPath = openSystemPath, 455 + .preseed = preseed, 456 + .poll = pollEvent, 457 + .updateConfig = updateConfig, 458 + }; 459 + 460 + static void audio_update(void) { 461 + ndspWaveBuf *wave_buf = &platform.audio.ndspBuf[platform.audio.curr_block]; 462 + 463 + if (wave_buf->status == NDSP_WBUF_DONE) { 464 + u16 *audio_ptr = wave_buf->data_pcm16; 465 + memcpy(audio_ptr, platform.studio->tic->samples.buffer, platform.audio.buffer_size); 466 + DSP_FlushDataCache(audio_ptr, platform.audio.buffer_size); 467 + 468 + ndspChnWaveBufAdd(0, wave_buf); 469 + platform.audio.curr_block = (platform.audio.curr_block + 1) % AUDIO_BLOCKS; 470 + } 471 + } 472 + 473 + static void touch_update(void) { 474 + u32 key_down = hidKeysDown(); 475 + u32 key_held = hidKeysHeld(); 476 + touchPosition touch; 477 + tic80_mouse *mouse = &platform.studio->tic->ram.input.mouse; 478 + 479 + if (key_held & KEY_TOUCH) 480 + { 481 + hidTouchRead(&touch); 482 + if ( 483 + touch.px >= platform.screen_size.x 484 + && touch.py >= platform.screen_size.y 485 + && touch.px < (platform.screen_size.x + platform.screen_size.width) 486 + && touch.py < (platform.screen_size.y + platform.screen_size.height) 487 + ) { 488 + int tic80_x = (int) ((touch.px - platform.screen_size.x) * TIC80_FULLWIDTH / platform.screen_size.width) - TIC80_OFFSET_LEFT; 489 + int tic80_y = (int) ((touch.py - platform.screen_size.y) * TIC80_FULLHEIGHT / platform.screen_size.height) - TIC80_OFFSET_TOP; 490 + if ( 491 + tic80_x >= 0 492 + && tic80_y >= 0 493 + && tic80_x < (TIC80_WIDTH) 494 + && tic80_y < (TIC80_HEIGHT) 495 + ) { 496 + mouse->x = tic80_x; 497 + mouse->y = tic80_y; 498 + mouse->left = true; 499 + } 500 + } 501 + } 502 + } 503 + 504 + static void keyboard_update(void) { 505 + hidScanInput(); 506 + 507 + platform.studio->tic->ram.input.mouse.btns = 0; 508 + if (!platform.render.on_bottom) { 509 + n3ds_keyboard_update(&platform.keyboard, platform.studio->tic, &platform.studio->text); 510 + } else { 511 + touch_update(); 512 + } 513 + n3ds_gamepad_update(&platform.keyboard, platform.studio->tic); 514 + 515 + u32 kup = hidKeysUp(); 516 + if (kup & KEY_SELECT) { 517 + platform.render.scaled = (platform.render.scaled + 1) % 3; 518 + 519 + if (platform.render.scaled == 2) { 520 + C3D_TexSetFilter(&platform.render.tic_tex, GPU_LINEAR, GPU_LINEAR); 521 + } else { 522 + C3D_TexSetFilter(&platform.render.tic_tex, GPU_NEAREST, GPU_LINEAR); 523 + } 524 + 525 + update_screen_size(); 526 + } 527 + if (kup & (KEY_L | KEY_R)) { 528 + platform.render.on_bottom = !platform.render.on_bottom; 529 + platform.keyboard.render_dirty = true; 530 + update_screen_size(); 531 + } 532 + } 533 + 534 + int main(int argc, char **argv) { 535 + char *backup_argv[] = { "/3ds/tic80/tic80.3dsx", 0 }; 536 + int argc_used = argc; 537 + char **argv_used = argv; 538 + 539 + if (argc_used <= 0 || argv_used[0] == NULL || argv_used[0][0] == '\0') { 540 + mkdir("/3ds/tic80", S_IRWXU | S_IRWXG | S_IRWXO); 541 + argc_used = 1; 542 + argv_used = backup_argv; 543 + } 544 + 545 + osSetSpeedupEnable(1); 546 + 547 + gfxInitDefault(); 548 + gfxSet3D(false); 549 + #ifdef RENDER_CONSOLE_TOP 550 + consoleInit(GFX_TOP, NULL); 551 + #endif 552 + romfsInit(); 553 + 554 + memset(&platform, 0, sizeof(platform)); 555 + LightLock_Init(&platform.tick_lock); 556 + 557 + #ifdef ENABLE_HTTPC 558 + n3ds_net_init(&platform.httpc, &platform.tick_lock); 559 + #endif 560 + 561 + n3ds_draw_init(); 562 + n3ds_keyboard_init(&platform.keyboard); 563 + 564 + #ifndef DISABLE_NETWORKING 565 + platform.net = createNet(); 566 + #endif 567 + platform.studio = studioInit(argc_used, argv_used, AUDIO_FREQ, "./", &systemInterface); 568 + platform.studio->tic->screen_format = TIC_PIXEL_COLOR_ABGR8888; 569 + 570 + n3ds_sound_init(AUDIO_FREQ); 571 + 572 + while (aptMainLoop() && !platform.studio->quit) { 573 + u32 start_frame = C3D_FrameCounter(0); 574 + 575 + LightLock_Lock(&platform.tick_lock); 576 + #ifndef DISABLE_NETWORKING 577 + netTick(platform.net); 578 + #endif 579 + keyboard_update(); 580 + 581 + platform.studio->tick(); 582 + audio_update(); 583 + n3ds_copy_frame(); 584 + 585 + LightLock_Unlock(&platform.tick_lock); 586 + 587 + bool sync = (C3D_FrameCounter(0) == start_frame); 588 + C3D_FrameBegin(sync ? C3D_FRAME_SYNCDRAW : 0); 589 + 590 + n3ds_draw_frame(); 591 + 592 + C3D_FrameEnd(0); 593 + } 594 + 595 + n3ds_sound_exit(); 596 + 597 + platform.studio->close(); 598 + #ifndef DISABLE_NETWORKING 599 + closeNet(platform.net); 600 + #endif 601 + 602 + n3ds_keyboard_free(&platform.keyboard); 603 + n3ds_draw_exit(); 604 + 605 + #ifdef ENABLE_HTTPC 606 + n3ds_net_free(&platform.httpc); 607 + #endif 608 + 609 + romfsExit(); 610 + gfxExit(); 611 + 612 + return 0; 613 + };
+227
src/system/n3ds/net_httpc.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #include <stdio.h> 24 + #include <stdlib.h> 25 + #include "system.h" 26 + #include "net_httpc.h" 27 + 28 + typedef struct { 29 + char url[TICNAME_MAX]; 30 + 31 + tic_n3ds_net *net; 32 + httpcContext httpc; 33 + HttpGetData data; 34 + HttpGetCallback callback; 35 + 36 + void *buffer; 37 + s32 size; 38 + } net_ctx; 39 + 40 + // #define DEBUG 41 + 42 + static int n3ds_net_setup_context(httpcContext *httpc, const char *url) { 43 + if (httpcOpenContext(httpc, HTTPC_METHOD_GET, url, 1)) return -101; 44 + if (httpcSetSSLOpt(httpc, SSLCOPT_DisableVerify)) { httpcCloseContext(httpc); return -102; } 45 + if (httpcSetKeepAlive(httpc, HTTPC_KEEPALIVE_ENABLED)) { httpcCloseContext(httpc); return -103; } 46 + if (httpcAddRequestHeaderField(httpc, "User-Agent", "tic80-n3ds/1.0.0 (httpc)")) { httpcCloseContext(httpc); return -104; } 47 + if (httpcAddRequestHeaderField(httpc, "Connection", "Keep-Alive")) { httpcCloseContext(httpc); return -105; } 48 + return 0; 49 + } 50 + 51 + #define NET_PAGE_SIZE 4096 52 + 53 + static inline bool ctx_resize_buf(net_ctx *ctx, s32 new_size) { 54 + if (ctx->buffer == NULL) { 55 + ctx->buffer = malloc(new_size); 56 + if (ctx->buffer == NULL) { 57 + return false; 58 + } 59 + } else if (ctx->size != new_size) { 60 + void *old_buf = ctx->buffer; 61 + ctx->buffer = realloc(ctx->buffer, new_size); 62 + if (ctx->buffer == NULL) { 63 + free(old_buf); 64 + return false; 65 + } 66 + } 67 + 68 + ctx->size = new_size; 69 + return true; 70 + } 71 + 72 + #define NET_EXEC_ERROR_CHECK \ 73 + if (status_code != 200) { \ 74 + printf("net_httpc: error %d\n", status_code); \ 75 + if (ctx->callback != NULL) { \ 76 + ctx->data.type = HttpGetError; \ 77 + ctx->data.error.code = status_code; \ 78 + if (!ignore_lock) LightLock_Lock(ctx->net->tick_lock); \ 79 + ctx->callback(&ctx->data); \ 80 + if (!ignore_lock) LightLock_Unlock(ctx->net->tick_lock); \ 81 + } \ 82 + httpcCloseContext(&ctx->httpc); \ 83 + if (ctx->buffer != NULL) { free(ctx->buffer); ctx->size = 0; } \ 84 + return; \ 85 + } 86 + 87 + static void n3ds_net_execute(net_ctx *ctx, bool ignore_lock) { 88 + bool redirecting = true; 89 + s32 status_code = -1; 90 + 91 + ctx->data.url = ctx->url; 92 + while (redirecting) { 93 + #ifdef DEBUG 94 + printf("url: %s\n", ctx->url); 95 + #endif 96 + redirecting = false; 97 + 98 + status_code = n3ds_net_setup_context(&ctx->httpc, ctx->url); 99 + if (status_code < 0) { 100 + break; 101 + } 102 + 103 + if (httpcBeginRequest(&ctx->httpc)) { 104 + status_code = -2; 105 + break; 106 + } 107 + 108 + if (httpcGetResponseStatusCode(&ctx->httpc, &status_code)) { 109 + status_code = -3; 110 + break; 111 + } 112 + 113 + if ((status_code >= 301 && status_code <= 303) || (status_code >= 307 && status_code <= 308)) { 114 + if (httpcGetResponseHeader(&ctx->httpc, "Location", ctx->url, TICNAME_MAX)) { 115 + status_code = -4; 116 + break; 117 + } 118 + 119 + redirecting = true; 120 + httpcCloseContext(&ctx->httpc); 121 + } 122 + } 123 + 124 + NET_EXEC_ERROR_CHECK; 125 + 126 + s32 state = HTTPC_RESULTCODE_DOWNLOADPENDING; 127 + s32 read_size; 128 + while (state == HTTPC_RESULTCODE_DOWNLOADPENDING) { 129 + s32 old_size = ctx->size; 130 + if (!ctx_resize_buf(ctx, ctx->size + NET_PAGE_SIZE)) { 131 + httpcCloseContext(&ctx->httpc); 132 + status_code = -5; 133 + break; 134 + } 135 + u8 *old_ptr = ((u8*) ctx->buffer) + old_size; 136 + state = httpcDownloadData(&ctx->httpc, old_ptr, NET_PAGE_SIZE, &read_size); 137 + if (state == HTTPC_RESULTCODE_DOWNLOADPENDING || state == 0) { 138 + ctx_resize_buf(ctx, old_size + read_size); 139 + if (ctx->callback != NULL) { 140 + if (ignore_lock || !LightLock_TryLock(ctx->net->tick_lock)) { 141 + ctx->data.type = HttpGetProgress; 142 + if (!httpcGetDownloadSizeState(&ctx->httpc, &ctx->data.progress.size, &ctx->data.progress.total)) { 143 + if (ctx->data.progress.total < ctx->data.progress.size) { 144 + ctx->data.progress.total = ctx->data.progress.size; 145 + } 146 + ctx->callback(&ctx->data); 147 + } 148 + if (!ignore_lock) LightLock_Unlock(ctx->net->tick_lock); 149 + } 150 + } 151 + } 152 + } 153 + 154 + #ifdef DEBUG 155 + printf("downloaded: %d bytes\n", ctx->size); 156 + #endif 157 + 158 + if (status_code == 200 && state != 0) { 159 + status_code = -6; 160 + } 161 + NET_EXEC_ERROR_CHECK; 162 + 163 + if (ctx->callback != NULL) { 164 + ctx->data.type = HttpGetDone; 165 + ctx->data.done.data = ctx->buffer; 166 + ctx->data.done.size = ctx->size; 167 + if (!ignore_lock) LightLock_Lock(ctx->net->tick_lock); 168 + ctx->callback(&ctx->data); 169 + if (!ignore_lock) LightLock_Unlock(ctx->net->tick_lock); 170 + } 171 + httpcCloseContext(&ctx->httpc); 172 + } 173 + 174 + void n3ds_net_init(tic_n3ds_net *net, LightLock *tick_lock) { 175 + httpcInit(0); 176 + 177 + memset(net, 0, sizeof(tic_n3ds_net)); 178 + net->tick_lock = tick_lock; 179 + } 180 + 181 + void n3ds_net_free(tic_n3ds_net *net) { 182 + httpcExit(); 183 + } 184 + 185 + static void n3ds_net_get_thread(net_ctx *ctx) { 186 + n3ds_net_execute(ctx, false); 187 + 188 + if (ctx->buffer != NULL) { 189 + free(ctx->buffer); 190 + } 191 + free(ctx); 192 + } 193 + 194 + static void n3ds_net_apply_url(net_ctx *ctx, const char *url) { 195 + strncpy(ctx->url, TIC_WEBSITE, TICNAME_MAX); 196 + strncat(ctx->url, url, TICNAME_MAX - 1); 197 + } 198 + 199 + void n3ds_net_get(tic_n3ds_net *net, const char *url, HttpGetCallback callback, void *calldata) { 200 + s32 priority; 201 + net_ctx *ctx; 202 + 203 + ctx = malloc(sizeof(net_ctx)); 204 + memset(&ctx, 0, sizeof(net_ctx)); 205 + 206 + n3ds_net_apply_url(ctx, url); 207 + ctx->net = net; 208 + ctx->callback = callback; 209 + ctx->data.calldata = calldata; 210 + 211 + svcGetThreadPriority(&priority, CUR_THREAD_HANDLE); 212 + threadCreate((ThreadFunc) n3ds_net_get_thread, ctx, 16 * 1024, priority - 1, -1, true); 213 + } 214 + 215 + void* n3ds_net_get_sync(tic_n3ds_net *net, const char *url, s32 *size) { 216 + net_ctx ctx; 217 + memset(&ctx, 0, sizeof(net_ctx)); 218 + 219 + n3ds_net_apply_url(&ctx, url); 220 + ctx.net = net; 221 + n3ds_net_execute(&ctx, true); 222 + 223 + if (size != NULL) { 224 + *size = ctx.size; 225 + } 226 + return ctx.buffer; 227 + }
+37
src/system/n3ds/net_httpc.h
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #pragma once 24 + 25 + #include "tic.h" 26 + #include "ticapi.h" 27 + 28 + #include <3ds.h> 29 + 30 + typedef struct { 31 + LightLock *tick_lock; 32 + } tic_n3ds_net; 33 + 34 + void n3ds_net_init(tic_n3ds_net *net, LightLock *tick_lock); 35 + void n3ds_net_free(tic_n3ds_net *net); 36 + void n3ds_net_get(tic_n3ds_net *net, const char *url, HttpGetCallback callback, void *calldata); 37 + void* n3ds_net_get_sync(tic_n3ds_net *net, const char *url, s32 *size);
src/system/n3ds/romfs/kbd_display.png

This is a binary file and will not be displayed.

+80
src/system/n3ds/utils.c
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #include <stdlib.h> 24 + 25 + #include <3ds.h> 26 + #include <citro3d.h> 27 + #include <png.h> 28 + 29 + #include "utils.h" 30 + 31 + static int npot(int v) { 32 + v--; 33 + v |= v >> 1; 34 + v |= v >> 2; 35 + v |= v >> 4; 36 + v |= v >> 8; 37 + v |= v >> 16; 38 + v++; 39 + return v; 40 + } 41 + 42 + bool ctr_load_png(C3D_Tex* tex, const char* name, texture_location loc) 43 + { 44 + png_image img; 45 + u32 *data; 46 + 47 + memset(&img, 0, sizeof(png_image)); 48 + img.version = PNG_IMAGE_VERSION; 49 + 50 + if (!png_image_begin_read_from_file(&img, name)) { 51 + return false; 52 + } 53 + 54 + img.format = PNG_FORMAT_ABGR; 55 + 56 + if (loc == TEXTURE_TARGET_VRAM) { 57 + C3D_TexInitVRAM(tex, npot(img.width), npot(img.height), GPU_RGBA8); 58 + } else { 59 + C3D_TexInit(tex, npot(img.width), npot(img.height), GPU_RGBA8); 60 + } 61 + data = linearAlloc(tex->width * tex->height * sizeof(u32)); 62 + 63 + if (!png_image_finish_read(&img, NULL, data, tex->width * sizeof(u32), NULL)) { 64 + linearFree(data); 65 + C3D_TexDelete(tex); 66 + return false; 67 + } 68 + 69 + GSPGPU_FlushDataCache(data, tex->width * tex->height * sizeof(u32)); 70 + 71 + C3D_SyncDisplayTransfer(data, GX_BUFFER_DIM(tex->width, tex->height), 72 + tex->data, GX_BUFFER_DIM(tex->width, tex->height), 73 + GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | 74 + GX_TRANSFER_IN_FORMAT(GPU_RGBA8) | GX_TRANSFER_OUT_FORMAT(GPU_RGBA8) 75 + | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)); 76 + 77 + linearFree(data); 78 + png_image_free(&img); 79 + return true; 80 + }
+34
src/system/n3ds/utils.h
··· 1 + // MIT License 2 + 3 + // Copyright (c) 2020 Adrian "asie" Siekierka 4 + 5 + // Permission is hereby granted, free of charge, to any person obtaining a copy 6 + // of this software and associated documentation files (the "Software"), to deal 7 + // in the Software without restriction, including without limitation the rights 8 + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + // copies of the Software, and to permit persons to whom the Software is 10 + // furnished to do so, subject to the following conditions: 11 + 12 + // The above copyright notice and this permission notice shall be included in all 13 + // copies or substantial portions of the Software. 14 + 15 + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + // SOFTWARE. 22 + 23 + #pragma once 24 + 25 + #include <3ds.h> 26 + #include <citro3d.h> 27 + #include <png.h> 28 + 29 + typedef enum { 30 + TEXTURE_TARGET_RAM, 31 + TEXTURE_TARGET_VRAM 32 + } texture_location; 33 + 34 + bool ctr_load_png(C3D_Tex* tex, const char *name, texture_location loc);
+10
src/tic.c
··· 28 28 #include <stddef.h> 29 29 #include <time.h> 30 30 31 + #ifdef _3DS 32 + #include <3ds.h> 33 + #endif 34 + 31 35 #include "ticapi.h" 32 36 #include "tools.h" 33 37 #include "tilesheet.h" ··· 2258 2262 2259 2263 machine->memory.screen_format = TIC_PIXEL_COLOR_RGBA8888; 2260 2264 machine->samplerate = samplerate; 2265 + #ifdef _3DS 2266 + // To feed texture data directly to the 3DS GPU, linearly allocated memory is required, which is 2267 + // not guaranteed by malloc. 2268 + // Additionally, allocate TIC80_FULLHEIGHT + 1 lines to minimize glitches in linear scaling mode. 2269 + machine->memory.screen = linearAlloc(TIC80_FULLWIDTH * (TIC80_FULLHEIGHT + 1) * sizeof(u32)); 2270 + #endif 2261 2271 machine->memory.samples.size = samplerate * TIC_STEREO_CHANNELS / TIC80_FRAMERATE * sizeof(s16); 2262 2272 machine->memory.samples.buffer = malloc(machine->memory.samples.size); 2263 2273
+4
src/ticapi.h
··· 162 162 s32 size; 163 163 } samples; 164 164 165 + #if defined(_3DS) 166 + u32 *screen; 167 + #else 165 168 u32 screen[TIC80_FULLWIDTH * TIC80_FULLHEIGHT]; 169 + #endif 166 170 tic_pixel_color_format screen_format; 167 171 }; 168 172