diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..711e4ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,254 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ +bld/ +[Bb]in/ +[Oo]bj/ +/Tools +/11.2 + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs +[Tt]humbs.db + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ + +#3DS +*.elf +*.cia +*.3dsx +output/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c3e59c5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "buildtools"] + path = buildtools + url = git@github.com:Steveice10/buildtools.git diff --git a/HBDummy.sln b/HBDummy.sln new file mode 100644 index 0000000..b9ff25b --- /dev/null +++ b/HBDummy.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HBDummy", "HBDummy.vcxproj", "{B2F0601F-BEC5-4653-A44F-BB9617A02F2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Debug|x64.ActiveCfg = Debug|x64 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Debug|x64.Build.0 = Debug|x64 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Debug|x86.ActiveCfg = Debug|Win32 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Debug|x86.Build.0 = Debug|Win32 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Release|x64.ActiveCfg = Release|x64 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Release|x64.Build.0 = Release|x64 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Release|x86.ActiveCfg = Release|Win32 + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/HBDummy.vcxproj b/HBDummy.vcxproj new file mode 100644 index 0000000..6b64e28 --- /dev/null +++ b/HBDummy.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {B2F0601F-BEC5-4653-A44F-BB9617A02F2C} + HBDummy + 8.1 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Makefile + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + C:\Users\Nath\Desktop\prog\HBDummy\source;C:\devkitPro\libctru\include;$(IncludePath) + + + C:\devkitPro\libctru\include;$(ProjectDir)\lib\ctrcommon\include\ctrcommon;$(IncludePath) + C:\devkitPro\libctru\include;$(ReferencePath) + + + make + make clean & make + make clean + C:\devkitPro\libctru\include;$(NMakeForcedIncludes) + C:\devkitPro\portlibs\3ds\include;C:\devkitPro\libctru\include;$(IncludePath) + C:\devkitPro\libctru\include; + + + + Level3 + Disabled + true + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HBDummy.vcxproj.filters b/HBDummy.vcxproj.filters new file mode 100644 index 0000000..d1e62f0 --- /dev/null +++ b/HBDummy.vcxproj.filters @@ -0,0 +1,153 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Fichiers de ressources + + + + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + + + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d718acc --- /dev/null +++ b/Makefile @@ -0,0 +1,91 @@ +# TARGET # + +TARGET := 3DS +LIBRARY := 0 + +ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU)) + ifeq ($(strip $(DEVKITPRO)),) + $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPro") + endif +endif + +# COMMON CONFIGURATION # + +NAME := Homebrew_Launcher + + +BUILD_DIR := build +OUTPUT_DIR := output +INCLUDE_DIRS := $(SOURCE_DIRS) include +SOURCE_DIRS := source source/json source/allocator + +EXTRA_OUTPUT_FILES := + +LIBRARY_DIRS := $(PORTLIBS) $(CTRULIB) +LIBRARIES := citro3d ctru png z m + +VERSION_MAJOR := 1 +VERSION_MINOR := 0 +VERSION_MICRO := 0 + + +BUILD_FLAGS := -march=armv6k -mtune=mpcore -mfloat-abi=hard +BUILD_FLAGS_CC := -g -Wall -Wno-strict-aliasing -O3 -mword-relocations \ + -fomit-frame-pointer -ffast-math $(ARCH) $(INCLUDE) -DARM11 -D_3DS $(BUILD_FLAGS) \ + -DAPP_VERSION_MAJOR=${VERSION_MAJOR} \ + -DAPP_VERSION_MINOR=${VERSION_MINOR} \ + -DAPP_VERSION_MICRO=${VERSION_MICRO} + +BUILD_FLAGS_CXX := $(COMMON_FLAGS) -std=gnu++11 +RUN_FLAGS := + + + + + +# 3DS/Wii U CONFIGURATION # + +ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU)) + TITLE := Homebrew Launcher + DESCRIPTION := HBL + AUTHOR := By Many People +endif + +# 3DS CONFIGURATION # + +ifeq ($(TARGET),3DS) + LIBRARY_DIRS += $(DEVKITPRO)/libctru $(DEVKITPRO)/portlibs/3ds/ + LIBRARIES += citro3d ctru png z m + + PRODUCT_CODE := HBL-LDR + UNIQUE_ID := 0xd921e + + CATEGORY := Application + USE_ON_SD := true + + MEMORY_TYPE := Application + SYSTEM_MODE := 64MB + SYSTEM_MODE_EXT := Legacy + CPU_SPEED := 268MHz + ENABLE_L2_CACHE := false + + ICON_FLAGS := --flags visible,ratingrequired,recordusage --cero 153 --esrb 153 --usk 153 --pegigen 153 --pegiptr 153 --pegibbfc 153 --cob 153 --grb 153 --cgsrr 153 + + ROMFS_DIR := romfs + BANNER_AUDIO := resources/audio.cwav + + BANNER_IMAGE := resources/banner.cgfx + + ICON := resources/icon.png + + LOGO := resources/logo.bcma.lz +endif + +# INTERNAL # + +include buildtools/make_base + +re: + @rm -rf $(BUILD_DIR) + echo cleaned build dir + make \ No newline at end of file diff --git a/buildtools/.buildconfig b/buildtools/.buildconfig new file mode 100644 index 0000000..116b101 --- /dev/null +++ b/buildtools/.buildconfig @@ -0,0 +1,10 @@ +[default] +name=Default +runtime=host +config-opts= +run-opts= +prefix=/home/steven/.cache/gnome-builder/install/buildtools/host +app-id= +postbuild= +prebuild= +default=true diff --git a/buildtools/3ds/logo.bcma.lz b/buildtools/3ds/logo.bcma.lz new file mode 100644 index 0000000..dd9db8c Binary files /dev/null and b/buildtools/3ds/logo.bcma.lz differ diff --git a/buildtools/3ds/servefiles.py b/buildtools/3ds/servefiles.py new file mode 100644 index 0000000..549ef3a --- /dev/null +++ b/buildtools/3ds/servefiles.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# coding: utf-8 -*- + +import os +import socket +import struct +import sys +import threading +import time +import urllib + +try: + from SimpleHTTPServer import SimpleHTTPRequestHandler + from SocketServer import TCPServer + from urlparse import urljoin + from urllib import pathname2url, quote +except ImportError: + from http.server import SimpleHTTPRequestHandler + from socketserver import TCPServer + from urllib.parse import urljoin, quote + from urllib.request import pathname2url + +if len(sys.argv) < 3 or len(sys.argv) > 5: + print('Usage: ' + sys.argv[0] + ' [host ip] [host port]') + sys.exit(1) + +accepted_extension = ('.cia', '.tik', '.cetk') +target_ip = sys.argv[1] +target_path = sys.argv[2] +hostPort = 8080 # Default value + +if not os.path.exists(target_path): + print(target_path + ': No such file or directory.') + sys.exit(1) + +if len(sys.argv) >= 4: + hostIp = sys.argv[3] + if len(sys.argv) == 5: + hostPort = int(sys.argv[4]) +else: + print('Detecting host IP...') + hostIp = [(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1] + +print('Preparing data...') +baseUrl = hostIp + ':' + str(hostPort) + '/' + +if os.path.isfile(target_path): + if target_path.endswith(accepted_extension): + file_list_payload = baseUrl + quote(os.path.basename(target_path)) + directory = os.path.dirname(target_path) # get file directory + else: + print('Unsupported file extension. Supported extensions are: ' + accepted_extension) + sys.exit(1) + +else: + directory = target_path # it's a directory + file_list_payload = '' # init the payload before adding lines + for file in [file for file in next(os.walk(target_path))[2] if file.endswith(accepted_extension)]: + file_list_payload += baseUrl + quote(file) + '\n' + +if len(file_list_payload) == 0: + print('No files to serve.') + sys.exit(1) + +file_list_payloadBytes = file_list_payload.encode('ascii') + +if directory and directory != '.': # doesn't need to move if it's already the current working directory + os.chdir(directory) # set working directory to the right folder to be able to serve files + +print('\nURLs:') +print(file_list_payload + '\n') + +print('Opening HTTP server on port ' + str(hostPort)) +server = TCPServer(('', hostPort), SimpleHTTPRequestHandler) +thread = threading.Thread(target=server.serve_forever) +thread.start() + +try: + print('Sending URL(s) to ' + target_ip + ' on port 5000...') + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((target_ip, 5000)) + sock.sendall(struct.pack('!L', len(file_list_payloadBytes)) + file_list_payloadBytes) + while len(sock.recv(1)) < 1: + time.sleep(0.05) + sock.close() +except Exception as e: + print('An error occurred: ' + str(e)) + server.shutdown() + sys.exit(1) + +print('Shutting down HTTP server...') +server.shutdown() diff --git a/buildtools/3ds/template.rsf b/buildtools/3ds/template.rsf new file mode 100644 index 0000000..e89849d --- /dev/null +++ b/buildtools/3ds/template.rsf @@ -0,0 +1,286 @@ +BasicInfo: + Title : $(APP_TITLE) + ProductCode : $(APP_PRODUCT_CODE) + Logo : Homebrew + +RomFs: + RootPath: $(APP_ROMFS) + +TitleInfo: + Category : $(APP_CATEGORY) + UniqueId : $(APP_UNIQUE_ID) + +Option: + UseOnSD : $(APP_USE_ON_SD) # true if App is to be installed to SD + FreeProductCode : true # Removes limitations on ProductCode + MediaFootPadding : false # If true CCI files are created with padding + EnableCrypt : $(APP_ENCRYPTED) # Enables encryption for NCCH and CIA + EnableCompress : true # Compresses where applicable (currently only exefs:/.code) + +AccessControlInfo: + CoreVersion : 2 + + # Exheader Format Version + DescVersion : 2 + + # Minimum Required Kernel Version (below is for 4.5.0) + ReleaseKernelMajor : "02" + ReleaseKernelMinor : "33" + + # ExtData + UseExtSaveData : false # enables ExtData + #ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId + + # FS:USER Archive Access Permissions + # Uncomment as required + FileSystemAccess: + - CategorySystemApplication + - CategoryHardwareCheck + - CategoryFileSystemTool + - Debug + - TwlCardBackup + - TwlNandData + - Boss + - DirectSdmc + - Core + - CtrNandRo + - CtrNandRw + - CtrNandRoWrite + - CategorySystemSettings + - CardBoard + - ExportImportIvs + - DirectSdmcWrite + - SwitchCleanup + - SaveDataMove + - Shop + - Shell + - CategoryHomeMenu + - SeedDB + IoAccessControl: + - FsMountNand + - FsMountNandRoWrite + - FsMountTwln + - FsMountWnand + - FsMountCardSpi + - UseSdif3 + - CreateSeed + - UseCardSpi + + # Process Settings + MemoryType : $(APP_MEMORY_TYPE) # Application/System/Base + SystemMode : $(APP_SYSTEM_MODE) # 64MB(Default)/96MB/80MB/72MB/32MB + IdealProcessor : 0 + AffinityMask : 1 + Priority : 16 + MaxCpu : 0x9E # Default + HandleTableSize : 0x200 + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : true + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : true + PermitMainFunctionArgument : true + CanShareDeviceMemory : true + RunnableOnSleep : false + SpecialMemoryArrange : true + + # New3DS Exclusive Process Settings + SystemModeExt : $(APP_SYSTEM_MODE_EXT) # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode + CpuSpeed : $(APP_CPU_SPEED) # 268MHz(Default)/804MHz + EnableL2Cache : $(APP_ENABLE_L2_CACHE) # false(default)/true + CanAccessCore2 : true + + # Virtual Address Mappings + IORegisterMapping: + - 1ff00000-1ff7ffff # DSP memory + MemoryMapping: + - 1f000000-1f5fffff:r # VRAM + + # Accessible SVCs, : + SystemCallAccess: + ControlMemory: 1 + QueryMemory: 2 + ExitProcess: 3 + GetProcessAffinityMask: 4 + SetProcessAffinityMask: 5 + GetProcessIdealProcessor: 6 + SetProcessIdealProcessor: 7 + CreateThread: 8 + ExitThread: 9 + SleepThread: 10 + GetThreadPriority: 11 + SetThreadPriority: 12 + GetThreadAffinityMask: 13 + SetThreadAffinityMask: 14 + GetThreadIdealProcessor: 15 + SetThreadIdealProcessor: 16 + GetCurrentProcessorNumber: 17 + Run: 18 + CreateMutex: 19 + ReleaseMutex: 20 + CreateSemaphore: 21 + ReleaseSemaphore: 22 + CreateEvent: 23 + SignalEvent: 24 + ClearEvent: 25 + CreateTimer: 26 + SetTimer: 27 + CancelTimer: 28 + ClearTimer: 29 + CreateMemoryBlock: 30 + MapMemoryBlock: 31 + UnmapMemoryBlock: 32 + CreateAddressArbiter: 33 + ArbitrateAddress: 34 + CloseHandle: 35 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + SignalAndWait: 38 + DuplicateHandle: 39 + GetSystemTick: 40 + GetHandleInfo: 41 + GetSystemInfo: 42 + GetProcessInfo: 43 + GetThreadInfo: 44 + ConnectToPort: 45 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + OpenProcess: 51 + OpenThread: 52 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetThreadId: 55 + GetResourceLimit: 56 + GetResourceLimitLimitValues: 57 + GetResourceLimitCurrentValues: 58 + GetThreadContext: 59 + Break: 60 + OutputDebugString: 61 + ControlPerformanceCounter: 62 + CreatePort: 71 + CreateSessionToPort: 72 + CreateSession: 73 + AcceptSession: 74 + ReplyAndReceive1: 75 + ReplyAndReceive2: 76 + ReplyAndReceive3: 77 + ReplyAndReceive4: 78 + ReplyAndReceive: 79 + BindInterrupt: 80 + UnbindInterrupt: 81 + InvalidateProcessDataCache: 82 + StoreProcessDataCache: 83 + FlushProcessDataCache: 84 + StartInterProcessDma: 85 + StopDma: 86 + GetDmaState: 87 + RestartDma: 88 + DebugActiveProcess: 96 + BreakDebugProcess: 97 + TerminateDebugProcess: 98 + GetProcessDebugEvent: 99 + ContinueDebugEvent: 100 + GetProcessList: 101 + GetThreadList: 102 + GetDebugThreadContext: 103 + SetDebugThreadContext: 104 + QueryDebugProcessMemory: 105 + ReadProcessMemory: 106 + WriteProcessMemory: 107 + SetHardwareBreakPoint: 108 + GetDebugThreadParam: 109 + ControlProcessMemory: 112 + MapProcessMemory: 113 + UnmapProcessMemory: 114 + CreateCodeSet: 115 + CreateProcess: 117 + TerminateProcess: 118 + SetProcessResourceLimits: 119 + CreateResourceLimit: 120 + SetResourceLimitValues: 121 + AddCodeSegment: 122 + Backdoor: 123 + KernelSetState: 124 + QueryProcessMemory: 125 + + # Service List + # Maximum 34 services (32 if firmware is prior to 9.6.0) + ServiceAccessControl: + - APT:U + - ac:u + - am:net + - boss:U + - cam:u + - cecd:u + - cfg:nor + - cfg:u + - csnd:SND + - dsp::DSP + - frd:u + - fs:USER + - gsp::Gpu + - gsp::Lcd + - hid:USER + - http:C + - ir:rst + - ir:u + - ir:USER + - mic:u + - mcu::HWC + - ndm:u + - news:s + - nwm::EXT + - nwm::UDS + - ptm:sysm + - ptm:u + - pxi:dev + - soc:U + - ssl:C + - y2r:u + + +SystemControlInfo: + SaveDataSize: 0KB # Change if the app uses savedata + RemasterVersion: $(APP_VERSION_MAJOR) + StackSize: 0x40000 + + # Modules that run services listed above should be included below + # Maximum 48 dependencies + # : + Dependency: + ac: 0x0004013000002402 + #act: 0x0004013000003802 + am: 0x0004013000001502 + boss: 0x0004013000003402 + camera: 0x0004013000001602 + cecd: 0x0004013000002602 + cfg: 0x0004013000001702 + codec: 0x0004013000001802 + csnd: 0x0004013000002702 + dlp: 0x0004013000002802 + dsp: 0x0004013000001a02 + friends: 0x0004013000003202 + gpio: 0x0004013000001b02 + gsp: 0x0004013000001c02 + hid: 0x0004013000001d02 + http: 0x0004013000002902 + i2c: 0x0004013000001e02 + ir: 0x0004013000003302 + mcu: 0x0004013000001f02 + mic: 0x0004013000002002 + ndm: 0x0004013000002b02 + news: 0x0004013000003502 + #nfc: 0x0004013000004002 + nim: 0x0004013000002c02 + nwm: 0x0004013000002d02 + pdn: 0x0004013000002102 + ps: 0x0004013000003102 + ptm: 0x0004013000002202 + #qtm: 0x0004013020004202 + ro: 0x0004013000003702 + socket: 0x0004013000002e02 + spi: 0x0004013000002302 + ssl: 0x0004013000002f02 diff --git a/buildtools/README.md b/buildtools/README.md new file mode 100644 index 0000000..f6589ee --- /dev/null +++ b/buildtools/README.md @@ -0,0 +1,13 @@ +# buildtools + +Common build tools for C/C++ projects. Supports PC and 3DS targets. + +Dependencies: + * [makerom](https://github.com/profi200/Project_CTR/tree/master/makerom/) - Building 3DS/CIA files. + * [bannertool](https://github.com/Steveice10/bannertool/) - Building 3DS/CIA files. + * [citra](https://github.com/citra-emu/citra/) - Testing 3DS/CIA builds on a PC. + * zip - Zipping up output files. + * xxd - Embedding binary files in executables. + * python - Installing CIA builds to a 3DS over the network. + +Credit for 3DS homebrew logo goes to [PabloMK7](http://gbatemp.net/members/pablomk7.345712/). diff --git a/buildtools/make_base b/buildtools/make_base new file mode 100644 index 0000000..48f152b --- /dev/null +++ b/buildtools/make_base @@ -0,0 +1,761 @@ +# Make Variables +# +# TARGET: Optional; Platform to build for. +# - Supported values: NATIVE, NATIVE32, NATIVE64, WIN32, WIN64, MAC32, MAC64, LINUX32, LINUX64, 3DS, WIIU, SWITCH +# - Default value: NATIVE +# LIBRARY: Optional; Whether to output a library. +# - Supported values: 0, 1 +# - Default value: 0 +# +# All: +# - NAME: Project name. +# - INCLUDE_DIRS: Directories containing include headers. +# - SOURCE_DIRS: Directories containing source files to compile. +# - BUILD_DIR: Directory to store build files in. +# - OUTPUT_DIR: Directory to output the final results to. +# - LIBRARY_DIRS: Optional; Directories containing libraries to compile against. +# - LIBRARIES: Optional; Libraries to compile against. +# - EXTRA_OUTPUT_FILES: Optional; Extra files to copy to the output directory. +# - BUILD_FLAGS: Optional; Shared build flags. +# - BUILD_FLAGS_CC: Optional; C build flags. +# - BUILD_FLAGS_CXX: Optional; C++ build flags. +# - RUN_FLAGS: Optional; Flags to pass when running output executables. +# - VERSION_MAJOR: Optional; Major version number. +# - Default value: 0 +# - VERSION_MINOR: Optional; Minor version number. +# - Default value: 0 +# - VERSION_MICRO: Optional; Micro version number. +# - Default value: 0 +# +# 3DS/Wii U/Switch: +# - TITLE: Optional; Formal application title, used in metadata. +# - Default value: NAME stripped of spaces. +# - AUTHOR: Optional; Application author. +# - Default value: "Unknown" +# - REMOTE_IP: Optional; IP to send executable to when running on hardware. Intended to be set in command line. +# - Default value: 127.0.0.1 +# +# 3DS/Wii U: +# - DESCRIPTION: Optional; Application description. +# - Default value: "No description." +# +# 3DS: +# - PRODUCT_CODE: CIA/3DS product code. +# - UNIQUE_ID: CIA/3DS unique ID. +# - BANNER_AUDIO: Audio file to use in the CIA/3DS banner. +# - Supported file types: WAV, CWAV +# - BANNER_IMAGE: Graphics to use in the CIA/3DS banner. +# - Supported file types: 256x128 PNG, CGFX +# - ICON: Application icon. +# - Supported file types: 48x48 PNG +# - Category: Optional; CIA/3DS category. +# - Supported values: Application, SystemApplication, Applet, Firmware, Base, DlpChild, Demo, Contents, SystemContents, SharedContents, AddOnContents, Patch, AutoUpdateContents +# - Default value: Application +# - USE_ON_SD: Optional; Whether the CIA/3DS should be installed to the SD card. +# - Supported values: true, false +# - Default value: true +# - MEMORY_TYPE: Optional; CIA/3DS application memory layout. +# - Supported values: Application, System, Base +# - Default value: Application +# - SYSTEM_MODE: Optional; CIA/3DS legacy system mode. +# - Supported values: 32MB, 64MB, 72MB, 80MB, 96MB +# - Default value: 64MB +# - SYSTEM_MODE_EXT: Optional; CIA/3DS extended system mode. +# - Supported values: Legacy, 124MB, 178MB +# - Default value: Legacy +# - CPU_MODE: Optional; CIA/3DS CPU frequency. 804MHz is N3DS-only. +# - Supported values: 268MHz, 804MHz +# - Default value: 268MHz +# - ENABLE_L2_CACHE: Optional; Whether the CIA/3DS should use the N3DS L2 cache. +# - Supported values: true, false +# - Default value: false +# - ICON_FLAGS: Optional; Flags to pass to bannertool when making an SMDH icon. +# - ROMFS_DIR: Optional; Directory containing RomFS files. +# - LOGO: Optional; Logo animation to use when launching the CIA/3DS. +# - Supported file types: BCMA.LZ +# +# Wii U: +# - ICON: Application icon. +# - Supported file types: 256x96 PNG +# - LONG_DESCRIPTION: Optional; Long version of the description field. +# - Default value: Value of DESCRIPTION. +# +# Switch: +# - TITLE_ID: Optional; Application title ID. +# - ICON: Optional; Application icon. +# - Supported file types: 256x256 JPEG + +# PROLOGUE # + +TARGET ?= NATIVE +LIBRARY ?= 0 + +ALL_PC_TARGETS := WIN32 WIN64 MAC32 MAC64 LINUX32 LINUX64 +ALL_SPECIFIC_TARGETS := $(ALL_PC_TARGETS) 3DS WIIU SWITCH +ALL_TARGETS := NATIVE NATIVE32 NATIVE64 $(ALL_SPECIFIC_TARGETS) + +TARGETS := + +ifneq (1,$(words $(TARGET))) + TARGETS := $(TARGET) +else ifeq ($(TARGET),ALL) + TARGETS := $(ALL_SPECIFIC_TARGETS) +else ifeq ($(TARGET),PC) + TARGETS := $(ALL_PC_TARGETS) +endif + +ifneq ($(TARGETS),) + +.PHONY: all clean +all: + @$(foreach target,$(TARGETS),make --no-print-directory TARGET=$(target);) + +else + +ifneq ($(MAKECMDGOALS),clean) + $(info Building for $(TARGET)...) +endif + +ifeq ($(TARGET),$(filter $(TARGET),3DS WIIU SWITCH)) + ifeq ($(strip $(DEVKITPRO)),) + $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPro") + endif +endif + +# TOOLS # + +BUILDTOOLS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) + +define createdirrule +$(1): | $(dir $(1)) + +ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED +$(dir $(1)): + @mkdir -p $$@ + +$(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1 +endif +endef + +rwildcard=$(wildcard $1/$2) $(foreach d,$(wildcard $1/*),$(call rwildcard,$d,$2)) + +# INITIAL COMMON SETUP # + +EMPTY := +SPACE := $(EMPTY) $(EMPTY) +STRIPPED_NAME := $(subst $(SPACE),,$(NAME)) + +ifeq ($(OS),Windows_NT) + HOST_OS := windows + ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) + HOST_ARCH := x86_64 + else + HOST_ARCH := i686 + endif +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Darwin) + HOST_OS := mac + else ifeq ($(UNAME_S),Linux) + HOST_OS := linux + else + $(error "Unsupported host OS.") + endif + + UNAME_M := $(shell uname -m) + ifeq ($(UNAME_M),$(filter $(UNAME_M),x86_64 amd64)) + HOST_ARCH := x86_64 + else ifeq ($(UNAME_M),$(filter $(UNAME_M),i386 i686)) + HOST_ARCH := i686 + else + $(error "Unsupported host architecture.") + endif +endif + +ifeq ($(TARGET),NATIVE) + TARGET_OS := $(HOST_OS) + TARGET_ARCH := $(HOST_ARCH) +else ifeq ($(TARGET),NATIVE32) + TARGET_OS := $(HOST_OS) + TARGET_ARCH := i686 +else ifeq ($(TARGET),NATIVE64) + TARGET_OS := $(HOST_OS) + TARGET_ARCH := x86_64 +else ifeq ($(TARGET),WIN32) + TARGET_OS := windows + TARGET_ARCH := i686 +else ifeq ($(TARGET),WIN64) + TARGET_OS := windows + TARGET_ARCH := x86_64 +else ifeq ($(TARGET),LINUX32) + TARGET_OS := linux + TARGET_ARCH := i686 +else ifeq ($(TARGET),LINUX64) + TARGET_OS := linux + TARGET_ARCH := x86_64 +else ifeq ($(TARGET),MAC32) + TARGET_OS := mac + TARGET_ARCH := i686 +else ifeq ($(TARGET),MAC64) + TARGET_OS := mac + TARGET_ARCH := x86_64 +else ifeq ($(TARGET),3DS) + TARGET_OS := 3ds + TARGET_ARCH := arm +else ifeq ($(TARGET),WIIU) + TARGET_OS := wiiu + TARGET_ARCH := ppc +else ifeq ($(TARGET),SWITCH) + TARGET_OS := switch + TARGET_ARCH := aarch64 +else + $(error "Unknown target. Supported targets: $(ALL_TARGETS)") +endif + +TARGET_BUILD_DIR := $(BUILD_DIR)/$(TARGET_OS)-$(TARGET_ARCH) +TARGET_OUTPUT_DIR := $(OUTPUT_DIR)/$(TARGET_OS)-$(TARGET_ARCH) + +BUILT_FILTER := $(patsubst %.bin,$(TARGET_BUILD_DIR)/%.bin.o,$(BUILD_FILTER)) \ + $(patsubst %.c,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER)) \ + $(patsubst %.cpp,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER)) \ + $(patsubst %.s,$(TARGET_BUILD_DIR)/%.o,$(BUILD_FILTER)) + +OBJECT_FILES := $(foreach dir,$(SOURCE_DIRS), \ + $(patsubst %.bin,$(TARGET_BUILD_DIR)/%.bin.o,$(call rwildcard,$(dir),*.bin)) \ + $(patsubst %.c,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.c)) \ + $(patsubst %.cpp,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.cpp)) \ + $(patsubst %.s,$(TARGET_BUILD_DIR)/%.o,$(call rwildcard,$(dir),*.s)) \ + ) + +OBJECT_FILES := $(filter-out $(BUILT_FILTER),$(OBJECT_FILES)) + +OUTPUT_ZIP_FILE ?= $(OUTPUT_DIR)/$(STRIPPED_NAME).zip + +ifeq ($(strip $(VERSION_MAJOR)),) + VERSION_MAJOR := 0 +endif + +ifeq ($(strip $(VERSION_MINOR)),) + VERSION_MINOR := 0 +endif + +ifeq ($(strip $(VERSION_MICRO)),) + VERSION_MICRO := 0 +endif + +LD_FLAGS := $(patsubst %,-L%/lib,$(LIBRARY_DIRS)) $(patsubst %,-l%,$(LIBRARIES)) +COMMON_CC_FLAGS := $(sort $(foreach dir,$(SOURCE_DIRS),$(patsubst %,-I$(TARGET_BUILD_DIR)/%,$(dir $(call rwildcard,$(dir),*))))) $(patsubst %,-I%,$(INCLUDE_DIRS)) $(patsubst %,-I%/include,$(LIBRARY_DIRS)) -g -Wall -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_MICRO=$(VERSION_MICRO) $(BUILD_FLAGS) +COMMON_CXX_FLAGS := + +ifeq ($(findstring -O,$(BUILD_FLAGS)),) + COMMON_CC_FLAGS += -O2 +endif + +# COMMON LIBRARY SETUP # + +ifeq ($(LIBRARY),1) + STRIPPED_NAME := lib$(STRIPPED_NAME) + EXTRA_OUTPUT_FILES += $(INCLUDE_DIRS) +endif + +# TARGET SETUP # + +REMOTE_IP ?= 127.0.0.1 # User-defined + +TITLE ?= $(NAME) +AUTHOR ?= "Unknown" +DESCRIPTION ?= "No description." +LONG_DESCRIPTION ?= $(DESCRIPTION) + +ifeq ($(TARGET_OS),windows) + ifeq ($(HOST_OS),windows) + AR := ar + AS := as + CC := gcc + CXX := g++ + else ifeq ($(TARGET_ARCH),i686) + AR := i686-w64-mingw32-ar + AS := i686-w64-mingw32-as + CC := i686-w64-mingw32-gcc + CXX := i686-w64-mingw32-g++ + else ifeq ($(TARGET_ARCH),x86_64) + AR := x86_64-w64-mingw32-ar + AS := x86_64-w64-mingw32-as + CC := x86_64-w64-mingw32-gcc + CXX := x86_64-w64-mingw32-g++ + endif + + ifeq ($(TARGET_ARCH),i686) + COMMON_CC_FLAGS += -m32 + else ifeq ($(TARGET_ARCH),x86_64) + COMMON_CC_FLAGS += -m64 + endif + + LD_FLAGS += -static-libstdc++ -static-libgcc -static + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).dll + COMMON_CC_FLAGS += -fPIC + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).exe + endif +else ifeq ($(TARGET_OS),mac) + ifeq ($(HOST_OS),mac) + AR := ar + AS := as + CC := gcc + CXX := g++ + else ifeq ($(TARGET_ARCH),i686) + AR := i386-apple-darwin15-ar + AS := i386-apple-darwin15-as + CC := i386-apple-darwin15-gcc + CXX := i386-apple-darwin15-g++ + else ifeq ($(TARGET_ARCH),x86_64) + AR := x86_64-apple-darwin15-ar + AS := x86_64-apple-darwin15-as + CC := x86_64-apple-darwin15-gcc + CXX := x86_64-apple-darwin15-g++ + endif + + ifeq ($(TARGET_ARCH),i686) + COMMON_CC_FLAGS += -m32 + else ifeq ($(TARGET_ARCH),x86_64) + COMMON_CC_FLAGS += -m64 + endif + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).so $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).dylib + COMMON_CC_FLAGS += -fPIC + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME) + endif +else ifeq ($(TARGET_OS),linux) + ifeq ($(HOST_OS),linux) + AR := ar + AS := as + CC := gcc + CXX := g++ + else ifeq ($(TARGET_ARCH),i686) + AR := i686-pc-linux-gnu-ar + AS := i686-pc-linux-gnu-as + CC := i686-pc-linux-gnu-gcc + CXX := i686-pc-linux-gnu-g++ + else ifeq ($(TARGET_ARCH),x86_64) + AR := x86_64-pc-linux-gnu-ar + AS := x86_64-pc-linux-gnu-as + CC := x86_64-pc-linux-gnu-gcc + CXX := x86_64-pc-linux-gnu-g++ + endif + + ifeq ($(TARGET_ARCH),i686) + COMMON_CC_FLAGS += -m32 + else ifeq ($(TARGET_ARCH),x86_64) + COMMON_CC_FLAGS += -m64 + endif + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).so + COMMON_CC_FLAGS += -fPIC + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME) + endif +else ifeq ($(TARGET_OS),3ds) + BUILT_FILTER := $(patsubst %.v.pica,$(TARGET_BUILD_DIR)/%.shbin.o,$(BUILD_FILTER)) \ + $(patsubst %.shlist,$(TARGET_BUILD_DIR)/%.shbin.o,$(BUILD_FILTER)) \ + + OBJECT_FILES := $(foreach dir,$(SOURCE_DIRS), \ + $(patsubst %.v.pica,$(TARGET_BUILD_DIR)/%.shbin.o,$(call rwildcard,$(dir),*.v.pica)) \ + $(patsubst %.shlist,$(TARGET_BUILD_DIR)/%.shbin.o,$(call rwildcard,$(dir),*.shlist)) \ + ) $(OBJECT_FILES) + + OBJECT_FILES := $(filter-out $(BUILT_FILTER),$(OBJECT_FILES)) + + DEVKITARM := $(DEVKITPRO)/devkitARM + + AR := $(DEVKITARM)/bin/arm-none-eabi-ar + AS := $(DEVKITARM)/bin/arm-none-eabi-as + CC := $(DEVKITARM)/bin/arm-none-eabi-gcc + CXX := $(DEVKITARM)/bin/arm-none-eabi-g++ + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).3ds $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).cia + endif + + LD_FLAGS += -specs=3dsx.specs + COMMON_CC_FLAGS += -mword-relocations -ffast-math -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft -DARM11 -D_3DS + + SERVEFILES := python $(BUILDTOOLS_DIR)/3ds/servefiles.py + + CATEGORY ?= Application + USE_ON_SD ?= true + MEMORY_TYPE ?= Application + SYSTEM_MODE ?= 64MB + SYSTEM_MODE_EXT ?= Legacy + CPU_SPEED ?= 268MHz + ENABLE_L2_CACHE ?= false + + _3DSXTOOL_FLAGS := + COMMON_MAKEROM_FLAGS := -rsf $(BUILDTOOLS_DIR)/3ds/template.rsf -target t -exefslogo -icon $(TARGET_BUILD_DIR)/icon.icn -banner $(TARGET_BUILD_DIR)/banner.bnr -major $(VERSION_MAJOR) -minor $(VERSION_MINOR) -micro $(VERSION_MICRO) -DAPP_TITLE="$(TITLE)" -DAPP_PRODUCT_CODE="$(PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(UNIQUE_ID)" -DAPP_SYSTEM_MODE="$(SYSTEM_MODE)" -DAPP_SYSTEM_MODE_EXT="$(SYSTEM_MODE_EXT)" -DAPP_CATEGORY="$(CATEGORY)" -DAPP_USE_ON_SD="$(USE_ON_SD)" -DAPP_MEMORY_TYPE="$(MEMORY_TYPE)" -DAPP_CPU_SPEED="$(CPU_SPEED)" -DAPP_ENABLE_L2_CACHE="$(ENABLE_L2_CACHE)" -DAPP_VERSION_MAJOR="$(VERSION_MAJOR)" + + ifneq ("$(wildcard $(ROMFS_DIR))","") + _3DSXTOOL_FLAGS += --romfs=$(ROMFS_DIR) + COMMON_MAKEROM_FLAGS += -DAPP_ROMFS="$(ROMFS_DIR)" + endif + + ifneq ("$(wildcard $(LOGO))","") + COMMON_MAKEROM_FLAGS += -logo "$(LOGO)" + else ifneq ($(LOGO),plain) + COMMON_MAKEROM_FLAGS += -logo "$(BUILDTOOLS_DIR)/3ds/logo.bcma.lz" + endif + + ifeq ($(suffix $(BANNER_IMAGE)),.cgfx) + BANNER_IMAGE_ARG := -ci + else + BANNER_IMAGE_ARG := -i + endif + + ifeq ($(suffix $(BANNER_AUDIO)),.cwav) + BANNER_AUDIO_ARG := -ca + else + BANNER_AUDIO_ARG := -a + endif +else ifeq ($(TARGET_OS),wiiu) + DEVKITPPC := $(DEVKITPRO)/devkitPPC + + AR := $(DEVKITPPC)/bin/powerpc-eabi-ar + AS := $(DEVKITPPC)/bin/powerpc-eabi-as + CC := $(DEVKITPPC)/bin/powerpc-eabi-gcc + CXX := $(DEVKITPPC)/bin/powerpc-eabi-g++ + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png + endif + + LD_FLAGS += -Wl,-d,--gc-sections + COMMON_CC_FLAGS += -mwup -mcpu=750 -meabi -mhard-float -ffast-math -DESPRESSO -DWIIU +else ifeq ($(TARGET_OS),switch) + DEVKITA64 := $(DEVKITPRO)/devkitA64 + + AR := $(DEVKITA64)/bin/aarch64-none-elf-ar + AS := $(DEVKITA64)/bin/aarch64-none-elf-as + CC := $(DEVKITA64)/bin/aarch64-none-elf-gcc + CXX := $(DEVKITA64)/bin/aarch64-none-elf-g++ + + ifeq ($(LIBRARY),1) + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/lib/$(STRIPPED_NAME).a + else + OUTPUT_FILES := $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).elf $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro + endif + + LD_FLAGS += -specs=$(DEVKITPRO)/libnx/switch.specs + COMMON_CC_FLAGS += -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -D__SWITCH__ + COMMON_CXX_FLAGS += -fno-rtti -fno-exceptions + + NRO_FLAGS := + + ifneq ("$(wildcard $(ICON))","") + NRO_FLAGS += --icon=$(ICON) + endif + + NACP_FLAGS := + + ifneq ($(TITLE_ID),) + NACP_FLAGS += --titleid=$(TITLE_ID) + endif +endif + +# FINAL COMMON SETUP # + +CLANG_CC := $(subst gcc,clang,$(CC)) +CLANG_CC_EXISTS := $(shell which $(CLANG_CC) > /dev/null 2> /dev/null; echo $$?) +ifeq ($(CLANG_CC_EXISTS),0) + CC := $(CLANG_CC) +endif + +CLANG_CXX := $(subst g++,clang++,$(CXX)) +CLANG_CXX_EXISTS := $(shell which $(CLANG_CXX) > /dev/null 2> /dev/null; echo $$?) +ifeq ($(CLANG_CXX_EXISTS),0) + CXX := $(CLANG_CXX) +endif + +CC_FLAGS := $(COMMON_CC_FLAGS) $(BUILD_FLAGS_CC) +CXX_FLAGS := $(COMMON_CC_FLAGS) $(COMMON_CXX_FLAGS) $(BUILD_FLAGS_CXX) + +ifeq ($(findstring -std,$(BUILD_FLAGS_CC)),) + CC_FLAGS += -std=gnu11 +endif + +ifeq ($(findstring -std,$(BUILD_FLAGS_CXX)),) + CXX_FLAGS += -std=gnu++11 +endif + +ifneq ($(EXTRA_OUTPUT_FILES),) + EXTRA_OUTPUT_COPY_CMD := cp -r $(EXTRA_OUTPUT_FILES) $(OUTPUT_DIR) +endif + +# MAIN RULES # + +.PHONY: all run install clean + +all: $(OUTPUT_ZIP_FILE) + +# TARGET RULES # + +ifeq ($(TARGET_OS),3ds) + +ifeq ($(LIBRARY),1) + +install: $(OUTPUT_ZIP_FILE) + @mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME) + @cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME) + @echo "Installed." + +else + +run: $(OUTPUT_ZIP_FILE) + @echo "Running..." + @citra $(RUN_FLAGS) $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx + +runhw: $(OUTPUT_ZIP_FILE) + @echo "Running..." + @3dslink --address $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/$(STRIPPED_NAME).3dsx + +install: $(OUTPUT_ZIP_FILE) + @echo "Installing..." + @$(SERVEFILES) $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME).cia + @echo "Installed." + +endif + +$(TARGET_BUILD_DIR)/%.shbin.o: $(TARGET_BUILD_DIR)/%.shbin.c + @echo $@ + @$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@ + +define shader-as + $(eval CURBIN := $(patsubst %.shbin.c,%.shbin,$@)) + @picasso -o $(CURBIN) $1 + @cd $(dir $(CURBIN)); \ + xxd -i $(notdir $(CURBIN)) "$(CURDIR)/$@" + echo "extern const u8" `(echo $(notdir $(CURBIN)) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h + echo "extern const u32" `(echo $(notdir $(CURBIN)) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_len";" >> `(echo $(CURBIN) | tr . _)`.h +endef + +$(TARGET_BUILD_DIR)/%.shbin.c: %.v.pica %.g.pica + @echo $@ + @$(call shader-as,$^) + +$(TARGET_BUILD_DIR)/%.shbin.c: %.v.pica + @echo $@ + @$(call shader-as,$<) + +$(TARGET_BUILD_DIR)/%.shbin.c: %.shlist + @echo $@ + @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file))) + +%.bnr: $(BANNER_IMAGE) $(BANNER_AUDIO) + @echo $@ + @bannertool makebanner $(BANNER_IMAGE_ARG) $(BANNER_IMAGE) $(BANNER_AUDIO_ARG) $(BANNER_AUDIO) -o $@ > /dev/null + +%.icn: $(ICON) + @echo $@ + @bannertool makesmdh -s "$(TITLE)" -l "$(TITLE) - $(DESCRIPTION)" -p "$(AUTHOR)" -i $(ICON) $(ICON_FLAGS) -o $@ > /dev/null + +%.smdh: $(ICON) + @echo $@ + @smdhtool --create "$(TITLE)" "$(DESCRIPTION)" "$(AUTHOR)" $(ICON) $@ + +$(TARGET_OUTPUT_DIR)/3ds/$(STRIPPED_NAME)/%.3dsx: $(TARGET_OUTPUT_DIR)/%.elf $(TARGET_BUILD_DIR)/meta.smdh + @echo $@ + @3dsxtool $< $@ --smdh=$(word 2,$^) $(_3DSXTOOL_FLAGS) + +%.3ds: %.elf $(TARGET_BUILD_DIR)/banner.bnr $(TARGET_BUILD_DIR)/icon.icn + @echo $@ + @makerom -f cci -o $@ -elf $< -DAPP_ENCRYPTED=true $(COMMON_MAKEROM_FLAGS) + +%.cia: %.elf $(TARGET_BUILD_DIR)/banner.bnr $(TARGET_BUILD_DIR)/icon.icn + @echo $@ + @makerom -f cia -o $@ -elf $< -DAPP_ENCRYPTED=false $(COMMON_MAKEROM_FLAGS) + +else ifeq ($(TARGET_OS),wiiu) + +ifeq ($(LIBRARY),1) + +install: $(OUTPUT_ZIP_FILE) + @mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME) + @cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME) + @echo "Installed." + +else + +runhw: $(OUTPUT_ZIP_FILE) + @echo "Running..." + @WIILOAD=tcp:$(REMOTE_IP) wiiload $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/$(STRIPPED_NAME).elf $(RUN_FLAGS) + +endif + +$(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml: + @echo $@ + @cp $(BUILDTOOLS_DIR)/wiiu/meta_template.xml $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(TITLE)/$(subst /,\/,$(TITLE))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(AUTHOR)/$(subst /,\/,$(AUTHOR))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(VERSION)/$(subst /,\/,$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(RELEASE_DATE)/$(subst /,\/,$(shell date +'%Y%m%d%H%M%S'))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(SHORT_DESCRIPTION)/$(subst /,\/,$(DESCRIPTION))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + @sed -i -- 's/$$(LONG_DESCRIPTION)/$(subst /,\/,$(LONG_DESCRIPTION))/g' $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/meta.xml + +$(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png: + @echo $@ + @cp $(ICON) $(TARGET_OUTPUT_DIR)/wiiu/apps/$(STRIPPED_NAME)/icon.png + +else ifeq ($(TARGET_OS),switch) + +ifeq ($(LIBRARY),1) + +install: $(OUTPUT_ZIP_FILE) + @mkdir -p $(DEVKITPRO)/$(STRIPPED_NAME) + @cp -r $(TARGET_OUTPUT_DIR)/* $(DEVKITPRO)/$(STRIPPED_NAME) + @echo "Installed." + +else + +run: $(OUTPUT_ZIP_FILE) + @echo "Running..." + @yuzu-cmd $(RUN_FLAGS) $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro + +runhw: $(OUTPUT_ZIP_FILE) + @echo "Running..." + @nxlink --address $(REMOTE_IP) $(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/$(STRIPPED_NAME).nro + +endif + +%.nacp: + @echo $@ + @nacptool --create "$(TITLE)" "$(AUTHOR)" "$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO)" $@ $(NACP_FLAGS) + +$(TARGET_OUTPUT_DIR)/switch/$(STRIPPED_NAME)/%.nro: $(TARGET_OUTPUT_DIR)/%.elf $(TARGET_BUILD_DIR)/meta.nacp + @echo $@ + @elf2nro $< $@ --nacp=$(word 2,$^) $(NRO_FLAGS) + +else ifeq ($(TARGET_OS),windows) + ifeq ($(HOST_OS),$(filter $(HOST_OS),linux mac)) + ifneq ($(LIBRARY),1) + +run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE) + @echo "Running..." + @wine ./$< $(RUN_FLAGS) + + endif + else ifeq ($(HOST_OS),windows) + ifneq ($(LIBRARY),1) + +run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE) + @echo "Running..." + @./$< $(RUN_FLAGS) + + endif + endif +else ifeq ($(TARGET_OS),$(filter $(TARGET_OS),mac linux)) + ifeq ($(HOST_OS),$(TARGET_OS)) + ifeq ($(LIBRARY),1) + +install: $(OUTPUT_ZIP_FILE) + @install -m 0755 $(OUTPUT_FILES) /usr/local/lib + @install -m 0644 $(foreach dir,$(INCLUDE_DIRS),$(wildcard $(dir)/*)) /usr/local/include + @echo "Installed." + + else + +run: $(OUTPUT_FILES) $(OUTPUT_ZIP_FILE) + @echo "Running..." + @./$< $(RUN_FLAGS) + +install: $(OUTPUT_ZIP_FILE) + @install -m 0755 $(OUTPUT_FILES) /usr/local/bin + @echo "Installed." + + endif + endif +endif + +# COMMON RULES # + +$(OUTPUT_ZIP_FILE): $(OUTPUT_FILES) $(EXTRA_OUTPUT_FILES) + @echo $@ + @$(EXTRA_OUTPUT_COPY_CMD) + @cd $(OUTPUT_DIR); \ + zip -r $(patsubst $(OUTPUT_DIR)/%,%,$@ * -x $(OUTPUT_ZIP_FILE)) > /dev/null + +$(TARGET_OUTPUT_DIR)/$(STRIPPED_NAME): $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS) + +%.elf: $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS) + +%.a: $(OBJECT_FILES) + @echo $@ + @$(AR) -rc $@ $^ + +%.so: $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) -shared $^ -o $@ $(LD_FLAGS) + +%.exe: $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) $^ -o $@ $(LD_FLAGS) + +%.dll: $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) -shared $^ -o $@ $(LD_FLAGS) + +%.dylib: $(OBJECT_FILES) + @echo $@ + @$(CXX) $(CXX_FLAGS) -dynamiclib -undefined suppress -flat_namespace $^ -o $@ $(LD_FLAGS) + +$(TARGET_BUILD_DIR)/%.o: %.c + @echo $@ + @$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@ + +$(TARGET_BUILD_DIR)/%.o: %.cpp + @echo $@ + @$(CXX) -c $(CXX_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@ + +$(TARGET_BUILD_DIR)/%.o: %.s + @echo $@ + @$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d -x assembler-with-cpp $< -o $@ + +$(TARGET_BUILD_DIR)/%.o: %.S + @echo $@ + @$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d -x assembler-with-cpp $< -o $@ + +$(TARGET_BUILD_DIR)/%.bin.o: $(TARGET_BUILD_DIR)/%.bin.c + @echo $@ + @$(CC) -c $(CC_FLAGS) -MMD -MP -MF $(TARGET_BUILD_DIR)/$*.d $< -o $@ + +$(TARGET_BUILD_DIR)/%.bin.c: %.bin + @echo $@ + @cd $(> `(echo $(TARGET_BUILD_DIR)/$< | tr . _)`.h + @echo "extern const u32" `(echo $(> `(echo $(TARGET_BUILD_DIR)/$< | tr . _)`.h + +$(foreach file,$(OBJECT_FILES),$(eval $(call createdirrule,$(file)))) +$(foreach file,$(OUTPUT_FILES),$(eval $(call createdirrule,$(file)))) + +# DEPENDS # + +DEPENDS := $(OBJECT_FILES:.o=.d) +-include $(DEPENDS) + +endif + +# CLEAN # + +clean: + @rm -rf $(BUILD_DIR) $(OUTPUT_DIR) + @echo "Cleaned." diff --git a/buildtools/wiiu/meta_template.xml b/buildtools/wiiu/meta_template.xml new file mode 100644 index 0000000..9e19b88 --- /dev/null +++ b/buildtools/wiiu/meta_template.xml @@ -0,0 +1,9 @@ + + + $(TITLE) + $(AUTHOR) + $(VERSION) + $(RELEASE_DATE) + $(SHORT_DESCRIPTION) + $(LONG_DESCRIPTION) + diff --git a/images/bottom.pdn b/images/bottom.pdn new file mode 100644 index 0000000..6802a35 Binary files /dev/null and b/images/bottom.pdn differ diff --git a/images/top.pdn b/images/top.pdn new file mode 100644 index 0000000..3b0fcaa Binary files /dev/null and b/images/top.pdn differ diff --git a/resources/audio.cwav b/resources/audio.cwav new file mode 100644 index 0000000..fd185d2 Binary files /dev/null and b/resources/audio.cwav differ diff --git a/resources/banner.cgfx b/resources/banner.cgfx new file mode 100644 index 0000000..68198ff Binary files /dev/null and b/resources/banner.cgfx differ diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000..e2210b0 Binary files /dev/null and b/resources/icon.png differ diff --git a/resources/logo.bcma.lz b/resources/logo.bcma.lz new file mode 100644 index 0000000..dd9db8c Binary files /dev/null and b/resources/logo.bcma.lz differ diff --git a/romfs/bottom.png b/romfs/bottom.png new file mode 100644 index 0000000..4548415 Binary files /dev/null and b/romfs/bottom.png differ diff --git a/romfs/top.png b/romfs/top.png new file mode 100644 index 0000000..3927bc9 Binary files /dev/null and b/romfs/top.png differ diff --git a/source/allocator/newlibHeap.c b/source/allocator/newlibHeap.c new file mode 100644 index 0000000..83ee0d0 --- /dev/null +++ b/source/allocator/newlibHeap.c @@ -0,0 +1,35 @@ +#include <3ds/types.h> +#include // for mallinfo() +#include // for sbrk() + +extern u8 *fake_heap_end; // current heap start +extern u8 *fake_heap_start; // current heap end + +u8 *getHeapStart(void) +{ + return fake_heap_start; +} + +u8 *getHeapEnd(void) +{ + return (u8*)sbrk(0); +} + +u8 *getHeapLimit(void) +{ + return fake_heap_end; +} + +// returns the amount of used memory in bytes +int getMemUsed(void) +{ + struct mallinfo mi = mallinfo(); + return mi.uordblks; +} + +// returns the amount of free memory in bytes +int getMemFree(void) +{ + struct mallinfo mi = mallinfo(); + return mi.fordblks + (getHeapLimit() - getHeapEnd()); +} diff --git a/source/allocator/newlibHeap.h b/source/allocator/newlibHeap.h new file mode 100644 index 0000000..a54c80b --- /dev/null +++ b/source/allocator/newlibHeap.h @@ -0,0 +1,18 @@ +#ifndef NEWLIBHEAP_H +#define NEWLIBHEAP_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "3ds/types.h" + +u8 *getHeapStart(void); +u8 *getHeapEnd(void); +u8 *getHeapLimit(void); +int getMemUsed(void); +int getMemFree(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/source/clock.c b/source/clock.c new file mode 100644 index 0000000..651fc19 --- /dev/null +++ b/source/clock.c @@ -0,0 +1,26 @@ +#include "clock.h" + +#define SYSCLOCK_SOC (16756991) +#define SYSCLOCK_ARM9 (SYSCLOCK_SOC * 8) +#define SYSCLOCK_ARM11 (SYSCLOCK_ARM9 * 2) +#define SYSCLOCK_ARM11_NEW (SYSCLOCK_ARM11 * 3) + +#define CPU_TICKS_PER_MSEC (SYSCLOCK_ARM11 / 1000.0) +#define CPU_TICKS_PER_USEC (SYSCLOCK_ARM11 / 1000000.0) + + +u64 Timer_Restart(void) +{ + return (svcGetSystemTick()); +} +u64 getTimeInMsec(u64 timer) { + return timer / CPU_TICKS_PER_MSEC; +} +bool Timer_HasTimePassed(float nbmsecToWait, u64 timer) +{ + u64 seconds = (u64)(nbmsecToWait * CPU_TICKS_PER_MSEC); + u64 current = svcGetSystemTick(); + u64 diff = current - timer; + + return (diff >= seconds); +} \ No newline at end of file diff --git a/source/clock.h b/source/clock.h new file mode 100644 index 0000000..b5347d9 --- /dev/null +++ b/source/clock.h @@ -0,0 +1,6 @@ +#pragma once +#include <3ds.h> + +u64 Timer_Restart(void); +bool Timer_HasTimePassed(float nbmsecToWait, u64 timer); +u64 getTimeInMsec(u64 timer); \ No newline at end of file diff --git a/source/draw.c b/source/draw.c new file mode 100644 index 0000000..746b582 --- /dev/null +++ b/source/draw.c @@ -0,0 +1,375 @@ +#include "draw.h" + +static DVLB_s *vshader_dvlb; +static shaderProgram_s program; +static int uLoc_projection; +static textVertex_s *textVtxArray; +static int textVtxArrayPos; +static drawTarget_t top; +static drawTarget_t bottom; +static bool frameStarted = false; +static gfxScreen_t currentScreen = -1; +static cursor_t cursor[2] = { { 10, 10 },{ 10, 10 } }; + +#define TEXT_VTX_ARRAY_COUNT (8 * 1024) + +#define TEX_MIN_SIZE 64 + +//Grabbed from: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 +unsigned int nextPow2(unsigned int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return (v >= TEX_MIN_SIZE ? v : TEX_MIN_SIZE); +} + +static void addTextVertex(float vx, float vy, float vz, float tx, float ty) +{ + textVertex_s *vtx; + + vtx = &textVtxArray[textVtxArrayPos++]; + vtx->position[0] = vx; + vtx->position[1] = vy; + vtx->position[2] = 0.0f; + vtx->texcoord[0] = tx; + vtx->texcoord[1] = ty; +} + +void printVertex(textVertex_s *vtx) +{ + printf("Vtx: pos[0] %f, pos[1] %f pos[2] %f, tx[0] %f, tx[1] %f\n", + vtx->position[0], + vtx->position[1], + vtx->position[2], + vtx->texcoord[0], + vtx->texcoord[1] + ); +} + +static void resetC3Denv() { + C3D_TexEnv *env; + for (int i = 0; i < 4; i++) { + env = C3D_GetTexEnv(i); + TexEnv_Init(env); + } +} + +static void bindImageGreyScale(C3D_Tex *texture, u32 texture_color) { + //((0.3 * R) + (0.59 * G) + (0.11 * B)). -> 0xFF1C964C + C3D_TexEnv *env; + u32 greyMask = 0xFF1C964C; + resetC3Denv(); + + C3D_TexBind(0, texture); + env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_RGB, GPU_TEXTURE0, GPU_CONSTANT, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, 0, 0); + C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); + C3D_TexEnvColor(env, texture_color); + env = C3D_GetTexEnv(1); + C3D_TexEnvSrc(env, C3D_RGB, GPU_PREVIOUS, GPU_CONSTANT, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_PREVIOUS, 0, 0); + C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); + C3D_TexEnvColor(env, greyMask); + C3D_TexEnvBufUpdate(C3D_RGB, 0b0010); + env = C3D_GetTexEnv(2); + C3D_TexEnvSrc(env, C3D_RGB, GPU_PREVIOUS, GPU_PREVIOUS, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_PREVIOUS, 0, 0); + C3D_TexEnvOp(env, C3D_RGB, GPU_TEVOP_RGB_SRC_R, GPU_TEVOP_RGB_SRC_G, 0); + C3D_TexEnvOp(env, C3D_Alpha, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_ADD); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); + env = C3D_GetTexEnv(3); + C3D_TexEnvSrc(env, C3D_RGB, GPU_PREVIOUS, GPU_PREVIOUS_BUFFER, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_PREVIOUS, 0, 0); + C3D_TexEnvOp(env, C3D_RGB, 0, GPU_TEVOP_RGB_SRC_B, 0); + C3D_TexEnvOp(env, C3D_Alpha, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_ADD); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); +} + +static void bindTexture(C3D_Tex *texture, u32 texture_color) +{ + C3D_TexEnv *env; + resetC3Denv(); + + C3D_TexBind(0, texture); + env = C3D_GetTexEnv(0); + C3D_TexEnvBufUpdate(C3D_RGB, 0); + C3D_TexEnvSrc(env, C3D_RGB, GPU_TEXTURE0, GPU_CONSTANT, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, 0, 0); + C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_MODULATE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_REPLACE); + C3D_TexEnvColor(env, texture_color); +} + +void setSpritePos(sprite_t *sprite, float posX, float posY) +{ + if (!sprite) return; + sprite->posX = posX; + sprite->posY = posY; +} + +void drawSprite(sprite_t *sprite) +{ + float height; + float width; + float u; + float v; + float x; + float y; + int arrayIndex; + C3D_Tex *texture; + + if (!sprite || sprite->isHidden) return; + texture = &sprite->texture; + height = sprite->height; + width = sprite->width; + x = sprite->posX; + y = sprite->posY; + u = width / (float)texture->width; + v = height / (float)texture->height; + + width = floor(width * sprite->amount); + u *= sprite->amount; + + C3D_BufInfo *bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, textVtxArray, sizeof(textVertex_s), 2, 0x10); + //Set the vertices + arrayIndex = textVtxArrayPos; + addTextVertex(x, y + height, sprite->depth, 0.0f, v); //left bottom + addTextVertex(x + width, y + height, sprite->depth, u, v); //right bottom + addTextVertex(x, y, sprite->depth, 0.0f, 0.0f); //left top + addTextVertex(x + width, y, sprite->depth, u, 0.0f); //right top + + //Bind the sprite's texture + if (sprite->isGreyedOut) { + bindImageGreyScale(texture, sprite->drawColor); + } + else { + bindTexture(texture, sprite->drawColor); + } + + //Draw + C3D_DrawArrays(GPU_TRIANGLE_STRIP, arrayIndex, 4); +} + +sprite_t *newSprite(int width, int height) +{ + sprite_t *sprite; + C3D_Tex *texture; + bool result; + + //Alloc the sprite + sprite = (sprite_t *)calloc(1, sizeof(sprite_t)); + if (!sprite) goto allocError; + texture = &sprite->texture; + + //Create and init the sprite's texture + result = C3D_TexInit(texture, nextPow2(width), nextPow2(height), GPU_RGBA8); + if (!result) goto texInitError; + //C3D_TexSetWrap(texture, GPU_CLAMP_TO_BORDER, GPU_CLAMP_TO_BORDER); + texture->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) + | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_BORDER) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_BORDER); + + sprite->width = (float)width; + sprite->height = (float)height; + sprite->drawColor = 0xFFFFFFFF; + sprite->isGreyedOut = false; + sprite->isHidden = false; + sprite->depth = 0.0f; + sprite->amount = 1.f; + return (sprite); +texInitError: + free(sprite); +allocError: + return (NULL); +} + +void deleteSprite(sprite_t *sprite) +{ + if (!sprite) return; + C3D_TexDelete(&sprite->texture); + free(sprite); + sprite = NULL; +} + +static void sceneInit(void) +{ + int i; + TGLP_s *glyphInfo; + C3D_Tex *tex; + C3D_AttrInfo *attrInfo; + + // Load the vertex shader, create a shader program and bind it + vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_len); + shaderProgramInit(&program); + shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]); + C3D_BindProgram(&program); + + // Get the location of the uniforms + uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + + // Configure attributes for use with the vertex shader + attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position + AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord + + // Compute the projection matrix + Mtx_OrthoTilt(&top.projection, 0.0f, 400.0f, 240.0f, 0.0f, 0.0f, 1.0f, true); + Mtx_OrthoTilt(&bottom.projection, 0.0f, 320.0f, 240.0f, 0.0f, 0.0f, 1.0f, true); + + // Configure depth test to overwrite pixels with the same depth (needed to draw overlapping glyphs) + C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); + + // Create the text vertex array + textVtxArray = (textVertex_s*)linearAlloc(sizeof(textVertex_s)*TEXT_VTX_ARRAY_COUNT); +} + +static void sceneExit(void) +{ + // Free the textures + + // Free the shader program + shaderProgramFree(&program); + DVLB_Free(vshader_dvlb); +} + +void drawInit(void) +{ + C3D_RenderTarget *target; + + //Init Citro3D + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + + // Initialize the top render target + target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0); + C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + top.target = target; + + // Initialize the bottom render target + target = C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0); + C3D_RenderTargetSetOutput(target, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + bottom.target = target; + + // Initialize the scene + sceneInit(); +} + +void drawEndFrame(void) +{ + if (frameStarted) + { + C3D_FrameEnd(0); + frameStarted = false; + } +} + +void drawExit(void) +{ + sceneExit(); + C3D_Fini(); +} + +void setTextColor(u32 color) +{ +#ifndef CITRA + C3D_TexEnv *env; + + env = C3D_GetTexEnv(0); + C3D_TexEnvSrc(env, C3D_RGB, GPU_CONSTANT, 0, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_CONSTANT, 0); + C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); + C3D_TexEnvColor(env, color); +#endif +} + +void updateScreen(void) +{ + if (frameStarted) + C3D_FrameEnd(0); + else + frameStarted = true; + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + textVtxArrayPos = 0; + cursor[0] = (cursor_t){ 10, 10 }; + cursor[1] = (cursor_t){ 10, 10 }; + currentScreen = -1; +} + +void setScreen(gfxScreen_t screen) +{ + if (screen == currentScreen) return; + currentScreen = screen; + if (!frameStarted) + { + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + frameStarted = true; + } + if (screen == GFX_TOP) + { + C3D_FrameDrawOn(top.target); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &top.projection); + } + else if (screen == GFX_BOTTOM) + { + C3D_FrameDrawOn(bottom.target); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &bottom.projection); + } + else return; +} +/* +void Printf(u32 color, u32 flags, char *text, ...) +{ + //TODO: Find the best size for BOLD and SKINNY + char buf[4096]; + va_list vaList; + float posX; + float posY; + float sizeX; + float sizeY; + + if (flags) + { + //Set the font size + if (flags & BIG) sizeX = sizeY = 1.0f; + else if (flags & SMALL) sizeX = sizeY = 0.35f; + else sizeX = sizeY = 0.5f; + //Set a style + if (flags & BOLD) + { + sizeX = 0.75f; + sizeY = 0.5f; + } + else if (flags & SKINNY) + { + sizeX = 0.5f; + sizeY = 0.75f; + } + } + else + sizeX = sizeY = 0.5f; + va_start(vaList, text); + vsnprintf(buf, 4096, text, vaList); + posX = cursor[currentScreen].posX; + posY = cursor[currentScreen].posY; + setTextColor(color); + renderText(posX, posY, sizeX, sizeY, false, buf, &cursor[currentScreen]); + va_end(vaList); +}*/ diff --git a/source/draw.h b/source/draw.h new file mode 100644 index 0000000..7d90eef --- /dev/null +++ b/source/draw.h @@ -0,0 +1,112 @@ +#ifndef DRAW_H +#define DRAW_H +#include +#include +#include +#include +#include +#include <3ds.h> +#include + +typedef struct sprite_s +{ + C3D_Tex texture; + float posX; + float posY; + float height; + float width; + u32 drawColor; + bool isGreyedOut; + bool isHidden; + float depth; + float amount; // from 0 to 1 +} sprite_t; + +typedef struct rectangle_s +{ + /* herited from drawableObject_t */ + bool(*draw)(void *self); + + float posX; + float posY; + float width; + float height; + sprite_t* sprite; + float amount; //Range from 0 to 1 + float depth; +} rectangle_t; + +#include "drawableObject.h" + +// These headers are generated by the build process +#include "vshader_shbin.h" + +//#define CITRA //Citra doesn't like the setTextColor + +#define CLEAR_COLOR 0x68B0D8FF +#define SCREEN_POS(x, y) (screenPos_t)((x << 16) | (y)) +#define POS_X(screenPos) (float)(screenPos >> 16) +#define POS_Y(screenPos) (float)(screenPos & 0xFFFF) + +// Used to transfer the final rendered display to the framebuffer +#define DISPLAY_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + +// Used to convert textures to 3DS tiled format +// Note: vertical flip flag set so 0,0 is top left of texture +#define TEXTURE_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + +typedef struct +{ + float position[3]; + float texcoord[2]; +} textVertex_s; + +typedef struct drawTarget_s +{ + C3D_RenderTarget *target; + C3D_Mtx projection; +} drawTarget_t; +typedef struct +{ + float posX; + float posY; +} cursor_t; + + +typedef u32 screenPos_t; + +void drawInit(void); +void drawExit(void); +void drawEndFrame(void); +void setScreen(gfxScreen_t screen); +void updateScreen(void); + +sprite_t *newSprite(int width, int height); +Result newSpriteFromPNG(sprite_t **out, const char *filename); +void deleteSprite(sprite_t *sprite); +void setSpritePos(sprite_t *sprite, float posX, float posY); +void drawSprite(sprite_t *sprite); + +#define COLOR_BLUE 0xFFFF0000 +#define COLOR_RED 0xFF0000FF +#define COLOR_GREEN 0xFF00FF00 +#define COLOR_BLANK 0xFFFFFFFF +#define COLOR_BLACK 0xFF000000 +#define COLOR_GREY 0xFF989898 +#define COLOR_ORANGE 0xFF00A5FF +#define COLOR_LIMEGREEN 0xFF32CD32 +#define COLOR_SALMON 0xFF7280FA +#define COLOR_SILVER 0xFFC0C0C0 +#define COLOR_CORAL 0xFF507FFF + +#define COLOR_DARKGREEN 0xFF006400 + + + +#endif \ No newline at end of file diff --git a/source/drawableObject.c b/source/drawableObject.c new file mode 100644 index 0000000..de81e49 --- /dev/null +++ b/source/drawableObject.c @@ -0,0 +1,53 @@ +#include "drawableObject.h" +#include "draw.h" + +backgroundScreen_t *newBackgroundObject(sprite_t *background) +{ + backgroundScreen_t *ret; + + ret = (backgroundScreen_t *)calloc(1, sizeof(backgroundScreen_t)); + if (!ret) goto error; + + if (background) ret->background = background; + ret->draw = drawBackground; + return (ret); +error: + return (NULL); +} + +bool drawBackground(void *self) +{ + backgroundScreen_t *bg; + + if (!self) goto error; + bg = (backgroundScreen_t *)self; + drawSprite(bg->background); +error: + return (false); +} + +drawableScreen_t *newDrawableScreen(backgroundScreen_t *background) +{ + drawableScreen_t *ret; + + ret = (drawableScreen_t *)calloc(1, sizeof(drawableScreen_t)); + if (!ret) goto error; + if (background) ret->background = background; + ret->draw = drawScreen; + return (ret); +error: + return (NULL); +} + +bool drawScreen(void *self) +{ + drawableScreen_t *screen; + + if (!self) goto error; + screen = (drawableScreen_t *)self; + if (screen->background) + screen->background->draw(screen->background); + return (true); +error: + return (false); +} \ No newline at end of file diff --git a/source/drawableObject.h b/source/drawableObject.h new file mode 100644 index 0000000..4356f5b --- /dev/null +++ b/source/drawableObject.h @@ -0,0 +1,39 @@ +#ifndef DRAWABLEOBJECT_H +#define DRAWABLEOBJECT_H +#define MAX_ELEMENTS 15 + +#include "draw.h" + +typedef struct drawableObject_s +{ + bool (*draw)(void *self); +} drawableObject_t; + +typedef struct backgroundScreen_s +{ + /* herited from drawableObject_t */ + bool (*draw)(void *self); + + sprite_t *background; + sprite_t *headerText; + sprite_t *footerText; + +} backgroundScreen_t; + +typedef struct drawableScreen_s +{ + /* herited from drawableObject_t */ + bool (*draw)(void *self); + + backgroundScreen_t *background; + int elementsCount; + int elementList[MAX_ELEMENTS]; +} drawableScreen_t; + +backgroundScreen_t *newBackgroundObject(sprite_t *background); +bool drawBackground(void *self); + +drawableScreen_t *newDrawableScreen(backgroundScreen_t *background); +bool drawScreen(void *self); + +#endif diff --git a/source/graphics.c b/source/graphics.c new file mode 100644 index 0000000..3ed1253 --- /dev/null +++ b/source/graphics.c @@ -0,0 +1,72 @@ +#include "graphics.h" +#include "drawableObject.h" + + +sprite_t *bottomSprite = NULL; +sprite_t *topSprite = NULL; +drawableScreen_t *botScreen = NULL; +drawableScreen_t *topScreen = NULL; + +void initUI(void) +{ + backgroundScreen_t *bg; + + newSpriteFromPNG(&topSprite, "romfs:/top.png"); + newSpriteFromPNG(&bottomSprite, "romfs:/bottom.png"); + + setSpritePos(topSprite, 0, 0); + setSpritePos(bottomSprite, 0, 0); + + topSprite->drawColor = 0xFF000000; + bottomSprite->drawColor = 0xFF000000; + + bg = newBackgroundObject(bottomSprite); + botScreen = newDrawableScreen(bg); + bg = newBackgroundObject(topSprite); + topScreen = newDrawableScreen(bg); + + updateUI(); +} + +void setExitMode() { + botScreen->background->background->isGreyedOut = true; + topScreen->background->background->isGreyedOut = true; +} + +void handleFadeIn(s64 time, u64 tot) { + float ratio = (float)(tot - time) / tot; + u8 col = (u8)(ratio * 0xff); + u32 finalcol = (0xFF << 24) | (col << 16) | (col << 8) | (col); + topScreen->background->background->drawColor = finalcol; + botScreen->background->background->drawColor = finalcol; +} + + +void exitUI(void) +{ + deleteSprite(bottomSprite); + deleteSprite(topSprite); +} + +static inline void drawUITop(void) +{ + setScreen(GFX_TOP); + + topScreen->draw(topScreen); +} + +static inline void drawUIBottom(void) +{ + setScreen(GFX_BOTTOM); + + botScreen->draw(botScreen); +} + +int updateUI(void) +{ + hidScanInput(); + drawUITop(); + drawUIBottom(); + updateScreen(); + return (1); +} \ No newline at end of file diff --git a/source/graphics.h b/source/graphics.h new file mode 100644 index 0000000..cd3780a --- /dev/null +++ b/source/graphics.h @@ -0,0 +1,23 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +#include "draw.h" +#include "main.h" + +#define STACKSIZE 0x1000 + +void initUI(void); +void exitUI(void); +int updateUI(void); +void setExitMode(); +void handleFadeIn(s64 time, u64 tot); + + +#define newAppTop(...) newAppInfoEntry(appTop, __VA_ARGS__) +#define removeAppTop() removeAppInfoEntry(appTop) +#define clearTop(update) clearAppInfo(appTop, update) + +#define TRACE() {newAppTop(DEFAULT_COLOR, SMALL, "%s:%d",__FUNCTION__, __LINE__); svcSleepThread(1000000000); updateUI(); svcSleepThread(1000000000);} +#define XTRACE(str, ...) {newAppTop(DEFAULT_COLOR, SMALL, str, __VA_ARGS__); updateUI(); svcSleepThread(500000000);} + +#endif \ No newline at end of file diff --git a/source/json/LICENSE b/source/json/LICENSE new file mode 100644 index 0000000..1aee375 --- /dev/null +++ b/source/json/LICENSE @@ -0,0 +1,26 @@ + + Copyright (C) 2012, 2013 James McLaughlin et al. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + diff --git a/source/json/json.c b/source/json/json.c new file mode 100644 index 0000000..6012bad --- /dev/null +++ b/source/json/json.c @@ -0,0 +1,1011 @@ +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "json.h" + +#ifdef _MSC_VER + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif + +const struct _json_value json_value_none; + +#include +#include +#include +#include + +typedef unsigned int json_uchar; + +static unsigned char hex_value (json_char c) +{ + if (isdigit(c)) + return c - '0'; + + switch (c) { + case 'a': case 'A': return 0x0A; + case 'b': case 'B': return 0x0B; + case 'c': case 'C': return 0x0C; + case 'd': case 'D': return 0x0D; + case 'e': case 'E': return 0x0E; + case 'f': case 'F': return 0x0F; + default: return 0xFF; + } +} + +typedef struct +{ + unsigned long used_memory; + + unsigned int uint_max; + unsigned long ulong_max; + + json_settings settings; + int first_pass; + + const json_char * ptr; + unsigned int cur_line, cur_col; + +} json_state; + +static void * default_alloc (size_t size, int zero, void * user_data) +{ + return zero ? calloc (1, size) : malloc (size); +} + +static void default_free (void * ptr, void * user_data) +{ + free (ptr); +} + +static void * json_alloc (json_state * state, unsigned long size, int zero) +{ + if ((state->ulong_max - state->used_memory) < size) + return 0; + + if (state->settings.max_memory + && (state->used_memory += size) > state->settings.max_memory) + { + return 0; + } + + return state->settings.mem_alloc (size, zero, state->settings.user_data); +} + +static int new_value (json_state * state, + json_value ** top, json_value ** root, json_value ** alloc, + json_type type) +{ + json_value * value; + int values_size; + + if (!state->first_pass) + { + value = *top = *alloc; + *alloc = (*alloc)->_reserved.next_alloc; + + if (!*root) + *root = value; + + switch (value->type) + { + case json_array: + + if (value->u.array.length == 0) + break; + + if (! (value->u.array.values = (json_value **) json_alloc + (state, value->u.array.length * sizeof (json_value *), 0)) ) + { + return 0; + } + + value->u.array.length = 0; + break; + + case json_object: + + if (value->u.object.length == 0) + break; + + values_size = sizeof (*value->u.object.values) * value->u.object.length; + + if (! (value->u.object.values = (json_object_entry *) json_alloc + (state, values_size + ((unsigned long) value->u.object.values), 0)) ) + { + return 0; + } + + value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; + + value->u.object.length = 0; + break; + + case json_string: + + if (! (value->u.string.ptr = (json_char *) json_alloc + (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) + { + return 0; + } + + value->u.string.length = 0; + break; + + default: + break; + }; + + return 1; + } + + if (! (value = (json_value *) json_alloc + (state, sizeof (json_value) + state->settings.value_extra, 1))) + { + return 0; + } + + if (!*root) + *root = value; + + value->type = type; + value->parent = *top; + + #ifdef JSON_TRACK_SOURCE + value->line = state->cur_line; + value->col = state->cur_col; + #endif + + if (*alloc) + (*alloc)->_reserved.next_alloc = value; + + *alloc = *top = value; + + return 1; +} + +#define whitespace \ + case '\n': ++ state.cur_line; state.cur_col = 0; \ + case ' ': case '\t': case '\r' + +#define string_add(b) \ + do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); + +#define line_and_col \ + state.cur_line, state.cur_col + +static const long + flag_next = 1 << 0, + flag_reproc = 1 << 1, + flag_need_comma = 1 << 2, + flag_seek_value = 1 << 3, + flag_escaped = 1 << 4, + flag_string = 1 << 5, + flag_need_colon = 1 << 6, + flag_done = 1 << 7, + flag_num_negative = 1 << 8, + flag_num_zero = 1 << 9, + flag_num_e = 1 << 10, + flag_num_e_got_sign = 1 << 11, + flag_num_e_negative = 1 << 12, + flag_line_comment = 1 << 13, + flag_block_comment = 1 << 14; + +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error_buf) +{ + json_char error [json_error_max]; + const json_char * end; + json_value * top, * root, * alloc = 0; + json_state state = { 0 }; + long flags; + long num_digits = 0, num_e = 0; + json_int_t num_fraction = 0; + + /* Skip UTF-8 BOM + */ + if (length >= 3 && ((unsigned char) json [0]) == 0xEF + && ((unsigned char) json [1]) == 0xBB + && ((unsigned char) json [2]) == 0xBF) + { + json += 3; + length -= 3; + } + + error[0] = '\0'; + end = (json + length); + + memcpy (&state.settings, settings, sizeof (json_settings)); + + if (!state.settings.mem_alloc) + state.settings.mem_alloc = default_alloc; + + if (!state.settings.mem_free) + state.settings.mem_free = default_free; + + memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); + memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); + + state.uint_max -= 8; /* limit of how much can be added before next check */ + state.ulong_max -= 8; + + for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) + { + json_uchar uchar; + unsigned char uc_b1, uc_b2, uc_b3, uc_b4; + json_char * string = 0; + unsigned int string_length = 0; + + top = root = 0; + flags = flag_seek_value; + + state.cur_line = 1; + + for (state.ptr = json ;; ++ state.ptr) + { + json_char b = (state.ptr == end ? 0 : *state.ptr); + + if (flags & flag_string) + { + if (!b) + { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col); + goto e_failed; + } + + if (string_length > state.uint_max) + goto e_overflow; + + if (flags & flag_escaped) + { + flags &= ~ flag_escaped; + + switch (b) + { + case 'b': string_add ('\b'); break; + case 'f': string_add ('\f'); break; + case 'n': string_add ('\n'); break; + case 'r': string_add ('\r'); break; + case 't': string_add ('\t'); break; + case 'u': + + if (end - state.ptr < 4 || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar = (uc_b1 << 8) | uc_b2; + + if ((uchar & 0xF800) == 0xD800) { + json_uchar uchar2; + + if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || + (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || + (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) + { + sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar2 = (uc_b1 << 8) | uc_b2; + + uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); + } + + if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) + { + string_add ((json_char) uchar); + break; + } + + if (uchar <= 0x7FF) + { + if (state.first_pass) + string_length += 2; + else + { string [string_length ++] = 0xC0 | (uchar >> 6); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + } + + if (uchar <= 0xFFFF) { + if (state.first_pass) + string_length += 3; + else + { string [string_length ++] = 0xE0 | (uchar >> 12); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + } + + if (state.first_pass) + string_length += 4; + else + { string [string_length ++] = 0xF0 | (uchar >> 18); + string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); + string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); + string [string_length ++] = 0x80 | (uchar & 0x3F); + } + + break; + + default: + string_add (b); + }; + + continue; + } + + if (b == '\\') + { + flags |= flag_escaped; + continue; + } + + if (b == '"') + { + if (!state.first_pass) + string [string_length] = 0; + + flags &= ~ flag_string; + string = 0; + + switch (top->type) + { + case json_string: + + top->u.string.length = string_length; + flags |= flag_next; + + break; + + case json_object: + + if (state.first_pass) + (*(json_char **) &top->u.object.values) += string_length + 1; + else + { + top->u.object.values [top->u.object.length].name + = (json_char *) top->_reserved.object_mem; + + top->u.object.values [top->u.object.length].name_length + = string_length; + + (*(json_char **) &top->_reserved.object_mem) += string_length + 1; + } + + flags |= flag_seek_value | flag_need_colon; + continue; + + default: + break; + }; + } + else + { + string_add (b); + continue; + } + } + + if (state.settings.settings & json_enable_comments) + { + if (flags & (flag_line_comment | flag_block_comment)) + { + if (flags & flag_line_comment) + { + if (b == '\r' || b == '\n' || !b) + { + flags &= ~ flag_line_comment; + -- state.ptr; /* so null can be reproc'd */ + } + + continue; + } + + if (flags & flag_block_comment) + { + if (!b) + { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col); + goto e_failed; + } + + if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') + { + flags &= ~ flag_block_comment; + ++ state.ptr; /* skip closing sequence */ + } + + continue; + } + } + else if (b == '/') + { + if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) + { sprintf (error, "%d:%d: Comment not allowed here", line_and_col); + goto e_failed; + } + + if (++ state.ptr == end) + { sprintf (error, "%d:%d: EOF unexpected", line_and_col); + goto e_failed; + } + + switch (b = *state.ptr) + { + case '/': + flags |= flag_line_comment; + continue; + + case '*': + flags |= flag_block_comment; + continue; + + default: + sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b); + goto e_failed; + }; + } + } + + if (flags & flag_done) + { + if (!b) + break; + + switch (b) + { + whitespace: + continue; + + default: + + sprintf (error, "%d:%d: Trailing garbage: `%c`", + state.cur_line, state.cur_col, b); + + goto e_failed; + }; + } + + if (flags & flag_seek_value) + { + switch (b) + { + whitespace: + continue; + + case ']': + + if (top && top->type == json_array) + flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; + else + { sprintf (error, "%d:%d: Unexpected ]", line_and_col); + goto e_failed; + } + + break; + + default: + + if (flags & flag_need_comma) + { + if (b == ',') + { flags &= ~ flag_need_comma; + continue; + } + else + { + sprintf (error, "%d:%d: Expected , before %c", + state.cur_line, state.cur_col, b); + + goto e_failed; + } + } + + if (flags & flag_need_colon) + { + if (b == ':') + { flags &= ~ flag_need_colon; + continue; + } + else + { + sprintf (error, "%d:%d: Expected : before %c", + state.cur_line, state.cur_col, b); + + goto e_failed; + } + } + + flags &= ~ flag_seek_value; + + switch (b) + { + case '{': + + if (!new_value (&state, &top, &root, &alloc, json_object)) + goto e_alloc_failure; + + continue; + + case '[': + + if (!new_value (&state, &top, &root, &alloc, json_array)) + goto e_alloc_failure; + + flags |= flag_seek_value; + continue; + + case '"': + + if (!new_value (&state, &top, &root, &alloc, json_string)) + goto e_alloc_failure; + + flags |= flag_string; + + string = top->u.string.ptr; + string_length = 0; + + continue; + + case 't': + + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || + *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + top->u.boolean = 1; + + flags |= flag_next; + break; + + case 'f': + + if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || + *(++ state.ptr) != 'e') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_boolean)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + case 'n': + + if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || + *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') + { + goto e_unknown_value; + } + + if (!new_value (&state, &top, &root, &alloc, json_null)) + goto e_alloc_failure; + + flags |= flag_next; + break; + + default: + + if (isdigit (b) || b == '-') + { + if (!new_value (&state, &top, &root, &alloc, json_integer)) + goto e_alloc_failure; + + if (!state.first_pass) + { + while (isdigit (b) || b == '+' || b == '-' + || b == 'e' || b == 'E' || b == '.') + { + if ( (++ state.ptr) == end) + { + b = 0; + break; + } + + b = *state.ptr; + } + + flags |= flag_next | flag_reproc; + break; + } + + flags &= ~ (flag_num_negative | flag_num_e | + flag_num_e_got_sign | flag_num_e_negative | + flag_num_zero); + + num_digits = 0; + num_fraction = 0; + num_e = 0; + + if (b != '-') + { + flags |= flag_reproc; + break; + } + + flags |= flag_num_negative; + continue; + } + else + { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b); + goto e_failed; + } + }; + }; + } + else + { + switch (top->type) + { + case json_object: + + switch (b) + { + whitespace: + continue; + + case '"': + + if (flags & flag_need_comma) + { sprintf (error, "%d:%d: Expected , before \"", line_and_col); + goto e_failed; + } + + flags |= flag_string; + + string = (json_char *) top->_reserved.object_mem; + string_length = 0; + + break; + + case '}': + + flags = (flags & ~ flag_need_comma) | flag_next; + break; + + case ',': + + if (flags & flag_need_comma) + { + flags &= ~ flag_need_comma; + break; + } + + default: + sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b); + goto e_failed; + }; + + break; + + case json_integer: + case json_double: + + if (isdigit (b)) + { + ++ num_digits; + + if (top->type == json_integer || flags & flag_num_e) + { + if (! (flags & flag_num_e)) + { + if (flags & flag_num_zero) + { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b); + goto e_failed; + } + + if (num_digits == 1 && b == '0') + flags |= flag_num_zero; + } + else + { + flags |= flag_num_e_got_sign; + num_e = (num_e * 10) + (b - '0'); + continue; + } + + top->u.integer = (top->u.integer * 10) + (b - '0'); + continue; + } + + num_fraction = (num_fraction * 10) + (b - '0'); + continue; + } + + if (b == '+' || b == '-') + { + if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) + { + flags |= flag_num_e_got_sign; + + if (b == '-') + flags |= flag_num_e_negative; + + continue; + } + } + else if (b == '.' && top->type == json_integer) + { + if (!num_digits) + { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col); + goto e_failed; + } + + top->type = json_double; + top->u.dbl = (double) top->u.integer; + + num_digits = 0; + continue; + } + + if (! (flags & flag_num_e)) + { + if (top->type == json_double) + { + if (!num_digits) + { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col); + goto e_failed; + } + + top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits)); + } + + if (b == 'e' || b == 'E') + { + flags |= flag_num_e; + + if (top->type == json_integer) + { + top->type = json_double; + top->u.dbl = (double) top->u.integer; + } + + num_digits = 0; + flags &= ~ flag_num_zero; + + continue; + } + } + else + { + if (!num_digits) + { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col); + goto e_failed; + } + + top->u.dbl *= pow (10.0, (double) + (flags & flag_num_e_negative ? - num_e : num_e)); + } + + if (flags & flag_num_negative) + { + if (top->type == json_integer) + top->u.integer = - top->u.integer; + else + top->u.dbl = - top->u.dbl; + } + + flags |= flag_next | flag_reproc; + break; + + default: + break; + }; + } + + if (flags & flag_reproc) + { + flags &= ~ flag_reproc; + -- state.ptr; + } + + if (flags & flag_next) + { + flags = (flags & ~ flag_next) | flag_need_comma; + + if (!top->parent) + { + /* root value done */ + + flags |= flag_done; + continue; + } + + if (top->parent->type == json_array) + flags |= flag_seek_value; + + if (!state.first_pass) + { + json_value * parent = top->parent; + + switch (parent->type) + { + case json_object: + + parent->u.object.values + [parent->u.object.length].value = top; + + break; + + case json_array: + + parent->u.array.values + [parent->u.array.length] = top; + + break; + + default: + break; + }; + } + + if ( (++ top->parent->u.array.length) > state.uint_max) + goto e_overflow; + + top = top->parent; + + continue; + } + } + + alloc = root; + } + + return root; + +e_unknown_value: + + sprintf (error, "%d:%d: Unknown value", line_and_col); + goto e_failed; + +e_alloc_failure: + + strcpy (error, "Memory allocation failure"); + goto e_failed; + +e_overflow: + + sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col); + goto e_failed; + +e_failed: + + if (error_buf) + { + if (*error) + strcpy (error_buf, error); + else + strcpy (error_buf, "Unknown error"); + } + + if (state.first_pass) + alloc = root; + + while (alloc) + { + top = alloc->_reserved.next_alloc; + state.settings.mem_free (alloc, state.settings.user_data); + alloc = top; + } + + if (!state.first_pass) + json_value_free_ex (&state.settings, root); + + return 0; +} + +json_value * json_parse (const json_char * json, size_t length) +{ + json_settings settings = { 0 }; + return json_parse_ex (&settings, json, length, 0); +} + +void json_value_free_ex (json_settings * settings, json_value * value) +{ + json_value * cur_value; + + if (!value) + return; + + value->parent = 0; + + while (value) + { + switch (value->type) + { + case json_array: + + if (!value->u.array.length) + { + settings->mem_free (value->u.array.values, settings->user_data); + break; + } + + value = value->u.array.values [-- value->u.array.length]; + continue; + + case json_object: + + if (!value->u.object.length) + { + settings->mem_free (value->u.object.values, settings->user_data); + break; + } + + value = value->u.object.values [-- value->u.object.length].value; + continue; + + case json_string: + + settings->mem_free (value->u.string.ptr, settings->user_data); + break; + + default: + break; + }; + + cur_value = value; + value = value->parent; + settings->mem_free (cur_value, settings->user_data); + } +} + +void json_value_free (json_value * value) +{ + json_settings settings = { 0 }; + settings.mem_free = default_free; + json_value_free_ex (&settings, value); +} + diff --git a/source/json/json.h b/source/json/json.h new file mode 100644 index 0000000..f6549ec --- /dev/null +++ b/source/json/json.h @@ -0,0 +1,283 @@ + +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. + * https://github.com/udp/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _JSON_H +#define _JSON_H + +#ifndef json_char + #define json_char char +#endif + +#ifndef json_int_t + #ifndef _MSC_VER + #include + #define json_int_t int64_t + #else + #define json_int_t __int64 + #endif +#endif + +#include + +#ifdef __cplusplus + + #include + + extern "C" + { + +#endif + +typedef struct +{ + unsigned long max_memory; + int settings; + + /* Custom allocator support (leave null to use malloc/free) + */ + + void * (* mem_alloc) (size_t, int zero, void * user_data); + void (* mem_free) (void *, void * user_data); + + void * user_data; /* will be passed to mem_alloc and mem_free */ + + size_t value_extra; /* how much extra space to allocate for values? */ + +} json_settings; + +#define json_enable_comments 0x01 + +typedef enum +{ + json_none, + json_object, + json_array, + json_integer, + json_double, + json_string, + json_boolean, + json_null + +} json_type; + +extern const struct _json_value json_value_none; + +typedef struct _json_object_entry +{ + json_char * name; + unsigned int name_length; + + struct _json_value * value; + +} json_object_entry; + +typedef struct _json_value +{ + struct _json_value * parent; + + json_type type; + + union + { + int boolean; + json_int_t integer; + double dbl; + + struct + { + unsigned int length; + json_char * ptr; /* null terminated */ + + } string; + + struct + { + unsigned int length; + + json_object_entry * values; + + #if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin () const + { return values; + } + decltype(values) end () const + { return values + length; + } + #endif + + } object; + + struct + { + unsigned int length; + struct _json_value ** values; + + #if defined(__cplusplus) && __cplusplus >= 201103L + decltype(values) begin () const + { return values; + } + decltype(values) end () const + { return values + length; + } + #endif + + } array; + + } u; + + union + { + struct _json_value * next_alloc; + void * object_mem; + + } _reserved; + + #ifdef JSON_TRACK_SOURCE + + /* Location of the value in the source JSON + */ + unsigned int line, col; + + #endif + + + /* Some C++ operator sugar */ + + #ifdef __cplusplus + + public: + + inline _json_value () + { memset (this, 0, sizeof (_json_value)); + } + + inline const struct _json_value &operator [] (int index) const + { + if (type != json_array || index < 0 + || ((unsigned int) index) >= u.array.length) + { + return json_value_none; + } + + return *u.array.values [index]; + } + + inline const struct _json_value &operator [] (const char * index) const + { + if (type != json_object) + return json_value_none; + + for (unsigned int i = 0; i < u.object.length; ++ i) + if (!strcmp (u.object.values [i].name, index)) + return *u.object.values [i].value; + + return json_value_none; + } + + inline operator const char * () const + { + switch (type) + { + case json_string: + return u.string.ptr; + + default: + return ""; + }; + } + + inline operator json_int_t () const + { + switch (type) + { + case json_integer: + return u.integer; + + case json_double: + return (json_int_t) u.dbl; + + default: + return 0; + }; + } + + inline operator bool () const + { + if (type != json_boolean) + return false; + + return u.boolean != 0; + } + + inline operator double () const + { + switch (type) + { + case json_integer: + return (double) u.integer; + + case json_double: + return u.dbl; + + default: + return 0; + }; + } + + #endif + +} json_value; + +json_value * json_parse (const json_char * json, + size_t length); + +#define json_error_max 128 +json_value * json_parse_ex (json_settings * settings, + const json_char * json, + size_t length, + char * error); + +void json_value_free (json_value *); + + +/* Not usually necessary, unless you used a custom mem_alloc and now want to + * use a custom mem_free. + */ +void json_value_free_ex (json_settings * settings, + json_value *); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif + + diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..26dab60 --- /dev/null +++ b/source/main.c @@ -0,0 +1,45 @@ +#include "main.h" +#include "draw.h" +#include +#include "clock.h" + + + +int main(void) +{ + //u32 kernelVersion; + gfxInitDefault(); + romfsInit(); + drawInit(); + initUI(); + bool loop = true; + s64 timenow = (s64)getTimeInMsec(Timer_Restart()); + s64 timefinish = timenow + 500; + s64 dif; + while (aptMainLoop() && loop) + { + timenow = (s64)getTimeInMsec(Timer_Restart()); + if (timefinish - timenow > 0) + dif = timefinish - timenow; + else + dif = 0; + + handleFadeIn(dif, 500); + + + hidScanInput(); + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) { + loop = false; + setExitMode(); + }; // break in order to return to hbmenu + updateUI(); + } + svcSleepThread(1000000000); + drawEndFrame(); + drawExit(); + exitUI(); + romfsExit(); + gfxExit(); + return (0); +} diff --git a/source/main.h b/source/main.h new file mode 100644 index 0000000..865d2a8 --- /dev/null +++ b/source/main.h @@ -0,0 +1,13 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include +#include +#include +#include +#include <3ds.h> +#include "graphics.h" +#include "drawableObject.h" +#endif \ No newline at end of file diff --git a/source/png.c b/source/png.c new file mode 100644 index 0000000..422d283 --- /dev/null +++ b/source/png.c @@ -0,0 +1,165 @@ +#include "draw.h" +#include +#include +#include +#include + +#define PNG_SIGSIZE (8) + +Result textureTile32(C3D_Tex *texture) +{ + u8 *tmp; + int i; + int height; + int width; + u32 pixel; + u32 size; + + height = (int)texture->height; + width = (int)texture->width; + tmp = linearAlloc(width * height * 4); + if (!tmp) goto error; + size = width * height * 4; + for (i = 0; i < size; i += 4) + { + pixel = *(u32 *)(texture->data + i); + *(u32 *)(tmp + i) = __builtin_bswap32(pixel); + } + GSPGPU_FlushDataCache(tmp, width * height * 4); + GSPGPU_FlushDataCache(texture->data, width * height * 4); + C3D_SafeDisplayTransfer((u32 *)tmp, GX_BUFFER_DIM(width, height), \ + (u32*)texture->data, GX_BUFFER_DIM(width, height), TEXTURE_TRANSFER_FLAGS); + gspWaitForPPF(); + linearFree(tmp); + return (MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_COMMON, RD_SUCCESS)); +error: + return (MAKERESULT(RL_TEMPORARY, RS_OUTOFRESOURCE, RM_COMMON, RD_OUT_OF_MEMORY)); +} + +static void readPNGFile(png_structp pngPtr, png_bytep data, png_size_t length) +{ + FILE *file = (FILE *)png_get_io_ptr(pngPtr); + fread(data, length, 1, file); +} + +static Result loadPNGGeneric(sprite_t **out, const void *ioPtr) +{ + png_structp pngPtr; + png_infop infoPtr; + png_bytep *rowPtrs; + sprite_t *sprite; + Result result; + unsigned int width; + unsigned int height; + int bitDepth; + int colorType; + int stride; + int i; + + rowPtrs = NULL; + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (pngPtr == NULL) + { + result = MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, RD_INVALID_RESULT_VALUE); + goto errorCreateRead; + } + infoPtr = png_create_info_struct(pngPtr); + if (infoPtr == NULL) + { + result = MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, RD_INVALID_RESULT_VALUE); + goto errorCreateInfo; + } + if (setjmp(png_jmpbuf(pngPtr))) + { + png_destroy_read_struct(&pngPtr, &infoPtr, (png_infopp)0); + if (rowPtrs != NULL) + free(rowPtrs); + result = MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_APPLICATION, RD_INVALID_RESULT_VALUE); + return (result); + } + png_set_read_fn(pngPtr, (png_voidp)ioPtr, readPNGFile); + png_set_sig_bytes(pngPtr, PNG_SIGSIZE); + png_read_info(pngPtr, infoPtr); + png_get_IHDR(pngPtr, infoPtr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); + if ((colorType == PNG_COLOR_TYPE_PALETTE && bitDepth <= 8) + || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) + || png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS) + || (bitDepth == 16)) + { + png_set_expand(pngPtr); + } + + if (bitDepth == 16) png_set_scale_16(pngPtr); + if (bitDepth == 8 && colorType == PNG_COLOR_TYPE_RGB) png_set_filler(pngPtr, 0xFF, PNG_FILLER_AFTER); + if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(pngPtr); + if (colorType == PNG_COLOR_TYPE_PALETTE) + { + png_set_palette_to_rgb(pngPtr); + png_set_filler(pngPtr, 0xFF, PNG_FILLER_AFTER); + } + if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) png_set_expand_gray_1_2_4_to_8(pngPtr); + if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(pngPtr); + if (bitDepth < 8) png_set_packing(pngPtr); + png_read_update_info(pngPtr, infoPtr); + rowPtrs = (png_bytep *)malloc(sizeof(png_bytep) * height); + if (!rowPtrs) + { + result = MAKERESULT(RL_PERMANENT, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY); + goto errorAllocRows; + } + sprite = newSprite(width, height); + if (!sprite) + { + result = MAKERESULT(RL_PERMANENT, RS_OUTOFRESOURCE, RM_APPLICATION, RD_OUT_OF_MEMORY); + goto errorCreateSprite; + } + else + *out = sprite; + stride = sprite->texture.width * 4; + + for (i = 0; i < height; i++) + { + rowPtrs[i] = (png_bytep)(sprite->texture.data + i * stride); + } + png_read_image(pngPtr, rowPtrs); + textureTile32(&sprite->texture); + result = MAKERESULT(RL_SUCCESS, RS_SUCCESS, RM_APPLICATION, RD_SUCCESS); +errorCreateSprite: + free(rowPtrs); +errorAllocRows: + png_destroy_info_struct(pngPtr, &infoPtr); +errorCreateInfo: + png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0); +errorCreateRead: + return (result); +} + + +Result newSpriteFromPNG(sprite_t **out, const char *filename) +{ + FILE *file; + Result result; + png_byte pngsig[PNG_SIGSIZE]; + + if (!(file = fopen(filename, "rb"))) + { + result = MAKERESULT(RL_PERMANENT, RS_NOTFOUND, RM_APPLICATION, RD_NOT_FOUND); + goto exitError; + } + if (fread(pngsig, 1, PNG_SIGSIZE, file) != PNG_SIGSIZE) + { + result = MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_APPLICATION, RD_INVALID_SIZE); + goto exitClose; + } + if (png_sig_cmp(pngsig, 0, PNG_SIGSIZE) != 0) + { + result = MAKERESULT(RL_PERMANENT, RS_INVALIDARG, RM_APPLICATION, RD_INVALID_SELECTION); + goto exitClose; + } + result = loadPNGGeneric(out, (void *)file); +exitClose: + fclose(file); +exitError: + return (result); +} diff --git a/source/vshader.v.pica b/source/vshader.v.pica new file mode 100644 index 0000000..12c673e --- /dev/null +++ b/source/vshader.v.pica @@ -0,0 +1,38 @@ +; Uniforms +.fvec projection[4] + +; Constants +.constf myconst(0.0, 1.0, -1.0, 0.1) +.constf RGBA_TO_FLOAT4(0.00392156862, 0, 0, 0) +.alias ones myconst.yyyy ; Vector full of ones +.alias zeros myconst.xxxx ; Vector full of zeros + +; Outputs +.out outpos position +.out outclr color +.out outtc0 texcoord0 + +; Inputs (defined as aliases for convenience) +.alias inpos v0 +.alias intex v1 + +.proc main + ; Force the zw component of inpos to be 1.0 + mov r0.xy, inpos + mov r0.z, zeros + mov r0.w, ones + + ; outpos = projectionMatrix * inpos + dp4 outpos.x, projection[0], r0 + dp4 outpos.y, projection[1], r0 + mov outpos.z, zeros + mov outpos.w, ones + + ;outtc0 = intexcoord + mov outtc0, intex + + ;outclr + mul outclr, RGBA_TO_FLOAT4.xxxx, intex + + end +.end \ No newline at end of file