MetalNES - v1.0

This commit is contained in:
Icer 2022-02-24 19:33:07 -08:00
parent 679058aa85
commit 56d7ea73ac
3167 changed files with 920341 additions and 0 deletions

203
CMakeLists.txt Normal file
View file

@ -0,0 +1,203 @@
cmake_minimum_required(VERSION 3.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_BUILD_TYPE RelWithDebInfo )
project(MetalNes LANGUAGES C CXX)
set(APP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/app)
set(COMMON_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/source)
set(EXTERNAL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)
set(IMGUI_SOURCE_DIR ${EXTERNAL_DIR}/imgui)
set(DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
add_subdirectory(${EXTERNAL_DIR}/hlsl2glslfork)
set(IMGUI_SOURCE
${IMGUI_SOURCE_DIR}/imgui.cpp
${IMGUI_SOURCE_DIR}/imgui_draw.cpp
${IMGUI_SOURCE_DIR}/imgui_widgets.cpp
${IMGUI_SOURCE_DIR}/imgui_demo.cpp
${IMGUI_SOURCE_DIR}/imgui_tables.cpp
)
set(TRIANGLE_SOURCE
${EXTERNAL_DIR}/triangle/triangle.c
${EXTERNAL_DIR}/triangle/tricall.c
)
set(COMMON_SOURCE
${COMMON_SOURCE_DIR}/Core/Matrix.cpp
${COMMON_SOURCE_DIR}/Core/File.cpp
${COMMON_SOURCE_DIR}/Core/DateTime.cpp
${COMMON_SOURCE_DIR}/Core/Log.cpp
${COMMON_SOURCE_DIR}/Core/Path.cpp
${COMMON_SOURCE_DIR}/Core/StopWatch.cpp
${COMMON_SOURCE_DIR}/Core/String.cpp
${COMMON_SOURCE_DIR}/metalnes/audio_device.cpp
${COMMON_SOURCE_DIR}/metalnes/chiprender.cpp
${COMMON_SOURCE_DIR}/metalnes/logger.cpp
${COMMON_SOURCE_DIR}/metalnes/nesdisasm.cpp
${COMMON_SOURCE_DIR}/metalnes/nesrom.cpp
${COMMON_SOURCE_DIR}/metalnes/raster_device.cpp
${COMMON_SOURCE_DIR}/metalnes/serializer.cpp
${COMMON_SOURCE_DIR}/metalnes/system.cpp
${COMMON_SOURCE_DIR}/metalnes/triangulate.cpp
${COMMON_SOURCE_DIR}/metalnes/wire_defs.cpp
${COMMON_SOURCE_DIR}/metalnes/wire_gui.cpp
${COMMON_SOURCE_DIR}/metalnes/wire_module.cpp
${COMMON_SOURCE_DIR}/metalnes/wire_node_resolver.cpp
${COMMON_SOURCE_DIR}/render/context.cpp
${COMMON_SOURCE_DIR}/imgui_support.cpp
${COMMON_SOURCE_DIR}/Application.cpp
${COMMON_SOURCE_DIR}/UnitTests.cpp
${COMMON_SOURCE_DIR}/AudioFileWriter.cpp
)
if (APPLE)
set(PLATFORM_SOURCE
${COMMON_SOURCE_DIR}/Platform/OSX/CoreAudio.mm
)
elseif (UNIX)
set(PLATFORM_SOURCE
)
elseif (WIN32)
set(PLATFORM_SOURCE
)
else()
message(FATAL_ERROR "Target platform not supported")
endif()
include_directories(
${COMMON_SOURCE_DIR}
)
if (APPLE)
add_executable(MetalNes
${TRIANGLE_SOURCE}
${IMGUI_SOURCE}
${COMMON_SOURCE}
${PLATFORM_SOURCE}
# ${APP_SOURCE_DIR}/OSX/main.mm
${APP_SOURCE_DIR}/Linux/main.cpp
)
target_link_libraries(
MetalNes
hlsl2glsl
"-framework CoreGraphics"
"-framework Foundation"
"-framework AppKit"
"-framework AudioToolbox"
"-framework CoreAudio"
"-framework Metal"
"-framework MetalKit"
"-framework GameController"
)
set_property (TARGET MetalNes APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc")
elseif (EMSCRIPTEN)
include_directories(
${INCLUDE_DIRS}
)
SET(APP_NAME ${CMAKE_PROJECT_NAME} )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_ZLIB -Wno-deprecated-register -Wno-version-check")
add_executable(MetalNes
${TRIANGLE_SOURCE}
${IMGUI_SOURCE}
${COMMON_SOURCE}
${PLATFORM_SOURCE}
# ${COMMON_SOURCE_DIR}/Platform/OSX/main.mm
${APP_SOURCE_DIR}/Linux/main.cpp
${COMMON_SOURCE_DIR}/render/gles/context_gles.cpp
# ${APP_SOURCE_DIR}/emscripten/emscripten_main.cpp
)
# Include libraries needed for lib
target_link_libraries(${APP_NAME}
${LIBS}
hlsl2glsl
)
# set(SHELL_FILE ${CMAKE_SOURCE_DIR}/app/emscripten/shell_minimal.html )
set(SHELL_FILE ${CMAKE_SOURCE_DIR}/app/emscripten/emscripten_shell.html )
set_target_properties(${APP_NAME} PROPERTIES LINK_FLAGS
"--preload-file ${CMAKE_SOURCE_DIR}/data@/assets \
--shell-file ${SHELL_FILE} \
-emrun \
-s TOTAL_MEMORY=536870912 \
-s LLD_REPORT_UNDEFINED \
-s NO_EXIT_RUNTIME=0 \
-s DEMANGLE_SUPPORT=1 \
-s WASM=1 \
-s ASSERTIONS=1 \
-s USE_WEBGL2=1 \
-s USE_SDL=2 \
-s MIN_WEBGL_VERSION=2 \
-s MAX_WEBGL_VERSION=2 \
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 \
-mnontrapping-fptoint \
-lopenal"
)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
# set_target_properties(${APP_NAME} PROPERTIES OUTPUT_NAME "metalnes.html")
elseif (UNIX)
target_link_libraries(
MetalNes
hlsl2glsl
pthread
)
elseif (WIN32)
target_link_libraries(
MetalNes
hlsl2glsl
)
else()
message(FATAL_ERROR "Target platform not supported")
endif()

View file

@ -0,0 +1,935 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
210E9DF02109AF3B00B5347F /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 210E9DED2109AF3B00B5347F /* MetalKit.framework */; };
210E9DF12109AF3B00B5347F /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 210E9DEE2109AF3B00B5347F /* Metal.framework */; };
210E9DF22109AF3B00B5347F /* MetalPerformanceShaders.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 210E9DEF2109AF3B00B5347F /* MetalPerformanceShaders.framework */; };
210E9DF62109B0C900B5347F /* ModelIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 210E9DF52109B0C800B5347F /* ModelIO.framework */; };
211402691BF2975800BB7AAB /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 211402681BF2975800BB7AAB /* OpenAL.framework */; };
212D4AA925A826F40034A93E /* imgui_support.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 212D4AA725A826F40034A93E /* imgui_support.cpp */; };
212FE02A259871E700B30F4A /* context_null.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F697237030EE001A1EA1 /* context_null.cpp */; };
21317D032591B971005F17D5 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21317CFF2591B971005F17D5 /* GameController.framework */; };
21445FEE25BC361A00E1E25A /* UnitTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21445FEC25BC361A00E1E25A /* UnitTests.cpp */; };
2154C5A2180392DE0013F26E /* data in Resources */ = {isa = PBXBuildFile; fileRef = 2154C5A1180392DE0013F26E /* data */; };
2167E91425C9603B0098EF95 /* chip_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2167E91325C9603B0098EF95 /* chip_tests.cpp */; };
217A5C2E258B891D004BB417 /* raster_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C19258B891D004BB417 /* raster_device.cpp */; };
217A5C2F258B891D004BB417 /* triangulate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C1B258B891D004BB417 /* triangulate.cpp */; };
217A5C30258B891D004BB417 /* wire_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C1C258B891D004BB417 /* wire_module.cpp */; };
217A5C31258B891D004BB417 /* chiprender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C1E258B891D004BB417 /* chiprender.cpp */; };
217A5C34258B891D004BB417 /* system.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C25258B891D004BB417 /* system.cpp */; };
217A5C35258B891D004BB417 /* logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C29258B891D004BB417 /* logger.cpp */; };
217A5C37258B891D004BB417 /* wire_defs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C2D258B891D004BB417 /* wire_defs.cpp */; };
217A5C3E258B8A72004BB417 /* nesrom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C3C258B8A72004BB417 /* nesrom.cpp */; };
217A5C41258B8E65004BB417 /* serializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 217A5C40258B8E65004BB417 /* serializer.cpp */; };
218DB3552485C16B00BF2FBF /* context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 218DB3542485C16A00BF2FBF /* context.cpp */; };
218DCFE6258B93E100E7C4AB /* triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = 218DCFE3258B93E100E7C4AB /* triangle.c */; };
218DCFE7258B93E100E7C4AB /* tricall.c in Sources */ = {isa = PBXBuildFile; fileRef = 218DCFE4258B93E100E7C4AB /* tricall.c */; };
218DCFF3258B9A8C00E7C4AB /* Matrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 218DCFF2258B9A8C00E7C4AB /* Matrix.cpp */; };
218DD008258DDACC00E7C4AB /* nesdisasm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 218DD006258DDACC00E7C4AB /* nesdisasm.cpp */; };
219294131BF3168300512C0B /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 219294121BF3168300512C0B /* AVFoundation.framework */; };
219294151BF316BC00512C0B /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 219294141BF316BC00512C0B /* CoreAudio.framework */; };
219294171BF316C700512C0B /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 219294161BF316C700512C0B /* AudioUnit.framework */; };
21A301D825BD6462005EE9FD /* AudioFileWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21A301D625BD6462005EE9FD /* AudioFileWriter.cpp */; };
21BAA75525987E4800C283D5 /* wire_gui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21BAA75425987E4800C283D5 /* wire_gui.cpp */; };
21C2F65B236E8ED2001A1EA1 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F648236E8ED2001A1EA1 /* imgui_widgets.cpp */; };
21C2F670236E8ED2001A1EA1 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F653236E8ED2001A1EA1 /* imgui.cpp */; };
21C2F673236E8ED2001A1EA1 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F655236E8ED2001A1EA1 /* imgui_impl_osx.mm */; };
21C2F676236E8ED2001A1EA1 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 21C2F657236E8ED2001A1EA1 /* LICENSE.txt */; };
21C2F679236E8ED2001A1EA1 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F658236E8ED2001A1EA1 /* imgui_demo.cpp */; };
21C2F67F236E8ED2001A1EA1 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F65A236E8ED2001A1EA1 /* imgui_draw.cpp */; };
21C2F6A2237030EE001A1EA1 /* context_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21C2F698237030EE001A1EA1 /* context_metal.mm */; };
21C2F6B223704490001A1EA1 /* libhlsl2glsl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21C2F6AD2370447C001A1EA1 /* libhlsl2glsl.a */; };
21C80C8817EDC60F0028195D /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21C80C4E17EDC2D80028195D /* Cocoa.framework */; };
21C80C8D17EDD3CC0028195D /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21C80C8C17EDD3CC0028195D /* CoreVideo.framework */; };
21D0467C27B0F0F600288EA1 /* emscripten in Resources */ = {isa = PBXBuildFile; fileRef = 21D0467B27B0F0F600288EA1 /* emscripten */; };
21D922BA27B0E97E005F2000 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 21D922A827B0E97D005F2000 /* InfoPlist.strings */; };
21D922BB27B0E97E005F2000 /* RenderViewControllerOSX.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922AD27B0E97D005F2000 /* RenderViewControllerOSX.mm */; };
21D922BC27B0E97E005F2000 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 21D922AF27B0E97D005F2000 /* Assets.xcassets */; };
21D922BD27B0E97E005F2000 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 21D922B027B0E97D005F2000 /* Main.storyboard */; };
21D922BE27B0E97E005F2000 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922B127B0E97D005F2000 /* main.mm */; };
21D922BF27B0E97E005F2000 /* CoreAudio.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922B227B0E97E005F2000 /* CoreAudio.mm */; };
21D922C027B0E97E005F2000 /* MetalView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922B327B0E97E005F2000 /* MetalView.mm */; };
21D922C127B0E97E005F2000 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 21D922B427B0E97E005F2000 /* Images.xcassets */; };
21D922C227B0E97E005F2000 /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922B527B0E97E005F2000 /* AppDelegate.mm */; };
21D922C427B0E97E005F2000 /* keycode_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 21D922B827B0E97E005F2000 /* keycode_osx.mm */; };
21DFEA641BD68C9F0041F553 /* DateTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFE9D81BD68C9F0041F553 /* DateTime.cpp */; };
21DFEA651BD68C9F0041F553 /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFE9DB1BD68C9F0041F553 /* Log.cpp */; };
21DFEA661BD68C9F0041F553 /* Path.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFE9DD1BD68C9F0041F553 /* Path.cpp */; };
21DFEA671BD68C9F0041F553 /* StopWatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFE9DF1BD68C9F0041F553 /* StopWatch.cpp */; };
21DFEA681BD68C9F0041F553 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFE9E11BD68C9F0041F553 /* String.cpp */; };
21DFEA941BD68C9F0041F553 /* Application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21DFEA4A1BD68C9F0041F553 /* Application.cpp */; };
21FA4F072589B71F009C4EAF /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FA4F062589B71F009C4EAF /* imgui_tables.cpp */; };
21FA4F572589BD29009C4EAF /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FA4F542589BD29009C4EAF /* File.cpp */; };
21FFCED225A2DBF40065C6C4 /* wire_node_resolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FFCECE25A2DBF40065C6C4 /* wire_node_resolver.cpp */; };
21FFCED625A2DF580065C6C4 /* audio_device.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FFCED425A2DF580065C6C4 /* audio_device.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
21C2F6AC2370447C001A1EA1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2B951C991135194700DBAF46;
remoteInfo = hlsl2glsl;
};
21C2F6AE2370447C001A1EA1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 21A3B13B22990C2700540D1A;
remoteInfo = "hlsl2glsl-ios";
};
21C2F6B02370447C001A1EA1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 21A3B185229C5B7300540D1A;
remoteInfo = "hlsl2glsl-tvos";
};
21C2F6B323704497001A1EA1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 2B951C981135194700DBAF46;
remoteInfo = hlsl2glsl;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
210E9DED2109AF3B00B5347F /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
210E9DEE2109AF3B00B5347F /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
210E9DEF2109AF3B00B5347F /* MetalPerformanceShaders.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalPerformanceShaders.framework; path = System/Library/Frameworks/MetalPerformanceShaders.framework; sourceTree = SDKROOT; };
210E9DF32109B0A100B5347F /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = System/Library/Frameworks/SceneKit.framework; sourceTree = SDKROOT; };
210E9DF52109B0C800B5347F /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = System/Library/Frameworks/ModelIO.framework; sourceTree = SDKROOT; };
211402251BEC764D00BB7AAB /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; };
211402271BEC765100BB7AAB /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; };
211402291BEC766100BB7AAB /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/AVKit.framework; sourceTree = DEVELOPER_DIR; };
2114022B1BEC766C00BB7AAB /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; };
211402421BEC810400BB7AAB /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/AudioUnit.framework; sourceTree = DEVELOPER_DIR; };
211402441BEC816200BB7AAB /* AVKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/AVKit.framework; sourceTree = DEVELOPER_DIR; };
211402461BED231C00BB7AAB /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; };
211402481BED233600BB7AAB /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; };
2114024A1BED235800BB7AAB /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/Accelerate.framework; sourceTree = DEVELOPER_DIR; };
2114025C1BEEC9C600BB7AAB /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
211402661BF2973D00BB7AAB /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
211402681BF2975800BB7AAB /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
212D4AA025A8119A0034A93E /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
212D4AA725A826F40034A93E /* imgui_support.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_support.cpp; sourceTree = "<group>"; };
212D4AA825A826F40034A93E /* imgui_support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_support.h; sourceTree = "<group>"; };
212FE034259D8BAE00B30F4A /* rapidjson */ = {isa = PBXFileReference; lastKnownFileType = folder; name = rapidjson; path = external/rapidjson; sourceTree = "<group>"; };
212FE039259DBFF800B30F4A /* handler_video_out.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_video_out.h; sourceTree = "<group>"; };
212FE03B259DC04000B30F4A /* handler_rom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_rom.h; sourceTree = "<group>"; };
212FE03C259DC07000B30F4A /* handler_ram.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_ram.h; sourceTree = "<group>"; };
212FE042259DC1D300B30F4A /* handler_log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_log.h; sourceTree = "<group>"; };
212FE044259DC37A00B30F4A /* handler_palette_ram.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_palette_ram.h; sourceTree = "<group>"; };
212FE045259DC37A00B30F4A /* handler_sprite_ram.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_sprite_ram.h; sourceTree = "<group>"; };
212FE048259DC79500B30F4A /* handler_nes_system.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_nes_system.h; sourceTree = "<group>"; };
212FE04B259DD0ED00B30F4A /* wire_handler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wire_handler.h; sourceTree = "<group>"; };
21317CFF2591B971005F17D5 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
21445FEC25BC361A00E1E25A /* UnitTests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnitTests.cpp; sourceTree = "<group>"; };
21445FED25BC361A00E1E25A /* UnitTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnitTests.h; sourceTree = "<group>"; };
2154C5A1180392DE0013F26E /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = data; sourceTree = "<group>"; };
2161A4BD1BD7855D00C89668 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
2161A4BF1BD7857B00C89668 /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.0.sdk/System/Library/Frameworks/SceneKit.framework; sourceTree = DEVELOPER_DIR; };
2167E91325C9603B0098EF95 /* chip_tests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = chip_tests.cpp; sourceTree = "<group>"; };
217A5C19258B891D004BB417 /* raster_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = raster_device.cpp; sourceTree = "<group>"; };
217A5C1A258B891D004BB417 /* wire_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wire_module.h; sourceTree = "<group>"; };
217A5C1B258B891D004BB417 /* triangulate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = triangulate.cpp; sourceTree = "<group>"; };
217A5C1C258B891D004BB417 /* wire_module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wire_module.cpp; sourceTree = "<group>"; };
217A5C1D258B891D004BB417 /* wire_defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wire_defs.h; sourceTree = "<group>"; };
217A5C1E258B891D004BB417 /* chiprender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chiprender.cpp; sourceTree = "<group>"; };
217A5C1F258B891D004BB417 /* JsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JsonParser.h; sourceTree = "<group>"; };
217A5C24258B891D004BB417 /* chiprender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chiprender.h; sourceTree = "<group>"; };
217A5C25258B891D004BB417 /* system.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = system.cpp; sourceTree = "<group>"; };
217A5C27258B891D004BB417 /* triangulate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = triangulate.h; sourceTree = "<group>"; };
217A5C28258B891D004BB417 /* system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = system.h; sourceTree = "<group>"; };
217A5C29258B891D004BB417 /* logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logger.cpp; sourceTree = "<group>"; };
217A5C2A258B891D004BB417 /* logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logger.h; sourceTree = "<group>"; };
217A5C2B258B891D004BB417 /* raster_device.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raster_device.h; sourceTree = "<group>"; };
217A5C2D258B891D004BB417 /* wire_defs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wire_defs.cpp; sourceTree = "<group>"; };
217A5C39258B8989004BB417 /* serializer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = serializer.h; sourceTree = "<group>"; };
217A5C3C258B8A72004BB417 /* nesrom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nesrom.cpp; sourceTree = "<group>"; };
217A5C3D258B8A72004BB417 /* nesrom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nesrom.h; sourceTree = "<group>"; };
217A5C40258B8E65004BB417 /* serializer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serializer.cpp; sourceTree = "<group>"; };
217A74971C86B86900F7E592 /* Application.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Application.h; sourceTree = "<group>"; };
218DB3542485C16A00BF2FBF /* context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context.cpp; sourceTree = "<group>"; };
218DCFE3258B93E100E7C4AB /* triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = triangle.c; sourceTree = "<group>"; };
218DCFE4258B93E100E7C4AB /* tricall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tricall.c; sourceTree = "<group>"; };
218DCFE5258B93E100E7C4AB /* triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = triangle.h; sourceTree = "<group>"; };
218DCFF1258B9A8C00E7C4AB /* Matrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Matrix.h; sourceTree = "<group>"; };
218DCFF2258B9A8C00E7C4AB /* Matrix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Matrix.cpp; sourceTree = "<group>"; };
218DCFF8258B9AF000E7C4AB /* Vector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; };
218DD006258DDACC00E7C4AB /* nesdisasm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nesdisasm.cpp; sourceTree = "<group>"; };
218DD007258DDACC00E7C4AB /* nesdisasm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nesdisasm.h; sourceTree = "<group>"; };
219294121BF3168300512C0B /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
219294141BF316BC00512C0B /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
219294161BF316C700512C0B /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
21A301D625BD6462005EE9FD /* AudioFileWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AudioFileWriter.cpp; sourceTree = "<group>"; };
21A301D725BD6462005EE9FD /* AudioFileWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioFileWriter.h; sourceTree = "<group>"; };
21A5C4AE1CAA012A003CAE7D /* Base.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Base.h; sourceTree = "<group>"; };
21BAA75025987E4800C283D5 /* wire_gui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wire_gui.h; sourceTree = "<group>"; };
21BAA75425987E4800C283D5 /* wire_gui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wire_gui.cpp; sourceTree = "<group>"; };
21BAA75925A1B79800C283D5 /* handler_audio_out.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = handler_audio_out.h; sourceTree = "<group>"; };
21C2F644236E8ED2001A1EA1 /* imgui_impl_win32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_win32.h; sourceTree = "<group>"; };
21C2F645236E8ED2001A1EA1 /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui.h; sourceTree = "<group>"; };
21C2F646236E8ED2001A1EA1 /* imstb_textedit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_textedit.h; sourceTree = "<group>"; };
21C2F647236E8ED2001A1EA1 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imconfig.h; sourceTree = "<group>"; };
21C2F648236E8ED2001A1EA1 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_widgets.cpp; sourceTree = "<group>"; };
21C2F649236E8ED2001A1EA1 /* imstb_truetype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_truetype.h; sourceTree = "<group>"; };
21C2F64A236E8ED2001A1EA1 /* imgui_impl_sdl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_sdl.h; sourceTree = "<group>"; };
21C2F64B236E8ED2001A1EA1 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_osx.h; sourceTree = "<group>"; };
21C2F652236E8ED2001A1EA1 /* imgui_impl_win32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_impl_win32.cpp; sourceTree = "<group>"; };
21C2F653236E8ED2001A1EA1 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui.cpp; sourceTree = "<group>"; };
21C2F654236E8ED2001A1EA1 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_internal.h; sourceTree = "<group>"; };
21C2F655236E8ED2001A1EA1 /* imgui_impl_osx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = imgui_impl_osx.mm; sourceTree = "<group>"; };
21C2F656236E8ED2001A1EA1 /* imstb_rectpack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imstb_rectpack.h; sourceTree = "<group>"; };
21C2F657236E8ED2001A1EA1 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
21C2F658236E8ED2001A1EA1 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_demo.cpp; sourceTree = "<group>"; };
21C2F659236E8ED2001A1EA1 /* imgui_impl_sdl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_impl_sdl.cpp; sourceTree = "<group>"; };
21C2F65A236E8ED2001A1EA1 /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_draw.cpp; sourceTree = "<group>"; };
21C2F68B236FDD9C001A1EA1 /* keycode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keycode.h; sourceTree = "<group>"; };
21C2F691237030EE001A1EA1 /* context_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context_metal.h; sourceTree = "<group>"; };
21C2F692237030EE001A1EA1 /* context_gles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context_gles.cpp; sourceTree = "<group>"; };
21C2F693237030EE001A1EA1 /* context_d3d9.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context_d3d9.cpp; sourceTree = "<group>"; };
21C2F694237030EE001A1EA1 /* context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context.h; sourceTree = "<group>"; };
21C2F695237030EE001A1EA1 /* context_gles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context_gles.h; sourceTree = "<group>"; };
21C2F697237030EE001A1EA1 /* context_null.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context_null.cpp; sourceTree = "<group>"; };
21C2F698237030EE001A1EA1 /* context_metal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = context_metal.mm; sourceTree = "<group>"; };
21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = hlslang.xcodeproj; path = external/hlsl2glslfork/hlslang.xcodeproj; sourceTree = "<group>"; };
21C80C4B17EDC2D80028195D /* MetalNes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MetalNes.app; sourceTree = BUILT_PRODUCTS_DIR; };
21C80C4E17EDC2D80028195D /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
21C80C5117EDC2D80028195D /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
21C80C5217EDC2D80028195D /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
21C80C5317EDC2D80028195D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
21C80C8C17EDD3CC0028195D /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
21D0467B27B0F0F600288EA1 /* emscripten */ = {isa = PBXFileReference; lastKnownFileType = folder; path = emscripten; sourceTree = "<group>"; };
21D9227F27B0E7A0005F2000 /* cmake-build-emscripten.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "cmake-build-emscripten.sh"; sourceTree = "<group>"; };
21D9228327B0E7A0005F2000 /* cmake-build-android.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "cmake-build-android.sh"; sourceTree = "<group>"; };
21D922A627B0E97D005F2000 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
21D922A927B0E97D005F2000 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
21D922AA27B0E97D005F2000 /* EventDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventDelegate.h; sourceTree = "<group>"; };
21D922AB27B0E97D005F2000 /* RenderViewControllerOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderViewControllerOSX.h; sourceTree = "<group>"; };
21D922AC27B0E97D005F2000 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
21D922AD27B0E97D005F2000 /* RenderViewControllerOSX.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderViewControllerOSX.mm; sourceTree = "<group>"; };
21D922AE27B0E97D005F2000 /* keycode_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keycode_osx.h; sourceTree = "<group>"; };
21D922AF27B0E97D005F2000 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
21D922B027B0E97D005F2000 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
21D922B127B0E97D005F2000 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
21D922B227B0E97E005F2000 /* CoreAudio.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreAudio.mm; sourceTree = "<group>"; };
21D922B327B0E97E005F2000 /* MetalView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MetalView.mm; sourceTree = "<group>"; };
21D922B427B0E97E005F2000 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
21D922B527B0E97E005F2000 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = "<group>"; };
21D922B627B0E97E005F2000 /* MetalView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MetalView.h; sourceTree = "<group>"; };
21D922B727B0E97E005F2000 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
21D922B827B0E97E005F2000 /* keycode_osx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = keycode_osx.mm; sourceTree = "<group>"; };
21DFE9D81BD68C9F0041F553 /* DateTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DateTime.cpp; sourceTree = "<group>"; };
21DFE9D91BD68C9F0041F553 /* DateTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateTime.h; sourceTree = "<group>"; };
21DFE9DB1BD68C9F0041F553 /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 5; lastKnownFileType = sourcecode.cpp.cpp; path = Log.cpp; sourceTree = "<group>"; };
21DFE9DC1BD68C9F0041F553 /* Log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = "<group>"; };
21DFE9DD1BD68C9F0041F553 /* Path.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Path.cpp; sourceTree = "<group>"; };
21DFE9DE1BD68C9F0041F553 /* Path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Path.h; sourceTree = "<group>"; };
21DFE9DF1BD68C9F0041F553 /* StopWatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StopWatch.cpp; sourceTree = "<group>"; };
21DFE9E01BD68C9F0041F553 /* StopWatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StopWatch.h; sourceTree = "<group>"; };
21DFE9E11BD68C9F0041F553 /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = "<group>"; };
21DFE9E21BD68C9F0041F553 /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = "<group>"; };
21DFEA4A1BD68C9F0041F553 /* Application.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Application.cpp; sourceTree = "<group>"; };
21FA4F062589B71F009C4EAF /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_tables.cpp; sourceTree = "<group>"; };
21FA4F342589BB53009C4EAF /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk/System/Library/Frameworks/Metal.framework; sourceTree = DEVELOPER_DIR; };
21FA4F392589BB5F009C4EAF /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = DEVELOPER_DIR; };
21FA4F3E2589BB82009C4EAF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.3.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
21FA4F542589BD29009C4EAF /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = File.cpp; sourceTree = "<group>"; };
21FA4F552589BD29009C4EAF /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = "<group>"; };
21FA4F562589BD29009C4EAF /* BinaryReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinaryReader.h; sourceTree = "<group>"; };
21FFCEC0259F05EA0065C6C4 /* dispatch_queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dispatch_queue.h; sourceTree = "<group>"; };
21FFCEC5259F101D0065C6C4 /* wire_thread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wire_thread.h; sourceTree = "<group>"; };
21FFCECA25A184FE0065C6C4 /* wire_node_resolver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wire_node_resolver.h; sourceTree = "<group>"; };
21FFCECE25A2DBF40065C6C4 /* wire_node_resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wire_node_resolver.cpp; sourceTree = "<group>"; };
21FFCED425A2DF580065C6C4 /* audio_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_device.cpp; sourceTree = "<group>"; };
21FFCED525A2DF580065C6C4 /* audio_device.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_device.h; sourceTree = "<group>"; };
449334861FB795B200FE2F0A /* Math.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Math.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
21C80C4817EDC2D80028195D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
21317D032591B971005F17D5 /* GameController.framework in Frameworks */,
21C2F6B223704490001A1EA1 /* libhlsl2glsl.a in Frameworks */,
210E9DF62109B0C900B5347F /* ModelIO.framework in Frameworks */,
210E9DF02109AF3B00B5347F /* MetalKit.framework in Frameworks */,
210E9DF12109AF3B00B5347F /* Metal.framework in Frameworks */,
210E9DF22109AF3B00B5347F /* MetalPerformanceShaders.framework in Frameworks */,
219294171BF316C700512C0B /* AudioUnit.framework in Frameworks */,
219294151BF316BC00512C0B /* CoreAudio.framework in Frameworks */,
219294131BF3168300512C0B /* AVFoundation.framework in Frameworks */,
211402691BF2975800BB7AAB /* OpenAL.framework in Frameworks */,
21C80C8D17EDD3CC0028195D /* CoreVideo.framework in Frameworks */,
21C80C8817EDC60F0028195D /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
212D4AB125A981240034A93E /* metal */ = {
isa = PBXGroup;
children = (
21C2F691237030EE001A1EA1 /* context_metal.h */,
21C2F698237030EE001A1EA1 /* context_metal.mm */,
);
path = metal;
sourceTree = "<group>";
};
212D4AB225A981290034A93E /* d3d9 */ = {
isa = PBXGroup;
children = (
21C2F693237030EE001A1EA1 /* context_d3d9.cpp */,
);
path = d3d9;
sourceTree = "<group>";
};
212D4AB325A9812E0034A93E /* gles */ = {
isa = PBXGroup;
children = (
21C2F695237030EE001A1EA1 /* context_gles.h */,
21C2F692237030EE001A1EA1 /* context_gles.cpp */,
);
path = gles;
sourceTree = "<group>";
};
212D4AB425A981460034A93E /* null */ = {
isa = PBXGroup;
children = (
21C2F697237030EE001A1EA1 /* context_null.cpp */,
);
path = null;
sourceTree = "<group>";
};
217A5C18258B891D004BB417 /* metalnes */ = {
isa = PBXGroup;
children = (
21FFCED425A2DF580065C6C4 /* audio_device.cpp */,
21FFCED525A2DF580065C6C4 /* audio_device.h */,
217A5C1E258B891D004BB417 /* chiprender.cpp */,
217A5C24258B891D004BB417 /* chiprender.h */,
21FFCEC0259F05EA0065C6C4 /* dispatch_queue.h */,
21BAA75925A1B79800C283D5 /* handler_audio_out.h */,
212FE042259DC1D300B30F4A /* handler_log.h */,
212FE048259DC79500B30F4A /* handler_nes_system.h */,
212FE044259DC37A00B30F4A /* handler_palette_ram.h */,
212FE03C259DC07000B30F4A /* handler_ram.h */,
212FE03B259DC04000B30F4A /* handler_rom.h */,
212FE045259DC37A00B30F4A /* handler_sprite_ram.h */,
212FE039259DBFF800B30F4A /* handler_video_out.h */,
217A5C29258B891D004BB417 /* logger.cpp */,
217A5C2A258B891D004BB417 /* logger.h */,
218DD006258DDACC00E7C4AB /* nesdisasm.cpp */,
218DD007258DDACC00E7C4AB /* nesdisasm.h */,
217A5C3C258B8A72004BB417 /* nesrom.cpp */,
217A5C3D258B8A72004BB417 /* nesrom.h */,
217A5C19258B891D004BB417 /* raster_device.cpp */,
217A5C2B258B891D004BB417 /* raster_device.h */,
217A5C40258B8E65004BB417 /* serializer.cpp */,
217A5C39258B8989004BB417 /* serializer.h */,
217A5C25258B891D004BB417 /* system.cpp */,
217A5C28258B891D004BB417 /* system.h */,
217A5C1B258B891D004BB417 /* triangulate.cpp */,
217A5C27258B891D004BB417 /* triangulate.h */,
217A5C2D258B891D004BB417 /* wire_defs.cpp */,
217A5C1D258B891D004BB417 /* wire_defs.h */,
21BAA75425987E4800C283D5 /* wire_gui.cpp */,
21BAA75025987E4800C283D5 /* wire_gui.h */,
212FE04B259DD0ED00B30F4A /* wire_handler.h */,
217A5C1C258B891D004BB417 /* wire_module.cpp */,
217A5C1A258B891D004BB417 /* wire_module.h */,
21FFCEC5259F101D0065C6C4 /* wire_thread.h */,
21FFCECE25A2DBF40065C6C4 /* wire_node_resolver.cpp */,
21FFCECA25A184FE0065C6C4 /* wire_node_resolver.h */,
2167E91325C9603B0098EF95 /* chip_tests.cpp */,
);
path = metalnes;
sourceTree = "<group>";
};
217A74981C8AAD6C00F7E592 /* external */ = {
isa = PBXGroup;
children = (
212FE034259D8BAE00B30F4A /* rapidjson */,
218DCFE2258B93E100E7C4AB /* triangle */,
21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */,
21C2F643236E8ED2001A1EA1 /* imgui */,
);
name = external;
sourceTree = "<group>";
};
218DCFE2258B93E100E7C4AB /* triangle */ = {
isa = PBXGroup;
children = (
218DCFE3258B93E100E7C4AB /* triangle.c */,
218DCFE4258B93E100E7C4AB /* tricall.c */,
218DCFE5258B93E100E7C4AB /* triangle.h */,
);
name = triangle;
path = external/triangle;
sourceTree = "<group>";
};
21C2F643236E8ED2001A1EA1 /* imgui */ = {
isa = PBXGroup;
children = (
21FA4F062589B71F009C4EAF /* imgui_tables.cpp */,
21C2F644236E8ED2001A1EA1 /* imgui_impl_win32.h */,
21C2F645236E8ED2001A1EA1 /* imgui.h */,
21C2F646236E8ED2001A1EA1 /* imstb_textedit.h */,
21C2F647236E8ED2001A1EA1 /* imconfig.h */,
21C2F648236E8ED2001A1EA1 /* imgui_widgets.cpp */,
21C2F649236E8ED2001A1EA1 /* imstb_truetype.h */,
21C2F64A236E8ED2001A1EA1 /* imgui_impl_sdl.h */,
21C2F64B236E8ED2001A1EA1 /* imgui_impl_osx.h */,
21C2F652236E8ED2001A1EA1 /* imgui_impl_win32.cpp */,
21C2F653236E8ED2001A1EA1 /* imgui.cpp */,
21C2F654236E8ED2001A1EA1 /* imgui_internal.h */,
21C2F655236E8ED2001A1EA1 /* imgui_impl_osx.mm */,
21C2F656236E8ED2001A1EA1 /* imstb_rectpack.h */,
21C2F657236E8ED2001A1EA1 /* LICENSE.txt */,
21C2F658236E8ED2001A1EA1 /* imgui_demo.cpp */,
21C2F659236E8ED2001A1EA1 /* imgui_impl_sdl.cpp */,
21C2F65A236E8ED2001A1EA1 /* imgui_draw.cpp */,
);
name = imgui;
path = external/imgui;
sourceTree = "<group>";
};
21C2F690237030EE001A1EA1 /* render */ = {
isa = PBXGroup;
children = (
212D4AB425A981460034A93E /* null */,
212D4AB325A9812E0034A93E /* gles */,
212D4AB225A981290034A93E /* d3d9 */,
212D4AB125A981240034A93E /* metal */,
218DB3542485C16A00BF2FBF /* context.cpp */,
21C2F694237030EE001A1EA1 /* context.h */,
);
path = render;
sourceTree = "<group>";
};
21C2F6A62370447C001A1EA1 /* Products */ = {
isa = PBXGroup;
children = (
21C2F6AD2370447C001A1EA1 /* libhlsl2glsl.a */,
21C2F6AF2370447C001A1EA1 /* libhlsl2glsl-ios.a */,
21C2F6B12370447C001A1EA1 /* libhlsl2glsl-tvos.a */,
);
name = Products;
sourceTree = "<group>";
};
21C80C4217EDC2D80028195D = {
isa = PBXGroup;
children = (
21D9228427B0E8B7005F2000 /* app */,
21D9228327B0E7A0005F2000 /* cmake-build-android.sh */,
21D9227F27B0E7A0005F2000 /* cmake-build-emscripten.sh */,
217A74981C8AAD6C00F7E592 /* external */,
2154C5A1180392DE0013F26E /* data */,
21DFE9D11BD68C9F0041F553 /* source */,
21C80C4D17EDC2D80028195D /* Frameworks */,
21C80C4C17EDC2D80028195D /* Products */,
212D4AA025A8119A0034A93E /* CMakeLists.txt */,
);
sourceTree = "<group>";
};
21C80C4C17EDC2D80028195D /* Products */ = {
isa = PBXGroup;
children = (
21C80C4B17EDC2D80028195D /* MetalNes.app */,
);
name = Products;
sourceTree = "<group>";
};
21C80C4D17EDC2D80028195D /* Frameworks */ = {
isa = PBXGroup;
children = (
21317CFF2591B971005F17D5 /* GameController.framework */,
21FA4F3E2589BB82009C4EAF /* CoreGraphics.framework */,
21FA4F392589BB5F009C4EAF /* MetalKit.framework */,
21FA4F342589BB53009C4EAF /* Metal.framework */,
210E9DF52109B0C800B5347F /* ModelIO.framework */,
210E9DF32109B0A100B5347F /* SceneKit.framework */,
210E9DEE2109AF3B00B5347F /* Metal.framework */,
210E9DED2109AF3B00B5347F /* MetalKit.framework */,
210E9DEF2109AF3B00B5347F /* MetalPerformanceShaders.framework */,
219294161BF316C700512C0B /* AudioUnit.framework */,
219294141BF316BC00512C0B /* CoreAudio.framework */,
219294121BF3168300512C0B /* AVFoundation.framework */,
211402681BF2975800BB7AAB /* OpenAL.framework */,
211402661BF2973D00BB7AAB /* OpenAL.framework */,
2114025C1BEEC9C600BB7AAB /* OpenAL.framework */,
2114024A1BED235800BB7AAB /* Accelerate.framework */,
211402481BED233600BB7AAB /* CoreAudio.framework */,
211402461BED231C00BB7AAB /* AudioToolbox.framework */,
211402441BEC816200BB7AAB /* AVKit.framework */,
211402421BEC810400BB7AAB /* AudioUnit.framework */,
2114022B1BEC766C00BB7AAB /* AVFoundation.framework */,
211402291BEC766100BB7AAB /* AVKit.framework */,
211402271BEC765100BB7AAB /* AudioToolbox.framework */,
211402251BEC764D00BB7AAB /* AVFoundation.framework */,
2161A4BF1BD7857B00C89668 /* SceneKit.framework */,
2161A4BD1BD7855D00C89668 /* UIKit.framework */,
21C80C8C17EDD3CC0028195D /* CoreVideo.framework */,
21C80C4E17EDC2D80028195D /* Cocoa.framework */,
21C80C5017EDC2D80028195D /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
21C80C5017EDC2D80028195D /* Other Frameworks */ = {
isa = PBXGroup;
children = (
21C80C5117EDC2D80028195D /* AppKit.framework */,
21C80C5217EDC2D80028195D /* CoreData.framework */,
21C80C5317EDC2D80028195D /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
21D9228427B0E8B7005F2000 /* app */ = {
isa = PBXGroup;
children = (
21D0467B27B0F0F600288EA1 /* emscripten */,
21D922A527B0E97D005F2000 /* Linux */,
21D922A727B0E97D005F2000 /* OSX */,
);
path = app;
sourceTree = "<group>";
};
21D922A527B0E97D005F2000 /* Linux */ = {
isa = PBXGroup;
children = (
21D922A627B0E97D005F2000 /* main.cpp */,
);
path = Linux;
sourceTree = "<group>";
};
21D922A727B0E97D005F2000 /* OSX */ = {
isa = PBXGroup;
children = (
21D922A827B0E97D005F2000 /* InfoPlist.strings */,
21D922AA27B0E97D005F2000 /* EventDelegate.h */,
21D922AB27B0E97D005F2000 /* RenderViewControllerOSX.h */,
21D922AC27B0E97D005F2000 /* AppDelegate.h */,
21D922AD27B0E97D005F2000 /* RenderViewControllerOSX.mm */,
21D922AE27B0E97D005F2000 /* keycode_osx.h */,
21D922AF27B0E97D005F2000 /* Assets.xcassets */,
21D922B027B0E97D005F2000 /* Main.storyboard */,
21D922B127B0E97D005F2000 /* main.mm */,
21D922B227B0E97E005F2000 /* CoreAudio.mm */,
21D922B327B0E97E005F2000 /* MetalView.mm */,
21D922B427B0E97E005F2000 /* Images.xcassets */,
21D922B527B0E97E005F2000 /* AppDelegate.mm */,
21D922B627B0E97E005F2000 /* MetalView.h */,
21D922B727B0E97E005F2000 /* Info.plist */,
21D922B827B0E97E005F2000 /* keycode_osx.mm */,
);
path = OSX;
sourceTree = "<group>";
};
21DFE9D11BD68C9F0041F553 /* source */ = {
isa = PBXGroup;
children = (
212D4AA725A826F40034A93E /* imgui_support.cpp */,
212D4AA825A826F40034A93E /* imgui_support.h */,
21DFEA4A1BD68C9F0041F553 /* Application.cpp */,
217A74971C86B86900F7E592 /* Application.h */,
217A5C18258B891D004BB417 /* metalnes */,
21C2F690237030EE001A1EA1 /* render */,
21DFE9D71BD68C9F0041F553 /* Core */,
21DFEA491BD68C9F0041F553 /* Platform */,
21445FEC25BC361A00E1E25A /* UnitTests.cpp */,
21445FED25BC361A00E1E25A /* UnitTests.h */,
21A301D625BD6462005EE9FD /* AudioFileWriter.cpp */,
21A301D725BD6462005EE9FD /* AudioFileWriter.h */,
);
path = source;
sourceTree = "<group>";
};
21DFE9D71BD68C9F0041F553 /* Core */ = {
isa = PBXGroup;
children = (
217A5C1F258B891D004BB417 /* JsonParser.h */,
218DCFF2258B9A8C00E7C4AB /* Matrix.cpp */,
218DCFF1258B9A8C00E7C4AB /* Matrix.h */,
449334861FB795B200FE2F0A /* Math.h */,
21FA4F562589BD29009C4EAF /* BinaryReader.h */,
21FA4F542589BD29009C4EAF /* File.cpp */,
21FA4F552589BD29009C4EAF /* File.h */,
21A5C4AE1CAA012A003CAE7D /* Base.h */,
21DFE9D81BD68C9F0041F553 /* DateTime.cpp */,
21DFE9D91BD68C9F0041F553 /* DateTime.h */,
21DFE9DB1BD68C9F0041F553 /* Log.cpp */,
21DFE9DC1BD68C9F0041F553 /* Log.h */,
21DFE9DD1BD68C9F0041F553 /* Path.cpp */,
21DFE9DE1BD68C9F0041F553 /* Path.h */,
21DFE9DF1BD68C9F0041F553 /* StopWatch.cpp */,
21DFE9E01BD68C9F0041F553 /* StopWatch.h */,
21DFE9E11BD68C9F0041F553 /* String.cpp */,
21DFE9E21BD68C9F0041F553 /* String.h */,
218DCFF8258B9AF000E7C4AB /* Vector.h */,
);
path = Core;
sourceTree = "<group>";
};
21DFEA491BD68C9F0041F553 /* Platform */ = {
isa = PBXGroup;
children = (
21C2F68B236FDD9C001A1EA1 /* keycode.h */,
);
path = Platform;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
21C80C4A17EDC2D80028195D /* MetalNesOSX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 21C80C7C17EDC2D90028195D /* Build configuration list for PBXNativeTarget "MetalNesOSX" */;
buildPhases = (
21C80C4717EDC2D80028195D /* Sources */,
21C80C4817EDC2D80028195D /* Frameworks */,
21C80C4917EDC2D80028195D /* Resources */,
);
buildRules = (
);
dependencies = (
21C2F6B423704497001A1EA1 /* PBXTargetDependency */,
);
name = MetalNesOSX;
productName = Emu901;
productReference = 21C80C4B17EDC2D80028195D /* MetalNes.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
21C80C4317EDC2D80028195D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1200;
ORGANIZATIONNAME = icer;
TargetAttributes = {
21C80C4A17EDC2D80028195D = {
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 21C80C4617EDC2D80028195D /* Build configuration list for PBXProject "MetalNes" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 21C80C4217EDC2D80028195D;
productRefGroup = 21C80C4C17EDC2D80028195D /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 21C2F6A62370447C001A1EA1 /* Products */;
ProjectRef = 21C2F6A52370447C001A1EA1 /* hlslang.xcodeproj */;
},
);
projectRoot = "";
targets = (
21C80C4A17EDC2D80028195D /* MetalNesOSX */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
21C2F6AD2370447C001A1EA1 /* libhlsl2glsl.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libhlsl2glsl.a;
remoteRef = 21C2F6AC2370447C001A1EA1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
21C2F6AF2370447C001A1EA1 /* libhlsl2glsl-ios.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libhlsl2glsl-ios.a";
remoteRef = 21C2F6AE2370447C001A1EA1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
21C2F6B12370447C001A1EA1 /* libhlsl2glsl-tvos.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libhlsl2glsl-tvos.a";
remoteRef = 21C2F6B02370447C001A1EA1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
21C80C4917EDC2D80028195D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
21C2F676236E8ED2001A1EA1 /* LICENSE.txt in Resources */,
21D0467C27B0F0F600288EA1 /* emscripten in Resources */,
21D922BD27B0E97E005F2000 /* Main.storyboard in Resources */,
21D922BA27B0E97E005F2000 /* InfoPlist.strings in Resources */,
21D922C127B0E97E005F2000 /* Images.xcassets in Resources */,
21D922BC27B0E97E005F2000 /* Assets.xcassets in Resources */,
2154C5A2180392DE0013F26E /* data in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
21C80C4717EDC2D80028195D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
21445FEE25BC361A00E1E25A /* UnitTests.cpp in Sources */,
21C2F670236E8ED2001A1EA1 /* imgui.cpp in Sources */,
218DCFE7258B93E100E7C4AB /* tricall.c in Sources */,
217A5C31258B891D004BB417 /* chiprender.cpp in Sources */,
218DD008258DDACC00E7C4AB /* nesdisasm.cpp in Sources */,
217A5C3E258B8A72004BB417 /* nesrom.cpp in Sources */,
21D922C427B0E97E005F2000 /* keycode_osx.mm in Sources */,
21FA4F072589B71F009C4EAF /* imgui_tables.cpp in Sources */,
21D922C027B0E97E005F2000 /* MetalView.mm in Sources */,
21D922BF27B0E97E005F2000 /* CoreAudio.mm in Sources */,
21DFEA941BD68C9F0041F553 /* Application.cpp in Sources */,
21D922C227B0E97E005F2000 /* AppDelegate.mm in Sources */,
217A5C41258B8E65004BB417 /* serializer.cpp in Sources */,
21D922BE27B0E97E005F2000 /* main.mm in Sources */,
21FFCED625A2DF580065C6C4 /* audio_device.cpp in Sources */,
21DFEA651BD68C9F0041F553 /* Log.cpp in Sources */,
217A5C35258B891D004BB417 /* logger.cpp in Sources */,
21C2F65B236E8ED2001A1EA1 /* imgui_widgets.cpp in Sources */,
217A5C34258B891D004BB417 /* system.cpp in Sources */,
21FA4F572589BD29009C4EAF /* File.cpp in Sources */,
217A5C37258B891D004BB417 /* wire_defs.cpp in Sources */,
21C2F673236E8ED2001A1EA1 /* imgui_impl_osx.mm in Sources */,
21DFEA671BD68C9F0041F553 /* StopWatch.cpp in Sources */,
21C2F6A2237030EE001A1EA1 /* context_metal.mm in Sources */,
21C2F67F236E8ED2001A1EA1 /* imgui_draw.cpp in Sources */,
21A301D825BD6462005EE9FD /* AudioFileWriter.cpp in Sources */,
218DCFF3258B9A8C00E7C4AB /* Matrix.cpp in Sources */,
218DB3552485C16B00BF2FBF /* context.cpp in Sources */,
217A5C2E258B891D004BB417 /* raster_device.cpp in Sources */,
212D4AA925A826F40034A93E /* imgui_support.cpp in Sources */,
21FFCED225A2DBF40065C6C4 /* wire_node_resolver.cpp in Sources */,
21DFEA641BD68C9F0041F553 /* DateTime.cpp in Sources */,
21D922BB27B0E97E005F2000 /* RenderViewControllerOSX.mm in Sources */,
21C2F679236E8ED2001A1EA1 /* imgui_demo.cpp in Sources */,
21DFEA661BD68C9F0041F553 /* Path.cpp in Sources */,
21DFEA681BD68C9F0041F553 /* String.cpp in Sources */,
217A5C30258B891D004BB417 /* wire_module.cpp in Sources */,
218DCFE6258B93E100E7C4AB /* triangle.c in Sources */,
212FE02A259871E700B30F4A /* context_null.cpp in Sources */,
21BAA75525987E4800C283D5 /* wire_gui.cpp in Sources */,
217A5C2F258B891D004BB417 /* triangulate.cpp in Sources */,
2167E91425C9603B0098EF95 /* chip_tests.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
21C2F6B423704497001A1EA1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = hlsl2glsl;
targetProxy = 21C2F6B323704497001A1EA1 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
21D922A827B0E97D005F2000 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
21D922A927B0E97D005F2000 /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
21C80C7A17EDC2D90028195D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = source;
};
name = Debug;
};
21C80C7B17EDC2D90028195D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = source;
};
name = Release;
};
21C80C7D17EDC2D90028195D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_PRECOMPILE_PREFIX_HEADER = NO;
INFOPLIST_FILE = "$(SRCROOT)/app/OSX/Info.plist";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.icer.MetalNes;
PRODUCT_NAME = MetalNes;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SUPPORTED_PLATFORMS = macosx;
WRAPPER_EXTENSION = app;
};
name = Debug;
};
21C80C7E17EDC2D90028195D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_PRECOMPILE_PREFIX_HEADER = NO;
INFOPLIST_FILE = "$(SRCROOT)/app/OSX/Info.plist";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = com.icer.MetalNes;
PRODUCT_NAME = MetalNes;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SUPPORTED_PLATFORMS = macosx;
WRAPPER_EXTENSION = app;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
21C80C4617EDC2D80028195D /* Build configuration list for PBXProject "MetalNes" */ = {
isa = XCConfigurationList;
buildConfigurations = (
21C80C7A17EDC2D90028195D /* Debug */,
21C80C7B17EDC2D90028195D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
21C80C7C17EDC2D90028195D /* Build configuration list for PBXNativeTarget "MetalNesOSX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
21C80C7D17EDC2D90028195D /* Debug */,
21C80C7E17EDC2D90028195D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 21C80C4317EDC2D80028195D /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

53
app/Linux/main.cpp Normal file
View file

@ -0,0 +1,53 @@
#include <assert.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "Core/File.h"
#if __linux__ || __APPLE__
#include <pthread.h>
#endif
#include "Application.h"
#include "imgui_support.h"
#include "../external/imgui/imgui.h"
void SetCurrentThreadName(const char* threadName)
{
#if __linux__
pthread_setname_np(pthread_self(), threadName); // For GDB.
#elif __APPLE__
pthread_setname_np(threadName); // For GDB.
#endif
}
int main(int argc, const char *argv[])
{
std::string _resourceDir = "./";
std::string _userDir = ".metalnes/";
render::ContextPtr _context = nullptr;
Core::Directory::Create(_userDir);
std::vector<std::string> args;
for (int i=1; i < argc; i++)
{
args.push_back(std::string(argv[i]));
}
AppInit(_context, _resourceDir, _userDir, args);
while (!AppShouldQuit())
{
AppRender(_context);
}
AppShutdown();
return 0;
}

22
app/OSX/AppDelegate.h Normal file
View file

@ -0,0 +1,22 @@
#import <Cocoa/Cocoa.h>
#import <MetalKit/MetalKit.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
//
@property (weak) IBOutlet NSWindow *window;
//
//@property (weak) IBOutlet NSOpenGLView *glView;
//
//
//
//@property (weak) IBOutlet MetalView *_mtkview;
//
//
//@property (weak) IBOutlet MetalViewController *_mtvc;
@end

61
app/OSX/AppDelegate.mm Normal file
View file

@ -0,0 +1,61 @@
#import "AppDelegate.h"
#import <AVFoundation/AVFoundation.h>
#include <string>
#import <GLKit/GLKit.h>
#include "Core/Path.h"
#include <pthread.h>
#include "Application.h"
void SetCurrentThreadName(const char* threadName)
{
;
[[NSThread currentThread] setName: [NSString stringWithUTF8String:threadName] ]; // For Cocoa
pthread_setname_np(threadName); // For GDB.
}
@implementation AppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
// AppShutdown();
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app {
return NSTerminateNow;
}
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
-(IBAction)saveState:(id)sender
{
}
-(IBAction)loadState:(id)sender
{
}
@end

View file

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,17 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"origin" : "bottom-left",
"interpretation" : "non-premultiplied-colors"
},
"textures" : [
{
"idiom" : "universal",
"filename" : "Universal.mipmapset"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -0,0 +1,12 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
},
"levels" : [
{
"filename" : "ColorMap.png",
"mipmap-level" : "base"
}
]
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

195
app/OSX/CoreAudio.mm Normal file
View file

@ -0,0 +1,195 @@
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <Accelerate/Accelerate.h>
#if TARGET_OS_IPHONE
#import <AVFoundation/AVFoundation.h>
#else
#import <CoreAudio/CoreAudio.h>
#endif
#include <vector>
#define CheckStatus() \
assert( status == 0 )
struct AudioSample
{
float left;
float right;
};
class AudioSource
{
public:
AudioSource() = default;
virtual ~AudioSource() = default;
virtual bool render(AudioSample *samples, size_t count) = 0;
AudioComponentInstance _output;
};
static OSStatus renderCallback (void *inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inOutputBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
AudioSource *source = (AudioSource *)inRefCon;
// clear all buffers
for (int i=0; i < ioData->mNumberBuffers; i++)
{
memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
}
// render to first buffer...
AudioBuffer *buffer = &ioData->mBuffers[0];
if (inNumberFrames * sizeof(AudioSample) <= buffer->mDataByteSize)
{
if (!source->render( (AudioSample *)buffer->mData, inNumberFrames))
{
if (source->_output) {
AudioOutputUnitStop(source->_output);
// AudioUnitUninitialize(source->_output);
// AudioComponentInstanceDispose(source->_output);
source->_output = nullptr;
}
// delete source;
}
}
return noErr;
}
class BufferAudioSource : public AudioSource
{
public:
virtual bool render(AudioSample *samples, size_t count) override
{
for (size_t i=0; i < count; i++)
{
if (_position < _samples.size()) {
float v = _samples[_position++];
samples[i] = {v, v};
} else {
samples[i] = {0, 0};
}
}
return (_position < _samples.size());
}
size_t _position = 0;
std::vector<float> _samples;
};
void AudioPlaySound(double sample_rate, const float *sample_data, size_t sample_count)
{
AudioComponentInstance output;
OSStatus status;
AudioComponentDescription desc = {0};
desc.componentType = kAudioUnitType_Output;
#if TARGET_OS_IPHONE
desc.componentSubType = kAudioUnitSubType_RemoteIO;
#else
desc.componentSubType = kAudioUnitSubType_HALOutput;
#endif
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
// Get component
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
status = AudioComponentInstanceNew(comp, &output);
CheckStatus();
// Enable IO for playback
UInt32 flag = 1;
status = AudioUnitSetProperty(output,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
0,
&flag,
sizeof(flag));
CheckStatus();
AudioStreamBasicDescription fmt;
UInt32 size = sizeof(fmt);
status = AudioUnitGetProperty(output,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&fmt,
&size );
CheckStatus();
fmt.mSampleRate = sample_rate;
fmt.mFormatID = kAudioFormatLinearPCM;
fmt.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; //kAudioFormatFlagIsPacked | kAudioFormatFlagIsFloat;
fmt.mChannelsPerFrame = 2;
fmt.mBitsPerChannel = 32;
fmt.mBytesPerFrame = fmt.mBitsPerChannel * fmt.mChannelsPerFrame / 8;
fmt.mBytesPerPacket = fmt.mBytesPerFrame * fmt.mFramesPerPacket;
size = sizeof(fmt);
status = AudioUnitSetProperty(output,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&fmt,
size );
CheckStatus();
status = AudioUnitInitialize(output);
CheckStatus();
status = AudioUnitGetProperty(output,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0,
&fmt,
&size );
CheckStatus();
BufferAudioSource *source = new BufferAudioSource();
source->_output = output;
source->_samples.assign( sample_data, sample_data + sample_count);
AURenderCallbackStruct cb;
cb.inputProc = renderCallback;
cb.inputProcRefCon = source;
status = AudioUnitSetProperty(output,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Output,
0,
&cb,
sizeof(cb)
);
CheckStatus();
status = AudioOutputUnitStart(output);
CheckStatus();
}

18
app/OSX/EventDelegate.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#import <Cocoa/Cocoa.h>
@protocol EventDelegate <NSObject>
@required
- (void)keyDown:(NSEvent * _Nonnull)event;
- (void)keyUp:(NSEvent * _Nonnull)event;
-(void)onDragDrop:(NSArray * _Nonnull)files;
@end

View file

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

34
app/OSX/Info.plist Normal file
View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 . All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

719
app/OSX/Main.storyboard Normal file
View file

@ -0,0 +1,719 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="qut-Dz-bWv">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="MetalNES" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="MetalNES" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About MetalNES" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide TestMetalApp" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit TestMetalApp" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
<connections>
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="jxT-CU-nIS">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="GEO-Iw-cKr">
<items>
<menuItem title="Font" id="Gi5-1S-RQB">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq">
<connections>
<action selector="orderFrontFontPanel:" target="YLy-65-1bz" id="WHr-nq-2xA"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="hqk-hr-sYV"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq">
<connections>
<action selector="addFontTrait:" target="YLy-65-1bz" id="IHV-OB-c03"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
<connections>
<action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="Uc7-di-UnL"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST">
<connections>
<action selector="modifyFont:" target="YLy-65-1bz" id="HcX-Lf-eNd"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
<menuItem title="Kern" id="jBQ-r6-VK2">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="tlD-Oa-oAM">
<items>
<menuItem title="Use Default" id="GUa-eO-cwY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
</connections>
</menuItem>
<menuItem title="Use None" id="cDB-IK-hbR">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="46P-cB-AYj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="ogc-rX-tC1">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="o6e-r0-MWq">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
<items>
<menuItem title="Use Default" id="agt-UL-0e3">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
</connections>
</menuItem>
<menuItem title="Use None" id="J7y-lM-qPV">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
</connections>
</menuItem>
<menuItem title="Use All" id="xQD-1f-W4t">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="OaQ-X3-Vso">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="ijk-EB-dga">
<items>
<menuItem title="Use Default" id="3Om-Ey-2VK">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="Rqc-34-cIF">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="I0S-gh-46l">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
</connections>
</menuItem>
<menuItem title="Raise" id="2h7-ER-AoG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
</connections>
</menuItem>
<menuItem title="Lower" id="1tx-W0-xDw">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
<menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
<connections>
<action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
<menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="Fal-I4-PZk">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="d9c-me-L2H">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
<connections>
<action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
<connections>
<action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
</connections>
</menuItem>
<menuItem title="Justify" id="J5U-5w-g23">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
<connections>
<action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
<menuItem title="Writing Direction" id="H1b-Si-o9J">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
<items>
<menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="YGs-j5-SAR">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
</connections>
</menuItem>
<menuItem id="Lbh-J2-qVU">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
</connections>
</menuItem>
<menuItem id="jFq-tB-4Kx">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
<menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="Nop-cj-93Q">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
</connections>
</menuItem>
<menuItem id="BgM-ve-c93">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
</connections>
</menuItem>
<menuItem id="RB4-Sm-HuC">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
<menuItem title="Show Ruler" id="vLm-3I-IUL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
<menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleSidebar:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
</connections>
</menuItem>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="TestMetalApp Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="54" y="-447"/>
</scene>
<!--MainWindow Controller-->
<scene sceneID="aaz-Hd-Sm6">
<objects>
<windowController id="qut-Dz-bWv" userLabel="MainWindow Controller" sceneMemberID="viewController">
<window key="window" title="MetalNES" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="" animationBehavior="default" id="bFf-q6-aJw">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="245" y="301" width="1280" height="720"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="qut-Dz-bWv" id="zaW-Zb-HNx"/>
</connections>
</window>
<connections>
<segue destination="UHy-w0-sJM" kind="relationship" relationship="window.shadowedContentViewController" id="jLk-fS-Kqe"/>
</connections>
</windowController>
<customObject id="Ili-yh-0UC" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="139" y="124"/>
</scene>
<!--Render View ControllerOSX-->
<scene sceneID="PpC-DY-wVr">
<objects>
<viewController id="UHy-w0-sJM" customClass="RenderViewControllerOSX" sceneMemberID="viewController">
<view key="view" id="ULQ-gd-dlI">
<rect key="frame" x="0.0" y="0.0" width="1200" height="900"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
</viewController>
<customObject id="sd5-bj-0DG" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1623" y="188"/>
</scene>
</scenes>
</document>

16
app/OSX/MetalView.h Normal file
View file

@ -0,0 +1,16 @@
#import <Cocoa/Cocoa.h>
#import <MetalKit/MetalKit.h>
#import "EventDelegate.h"
@interface MetalView : MTKView
@property (weak, nonatomic) IBOutlet id<EventDelegate> _Nullable eventDelegate;
- (void)registerDragDrop;
@end

54
app/OSX/MetalView.mm Normal file
View file

@ -0,0 +1,54 @@
#import "MetalView.h"
@implementation MetalView
-(BOOL)acceptsFirstResponder
{
return YES;
}
- (void)keyDown:(NSEvent *)event
{
[self.eventDelegate keyDown:event];
}
- (void)keyUp:(NSEvent *)event
{
[self.eventDelegate keyUp:event];
}
- (void)registerDragDrop
{
[self registerForDraggedTypes:[NSArray arrayWithObjects:
NSPasteboardTypeFileURL, nil]];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSPasteboardTypeFileURL] ) {
if (sourceDragMask & NSDragOperationLink) {
return NSDragOperationLink;
} else if (sourceDragMask & NSDragOperationCopy) {
return NSDragOperationCopy;
}
}
return NSDragOperationNone;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard *pboard = [sender draggingPasteboard];
if ( [[pboard types] containsObject:NSPasteboardTypeFileURL] ) {
NSArray *files = [pboard propertyListForType:NSPasteboardTypeFileURL];
[self.eventDelegate onDragDrop:files];
}
return YES;
}
@end

View file

@ -0,0 +1,12 @@
#import <Cocoa/Cocoa.h>
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import "MetalView.h"
// Our macOS view controller.
@interface RenderViewControllerOSX : NSViewController <MTKViewDelegate, EventDelegate>
@end

View file

@ -0,0 +1,347 @@
#import <GLKit/GLKit.h>
#import <GameController/GameController.h>
#include <sys/stat.h>
#include <sys/types.h>
#import "RenderViewControllerOSX.h"
#include "render/context.h"
#include "render/metal/context_metal.h"
#include "keycode_osx.h"
#include "../external/imgui/imgui.h"
#include "../external/imgui/imgui_impl_osx.h"
#include "Application.h"
#include "imgui_support.h"
static bool GetApplicationSupportDir(std::string &user_dir)
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory,
NSUserDomainMask,
YES);
for (int i=0; i < paths.count; i++)
{
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
NSString *resolvedPath = [paths objectAtIndex:i];
NSString *dir = [resolvedPath stringByAppendingPathComponent:bundleId];
NSError *error;
if ([[NSFileManager defaultManager] createDirectoryAtPath:dir
withIntermediateDirectories:YES
attributes:nil
error:&error])
{
user_dir = [dir UTF8String];
return true;
}
}
return false;
}
static int readGamePad(GCExtendedGamepad *pad)
{
if (!pad) return 0;
int bits = 0;
if (pad.buttonA.pressed) bits |= (1 << 0);
if (pad.buttonB.pressed) bits |= (1 << 0);
if (pad.buttonX.pressed) bits |= (1 << 1);
if (pad.buttonY.pressed) bits |= (1 << 1);
if (pad.buttonOptions.pressed) bits |= (1 << 2);
if (pad.buttonMenu.pressed) bits |= (1 << 3);
if (pad.dpad.up.pressed) bits |= (1 << 4);
if (pad.dpad.down.pressed) bits |= (1 << 5);
if (pad.dpad.left.pressed) bits |= (1 << 6);
if (pad.dpad.right.pressed) bits |= (1 << 7);
return bits;
}
int readGamePad(int index)
{
NSArray<GCController *> *controllers = [GCController controllers];
if (index >= controllers.count)
return 0;
GCController *controller = [controllers objectAtIndex:index];
if (!controller) {
return 0;
}
return readGamePad(controller.extendedGamepad);
}
@implementation RenderViewControllerOSX
{
std::string _resourceDir;
std::string _userDir;
render::ContextPtr _context;
render::ContextPtr _gl_context;
render::metal::IMetalContextPtr _metal_context;
NSTrackingArea *_trackingArea;
}
- (void)flagsChanged:(NSEvent *)event
{
ImGuiIO& io = ImGui::GetIO();
unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
bool oldKeyCtrl = io.KeyCtrl;
bool oldKeyShift = io.KeyShift;
bool oldKeyAlt = io.KeyAlt;
bool oldKeySuper = io.KeySuper;
io.KeyCtrl = flags & NSEventModifierFlagControl;
io.KeyShift = flags & NSEventModifierFlagShift;
io.KeyAlt = flags & NSEventModifierFlagOption;
io.KeySuper = flags & NSEventModifierFlagCommand;
// We must reset them as we will not receive any keyUp event if they where pressed with a modifier
if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper))
{
//memset(io.KeysDown,0, sizeof(io.KeysDown));// resetKeys();
}
}
- (void)keyDown:(NSEvent *)event
{
ImGui_ImplOSX_HandleEvent(event, self.view);
ImGuiIO& io = ImGui::GetIO();
io.KeyCtrl = (event.modifierFlags & NSEventModifierFlagControl) != 0;
io.KeyShift = (event.modifierFlags & NSEventModifierFlagShift) != 0;
io.KeyAlt = (event.modifierFlags & NSEventModifierFlagOption) != 0;
io.KeySuper = (event.modifierFlags & NSEventModifierFlagCommand) != 0;
KeyCode code = ConvertKeyCode_OSX(event.keyCode);
if (code != 0 && code < sizeof(io.KeysDown))
{
io.KeysDown[code] = true;
}
NSString* str = event.characters;
int len = (int)[str length];
for (int i = 0; i < len; i++)
{
int c = [str characterAtIndex:i];
if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF))
io.AddInputCharacter((unsigned int)c);
}
}
- (void)keyUp:(NSEvent *)event
{
ImGuiIO& io = ImGui::GetIO();
io.KeyCtrl = (event.modifierFlags & NSEventModifierFlagControl) != 0;
io.KeyShift = (event.modifierFlags & NSEventModifierFlagShift) != 0;
io.KeyAlt = (event.modifierFlags & NSEventModifierFlagOption) != 0;
io.KeySuper = (event.modifierFlags & NSEventModifierFlagCommand) != 0;
KeyCode code = ConvertKeyCode_OSX(event.keyCode);
if (code != 0 && code < sizeof(io.KeysDown))
{
io.KeysDown[code] = false;
}
}
-(void)onDragDrop:(NSArray * _Nonnull)files
{
// [self.visualizer onDragDrop:files];
}
#define HANDLE_EVENT( __name) \
- (void)__name:(NSEvent *)event { \
ImGui_ImplOSX_HandleEvent(event, self.view); \
}
HANDLE_EVENT(mouseMoved)
HANDLE_EVENT(mouseDown)
HANDLE_EVENT(mouseUp)
HANDLE_EVENT(mouseDragged)
HANDLE_EVENT(rightMouseDown)
HANDLE_EVENT(rightMouseUp)
HANDLE_EVENT(rightMouseDragged)
HANDLE_EVENT(otherMouseDown)
HANDLE_EVENT(otherMouseUp)
HANDLE_EVENT(otherMouseDragged)
HANDLE_EVENT(scrollWheel)
- (void)viewDidLoad
{
[super viewDidLoad];
_resourceDir = [[[NSBundle mainBundle] resourcePath] UTF8String];
GetApplicationSupportDir(_userDir);
[self initMetal];
_context->SetAssetDir(_resourceDir);
std::vector<std::string> args;
AppInit(_context, _resourceDir, _userDir, args);
ImGui_ImplOSX_Init();
auto &io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
// Add a tracking area in order to receive mouse events whenever the mouse is within the bounds of our view
_trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
options:NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
owner:self
userInfo:nil];
[self.view addTrackingArea:_trackingArea];
[self.view becomeFirstResponder];
}
-(void)viewWillDisappear
{
AppShutdown();
}
-(void)initMetal
{
id <MTLDevice> device = MTLCreateSystemDefaultDevice();
if(!device)
{
NSLog(@"Metal is not supported on this device");
return;
}
MetalView *view = [[MetalView alloc] initWithFrame:self.view.frame device:device];;
// configure view
// view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
view.depthStencilPixelFormat = MTLPixelFormatInvalid;
view.sampleCount = 1;
view.framebufferOnly = YES;
view.delegate = self;
view.preferredFramesPerSecond = 60.0f;
view.eventDelegate = self;
[view registerDragDrop];
self.view = view;
_metal_context = render::metal::MetalCreateContext(device);
_context = _metal_context;
_metal_context->SetView( view );
// _context->SetRenderTarget(nullptr);
}
/*
ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard)
ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard)
ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)
ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)
ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)
ImGuiNavInput_DpadRight, //
ImGuiNavInput_DpadUp, //
ImGuiNavInput_DpadDown, //
ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down
ImGuiNavInput_LStickRight, //
ImGuiNavInput_LStickUp, //
ImGuiNavInput_LStickDown, //
ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
*/
-(void)updateControllers
{
auto &io = ImGui::GetIO();
NSArray<GCController *> *controllers = [GCController controllers];
int i = 0;
for (GCController *controller in controllers)
{
GCExtendedGamepad *pad = controller.extendedGamepad;
if (!pad) continue;
io.NavInputs[ImGuiNavInput_Activate] = pad.buttonA.value;
io.NavInputs[ImGuiNavInput_Cancel] = pad.buttonB.value;
io.NavInputs[ImGuiNavInput_Input] = pad.buttonY.value;
io.NavInputs[ImGuiNavInput_Menu] = pad.buttonX.value;
io.NavInputs[ImGuiNavInput_DpadLeft] = pad.dpad.left.value;
io.NavInputs[ImGuiNavInput_DpadRight] = pad.dpad.right.value;
io.NavInputs[ImGuiNavInput_DpadUp] = pad.dpad.up.value;
io.NavInputs[ImGuiNavInput_DpadDown] = pad.dpad.down.value;
io.NavInputs[ImGuiNavInput_LStickLeft] = pad.leftThumbstick.left.value;
io.NavInputs[ImGuiNavInput_LStickRight] = pad.leftThumbstick.right.value;
io.NavInputs[ImGuiNavInput_LStickUp] = pad.leftThumbstick.up.value;
io.NavInputs[ImGuiNavInput_LStickDown] = pad.leftThumbstick.down.value;
io.NavInputs[ImGuiNavInput_FocusPrev] = pad.leftShoulder.value;
io.NavInputs[ImGuiNavInput_FocusNext] = pad.rightShoulder.value;
io.NavInputs[ImGuiNavInput_TweakSlow] = pad.leftTrigger.value;
io.NavInputs[ImGuiNavInput_TweakFast] = pad.rightTrigger.value;
i++;
}
}
- (void)drawInMTKView:(nonnull MTKView *)view
{
@autoreleasepool {
[self updateControllers];
// ImGuiSupport_NewFrame();
ImGui_ImplOSX_NewFrame();
_metal_context->SetView( view );
_context->NextFrame();
AppRender(_context);
_context->Present();
// if (AppShouldQuit())
// {
// NSWindow *window = view.window;
// [window close];
// }
}
}
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
/// Respond to drawable size or orientation changes here
// _context->SetDisplaySize(size.width, size.height);
}
@end

View file

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

10
app/OSX/keycode_osx.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "../source/Platform/keycode.h"
KeyCode ConvertKeyCode_OSX(int code);

244
app/OSX/keycode_osx.mm Normal file
View file

@ -0,0 +1,244 @@
#import <TargetConditionals.h>
#import <Carbon/Carbon.h>
#include "keycode_osx.h"
KeyCode ConvertKeyCode_OSX(int code)
{
switch (code)
{
case kVK_ANSI_A :
return KEYCODE_A;
case kVK_ANSI_S :
return KEYCODE_S;
case kVK_ANSI_D :
return KEYCODE_D;
case kVK_ANSI_F :
return KEYCODE_F;
case kVK_ANSI_H :
return KEYCODE_H;
case kVK_ANSI_G :
return KEYCODE_G;
case kVK_ANSI_Z :
return KEYCODE_Z;
case kVK_ANSI_X :
return KEYCODE_X;
case kVK_ANSI_C :
return KEYCODE_C;
case kVK_ANSI_V :
return KEYCODE_V;
case kVK_ANSI_B :
return KEYCODE_B;
case kVK_ANSI_Q :
return KEYCODE_Q;
case kVK_ANSI_W :
return KEYCODE_W;
case kVK_ANSI_E :
return KEYCODE_E;
case kVK_ANSI_R :
return KEYCODE_R;
case kVK_ANSI_Y :
return KEYCODE_Y;
case kVK_ANSI_T :
return KEYCODE_T;
case kVK_ANSI_1 :
return KEYCODE_1;
case kVK_ANSI_2 :
return KEYCODE_2;
case kVK_ANSI_3 :
return KEYCODE_3;
case kVK_ANSI_4 :
return KEYCODE_4;
case kVK_ANSI_6 :
return KEYCODE_6;
case kVK_ANSI_5 :
return KEYCODE_5;
case kVK_ANSI_Equal :
return KEYCODE_EQUALS;
case kVK_ANSI_9 :
return KEYCODE_9;
case kVK_ANSI_7 :
return KEYCODE_7;
case kVK_ANSI_Minus :
return KEYCODE_MINUS;
case kVK_ANSI_8 :
return KEYCODE_8;
case kVK_ANSI_0 :
return KEYCODE_0;
case kVK_ANSI_RightBracket :
return KEYCODE_RIGHTBRACKET;
case kVK_ANSI_O :
return KEYCODE_O;
case kVK_ANSI_U :
return KEYCODE_U;
case kVK_ANSI_LeftBracket :
return KEYCODE_LEFTBRACKET;
case kVK_ANSI_I :
return KEYCODE_I;
case kVK_ANSI_P :
return KEYCODE_P;
case kVK_ANSI_L :
return KEYCODE_L;
case kVK_ANSI_J :
return KEYCODE_J;
case kVK_ANSI_Quote :
return KEYCODE_APOSTROPHE;
case kVK_ANSI_K :
return KEYCODE_K;
case kVK_ANSI_Semicolon :
return KEYCODE_SEMICOLON;
case kVK_ANSI_Backslash :
return KEYCODE_BACKSLASH;
case kVK_ANSI_Comma :
return KEYCODE_COMMA;
case kVK_ANSI_Slash :
return KEYCODE_SLASH;
case kVK_ANSI_N :
return KEYCODE_N;
case kVK_ANSI_M :
return KEYCODE_M;
case kVK_ANSI_Period :
return KEYCODE_PERIOD;
case kVK_ANSI_Grave :
return KEYCODE_GRAVE;
case kVK_ANSI_KeypadDecimal :
return KEYCODE_KP_DECIMAL;
case kVK_ANSI_KeypadMultiply :
return KEYCODE_KP_MULTIPLY;
case kVK_ANSI_KeypadPlus :
return KEYCODE_KP_PLUS;
case kVK_ANSI_KeypadClear :
return KEYCODE_KP_CLEAR;
case kVK_ANSI_KeypadDivide :
return KEYCODE_KP_DIVIDE;
case kVK_ANSI_KeypadEnter :
return KEYCODE_KP_ENTER;
case kVK_ANSI_KeypadMinus :
return KEYCODE_KP_MINUS;
case kVK_ANSI_KeypadEquals :
return KEYCODE_KP_EQUALS;
case kVK_ANSI_Keypad0 :
return KEYCODE_KP_0;
case kVK_ANSI_Keypad1 :
return KEYCODE_KP_1;
case kVK_ANSI_Keypad2 :
return KEYCODE_KP_2;
case kVK_ANSI_Keypad3 :
return KEYCODE_KP_3;
case kVK_ANSI_Keypad4 :
return KEYCODE_KP_4;
case kVK_ANSI_Keypad5 :
return KEYCODE_KP_5;
case kVK_ANSI_Keypad6 :
return KEYCODE_KP_6;
case kVK_ANSI_Keypad7 :
return KEYCODE_KP_7;
case kVK_ANSI_Keypad8 :
return KEYCODE_KP_8;
case kVK_ANSI_Keypad9 :
return KEYCODE_KP_9;
case kVK_Return :
return KEYCODE_RETURN;
case kVK_Tab :
return KEYCODE_TAB;
case kVK_Space :
return KEYCODE_SPACE;
case kVK_Delete :
return KEYCODE_BACKSPACE;
case kVK_Escape :
return KEYCODE_ESCAPE;
case kVK_Command :
return KEYCODE_LGUI;
case kVK_Shift :
return KEYCODE_LSHIFT;
case kVK_CapsLock :
return KEYCODE_CAPSLOCK;
case kVK_Option :
return KEYCODE_LALT;
case kVK_Control :
return KEYCODE_LCTRL;
case kVK_RightShift :
return KEYCODE_RSHIFT;
case kVK_RightOption :
return KEYCODE_RALT;
case kVK_RightControl :
return KEYCODE_RCTRL;
case kVK_Function :
return KEYCODE_MODE;
case kVK_F17 :
return KEYCODE_F17;
case kVK_VolumeUp :
return KEYCODE_VOLUMEUP;
case kVK_VolumeDown :
return KEYCODE_VOLUMEDOWN;
case kVK_Mute :
return KEYCODE_MUTE;
case kVK_F18 :
return KEYCODE_F18;
case kVK_F19 :
return KEYCODE_F19;
case kVK_F20 :
return KEYCODE_F20;
case kVK_F5 :
return KEYCODE_F5;
case kVK_F6 :
return KEYCODE_F6;
case kVK_F7 :
return KEYCODE_F7;
case kVK_F3 :
return KEYCODE_F3;
case kVK_F8 :
return KEYCODE_F8;
case kVK_F9 :
return KEYCODE_F9;
case kVK_F11 :
return KEYCODE_F11;
case kVK_F13 :
return KEYCODE_F13;
case kVK_F16 :
return KEYCODE_F16;
case kVK_F14 :
return KEYCODE_F14;
case kVK_F10 :
return KEYCODE_F10;
case kVK_F12 :
return KEYCODE_F12;
case kVK_F15 :
return KEYCODE_F15;
case kVK_Help :
return KEYCODE_HELP;
case kVK_Home :
return KEYCODE_HOME;
case kVK_PageUp :
return KEYCODE_PAGEUP;
case kVK_ForwardDelete :
return KEYCODE_DELETE;
case kVK_F4 :
return KEYCODE_F4;
case kVK_End :
return KEYCODE_END;
case kVK_F2 :
return KEYCODE_F2;
case kVK_PageDown :
return KEYCODE_PAGEDOWN;
case kVK_F1 :
return KEYCODE_F1;
case kVK_LeftArrow :
return KEYCODE_LEFT;
case kVK_RightArrow :
return KEYCODE_RIGHT;
case kVK_DownArrow :
return KEYCODE_DOWN;
case kVK_UpArrow :
return KEYCODE_UP;
default:
return KEYCODE_UNKNOWN;
}
}

17
app/OSX/main.mm Normal file
View file

@ -0,0 +1,17 @@
#import <Cocoa/Cocoa.h>
#include "UnitTests.h"
int main(int argc, const char * argv[])
{
if (argc >=2 ) {
if (strcmp(argv[1], "runtests") == 0)
{
UnitTestsSetArgs(argc, argv);
return RunUnitTests();
}
}
return NSApplicationMain(argc, argv);
}

208
app/emscripten/Makefile Normal file
View file

@ -0,0 +1,208 @@
#
# Makefile for building with emscripten
# This is intended to be run from the root dir:
# make -f app/emscripten/Makefile
#
CC = emcc
S3_BUCKET_URL = s3://m1lkdr0p.com/
CONFIG ?= release
BUILD_DIR = build/emscripten/$(CONFIG)
OUTPUT_DIR = $(BUILD_DIR)/bin
OUTPUT_HTML = $(OUTPUT_DIR)/index.html
OUTPUT_WASM = $(OUTPUT_DIR)/index.wasm
OUTPUT_DATA = $(OUTPUT_DIR)/index.data
OUTPUT_FAVICON = $(OUTPUT_DIR)/favicon.ico
EMRUN = emrun
BROWSER ?= chrome
INCLUDE_DIRS += src
INCLUDE_DIRS += src/script
INCLUDE_DIRS += src/script/mdp-eel2
SOURCES := $(shell find src -name '*.cpp')
SOURCES += $(shell find src -name '*.c' )
SOURCES += $(shell find app/emscripten -name '*.cpp')
WEBROOT_SOURCES += $(shell find app/emscripten/www)
# include ImGui
IMGUI_ROOT := external/imgui
SOURCES += $(IMGUI_ROOT)/imgui.cpp
SOURCES += $(IMGUI_ROOT)/imgui_widgets.cpp
SOURCES += $(IMGUI_ROOT)/imgui_draw.cpp
SOURCES += $(IMGUI_ROOT)/imgui_demo.cpp
SOURCES += $(IMGUI_ROOT)/imgui_tables.cpp
INCLUDE_DIRS += $(IMGUI_ROOT)
# HLSL2GLSL
HLSL2GLSL_ROOT := external/hlsl2glslfork/hlslang
SOURCES += $(shell find $(HLSL2GLSL_ROOT)/GLSLCodeGen -name '*.cpp')
SOURCES += $(shell find $(HLSL2GLSL_ROOT)/MachineIndependent -name '*.cpp')
SOURCES += $(shell find $(HLSL2GLSL_ROOT)/OSDependent/Emscripten -name '*.cpp')
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)/hlslang
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)/Include
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)/MachineIndependent
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)/GLSLCodeGen
INCLUDE_DIRS += $(HLSL2GLSL_ROOT)/OSDependent/Emscripten
# MINIZIP
MINIZIP_ROOT := external/minizip
SOURCES += $(MINIZIP_ROOT)/ioapi.c
SOURCES += $(MINIZIP_ROOT)/ioapi_buf.c
SOURCES += $(MINIZIP_ROOT)/ioapi_mem.c
SOURCES += $(MINIZIP_ROOT)/unzip.c
SOURCES += $(MINIZIP_ROOT)/zip.c
# LZMA
LZMA_SOURCE_DIR = external/lzma1801/C
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Lzma2Dec.c ${LZMA_SOURCE_DIR}/Ppmd7Dec.c ${LZMA_SOURCE_DIR}/Aes.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Bcj2.c ${LZMA_SOURCE_DIR}/LzFind.c ${LZMA_SOURCE_DIR}/DllSecur.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Sort.c ${LZMA_SOURCE_DIR}/Ppmd7.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Bra.c ${LZMA_SOURCE_DIR}/Bra86.c ${LZMA_SOURCE_DIR}/7zArcIn.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/7zAlloc.c ${LZMA_SOURCE_DIR}/Alloc.c ${LZMA_SOURCE_DIR}/LzmaDec.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Ppmd7Enc.c ${LZMA_SOURCE_DIR}/7zDec.c ${LZMA_SOURCE_DIR}/7zBuf2.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/BraIA64.c ${LZMA_SOURCE_DIR}/Lzma86Dec.c ${LZMA_SOURCE_DIR}/7zStream.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/Sha256.c ${LZMA_SOURCE_DIR}/Delta.c ${LZMA_SOURCE_DIR}/7zFile.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/7zCrc.c ${LZMA_SOURCE_DIR}/AesOpt.c ${LZMA_SOURCE_DIR}/CpuArch.c
LZMA_SOURCE += ${LZMA_SOURCE_DIR}/7zCrcOpt.c ${LZMA_SOURCE_DIR}/7zBuf.c
SOURCES += ${LZMA_SOURCE}
SOURCES_JS = $(shell find src -name '*.js')
OBJS := $(SOURCES:%=$(BUILD_DIR)/%.o)
DEPS := $(SOURCES:%=$(BUILD_DIR)/%.d)
#DATA_FILES := $(shell find assets)
#SHELL_HTML ?= app/emscripten/emscripten_shell.html
SHELL_HTML ?= app/emscripten/shell_minimal.html
#
# compile flags
#
CC_FLAGS += -Wno-register
ifeq ($(CONFIG),debug)
CC_FLAGS += -g
CC_FLAGS += -O1
CC_FLAGS += -DDEBUG=1
else ifeq ($(CONFIG),profile)
CC_FLAGS += -O2
CC_FLAGS += --profiling
CC_FLAGS += --tracing
CC_FLAGS += --cpuprofiler
CC_FLAGS += -DPROFILE=1
else ifeq ($(CONFIG),release)
CC_FLAGS += -O2
CC_FLAGS += -DRELEASE=1
else
error invalid configuration $(CONFIG) (must be debug,profile,release)
endif
CC_FLAGS += -DBUILD_CONFIG=$(CONFIG)
CC_FLAGS += -Wno-deprecated-register
CC_FLAGS += -Wreorder-init-list
CC_FLAGS += -s USE_ZLIB
#
# linker flags
#
LD_FLAGS += --preload-file assets
# LD_FLAGS += --use-preload-plugins
LD_FLAGS += --emrun
LD_FLAGS += -s TOTAL_MEMORY=536870912
LD_FLAGS += -s DEMANGLE_SUPPORT=1
ifneq ($(CONFIG),profile)
LD_FLAGS += --shell-file $(SHELL_HTML)
endif
LD_FLAGS += -s WASM=1
LD_FLAGS += -s ASSERTIONS=1
LD_FLAGS += -s USE_WEBGL2=1
LD_FLAGS += -s USE_SDL=2
#LD_FLAGS += -s "BINARYEN_TRAP_MODE='clamp'"
LD_FLAGS += -mnontrapping-fptoint
LD_FLAGS += -s MIN_WEBGL_VERSION=2
LD_FLAGS += -s MAX_WEBGL_VERSION=2
# LD_FLAGS += -s FULL_ES3=1
LD_FLAGS += -lopenal
LD_FLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1
LD_FLAGS += $(addprefix --post-js , $(SOURCES_JS) )
#
#
.PHONY: default
default: build
.PHONY: run
run: build
$(EMRUN) --serve_after_close --browser $(BROWSER) $(OUTPUT_HTML)
.PHONY: build
build: $(OUTPUT_HTML)
.PHONY: serve
serve: $(OUTPUT_HTML)
open http://localhost:6931/ &
$(EMRUN) --no_browser $(OUTPUT_HTML)
test:
echo $(addprefix --post-js , $(SOURCES_JS) )
.PHONY: clean
clean:
rm -Rf $(BUILD_DIR)
$(OUTPUT_HTML) $(OUTPUT_WASM) $(OUTPUT_DATA): $(OBJS) $(SHELL_HTML) $(SOURCES_JS) $(MAKEFILE_LIST)
@mkdir -p $(@D)
@echo Linking $@
@$(CC) $(OBJS) -o $@ $(CC_FLAGS) $(LD_FLAGS)
$(BUILD_DIR)/%.c.o: %.c
@mkdir -p $(@D)
@echo Compiling $<
@$(CC) -c $< -o $@ -MMD $(CC_FLAGS) $(INCLUDE_DIRS:%=-I%)
$(BUILD_DIR)/%.cpp.o: %.cpp
@mkdir -p $(@D)
@echo Compiling $<
@$(CC) -c $< -o $@ -MMD $(CC_FLAGS) -std=c++17 $(INCLUDE_DIRS:%=-I%)
$(OUTPUT_DIR): $(OUTPUT_HTML) $(OUTPUT_WASM) $(OUTPUT_DATA) $(WEBROOT_SOURCES)
@mkdir -p $@
cp -av $(WEBROOT_SOURCES) $@
touch $@
.PHONY: deploy
deploy: build
aws s3 cp $(OUTPUT_DIR) $(S3_BUCKET_URL) --recursive
-include $(DEPS)

View file

@ -0,0 +1,296 @@
#include "../external/imgui/imgui.h"
#include "imgui_support.h"
#include <stdio.h>
#include <assert.h>
#include <emscripten.h>
#include <SDL.h>
#include <SDL_opengles2.h>
#include <stdlib.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <emscripten/html5.h>
#include <emscripten/trace.h>
#include "render/context.h"
#include "render/context_gles.h"
#include "VizController.h"
#include "audio/IAudioSource.h"
using namespace render;
// Emscripten requires to have full control over the main loop. We're going to store our SDL book-keeping variables globally.
// Having a single function that acts as a loop prevents us to store state in the stack of said function. So we need some location for this.
static SDL_Window *g_Window;
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE g_context_handle;
static ContextPtr _context;
static IVizControllerPtr _vizController;
static IAudioSourcePtr m_audioSource;
static bool g_MousePressed[3] = { false, false, false };
static void SetCanvasFocus()
{
// needed to ensure canvas has focus
EM_ASM({
var canvas = document.getElementById('canvas');
if (canvas)
canvas.focus();
});
}
static void ShowOutputTextArea()
{
EM_ASM({
// show output element
var output = document.getElementById('output');
if (output)
output.style.display = 'block';
});
}
static void ShowControls()
{
EM_ASM({
// show output element
var e = document.getElementById('controls');
if (e)
e.style.display = 'block';
});
}
static void HideControls()
{
EM_ASM({
// show output element
var e = document.getElementById('controls');
if (e)
e.style.display = 'none';
});
}
static void UpdateMousePosAndButtons()
{
ImGuiIO& io = ImGui::GetIO();
int mx, my;
Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
io.MousePos = ImVec2((float)mx, (float)my);
}
static bool ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
switch (event->type)
{
case SDL_MOUSEWHEEL:
{
if (event->wheel.x > 0) io.MouseWheelH += 1;
if (event->wheel.x < 0) io.MouseWheelH -= 1;
if (event->wheel.y > 0) io.MouseWheel += 1;
if (event->wheel.y < 0) io.MouseWheel -= 1;
return true;
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.sym;
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
{
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
}
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
return true;
}
}
return false;
}
void main_loop(void* arg)
{
PROFILE_FRAME()
ImGuiIO& io = ImGui::GetIO();
IM_UNUSED(io);
IM_UNUSED(arg); // We can pass this argument as the second parameter of emscripten_set_main_loop_arg(), but we don't use that.
SetCanvasFocus();
// Poll and handle events (inputs, window resize, etc.)
SDL_Event event;
while (SDL_PollEvent(&event))
{
ProcessEvent(&event);
}
if (_vizController->IsDebugUIVisible()) {
SDL_ShowCursor(1);
ShowControls();
} else {
SDL_ShowCursor(0);
HideControls();
}
emscripten_webgl_make_context_current(g_context_handle);
SDL_GL_SetSwapInterval(1); // Enable vsync
double width, height;
emscripten_get_element_css_size("canvas", &width, &height);
emscripten_set_canvas_element_size("canvas", (int)width, (int)height);
double dpr = emscripten_get_device_pixel_ratio();
// emscripten_set_canvas_element_size("canvas", (int)(width * dpr), (int)(height * dpr));
int buffer_width, buffer_height;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE webgl_context = emscripten_webgl_get_current_context();
emscripten_webgl_get_drawing_buffer_size(webgl_context, &buffer_width, &buffer_height);
Size2D displaySize(buffer_width, buffer_height);
// printf("canvas_element_size:(%f,%f) dpr:%f buffer:(%d,%d)\n", width, height, dpr, buffer_width, buffer_height);
float scale = (int)displaySize.width / (int)width;
render::DisplayInfo info;
info.size= displaySize;
info.format= render::PixelFormat::RGBA8Unorm;
info.refreshRate = 60.0f;
info.scale = scale;
info.samples = 1;
info.maxEDR = 1;
_context->SetDisplayInfo(info);
UpdateMousePosAndButtons();
_context->BeginScene();
float dt = 1.0f / 60.0f;
_vizController->Update(dt);
_vizController->DrawVisualizer(nullptr, true);
_vizController->DrawGUI(nullptr, false);
_context->EndScene();
_context->Present();
emscripten_webgl_commit_frame();
// SDL_GL_SwapWindow(g_Window);
}
void WebClientSend(const WebRequest &wr, std::function<void (const WebResponse &)> complete )
{
}
void HttpSend(std::string method, std::string url, const char *content, size_t content_size, bool compress, const char *contentType, HttpCompleteFunc complete)
{
}
extern "C" int main(int argc, const char *argv[])
{
for (int i=1; i < argc; i++)
LogPrint("arg[%d] = %s\n", i, argv[i]);
SDL_version compiled;
SDL_version linked;
SDL_VERSION(&compiled);
SDL_GetVersion(&linked);
LogPrint("Compiled SDL version %d.%d.%d\n",
compiled.major, compiled.minor, compiled.patch);
LogPrint("Linked SDL version %d.%d.%d\n",
linked.major, linked.minor, linked.patch);
EmscriptenWebGLContextAttributes attr = {};
attr.alpha = false;
attr.depth = false;
attr.stencil = false;
attr.antialias = false;
attr.premultipliedAlpha = false;
attr.preserveDrawingBuffer = false;
attr.majorVersion = 2;
attr.minorVersion = 0;
attr.enableExtensionsByDefault = true;
g_context_handle = emscripten_webgl_create_context("canvas", &attr);
if (!g_context_handle) {
LogError("This browser does not support WebGL2. If using safari, enable WebGL in the experimental settings\n");
ShowOutputTextArea();
return -1;
}
emscripten_webgl_make_context_current(g_context_handle);
// Setup SDL
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
LogError("SDL_GetError: %s\n", SDL_GetError());
ShowOutputTextArea();
return -1;
}
SDL_WindowFlags window_flags = (SDL_WindowFlags)( SDL_WINDOW_RESIZABLE);
g_Window = SDL_CreateWindow("m1lkdr0p", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 1024, window_flags);
_context = render::gles::GLCreateContext();
std::string resourceDir = "";
std::string assetDir = resourceDir + "/assets";
std::string userDir= "/user";
ImGuiSupport_Init(_context, assetDir);
// Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO();
// io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
// io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "emscripten";
_vizController = CreateVizController(_context, assetDir, userDir);
// This function call won't return, and will engage in an infinite loop, processing events from the browser, and dispatching them.
emscripten_set_main_loop_arg(main_loop, NULL, 0, true);
}

View file

@ -0,0 +1,191 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>m1lkdr0p</title>
<style>
body {
font-family: arial;
margin: 0;
padding: none;
}
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
}
#status {
display: inline-block;
vertical-align: top;
margin-top: 30px;
margin-left: 20px;
font-weight: bold;
color: rgb(120, 120, 120);
}
#progress {
height: 20px;
width: 30px;
}
#controls {
position: fixed;
display: none;
vertical-align: top;
bottom: 30px;
left:32px;
}
#output {
position: absolute;
width: 80%;
height: 200px;
border: 0px;
display: none;
background-color: black;
color: white;
font-family: 'Lucida Console', Monaco, monospace;
outline: none;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" tabindex="-1" oncontextmenu="event.preventDefault()"></canvas>
<textarea id="output" rows="8">Output Text</textarea>
<div class="emscripten" id="controls">
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(false, true)">
</div>
<div class="emscripten_border" hidden=1>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
</div>
<!-- <script type='text/javascript' src='audiotest.js'></script>-->
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
/*
window.onerror = function(event) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console');
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
*/
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1){
printErr('Script Error: See Browser Console for Detail');
} else {
var message = [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
printErr(message);
}
outputElement.style.display = 'block';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
return false;
};
</script>
{{{ SCRIPT }}}
</body>
</html>

View file

@ -0,0 +1,247 @@
#include <emscripten.h>
#include <emscripten/key_codes.h>
#include "keycode_emscripten.h"
KeyCode ConvertKeyCode_Emscripten(const char *keyCode)
{
int dom_pk_code = emscripten_compute_dom_pk_code(keyCode);
return ConvertKeyCode_Emscripten(dom_pk_code);
}
KeyCode ConvertKeyCode_Emscripten(int code)
{
switch (code)
{
case DOM_PK_A :
return KEYCODE_A;
case DOM_PK_S :
return KEYCODE_S;
case DOM_PK_D :
return KEYCODE_D;
case DOM_PK_F :
return KEYCODE_F;
case DOM_PK_H :
return KEYCODE_H;
case DOM_PK_G :
return KEYCODE_G;
case DOM_PK_Z :
return KEYCODE_Z;
case DOM_PK_X :
return KEYCODE_X;
case DOM_PK_C :
return KEYCODE_C;
case DOM_PK_V :
return KEYCODE_V;
case DOM_PK_B :
return KEYCODE_B;
case DOM_PK_Q :
return KEYCODE_Q;
case DOM_PK_W :
return KEYCODE_W;
case DOM_PK_E :
return KEYCODE_E;
case DOM_PK_R :
return KEYCODE_R;
case DOM_PK_Y :
return KEYCODE_Y;
case DOM_PK_T :
return KEYCODE_T;
case DOM_PK_1 :
return KEYCODE_1;
case DOM_PK_2 :
return KEYCODE_2;
case DOM_PK_3 :
return KEYCODE_3;
case DOM_PK_4 :
return KEYCODE_4;
case DOM_PK_6 :
return KEYCODE_6;
case DOM_PK_5 :
return KEYCODE_5;
case DOM_PK_EQUAL :
return KEYCODE_EQUALS;
case DOM_PK_9 :
return KEYCODE_9;
case DOM_PK_7 :
return KEYCODE_7;
case DOM_PK_MINUS :
return KEYCODE_MINUS;
case DOM_PK_8 :
return KEYCODE_8;
case DOM_PK_0 :
return KEYCODE_0;
case DOM_PK_BRACKET_RIGHT :
return KEYCODE_RIGHTBRACKET;
case DOM_PK_O :
return KEYCODE_O;
case DOM_PK_U :
return KEYCODE_U;
case DOM_PK_BRACKET_LEFT :
return KEYCODE_LEFTBRACKET;
case DOM_PK_I :
return KEYCODE_I;
case DOM_PK_P :
return KEYCODE_P;
case DOM_PK_L :
return KEYCODE_L;
case DOM_PK_J :
return KEYCODE_J;
case DOM_PK_QUOTE :
return KEYCODE_APOSTROPHE;
case DOM_PK_K :
return KEYCODE_K;
case DOM_PK_SEMICOLON :
return KEYCODE_SEMICOLON;
case DOM_PK_BACKSLASH :
return KEYCODE_BACKSLASH;
case DOM_PK_COMMA :
return KEYCODE_COMMA;
case DOM_PK_SLASH :
return KEYCODE_SLASH;
case DOM_PK_N :
return KEYCODE_N;
case DOM_PK_M :
return KEYCODE_M;
case DOM_PK_PERIOD :
return KEYCODE_PERIOD;
case DOM_PK_BACKQUOTE :
return KEYCODE_GRAVE;
case DOM_PK_NUMPAD_DECIMAL :
return KEYCODE_KP_DECIMAL;
case DOM_PK_NUMPAD_MULTIPLY :
return KEYCODE_KP_MULTIPLY;
case DOM_PK_NUMPAD_ADD :
return KEYCODE_KP_PLUS;
// case DOM_PK_KeypadClear :
// return KEYCODE_KP_CLEAR;
// case DOM_PK_KeypadDivide :
// return KEYCODE_KP_DIVIDE;
case DOM_PK_NUMPAD_ENTER :
return KEYCODE_KP_ENTER;
case DOM_PK_NUMPAD_SUBTRACT :
return KEYCODE_KP_MINUS;
case DOM_PK_NUMPAD_EQUAL :
return KEYCODE_KP_EQUALS;
case DOM_PK_NUMPAD_0 :
return KEYCODE_KP_0;
case DOM_PK_NUMPAD_1 :
return KEYCODE_KP_1;
case DOM_PK_NUMPAD_2 :
return KEYCODE_KP_2;
case DOM_PK_NUMPAD_3 :
return KEYCODE_KP_3;
case DOM_PK_NUMPAD_4 :
return KEYCODE_KP_4;
case DOM_PK_NUMPAD_5 :
return KEYCODE_KP_5;
case DOM_PK_NUMPAD_6 :
return KEYCODE_KP_6;
case DOM_PK_NUMPAD_7 :
return KEYCODE_KP_7;
case DOM_PK_NUMPAD_8 :
return KEYCODE_KP_8;
case DOM_PK_NUMPAD_9 :
return KEYCODE_KP_9;
case DOM_PK_ENTER :
return KEYCODE_RETURN;
case DOM_PK_TAB :
return KEYCODE_TAB;
case DOM_PK_SPACE :
return KEYCODE_SPACE;
case DOM_PK_BACKSPACE :
return KEYCODE_BACKSPACE;
case DOM_PK_ESCAPE :
return KEYCODE_ESCAPE;
case DOM_PK_META_LEFT :
return KEYCODE_LGUI;
case DOM_PK_SHIFT_LEFT :
return KEYCODE_LSHIFT;
case DOM_PK_CAPS_LOCK :
return KEYCODE_CAPSLOCK;
case DOM_PK_ALT_LEFT :
return KEYCODE_LALT;
case DOM_PK_CONTROL_LEFT :
return KEYCODE_LCTRL;
case DOM_PK_SHIFT_RIGHT :
return KEYCODE_RSHIFT;
case DOM_PK_ALT_RIGHT :
return KEYCODE_RALT;
case DOM_PK_CONTROL_RIGHT :
return KEYCODE_RCTRL;
// case DOM_PK_Function :
// return KEYCODE_MODE;
case DOM_PK_F17 :
return KEYCODE_F17;
case DOM_PK_AUDIO_VOLUME_UP :
return KEYCODE_VOLUMEUP;
case DOM_PK_AUDIO_VOLUME_DOWN :
return KEYCODE_VOLUMEDOWN;
// case DOM_PK_VOLUMEMUTE :
// return KEYCODE_MUTE;
case DOM_PK_F18 :
return KEYCODE_F18;
case DOM_PK_F19 :
return KEYCODE_F19;
case DOM_PK_F20 :
return KEYCODE_F20;
case DOM_PK_F5 :
return KEYCODE_F5;
case DOM_PK_F6 :
return KEYCODE_F6;
case DOM_PK_F7 :
return KEYCODE_F7;
case DOM_PK_F3 :
return KEYCODE_F3;
case DOM_PK_F8 :
return KEYCODE_F8;
case DOM_PK_F9 :
return KEYCODE_F9;
case DOM_PK_F11 :
return KEYCODE_F11;
case DOM_PK_F13 :
return KEYCODE_F13;
case DOM_PK_F16 :
return KEYCODE_F16;
case DOM_PK_F14 :
return KEYCODE_F14;
case DOM_PK_F10 :
return KEYCODE_F10;
case DOM_PK_F12 :
return KEYCODE_F12;
case DOM_PK_F15 :
return KEYCODE_F15;
// case DOM_PK_Help :
// return KEYCODE_HELP;
case DOM_PK_HOME :
return KEYCODE_HOME;
case DOM_PK_PAGE_UP :
return KEYCODE_PAGEUP;
case DOM_PK_DELETE :
return KEYCODE_DELETE;
case DOM_PK_F4 :
return KEYCODE_F4;
case DOM_PK_END :
return KEYCODE_END;
case DOM_PK_F2 :
return KEYCODE_F2;
case DOM_PK_PAGE_DOWN :
return KEYCODE_PAGEDOWN;
case DOM_PK_F1 :
return KEYCODE_F1;
case DOM_PK_ARROW_LEFT :
return KEYCODE_LEFT;
case DOM_PK_ARROW_RIGHT :
return KEYCODE_RIGHT;
case DOM_PK_ARROW_DOWN :
return KEYCODE_DOWN;
case DOM_PK_ARROW_UP :
return KEYCODE_UP;
default:
return KEYCODE_UNKNOWN;
}
}

View file

@ -0,0 +1,10 @@
#pragma once
#include "keycode.h"
KeyCode ConvertKeyCode_Emscripten(int code);
KeyCode ConvertKeyCode_Emscripten(const char *keyCode);

View file

@ -0,0 +1,106 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
<title>m1lkdr0p</title>
<style>
body { margin: 0; background-color: black }
.emscripten {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
#output {
position: absolute;
width: 100%;
height: 200px;
border: 0px;
display: none;
background-color: black;
color: white;
font-family: 'Lucida Console', Monaco, monospace;
outline: none;
}
#controls {
position: fixed;
display: none;
vertical-align: top;
bottom: 30px;
left:32px;
}
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<textarea id="output" rows="8"></textarea>
<div id="controls">
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(false, true)">
</div>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
var element = document.getElementById('output');
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
},
canvas: (function() {
var canvas = document.getElementById('canvas');
//canvas.addEventListener("webglcontextlost", function(e) { alert('FIXME: WebGL context lost, please reload the page'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
console.log("status: " + text);
},
monitorRunDependencies: function(left) {
// no run dependencies to log
}
};
window.onerror = function() {
console.log("onerror: " + event);
};
</script>
{{{ SCRIPT }}}
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

14
cmake-build-android.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
set -e
ANDROID_NDK_ROOT=~/Library/Android/sdk//ndk/22.1.7171670/
#ANDROID_NDK_ROOT=~/Library/Android/sdk//ndk/ndk-bundle/
cmake -S . \
-B build.android \
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-24 \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
make -C build.android

10
cmake-build-emscripten.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
set -e
set -x
cmake -S . \
-B build.emscripten \
-DCMAKE_TOOLCHAIN_FILE=${EMSDK}/emscripten/main/cmake/Modules/Platform/Emscripten.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
make -C build.emscripten

Binary file not shown.

BIN
data/fonts/DroidSans.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
data/fonts/ProggyClean.ttf Normal file

Binary file not shown.

BIN
data/fonts/ProggyTiny.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,66 @@
;MMC1 write handler
.define R0 $9fff
.define R1 $bfff
.define R2 $dfff
.define R3 $f000
.section "MMC1" FREE
WriteR0
sta R0
lsr A
sta R0
lsr A
sta R0
lsr A
sta R0
lsr A
sta R0
rts
WriteR1
sta R1
lsr A
sta R1
lsr A
sta R1
lsr A
sta R1
lsr A
sta R1
rts
WriteR2
sta R2
lsr A
sta R2
lsr A
sta R2
lsr A
sta R2
lsr A
sta R2
rts
ProgramSwitch1
sta BankLatch1
ProgramSwitch2
sta BankLatch2
WriteR3
tax
lda M2000
and #$7f
sta $2000
txa
sta R3
lsr A
sta R3
lsr A
sta R3
lsr A
sta R3
lsr A
sta R3
lda M2000
sta $2000
rts
.ends

Binary file not shown.

View file

@ -0,0 +1,68 @@
;Joypad handling
.section "ReadnLockPads" FREE
ReadLockJoypad
jsr ReadJoypad
ldx #$01
- lda Pad1,X
tay
eor Pad1Locked,X ;This detects the key who had a '0' to '1' transition
and Pad1,X
sta Pad1,X
sty Pad1Locked,X
dex
bpl -
rts
.ends
.section "ReadLockPadsDPCM" FREE ;To be used when the DPCM may occasionally glitch the reads
ReadLockJoypadDPCM
jsr ReadJoypad
- ldx Pad1
ldy Pad2 ;Read until 2 consecutive reads returns the same data
jsr ReadJoypad
cpx Pad1
bne -
cpy Pad2
bne -
ldx #$01
- lda Pad1,X
tay
eor Pad1Locked,X ;This detects the key who had a '0' to '1' transition
and Pad1,X
sta Pad1,X
sty Pad1Locked,X
dex
bpl -
rts
.ends
.section "ReadPad" FREE
;Do read the hardware joypads ports
;Exit with JoyData=Joypad value
;X and Y unchanged
ReadJoypad
lda #$01
sta $4016 ;Be sure to reset the shift counters
sta Pad1
sta Pad2
lsr A ;Simple trick to get a 0, heh
sta $4016
- lda $4016 ;Read the value of JoyPad 1
lsr A
bcs +
lsr A
+ rol Pad1
bcc - ;Carry will be set when all 8 keys are read
- lda $4017 ;Read the value of JoyPad 1
lsr A
bcs +
lsr A
+ rol Pad2
bcc - ;Carry will be set when all 8 keys are read
rts
.ends

Binary file not shown.

View file

@ -0,0 +1,9 @@
[objects]
mmc1_a12.o
[libraries]
BANK 7 SLOT 3 mmc1.lib
BANK 7 SLOT 3 joypad.lib
[header]
snrom.bin

View file

@ -0,0 +1,23 @@
;Defines NES's RAM for any games witout SRAM
;Stack isn't defined, it's use is reserved
;Also $200-$2ff is reserved for SpriteRam and isn't defined here
.memorymap
defaultslot 0
slotsize $100
slot 0 $0 ;0 page RAM
slotsize $500
slot 1 $300 ;BSS RAM
slotsize $4000 ;PRG ROM slot (16kb)
slot 2 $8000
slotsize $4000
slot 3 $c000 ;Resitant PRG slot (16kb)
.endme
;Define a CNROM structure with 32kb PRG and 32kb CHR
.rombankmap
bankstotal 8
banksize $4000 ;4x 32kb PRG
banks 8
.endro

Binary file not shown.

View file

@ -0,0 +1,552 @@
**** PRIOR DEFINITIONS ****
.include "maping.asm" ;This tells the ROM definition for the hardware
;.define PAL
.asctable
MAP "1" TO "9" = $10
MAP "A" TO "Z" = $20
MAP "=" = $1c
MAP "?" = $1e
MAP " " = $1f
MAP "/" = $3b
.enda
.ramsection "NMIVars" SLOT 0
;Thoose variables are used in the NMI routine
;Don't do calculations with them if a VBlank is pending
;set them after the calculation
SpriteDMAFlag db ;This tells if sprite DMA is ready in a frame
PalFlag db ;Check if palette uploaded is needed
NMIFlag db ;Check if a NMI is pending or not
FrameCounter db
NMITemp db
NMITemp2 db
NMITemp3 db
NMITemp4 db
ScrollV db
ScrollH db
M2001 db
M2000 db
.ends
.ramsection "Palette" SLOT 1
PaletteBuffer dsb $20
.ends
.ramsection "Main Vars" SLOT 0
Pointer .dw
PointerL db
PointerH db
Temp db
Temp2 db
Temp3 db
Temp4 db
EffectCtr db
DataCtr db
VRAMPointerH db
VRAMPointerL db
.ends
.ramsection "JoypadVar" SLOT 0
Pad1 db
Pad2 db
Pad1Locked db
Pad2Locked db
.ends
.ramsection "PlayerVars" SLOT 0
Delay db
.ends
.define DelayMax = $50
.struct SpriteDMA ;Structure for the Sprites
PosV db
TileNmr db
Palette db
PosH db
.endst
;$200-$2ff is reserved for sprite DMA
.enum $200
SpriteBuffer INSTANCEOF SpriteDMA 64
.ende
.ramsection "MMC1" SLOT 0
BankLatch1 db
BankLatch2 db
.ends
****** ROM aera begins here *******
.bank 0 SLOT 2
.orga $8000
.bank 1 SLOT 2
.orga $8000
.bank 3 SLOT 2
.orga $8000
.bank 4 SLOT 2
.orga $8000
.bank 5 SLOT 2
.orga $8000
.bank 6 SLOT 2
.orga $8000
.bank 7 SLOT 3
.orga $c000
***********************
*** Wait for a VBlank ***
***********************
.section "WaitNMI" FREE
WaitNMI
lda #$01
sta NMIFlag
- lda NMIFlag
bne -
rts
;Wait multiple NMIs in function of the value in X
WaitNMIs
- jsr WaitNMI
dex
bne -
rts
.ends
.section "NMIRoutine" FREE
NMI
pha
txa
pha
tya
pha
bit $2002
lda M2001
sta $2001
lda SpriteDMAFlag
beq _skipSpriteDMA ;Is the sprite buffer ready ?
lda #$00
sta SpriteDMAFlag ;Sprite buffer is read
sta $2003.w
lda #$02
sta $4014.w ;Do sprite DMA at $200
_skipSpriteDMA
lda PalFlag
beq + ;Do we need to update tiles ?
lda #$00
sta PalFlag
jsr WritePalette
+ lda #$22
sta $2006.w
lda #$1d
sta $2006.w
ldx #$00
lda Delay
- cmp #$0a ;Display units and tens of delay to NT
bcc +
sbc #$0a
inx
jmp -
+ tay
txa
clc
bne +
lda #$3f
bne ++
+ adc #$0f
++ sta $2007.w
tya
bne +
lda #$2e
bne ++
+ adc #$0f
++ sta $2007.w
lda ScrollH
sta $2005.w
lda ScrollV
sta $2005.w ;Upload scrolling regs
lda M2000
sta $2000.w
lda FrameCounter
eor #$01
sta FrameCounter
lda #$00 ;Clears the flag to stop waiting the frame
sta NMIFlag
pla ;Restore registers
tay
pla
tax
pla
IRQ rti
.ends
******************
* Graphics Stuff **
******************
;then clear all nametables and attribute tables with spaces ($60)
.section "ClearVRAM" FREE
ClearVRAM
lda M2000 ;Enable NMIs
ora #$80
sta M2000
sta $2000
jsr PaletteFadeOut ;Fade out palette (trick to save a routine to clear it)
lda #$00
sta $2000
lda #$06
sta M2001
sta $2001 ;Rendering off (so that nametables can be cleared)
jsr Clr2ndNamTbl ;Clear 2 active name tables
jmp ClrNamTbl
.ends
.section "PaletteFadeOut" FREE
PaletteFadeOut ;Fade out the palette
lda #$04
sta EffectCtr
_palfadeLoop
ldy #$1f
- lda PaletteBuffer.w,Y
sec
sbc #$10 ;Remove $10 from the color
bpl +
lda #$0f ;"Negative" colors forced to black
+ sta PaletteBuffer.w,Y
dey
bpl -
jsr WritePalette ;Palette will be uploaded at next NMI
ldx #$05
jsr WaitNMIs ;Wait 5 NMIs
dec EffectCtr
bne _palfadeLoop
rts
.ends
.section "ClrNamTbl" FREE
Clr2ndNamTbl
lda #$24 ;Clears the name tables
.db $cd
ClrNamTbl
lda #$20
SetNamAdress
sta $2006 ;Begin at $2000/$2400 (vertical mirroring)
lda #$00
sta $2006
lda #$0f
ldx #$1e ;Clears 30 rows with spaces ($60)
_screenloop
ldy #$20
_rowloop
sta $2007
dey
bne _rowloop
dex
bne _screenloop
lda #$00
ldx #$40 ;Clear attribute table with color $0
_attribloop
sta $2007
dex
bne _attribloop
rts
.ends
.section "ClrSprRam" FREE
ClrSprRam ;Clears the whole OAM buffer at $200
ldx #$00
beq _ClearRemainingSprites
FillBlankSprites ;This does just clears the unused sprites in $200-$2ff
lda SpriteDMAFlag ;For proper filling before sprite DMA
bne _endClrSprRam
_ClearRemainingSprites
lda #$f0
- sta SpriteBuffer.w,X
inx
inx
inx
inx
bne -
_endClrSprRam
inc SpriteDMAFlag
rts
.ends
;Turn the screen back on without scrolling glitches
;Set nametable 0 and scrolling to 0,0
;To be used only when the screen is disabled
.section "ResetScreen" FREE
ResetScreen
- bit $2002
bpl - ;Wait for VBlank and acknownledge it (no NMI)
lda #$88
sta M2000
sta $2000
lda #$00
sta ScrollV ;Enable NMI, enable endering, reset scrolling
sta ScrollH
lda M2001
ora #$1e
sta M2001 ;Enable rendering
sta $2001
rts
.ends
*****************
* Main programm *
*****************
.section "RESET" FREE
RESET ;The programm will start here
sei
ldx #$ff
txs ;Init stack pointer
inx
stx $2000.w
stx $2001.w ;Turn off rendering and interrupts
lda #$40
sta $4017.w ;Set sound clock, IRQ off
txa
sta PointerL
tay
ldx #$07
_initRAMloop
stx PointerH
- dey
sta [Pointer],Y ;Clear RAM
bne -
dex
bpl _initRAMloop
- bit $2002.w
bpl -
- bit $2002.w ;Wait for several VBlanks
bpl -
_MMC1
inc _MMC1.w
jsr ClearVRAM ;Clear the whole PPU
jsr LoadAlphabet ;Load character set
lda #$1e
jsr WriteR0 ;Initialise mapper
lda #$00
jsr WriteR1
lda #$00
jsr WriteR2 ;WRAM always enabled (for now)
lda #$06
jsr WriteR3
lda #$00
sta $2000.w
sta $2001.w
jsr PaletteInit
jsr PrintMsg
jsr ResetScreen ;This will make sprites use right pattern table (important !)
lda #$10
sta Delay ;Initial delay of $10
Loop
jsr ClrSprRam
lda #$85
sta $200
lda #$0f
sta $201
lda #$0f
sta $202
lda #$de
sta $203 ;Setup sprite zero hit
inc SpriteDMAFlag
jsr WaitNMI ;Wait a frame
jsr ReadLockJoypad
lda Pad1
lsr A ;Increase delay if right is pressed
bcc _noRight
lda Delay
cmp #DelayMax
bcs _noRight
inc Delay
_noRight
lda #$02
and Pad1
beq _noLeft
lda Delay ;Decrease delay if left is pressed
cmp #$01
beq _noLeft
dec Delay
_noLeft
lda #$04
and Pad1
beq _noDown
lda Delay ;Substract 10 to delay if down is pressed
sec
sbc #$0a
bcc +
bne ++
+ lda #$01
++ sta Delay
_noDown
lda #$08
and Pad1
beq _noUp ;Add 10 to delay if up is pressed
lda Delay
clc
adc #$0a
cmp #DelayMax
bcc +
lda #DelayMax
+ sta Delay
_noUp
jsr DisplayTestBar ;Display the grayscale test area
jmp Loop
.ends
.section "PaletteInit" FREE
PaletteInit
ldx #$00
- lda PalData.w,X
sta PaletteBuffer.w,X
inx
cpx #$20
bne -
inc PalFlag
rts
PalData
.db $01, $06, $26, $36
.db $01, $06, $27, $36
.db $01, $06, $0a, $0a
.db $01, $06, $0a, $0a
.db $01, $06, $0a, $0a
.db $01, $06, $0a, $0a
.db $01, $06, $0a, $0a
.db $01, $06, $0a, $0a
.ends
.section "WritePalette" FREE
WritePalette
lda #$3f
sta $2006.w
lda #$00
sta $2006.w
tay
_palLoop
lda PaletteBuffer.w,Y
sta $2007.w
iny
cpy #$20
bne _palLoop
rts
.ends
.section "LoadAlphabet" FREE
LoadAlphabet
ldy #$00
jsr + ;Load tileset into first pattern table
ldy #$10 ;Load identical tileset into second pattern table
+ sty $2006.w
ldy #$00
sty $2006.w
sty PointerL
ldx #$04
lda #>Alphabet
sta PointerH
- lda [Pointer],Y
sta $2007
iny
bne -
inc PointerH
dex
bne -
rts
.ends
.section "Alphabet" ALIGN $100
Alphabet
.incbin "alphabet.chr"
.ends
.section "PrintMsg" FREE
PrintMsg
lda #$21
sta $2006
lda #$a0
sta $2006
ldy #$00
- lda Msg.w,Y
sta $2007
iny
bpl -
rts
Msg
.asc " MMC1 WRAM DISABLE SCANLINE "
.asc " COUNTER TEST "
.asc " C 2O1O BREGALAD "
.asc " USE U/D L/R TO ADJUST DELAY= "
.ends
.section "DisplayTestBar" FREE
.define TestConst = $60~$ff ;Use the value oposite as the open bus value.
DisplayTestBar
lda #TestConst
sta $6000 ;Write a test constant in PRG RAM
lda #$10
jsr WriteR2 ;WRAM disabled when fecthing sprites, but enabled when fetchin BG (!)
;Now we can read $6000 as if we were reading PPU A12 directly...
;We can detect
- bit $2002
bvs -
- bit $2002 ;Wait for sprite zero hit
bvc -
lda #$1f
sta $2001 ;Turn on grayscale mode
ldx Delay
_delayLoop
- lda $6000
cmp #TestConst ;Wait until PRG RAM is disabled (emulators will freeze here)
beq -
ldy #$05
- dey ;Delay while sprites are being fetched
bne -
dex
bne _delayLoop ;Loop until the delay is expired
lda #$1e
sta $2001
lda #$00
jsr WriteR2 ;WRAM always enabled
sta $6000
rts
.ends
*************************
**** INTERUPTS VECTORS ****
*************************
.orga $fffa
.section "vectors" FORCE
.dw NMI
.dw RESET ;Thoose are the actual interupts vectors
.dw IRQ
.ends

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,3 @@
Use NESASM3 to assemble code.
Program made by Aaron Bottegal (3GenGames) and finished on 3/17/2011, at 2:25AM. No warranty implied on this program. Use at your own risk. Don't steal my code! If you want to use my program, contact me please. Some of this is still a template from the Nerdy Nights tutorials that I've never really had to change yet, thanks bunnyboy. (www.retrousb.com)

View file

@ -0,0 +1,2 @@
NESASM3 PaddleTest.asm
pause

View file

@ -0,0 +1,287 @@
.inesprg 1 ; 1x 16KB PRG code
.ineschr 1 ; 1x 8KB CHR data
.inesmap 0 ; mapper 0 = NROM, no bank swapping
.inesmir 1 ; background mirroring
;;;;;;;;;;;;;;;
;$0000-$00FF:Zeropage
;$0100-$01FF:Stack
;$0200-$02FF:Sprites
;$0300-$07FF:RAM
.org $0000 ;Zeropage Variables
SixteenBitBackgroundPointer: .rs $02
.org $0300 ;Normal RAM
Frame: .rs 1
PaddleButtons: .rs 1
GreenFlag: .rs 1
.bank 0
.org $C000
RESET:
SEI ; disable IRQs
CLD ; disable decimal mode
LDX #$40
STX $4017 ; disable APU frame IRQ
LDX #$FF
TXS ; Set up stack
INX ; now X = 0
STX $2000 ; disable NMI
STX $2001 ; disable rendering
STX $4010 ; disable DMC IRQs
vblankwait1: ; First wait for vblank to make sure PPU is ready
BIT $2002
BPL vblankwait1
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
LDA #$FF
STA $0200, x
INX
BNE clrmem
TAX
TXS
vblankwait2: ; Second wait for vblank, PPU is ready after this
BIT $2002
BPL vblankwait2
LoadPalettes:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$3F
STA $2006 ; write the high byte of $3F00 address
LDA #$00
STA $2006 ; write the low byte of $3F00 address
LDX #$20
LoadPalettesLoop:
LDA Palette-1,x ;Run pallete loading from +$1F to +$0.
STA $2007
DEX
BNE LoadPalettesLoop
LDA Palette
STA $2007
LDA $2002 ;Starts background loading.
LDA #$20
STA $2006
LDA #$00
STA $2006
LDA #LOW(BackgroundPage)
STA SixteenBitBackgroundPointer
LDA #HIGH(BackgroundPage)
STA SixteenBitBackgroundPointer+1
LDX #$04
LDY #$00
BackgroundLoop: ;Loop to upload 1K of data to the PPU as pointed at by the pointer in zeropage.
LDA [SixteenBitBackgroundPointer],Y
STA $2007
INY
BNE BackgroundLoop
INC SixteenBitBackgroundPointer+1
DEX
BNE BackgroundLoop
LDA Sprite ;Put scale on screen.
STA $200
LDA Sprite+1
STA $201
LDA Sprite+2
STA $202
LDA Sprite+3
STA $203
LoopUpOne:
BIT $2002
BPL LoopUpOne
LDA #%10001000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
STA $2000
LDA #%00011110 ; enable sprites, enable background
STA $2001
JSR ReadPaddle
FOREVER:
LDA Frame ;Get Frame number.
CMP Frame ;Wait for it to change.
BEQ FOREVER ;Still waiting for frame to end, will change when NMI is done.
JSR ReadPaddle ;NMI is done, read paddle outside of NMI to save NMI resources.
JMP FOREVER ;Wait again.
ReadPaddle:
LDA #$01
STA $4016
LDA #$00
STA $4016
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA $4016
AND #$10
ASL A
ASL A
ASL A
ASL A
ROL PaddleButtons
LDA PaddleButtons
EOR #$FF
STA PaddleButtons
RTS
NMI:
PHA
LDA $2002 ;Recognize interrupt
LDA PaddleButtons
CMP #$FF ;Paddle plugged in?
BEQ NoController ;No, take the square off the scale.
LDA PaddleYWhenPluggedIn ;Put square on screen, paddle is plugged in.
STA $200
LDA PaddleButtons ;Get paddle value.
SEC
SBC #$30 ;Put in range of the bar on screen.
BCS QuickJump ;Just check for subtracting wrap.
LDA #$00 ;If wraps for some reason, put on leftmost side of screen.
QuickJump:
JMP SkipTextBelow
NoController:
LDA PaddleYWhenNotPluggedIn
STA $200 ;Paddle not reading if this runs, so put it a different sprite Y position off graph.
LDA #$7D
SkipTextBelow:
STA $203 ;Assign X value, either on graph value if plugged in, or middle if not plugged in.
LDA $4016
AND #$08 ;Button pressed?
BEQ Red ;Nope, Red Block.
LDA #$02 ;Yes, Green Block to show paddle button is pressed is loaded.
JMP SetBackgroundValue
Red:
LDA #$01 ;Red Block to show paddle button isn't pressed is loaded.
SetBackgroundValue:
STA $201 ;Set Block color via sprite block change.
LDA $2002 ;Reset latch to write value in text to the screen.
LDA #$21
STA $2006
LDA #$72
STA $2006
LDA PaddleButtons
CMP #$FF
BEQ NotConnectedText ;Not connected/readable, put letters ND on screen.
LSR A
LSR A
LSR A
LSR A
CLC
ADC #$10
STA $2007
LDA PaddleButtons
AND #$0F
CLC
ADC #$10
STA $2007
JMP SpritesToScreen
NotConnectedText:
LDA #$4E
STA $2007
LDA #$44
STA $2007
SpritesToScreen:
LDA #$00
STA $2003 ; set the low byte (00) of the RAM address
LDA #$02
STA $4014 ; set the high byte (02) of the RAM address, start the transfer
LDA #$00
STA $2005
STA $2005 ;Reset scroll.
INC Frame ;Tell main engine NMI is done.
PLA
RTI ;Return to the infinite loop.
;;;;;;;;;;;;;;
.bank 1
.org $E000
Palette:
.incbin "Palette.bin"
Sprite:
.db $FF,$01,$00,$FF
PaddleYWhenPluggedIn:
.db $47
PaddleYWhenNotPluggedIn:
.db $37
BackgroundPage:
.incbin "PaddleTestScreen.bin"
.org $FFFA
.dw NMI
.dw RESET
.dw 0
;;;;;;;;;;;;;;
.bank 2
.org $0000
.incbin "PaddleTestGraphics.chr" ;includes 8KB graphics file for game.

Binary file not shown.

View file

@ -0,0 +1 @@
0

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,94 @@
NES APU Mixer Tests
-------------------
These tests verify proper operation of the NES APU's sound channel
mixer, including relative volumes of channels and non-linear mixing.
Tests MUST be run from a freshly-powered NES, as this is the only way to
ensure that the triangle wave doesn't interfere.
All tests beep, play a test sound, then beep again. For all but the
noise test, there should be near silence between the beeps. For the
noise test, noise will fade in and out. There shouldn't be any
noticeable tone when heard through a speaker (through headphones, faint
tones might be audible).
Internal operation
------------------
The tests have the channel under test generate a tone, then generate the
inverse waveform using the DMC DAC, canceling to (near) silence if
everything is correct.
The DMC test verifies that non-linearity of the DMC DAC. The noise and
triangle tests verify relative volume of the noise and triangle to the
DMC, and that the DMC DAC affects attenuation of them properly. Finally,
the square test verifies relative volume of the squares to the DMC,
non-linearity of the square DACs, how one square affects the other
(slightly), and that the square DAC non-linearity is separate from the
DMC.
Flashes, clicks, other glitches
-------------------------------
If a test prints "passed", it passed, even if there were some flashes or
odd sounds. Only a test which prints "done" at the end requires that you
watch/listen while it runs in order to determine whether it passed. Such
tests involve things which the CPU cannot directly test.
Alternate output
----------------
Tests generally print information on screen, but also report the final
result audibly, and output text to memory, in case the PPU doesn't work
or there isn't one, as in an NSF or a NES emulator early in development.
After the tests are done, the final result is reported as a series of
beeps (see below). For NSF builds, any important diagnostic bytes are
also reported as beeps, before the final result.
Output at $6000
---------------
All text output is written starting at $6004, with a zero-byte
terminator at the end. As more text is written, the terminator is moved
forward, so an emulator can print the current text at any time.
The test status is written to $6000. $80 means the test is running, $81
means the test needs the reset button pressed, but delayed by at least
100 msec from now. $00-$7F means the test has completed and given that
result code.
To allow an emulator to know when one of these tests is running and the
data at $6000+ is valid, as opposed to some other NES program, $DE $B0
$G1 is written to $6001-$6003.
Audible output
--------------
A byte is reported as a series of tones. The code is in binary, with a
low tone for 0 and a high tone for 1, and with leading zeroes skipped.
The first tone is always a zero. A final code of 0 means passed, 1 means
failure, and 2 or higher indicates a specific reason. See the source
code of the test for more information about the meaning of a test code.
They are found after the set_test macro. For example, the cause of test
code 3 would be found in a line containing set_test 3. Examples:
Tones Binary Decimal Meaning
- - - - - - - - - - - - - - - - - - - -
low 0 0 passed
low high 01 1 failed
low high low 010 2 error 2
NSF versions
------------
Many NSF-based tests require that the NSF player either not interrupt
the init routine with the play routine, or if it does, not interrupt the
play routine again if it hasn't returned yet. This is because many tests
need to run for a while without returning.
NSF versions also make periodic clicks to prevent the NSF player from
thinking the track is silent and thus ending the track before it's done
testing.
--
Shay Green <gblargg@gmail.com>

View file

@ -0,0 +1,92 @@
; Builds program as iNES ROM
; Default is 32K PRG and 8K CHR ROM, NROM (0)
.if 0 ; Options to set before .include "shell.inc":
CHR_RAM=1 ; Use CHR-RAM instead of CHR-ROM
CART_WRAM=1 ; Use mapper that supports 8K WRAM in cart
CUSTOM_MAPPER=n ; Specify mapper number
.endif
.ifndef CUSTOM_MAPPER
.ifdef CART_WRAM
CUSTOM_MAPPER = 2 ; UNROM
.else
CUSTOM_MAPPER = 0 ; NROM
.endif
.endif
;;;; iNES header
.ifndef CUSTOM_HEADER
.segment "HEADER"
.byte $4E,$45,$53,26 ; "NES" EOF
.ifdef CHR_RAM
.byte 2,0 ; 32K PRG, CHR RAM
.else
.byte 2,1 ; 32K PRG, 8K CHR
.endif
.byte CUSTOM_MAPPER*$10+$01 ; vertical mirroring
.endif
.ifndef CUSTOM_VECTORS
.segment "VECTORS"
.word -1,-1,-1, nmi, reset, irq
.endif
;;;; CHR-RAM/ROM
.ifdef CHR_RAM
.define CHARS "CHARS_PRG"
.segment CHARS
ascii_chr:
.segment "CHARS_PRG_ASCII"
.align $200
.incbin "ascii.chr"
ascii_chr_end:
.else
.define CHARS "CHARS"
.segment "CHARS_ASCII"
.align $200
.incbin "ascii.chr"
.res $1800
.endif
.segment CHARS
.res $10,0
;;;; Shell
.ifndef NEED_CONSOLE
NEED_CONSOLE=1
.endif
.segment "CODE"
.res $4000
.include "shell.s"
std_reset:
lda #0
sta PPUCTRL
sta PPUMASK
jmp run_shell
init_runtime:
.ifdef CHR_RAM
load_chr_ram
.endif
rts
post_exit:
jsr set_final_result
jsr play_hex
jmp forever
; This helps devcart recover after running test.
; It is never executed by test ROM.
.segment "LOADER"
.incbin "devcart.bin"
.code
.align 256

View file

@ -0,0 +1,328 @@
; Scrolling text console with word wrapping, 30x29 characters.
;
; * Defers PPU initialization until first flush/ newline.
; * Works even if PPU doesn't support scrolling.
; * Keeps border around edge of screen for TV overscan.
; * Requires vertical or single-screen mirroring.
; * Requires ASCII font in CHR.
.ifndef CONSOLE_COLOR
CONSOLE_COLOR = $30 ; white
.endif
console_screen_width = 32 ; if lower than 32, left-justifies
; Number of characters of margin on left and right, to avoid
; text getting cut off by common TVs. OK if either/both are 0.
console_left_margin = 1
console_right_margin = 1
console_width = console_screen_width - console_left_margin - console_right_margin
zp_byte console_pos ; 0 to console_width
zp_byte console_scroll
zp_byte console_temp
bss_res console_buf,console_width
; Initializes console
console_init:
; Flag that console hasn't been initialized
setb console_scroll,-1
setb console_pos,0
rts
; Hides console by disabling PPU rendering and blacking out
; first four entries of palette.
; Preserved: A, X, Y
console_hide:
pha
jsr console_wait_vbl_
setb PPUMASK,0
lda #$0F
jsr console_load_palette_
pla
rts
; Shows console display
; Preserved: A, X, Y
console_show:
pha
lda #CONSOLE_COLOR
jsr console_show_custom_color_
pla
rts
; Prints char A to console. Will not appear until
; a newline or flush occurs.
; Preserved: A, X, Y
console_print:
cmp #10
beq console_newline
sty console_temp
ldy console_pos
cpy #console_width
beq console_full_
sta console_buf,y
iny
sty console_pos
ldy console_temp
rts
; Displays current line and starts new one
; Preserved: A, X, Y
console_newline:
pha
jsr console_wait_vbl_
jsr console_flush_
jsr console_scroll_up_
setb console_pos,0
pla
rts
; Displays current line's contents without scrolling.
; Preserved: A, X, Y
console_flush:
pha
jsr console_wait_vbl_
jsr console_flush_
jsr console_apply_scroll_
pla
rts
;**** Internal routines ****
console_full_:
ldy console_temp
; Line is full
; If space, treat as newline
cmp #' '
beq console_newline
; Wrap current line at appropriate point
pha
tya
pha
jsr console_wrap_
pla
tay
pla
jmp console_print
; Inserts newline into buffer at appropriate position, leaving
; next line ready in buffer
; Preserved: X, console_temp
console_wrap_:
; Find beginning of last word
ldy #console_width
lda #' '
: dey
bmi console_newline
cmp console_buf,y
bne :-
; y = 0 to console_width-1
; Flush through current word and put remaining
; in buffer for next line
jsr console_wait_vbl_
; Time to last PPU write: 207 + 32*(26 + 10)
lda console_scroll
jsr console_set_ppuaddr_
stx console_pos ; save X
ldx #0
; Print everything before last word
: lda console_buf,x
sta PPUDATA
inx
dey
bpl :-
; x = 1 to console_width
; Move last word to beginning of buffer, and
; print spaces for rest of line
ldy #0
beq :++
: lda #' '
sta PPUDATA
lda console_buf,x
inx
sta console_buf,y
iny
: cpx #console_width
bne :--
ldx console_pos ; restore X
; Append new text after that
sty console_pos
; FALL THROUGH
; Scrolls up 8 pixels and clears one line BELOW new line
; Preserved: X, console_temp
console_scroll_up_:
; Scroll up 8 pixels
lda console_scroll
jsr console_add_8_to_scroll_
sta console_scroll
; Clear line AFTER that on screen
jsr console_add_8_to_scroll_
jsr console_set_ppuaddr_
ldy #console_width
lda #' '
: sta PPUDATA
dey
bne :-
; FALL THROUGH
; Applies current scrolling position to PPU
; Preserved: X, Y, console_temp
console_apply_scroll_:
lda #0
sta PPUADDR
sta PPUADDR
sta PPUSCROLL
lda console_scroll
jsr console_add_8_to_scroll_
jsr console_add_8_to_scroll_
sta PPUSCROLL
rts
; Sets PPU address for row
; In: A = scroll position
; Preserved: X, Y
console_set_ppuaddr_:
sta console_temp
lda #$08
asl console_temp
rol a
asl console_temp
rol a
sta PPUADDR
lda console_temp
ora #console_left_margin
sta PPUADDR
rts
; A = (A + 8) % 240
; Preserved: X, Y
console_add_8_to_scroll_:
cmp #240-8
bcc :+
adc #16-1;+1 for set carry
: adc #8
rts
console_show_custom_color_:
pha
jsr console_wait_vbl_
setb PPUMASK,PPUMASK_BG0
pla
jsr console_load_palette_
jmp console_apply_scroll_
console_load_palette_:
pha
setb PPUADDR,$3F
setb PPUADDR,$00
setb PPUDATA,$0F ; black
pla
sta PPUDATA
sta PPUDATA
sta PPUDATA
rts
; Initializes PPU if necessary, then waits for VBL
; Preserved: A, X, Y, console_temp
console_wait_vbl_:
lda console_scroll
cmp #-1
bne @already_initialized
; Deferred initialization of PPU until first use of console
; In case PPU doesn't support scrolling, start a
; couple of lines down
setb console_scroll,16
jsr console_hide
tya
pha
; Fill nametable with spaces
setb PPUADDR,$20
setb PPUADDR,$00
ldy #240
lda #' '
: sta PPUDATA
sta PPUDATA
sta PPUDATA
sta PPUDATA
dey
bne :-
; Clear attributes
lda #0
ldy #$40
: sta PPUDATA
dey
bne :-
pla
tay
jsr console_show
@already_initialized:
jmp wait_vbl_optional
; Flushes current line
; Preserved: X, Y
console_flush_:
lda console_scroll
jsr console_set_ppuaddr_
sty console_temp
; Copy line
ldy #0
beq :++
: lda console_buf,y
sta PPUDATA
iny
: cpy console_pos
bne :--
ldy console_temp
rts

View file

@ -0,0 +1,118 @@
; CRC-32 checksum calculation
zp_res checksum,4
zp_byte checksum_temp
zp_byte checksum_off_
; Turns CRC updating on/off. Allows nesting.
; Preserved: A, X, Y
crc_off:
dec checksum_off_
rts
crc_on: inc checksum_off_
beq :+
jpl internal_error ; catch unbalanced crc calls
: rts
; Initializes checksum module. Might initialize tables
; in the future.
init_crc:
jmp reset_crc
; Clears checksum and turns it on
; Preserved: X, Y
reset_crc:
lda #0
sta checksum_off_
lda #$FF
sta checksum
sta checksum + 1
sta checksum + 2
sta checksum + 3
rts
; Updates checksum with byte in A (unless disabled via crc_off)
; Preserved: A, X, Y
; Time: 357 clocks average
update_crc:
bit checksum_off_
bmi update_crc_off
update_crc_:
pha
stx checksum_temp
eor checksum
ldx #8
@bit: lsr checksum+3
ror checksum+2
ror checksum+1
ror a
bcc :+
sta checksum
lda checksum+3
eor #$ED
sta checksum+3
lda checksum+2
eor #$B8
sta checksum+2
lda checksum+1
eor #$83
sta checksum+1
lda checksum
eor #$20
: dex
bne @bit
sta checksum
ldx checksum_temp
pla
update_crc_off:
rts
; Prints checksum as 8-character hex value
print_crc:
jsr crc_off
; Print complement
ldx #3
: lda checksum,x
eor #$FF
jsr print_hex
dex
bpl :-
jmp crc_on
; EQ if checksum matches CRC
; Out: A=0 and EQ if match, A>0 and NE if different
; Preserved: X, Y
.macro is_crc crc
jsr_with_addr is_crc_,{.dword crc}
.endmacro
is_crc_:
tya
pha
; Compare with complemented checksum
ldy #3
: lda (ptr),y
sec
adc checksum,y
bne @wrong
dey
bpl :-
pla
tay
lda #0
rts
@wrong:
pla
tay
lda #1
rts

View file

@ -0,0 +1,190 @@
; Delays in CPU clocks, milliseconds, etc. All routines are re-entrant
; (no global data). No routines touch X or Y during execution.
; Code generated by macros is relocatable; it contains no JMPs to itself.
zp_byte delay_temp_ ; only written to
; Delays n clocks, from 2 to 16777215
; Preserved: A, X, Y, flags
.macro delay n
.if (n) < 0 .or (n) = 1 .or (n) > 16777215
.error "Delay out of range"
.endif
delay_ (n)
.endmacro
; Delays n milliseconds (1/1000 second)
; n can range from 0 to 1100.
; Preserved: A, X, Y, flags
.macro delay_msec n
.if (n) < 0 .or (n) > 1100
.error "time out of range"
.endif
delay ((n)*CLOCK_RATE+500)/1000
.endmacro
; Delays n microseconds (1/1000000 second).
; n can range from 0 to 100000.
; Preserved: A, X, Y, flags
.macro delay_usec n
.if (n) < 0 .or (n) > 100000
.error "time out of range"
.endif
delay ((n)*((CLOCK_RATE+50)/100)+5000)/10000
.endmacro
.align 64
; Delays A clocks + overhead
; Preserved: X, Y
; Time: A+25 clocks (including JSR)
: sbc #7 ; carry set by CMP
delay_a_25_clocks:
cmp #7
bcs :- ; do multiples of 7
lsr a ; bit 0
bcs :+
: ; A=clocks/2, either 0,1,2,3
beq @zero ; 0: 5
lsr a
beq :+ ; 1: 7
bcc :+ ; 2: 9
@zero: bne :+ ; 3: 11
: rts ; (thanks to dclxvi for the algorithm)
; Delays A*256 clocks + overhead
; Preserved: X, Y
; Time: A*256+16 clocks (including JSR)
delay_256a_16_clocks:
cmp #0
bne :+
rts
delay_256a_11_clocks_:
: pha
lda #256-19-22
jsr delay_a_25_clocks
pla
clc
adc #-1
bne :-
rts
; Delays A*65536 clocks + overhead
; Preserved: X, Y
; Time: A*65536+16 clocks (including JSR)
delay_65536a_16_clocks:
cmp #0
bne :+
rts
delay_65536a_11_clocks_:
: pha
lda #256-19-22-13
jsr delay_a_25_clocks
lda #255
jsr delay_256a_11_clocks_
pla
clc
adc #-1
bne :-
rts
max_short_delay = 41
; delay_short_ macro jumps into these
.res (max_short_delay-12)/2,$EA ; NOP
delay_unrolled_:
rts
.macro delay_short_ n
.if n < 0 .or n = 1 .or n > max_short_delay
.error "Internal delay error"
.endif
.if n = 0
; nothing
.elseif n = 2
nop
.elseif n = 3
sta <delay_temp_
.elseif n = 4
nop
nop
.elseif n = 5
sta <delay_temp_
nop
.elseif n = 6
nop
nop
nop
.elseif n = 7
php
plp
.elseif n = 8
nop
nop
nop
nop
.elseif n = 9
php
plp
nop
.elseif n = 10
sta <delay_temp_
php
plp
.elseif n = 11
php
plp
nop
nop
.elseif n = 13
php
plp
nop
nop
nop
.elseif n & 1
sta <delay_temp_
jsr delay_unrolled_-((n-15)/2)
.else
jsr delay_unrolled_-((n-12)/2)
.endif
.endmacro
.macro delay_nosave_ n
; 65536+17 = maximum delay using delay_256a_11_clocks_
; 255+27 = maximum delay using delay_a_25_clocks
; 27 = minimum delay using delay_a_25_clocks
.if n > 65536+17
lda #^(n - 15)
jsr delay_65536a_11_clocks_
; +2 ensures remaining clocks is never 1
delay_nosave_ (((n - 15) & $FFFF) + 2)
.elseif n > 255+27
lda #>(n - 15)
jsr delay_256a_11_clocks_
; +2 ensures remaining clocks is never 1
delay_nosave_ (<(n - 15) + 2)
.elseif n >= 27
lda #<(n - 27)
jsr delay_a_25_clocks
.else
delay_short_ n
.endif
.endmacro
.macro delay_ n
.if n > max_short_delay
php
pha
delay_nosave_ (n - 14)
pla
plp
.else
delay_short_ n
.endif
.endmacro

View file

@ -0,0 +1,188 @@
; jxx equivalents to bxx
.macpack longbranch
; blt, bge equivalents to bcc, bcs
.define blt bcc
.define bge bcs
.define jge jcs
.define jlt jcc
; Puts data in another segment
.macro seg_data seg,data
.pushseg
.segment seg
data
.popseg
.endmacro
; Reserves size bytes in zeropage/bss for name.
; If size is omitted, reserves one byte.
.macro zp_res name,size
.ifblank size
zp_res name,1
.else
seg_data "ZEROPAGE",{name: .res size}
.endif
.endmacro
.macro bss_res name,size
.ifblank size
bss_res name,1
.else
seg_data "BSS",{name: .res size}
.endif
.endmacro
.macro nv_res name,size
.ifblank size
nv_res name,1
.else
seg_data "NVRAM",{name: .res size}
.endif
.endmacro
; Reserves one byte in zeropage for name (very common)
.macro zp_byte name
seg_data "ZEROPAGE",{name: .res 1}
.endmacro
; Passes constant data to routine in addr
; Preserved: A, X, Y
.macro jsr_with_addr routine,data
.local Addr
pha
lda #<Addr
sta addr
lda #>Addr
sta addr+1
pla
jsr routine
seg_data "RODATA",{Addr: data}
.endmacro
; Calls routine multiple times, with A having the
; value 'start' the first time, 'start+step' the
; second time, up to 'end' for the last time.
.macro for_loop routine,start,end,step
lda #start
: pha
jsr routine
pla
clc
adc #step
cmp #<((end)+(step))
bne :-
.endmacro
; Calls routine n times. The value of A in the routine
; counts from 0 to n-1.
.macro loop_n_times routine,n
for_loop routine,0,n-1,+1
.endmacro
; Same as for_loop, except uses 16-bit value in YX.
; -256 <= step <= 255
.macro for_loop16 routine,start,end,step
.if (step) < -256 || (step) > 255
.error "Step must be within -256 to 255"
.endif
ldy #>(start)
lda #<(start)
: tax
pha
tya
pha
jsr routine
pla
tay
pla
clc
adc #step
.if (step) > 0
bcc :+
iny
.else
bcs :+
dey
.endif
: cmp #<((end)+(step))
bne :--
cpy #>((end)+(step))
bne :--
.endmacro
; Copies byte from in to out
; Preserved: X, Y
.macro mov out, in
lda in
sta out
.endmacro
; Stores byte at addr
; Preserved: X, Y
.macro setb addr, byte
lda #byte
sta addr
.endmacro
; Stores word at addr
; Preserved: X, Y
.macro setw addr, word
lda #<(word)
sta addr
lda #>(word)
sta addr+1
.endmacro
; Loads XY with 16-bit immediate or value at address
.macro ldxy Arg
.if .match( .left( 1, {Arg} ), # )
ldy #<(.right( .tcount( {Arg} )-1, {Arg} ))
ldx #>(.right( .tcount( {Arg} )-1, {Arg} ))
.else
ldy (Arg)
ldx (Arg)+1
.endif
.endmacro
; Increments word at Addr and sets Z flag appropriately
; Preserved: A, X, Y
.macro incw Addr
.local @incw_skip ; doesn't work, so HOW THE HELL DO YOU MAKE A LOCAL LABEL IN A MACRO THAT DOESN"T DISTURB INVOKING CODE< HUH?????? POS
inc Addr
bne @incw_skip
inc Addr+1
@incw_skip:
.endmacro
; Increments XY as 16-bit register, in CONSTANT time.
; Z flag set based on entire result.
; Preserved: A
; Time: 7 clocks
.macro inxy
iny ; 2
beq *+4 ; 3
; -1
bne *+3 ; 3
; -1
inx ; 2
.endmacro
; Negates A and adds it to operand
.macro subaf Operand
eor #$FF
sec
adc Operand
.endmacro
; Initializes CPU registers to reasonable values
.macro init_cpu_regs
sei
cld ; unnecessary on NES, but might help on clone
ldx #$FF
txs
.ifndef BUILD_NSF
inx
stx PPUCTRL
.endif
.endmacro

View file

@ -0,0 +1,56 @@
; NES I/O locations and masks
.ifndef BUILD_NSF
; PPU
PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
SPRADDR = $2003
SPRDATA = $2004
PPUSCROLL = $2005
PPUADDR = $2006
PPUDATA = $2007
SPRDMA = $4014
PPUCTRL_NMI = $80
PPUMASK_BG0 = $0A
PPUCTRL_8X8 = $00
PPUCTRL_8X16 = $20
PPUMASK_SPR = $14
PPUMASK_BG0CLIP = $08
.endif
; APU
SNDCHN = $4015
JOY1 = $4016
JOY2 = $4017
SNDMODE = $4017
SNDMODE_NOIRQ = $40
.ifndef REGION_FREE
.ifndef PAL_ONLY
.ifndef NTSC_ONLY
NTSC_ONLY = 1
.endif
.endif
.else
.ifdef NTSC_ONLY
.error "NTSC_ONLY and REGION_FREE defined"
.endif
.ifdef PAL_ONLY
.error "PAL_ONLY and REGION_FREE defined"
.endif
.endif
.ifdef NTSC_ONLY
CLOCK_RATE = 1789773
PPU_FRAMELEN = 29781
.endif
.ifdef PAL_ONLY
CLOCK_RATE = 1662607
PPU_FRAMELEN = 33248
.endif

View file

@ -0,0 +1,203 @@
; PPU utilities
bss_res ppu_not_present
; Sets PPUADDR to w
; Preserved: X, Y
.macro set_ppuaddr w
bit PPUSTATUS
setb PPUADDR,>w
setb PPUADDR,<w
.endmacro
; Delays by no more than n scanlines
.macro delay_scanlines n
.if CLOCK_RATE <> 1789773
.error "Currently only supports NTSC"
.endif
delay ((n)*341)/3
.endmacro
; Waits for VBL then disables PPU rendering.
; Preserved: A, X, Y
disable_rendering:
pha
jsr wait_vbl_optional
setb PPUMASK,0
pla
rts
; Fills first nametable with $00
; Preserved: Y
clear_nametable:
ldx #$20
bne clear_nametable_
clear_nametable2:
ldx #$24
clear_nametable_:
lda #0
jsr fill_screen_
; Clear pattern table
ldx #64
: sta PPUDATA
dex
bne :-
rts
; Fills screen with tile A
; Preserved: A, Y
fill_screen:
ldx #$20
bne fill_screen_
; Same as fill_screen, but fills other nametable
fill_screen2:
ldx #$24
fill_screen_:
stx PPUADDR
ldx #$00
stx PPUADDR
ldx #240
: sta PPUDATA
sta PPUDATA
sta PPUDATA
sta PPUDATA
dex
bne :-
rts
; Fills palette with $0F
; Preserved: Y
clear_palette:
set_ppuaddr $3F00
ldx #$20
lda #$0F
: sta PPUDATA
dex
bne :-
; Fills OAM with $FF
; Preserved: Y
clear_oam:
lda #$FF
; Fills OAM with A
; Preserved: A, Y
fill_oam:
ldx #0
stx SPRADDR
: sta SPRDATA
dex
bne :-
rts
; Initializes wait_vbl_optional. Must be called before
; using it.
.align 32
init_wait_vbl:
; Wait for VBL flag to be set, or ~60000
; clocks (2 frames) to pass
ldy #24
ldx #1
bit PPUSTATUS
: bit PPUSTATUS
bmi @set
dex
bne :-
dey
bpl :-
@set:
; Be sure flag didn't stay set (in case
; PPUSTATUS always has high bit set)
tya
ora PPUSTATUS
sta ppu_not_present
rts
; Same as wait_vbl, but returns immediately if PPU
; isn't working or doesn't support VBL flag
; Preserved: A, X, Y
.align 16
wait_vbl_optional:
bit ppu_not_present
bmi :++
; FALL THROUGH
; Clears VBL flag then waits for it to be set.
; Preserved: A, X, Y
wait_vbl:
bit PPUSTATUS
: bit PPUSTATUS
bpl :-
: rts
.macro check_ppu_region_ Len
; Delays since VBL began
jsr wait_vbl_optional ; 10 average
delay Len - 18 - 200
lda PPUSTATUS ; 4
bmi @ok ; 2
delay 200
; Next VBL should roughly begin here if it's the
; one we are detecting
delay 200
lda PPUSTATUS ; 2
bpl @ok
.endmacro
check_ppu_region:
.ifndef REGION_FREE
.ifdef PAL_ONLY
check_ppu_region_ 29781
print_str {newline,"Note: This test is meant for PAL NES only.",newline,newline}
.endif
.ifdef NTSC_ONLY
check_ppu_region_ 33248
print_str {newline,"Note: This test is meant for NTSC NES only.",newline,newline}
.endif
.endif
@ok: rts
; Loads ASCII font into CHR RAM and fills rest with $FF
.macro load_chr_ram
bit PPUSTATUS
setb PPUADDR,0
setb PPUADDR,0
; Copy ascii_chr to 0
setb addr,<ascii_chr
ldx #>ascii_chr
ldy #0
@page:
stx addr+1
: lda (addr),y
sta PPUDATA
iny
bne :-
inx
cpx #>ascii_chr_end
bne @page
; Fill rest
lda #$FF
: sta PPUDATA
iny
bne :-
inx
cpx #$20
bne :-
.endmacro

View file

@ -0,0 +1,247 @@
; Prints values in various ways to output,
; including numbers and strings.
newline = 10
zp_byte print_temp_
; Prints indicated register to console as two hex
; chars and space
; Preserved: A, X, Y, flags
print_a:
php
pha
print_reg_:
jsr print_hex
lda #' '
jsr print_char_
pla
plp
rts
print_x:
php
pha
txa
jmp print_reg_
print_y:
php
pha
tya
jmp print_reg_
print_p:
php
pha
php
pla
jmp print_reg_
print_s:
php
pha
txa
tsx
inx
inx
inx
inx
jsr print_x
tax
pla
plp
rts
; Prints A as two hex characters, NO space after
; Preserved: A, X, Y
print_hex:
jsr update_crc
pha
lsr a
lsr a
lsr a
lsr a
jsr print_nibble_
pla
pha
and #$0F
jsr print_nibble_
pla
rts
print_nibble_:
cmp #10
blt @digit
adc #6;+1 since carry is set
@digit: adc #'0'
jmp print_char_
; Prints low 4 bits of A as single hex character
; Preserved: A, X, Y
print_nibble:
pha
and #$0F
jsr update_crc
jsr print_nibble_
pla
rts
; Prints character and updates checksum UNLESS
; it's a newline.
; Preserved: A, X, Y
print_char:
cmp #newline
beq :+
jsr update_crc
: pha
jsr print_char_
pla
rts
; Prints space. Does NOT update checksum.
; Preserved: A, X, Y
print_space:
pha
lda #' '
jsr print_char_
pla
rts
; Advances to next line. Does NOT update checksum.
; Preserved: A, X, Y
print_newline:
pha
lda #newline
jsr print_char_
pla
rts
; Prints string
; Preserved: A, X, Y
.macro print_str str,str2
jsr print_str_
.byte str
.ifnblank str2
.byte str2
.endif
.byte 0
.endmacro
print_str_:
sta print_temp_
pla
sta addr
pla
sta addr+1
jsr inc_addr
jsr print_str_addr
lda print_temp_
jmp (addr)
; Prints string at addr and leaves addr pointing to
; byte AFTER zero terminator.
; Preserved: A, X, Y
print_str_addr:
pha
tya
pha
ldy #0
beq :+ ; always taken
@loop: jsr print_char
jsr inc_addr
: lda (addr),y
bne @loop
pla
tay
pla
; FALL THROUGH
; Increments 16-bit value in addr.
; Preserved: A, X, Y
inc_addr:
inc addr
beq :+
rts
: inc addr+1
rts
; Prints A as 1-3 digit decimal value, NO space after.
; Preserved: A, X, Y
print_dec:
pha
sta print_temp_
jsr update_crc
txa
pha
lda print_temp_
; Hundreds
cmp #10
blt @ones
cmp #100
blt @tens
ldx #'0'-1
: inx
sbc #100
bge :-
adc #100
jsr @digit
; Tens
@tens: sec
ldx #'0'-1
: inx
sbc #10
bge :-
adc #10
jsr @digit
; Ones
@ones: ora #'0'
jsr print_char
pla
tax
pla
rts
; Print a single digit
@digit: pha
txa
jsr print_char
pla
rts
; Prints one of two characters based on condition.
; SEC; print_cc bcs,'C','-' prints 'C'.
; Preserved: A, X, Y, flags
.macro print_cc cond,yes,no
; Avoids labels since they're not local
; to macros in ca65.
php
pha
cond *+6
lda #no
bne *+4
lda #yes
jsr print_char
pla
plp
.endmacro

View file

@ -0,0 +1,32 @@
; Included at beginning of program
.ifdef CUSTOM_PREFIX
.include "custom_prefix.s"
.endif
; Sub-test in a multi-test ROM
.ifdef BUILD_MULTI
.include "build_multi.s"
.else
; NSF music file
.ifdef BUILD_NSF
.include "build_nsf.s"
.endif
; Devcart
.ifdef BUILD_DEVCART
.include "build_devcart.s"
.endif
; NES internal RAM
.ifdef BUILD_NOCART
.include "build_nocart.s"
.endif
; NES ROM (default)
.ifndef SHELL_INCLUDED
.include "build_rom.s"
.endif
.endif ; .ifdef BUILD_MULTI

View file

@ -0,0 +1,180 @@
; Shell that sets up testing framework and calls main
; Detect inclusion loops (otherwise ca65 goes crazy)
.ifdef SHELL_INCLUDED
.error "shell.s included twice"
.end
.endif
SHELL_INCLUDED = 1
; Temporary variables that ANY routine might modify, so
; only use them between routine calls.
temp = <$A
temp2 = <$B
temp3 = <$C
addr = <$E
ptr = addr
; Move code from $C000 to $E200, to accommodate my devcarts
.segment "CODE"
.res $2200
; Put shell code after user code, so user code is in more
; consistent environment
.segment "CODE2"
; Any user code which runs off end might end up here,
; so catch that mistake.
nop ; in case there was three-byte opcode before this
nop
jmp internal_error
;**** Common routines ****
.include "macros.inc"
.include "neshw.inc"
.include "delay.s"
.include "print.s"
.include "crc.s"
.include "testing.s"
;**** Shell core ****
.ifndef CUSTOM_RESET
reset:
sei
jmp std_reset
.endif
; Sets up hardware then runs main
run_shell:
init_cpu_regs
jsr init_shell
set_test $FF
jmp run_main
; Initializes shell without affecting current set_test values
init_shell:
jsr clear_ram
jsr init_wait_vbl ; waits for VBL once here,
jsr wait_vbl_optional ; so only need to wait once more
jsr init_text_out
jsr init_testing
jsr init_runtime
jsr console_init
rts
; Runs main in consistent PPU/APU environment, then exits
; with code 0
run_main:
jsr pre_main
jsr main
lda #0
jmp exit
; Sets up environment for main to run in
pre_main:
.ifndef BUILD_NSF
jsr disable_rendering
setb PPUCTRL,0
jsr clear_palette
jsr clear_nametable
jsr clear_nametable2
jsr clear_oam
.endif
; Clear APU registers
lda #0
sta $4015
ldx #$13
: sta $4000,x
dex
bpl :-
; CPU registers
lda #$34
pha
lda #0
tax
tay
jsr wait_vbl_optional
plp
sta SNDMODE
rts
.ifndef CUSTOM_EXIT
exit:
.endif
; Reports result and ends program
std_exit:
sta temp
init_cpu_regs
setb SNDCHN,0
lda temp
jsr report_result
pha
jsr check_ppu_region
pla
jmp post_exit
; Reports final result code in A
report_result:
jsr :+
jmp play_byte
: jsr print_newline
jsr console_show
; 0: ""
cmp #1
bge :+
rts
:
; 1: "Failed"
bne :+
print_str {"Failed",newline}
rts
; n: "Failed #n"
: print_str "Failed #"
jsr print_dec
jsr print_newline
rts
;**** Other routines ****
.include "shell_misc.s"
.ifdef NEED_CONSOLE
.include "console.s"
.else
; Stubs so code doesn't have to care whether
; console exists
console_init:
console_show:
console_hide:
console_print:
console_flush:
rts
.endif
.ifndef CUSTOM_PRINT
.include "text_out.s"
print_char_:
jsr write_text_out
jmp console_print
stop_capture:
rts
.endif

View file

@ -0,0 +1,211 @@
; Reports internal error and exits program
internal_error:
print_str newline,"Internal error"
lda #255
jmp exit
.import __NVRAM_LOAD__, __NVRAM_SIZE__
.macro fill_ram_ Begin, End
; Simpler to count from negative size up to 0,
; and adjust address downward to compensate
; for initial low byte in Y index
.local Neg_size
Neg_size = (Begin) - (End)
ldxy #(Begin) - <Neg_size
sty addr
stx addr+1
ldxy #Neg_size
: sta (addr),y
iny
bne :-
inc addr+1
inx
bne :-
.endmacro
; Clears 0 through ($100+S), $200 through __NVRAM_LOAD__-1, and
; __NVRAM_LOAD__+__NVRAM_SIZE__ through $7FF
clear_ram:
lda #0
bss_begin = $200
fill_ram_ bss_begin,__NVRAM_LOAD__
fill_ram_ __NVRAM_LOAD__+__NVRAM_SIZE__,$800
; Zero-page
tax
: sta 0,x
inx
bne :-
; Stack below S
tsx
inx
: dex
sta $100,x
bne :-
rts
nv_res unused_nv_var ; to avoid size=0
; Clears nvram
clear_nvram:
lda #0
fill_ram_ __NVRAM_LOAD__,__NVRAM_LOAD__+__NVRAM_SIZE__
rts
; Prints filename and newline, if available, otherwise nothing.
; Preserved: A, X, Y
print_filename:
.ifdef FILENAME_KNOWN
pha
jsr print_newline
setw addr,filename
jsr print_str_addr
jsr print_newline
pla
.endif
rts
.pushseg
.segment "RODATA"
; Filename terminated with zero byte.
filename:
.ifdef FILENAME_KNOWN
.incbin "ram:nes_temp"
.endif
.byte 0
.popseg
;**** ROM-specific ****
.ifndef BUILD_NSF
.include "ppu.s"
avoid_silent_nsf:
play_byte:
rts
; Disables interrupts and loops forever
.ifndef CUSTOM_FOREVER
forever:
sei
lda #0
sta PPUCTRL
: beq :-
.res $10,$EA ; room for code to run loader
.endif
; Default NMI
.ifndef CUSTOM_NMI
zp_byte nmi_count
zp_byte flags_from_nmi
zp_byte pclo_from_nmi
nmi: ; Record flags and PC low byte from stack
pla
sta flags_from_nmi
pla
sta pclo_from_nmi
pha
lda flags_from_nmi
pha
inc nmi_count
rti
; Waits for NMI. Must be using NMI handler that increments
; nmi_count, with NMI enabled.
; Preserved: X, Y
wait_nmi:
lda nmi_count
: cmp nmi_count
beq :-
rts
.endif
; Default IRQ
.ifndef CUSTOM_IRQ
zp_byte flags_from_irq
zp_byte pclo_from_irq
zp_byte irq_count
irq: ; Record flags and PC low byte from stack
pla
sta flags_from_irq
pla
sta pclo_from_irq
pha
lda flags_from_irq
pha
inc irq_count
bit SNDCHN ; clear frame IRQ flag
rti
.endif
.endif
; Reports A in binary as high and low tones, with
; leading low tone for reference. Omits leading
; zeroes. Doesn't hang if no APU is present.
; Preserved: A, X, Y
play_hex:
pha
; Make low reference beep
clc
jsr @beep
; Remove high zero bits
sec
: rol a
bcc :-
; Play remaining bits
beq @zero
: jsr @beep
asl a
bne :-
@zero:
delay_msec 300
pla
rts
; Plays low/high beep based on carry
; Preserved: A, X, Y
@beep:
pha
; Set up square
lda #1
sta SNDCHN
sta $4001
sta $4003
adc #$FE ; period=$100 if carry, $1FF if none
sta $4002
; Fade volume
lda #$0F
: ora #$30
sta $4000
delay_msec 8
sec
sbc #$31
bpl :-
; Silence
setb SNDCHN,0
delay_msec 160
pla
rts

View file

@ -0,0 +1,105 @@
; Utilities for writing test ROMs
; In NVRAM so these can be used before initializing runtime,
; then runtime initialized without clearing them
nv_res test_code ; code of current test
nv_res test_name,2 ; address of name of current test, or 0 of none
; Sets current test code and optional name. Also resets
; checksum.
; Preserved: A, X, Y
.macro set_test code,name
pha
lda #code
jsr set_test_
.ifblank name
setb test_name+1,0
.else
.local Addr
setw test_name,Addr
seg_data "RODATA",{Addr: .byte name,0}
.endif
pla
.endmacro
set_test_:
sta test_code
jmp reset_crc
; Initializes testing module
init_testing = init_crc
; Reports that all tests passed
tests_passed:
jsr print_filename
print_str newline,"Passed"
lda #0
jmp exit
; Reports "Done" if set_test has never been used,
; "Passed" if set_test 0 was last used, or
; failure if set_test n was last used.
tests_done:
ldx test_code
jeq tests_passed
inx
bne test_failed
jsr print_filename
print_str newline,"Done"
lda #0
jmp exit
; Reports that the current test failed. Prints code and
; name last set with set_test, or just "Failed" if none
; have been set yet.
test_failed:
ldx test_code
; Treat $FF as 1, in case it wasn't ever set
inx
bne :+
inx
stx test_code
:
; If code >= 2, print name
cpx #2-1 ; -1 due to inx above
blt :+
lda test_name+1
beq :+
jsr print_newline
sta addr+1
lda test_name
sta addr
jsr print_str_addr
jsr print_newline
:
jsr print_filename
; End program
lda test_code
jmp exit
; If checksum doesn't match expected, reports failed test.
; Clears checksum afterwards.
; Preserved: A, X, Y
.macro check_crc expected
jsr_with_addr check_crc_,{.dword expected}
.endmacro
check_crc_:
pha
jsr is_crc_
bne :+
jsr reset_crc
pla
rts
: jsr print_newline
jsr print_crc
jmp test_failed

View file

@ -0,0 +1,61 @@
; Text output as expanding zero-terminated string at text_out_base
; The final exit result byte is written here
final_result = $6000
; Text output is written here as an expanding
; zero-terminated string
text_out_base = $6004
bss_res text_out_temp
zp_res text_out_addr,2
init_text_out:
ldx #0
; Put valid data first
setb text_out_base,0
lda #$80
jsr set_final_result
; Now fill in signature that tells emulator there's
; useful data there
setb text_out_base-3,$DE
setb text_out_base-2,$B0
setb text_out_base-1,$61
ldx #>text_out_base
stx text_out_addr+1
setb text_out_addr,<text_out_base
rts
; Sets final result byte in memory
set_final_result:
sta final_result
rts
; Writes character to text output
; In: A=Character to write
; Preserved: A, X, Y
write_text_out:
sty text_out_temp
; Write new terminator FIRST, then new char before it,
; in case emulator looks at string in middle of this routine.
ldy #1
pha
lda #0
sta (text_out_addr),y
dey
pla
sta (text_out_addr),y
inc text_out_addr
bne :+
inc text_out_addr+1
:
ldy text_out_temp
rts

View file

@ -0,0 +1,126 @@
; Shell for mixer tests
CUSTOM_PLAY=1
.include "shell.inc"
.ifndef CUSTOM_TEXT
text: .byte "2. Should be nearly silent.",0
.endif
main:
jsr dmc_dac_to_127
jsr make_triangle_zero
jsr show_instructions
jsr quiet_ppu
jsr short_tone
jsr test_main
jsr short_tone
jsr console_show
rts
dmc_dac_to_127:
ldx #0
: dey
bne :-
ldy #20
stx $4011
inx
bpl :-
rts
; Runs triangle until its output is zero, avoiding its
; attenuating effect on tests (at power, it starts with
; its DAC at 15).
make_triangle_zero:
.ifndef USING_DEVCART
setb $4015,0 ; off
setb $4008,$04 ; lin ctr
setb $400A,$FF ; period=256
setb $400B,$08
delay_msec 10 ; wait for lin ctr to load
setb $4015,$04 ; on
setb $400B,$08 ; start
delay 256*16-12 ; allow 16 clocks
setb $4015,0 ; off
.endif
rts
; Prints instructions for test
show_instructions:
.ifdef USING_DEVCART
rts
.endif
setw addr,filename
jsr print_str_addr
print_str " channel mixing test",{newline,newline}
print_str "1. Should play short tone.",{newline,newline}
setw addr,text
jsr print_str_addr
print_str {newline,newline}
print_str "3. Should play short tone.",{newline,newline}
print_str "Some clicking might occur between the two tones."
print_str "Also, a faint tone might be audible through headphones."
print_str newline,newline
.ifndef BUILD_NSF
delay_msec 1000
delay_msec 1000
delay_msec 1000
.endif
rts
; Disables PPU rendering and sets color to blacker-than-black,
; to reduce background sound
quiet_ppu:
.ifndef BUILD_NSF
jsr wait_vbl
setb PPUMASK,0
setb PPUADDR,$3F
setb PPUADDR,$00
setb PPUDATA,$0D; thanks to tepples for $0D idea
setb PPUADDR,$3F
setb PPUADDR,$00
.endif
rts
; Makes short tone, with silence on either side
short_tone:
setb $4015,0
delay_msec 300
setb $4015,$01
setb $4000,$BF
setb $4001,$7F
setb $4002,$6F
setb $4003,$00
delay_msec 300
setb $4015,0
delay_msec 300
rts
; Decrements 16-bit temp in constant time
; Time: 18 cycles
.macro dec_tempw
lda temp
sec
sbc #1
sta temp
lda temp+1
sbc #0
sta temp+1
.endmacro
; Be sure user code doesn't cross pages, affecting timing
.align 256

View file

@ -0,0 +1,43 @@
; Verifies DMC DAC and non-linear mixing
;
; Plays square channel at maximum volume. Cancels this
; to silence with inverse wave generated using DMC DAC.
; Scans over range of DMC DAC to test non-linearity.
.include "vol_shell.inc"
test_main:
setb $4000,$BF ; max volume
setb $4001,$7F ; disable sweep
setb $4002,0 ; period = 0
setb $4003,0
delay 5000 ; allow period to settle in
setb $4015,$01
ldx #82
ldy #0
setb $4002,$6F ; period = 896*2
setb $4003,0
delay 216-6
@1: delay 6
@2: stx $4011
delay 896-4-4
lda vols,x
sta $4011
delay 896-4-5-6
dey
bne @1
ldy #80
dex
bne @2
rts
.align 128
vols: .byte 23,25,26,27,28,29,31,32,33,34,36,37,38,39,40,42
.byte 43,44,45,47,48,49,50,52,53,54,55,57,58,59,60,62
.byte 63,64,65,67,68,69,70,72,73,74,75,77,78,79,81,82
.byte 83,84,86,87,88,89,91,92,93,95,96,97,98,100,101
.byte 102,104,105,106,107,109,110,111,113,114,115,117
.byte 118,119,120,122,123,124,126,127

View file

@ -0,0 +1,36 @@
# 32K iNES ROM with optional 8K CHR
MEMORY
{
ZP: start = $10, size = $E0; # leave $10 free at each end
RAM: start = $200, size = $500;
HEADER: start = 0, size = $10, fill=yes;
ROM: start = $8000, size = $7E00, fill=yes, fillval=$FF;
LOADER: start = $FE00, size = $100, fill=yes, fillval=$FF;
FF00: start = $FF00, size = $F4, fill=yes, fillval=$FF;
VECTORS:start = $FFF4, size = $C, fill=yes;
CHARS: start = 0, size = $2000, fillval=$FF;
}
SEGMENTS
{
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss,align=$100;
NVRAM: load = RAM, type = bss,define=yes, optional=yes;
HEADER: load = HEADER, type = ro;
CODE: load = ROM, type = ro, align=$100;
CODE2: load = ROM, type = ro, align=$100, optional=yes;
RODATA: load = ROM, type = ro, align=$100;
CHARS_PRG: load = ROM, type = ro, align=$200, optional=yes;
CHARS_PRG_ASCII:load = ROM, type = ro, align=$200, optional=yes;
LOADER: load = LOADER, type = ro, optional=yes;
FF00: load = FF00, type = ro, align=$100, optional=yes;
VECTORS: load = VECTORS, type = ro;
CHARS: load = CHARS, type = ro, align=$100, optional=yes;
CHARS_ASCII:load = CHARS, type = ro, align=$200, optional=yes;
}

View file

@ -0,0 +1,88 @@
; Verifies noise DAC and non-linear mixing
;
; Makes tone by running noise at maximum frequency to get
; soft noise, then toggling its volume between 0 and some
; other value. Cancels this to silence with inverse wave
; generated using DMC DAC.
CUSTOM_TEXT = 1
.include "vol_shell.inc"
text: .byte "2. Should fade noise in,",newline
.byte "and out, without any tone.",0
test_main:
jsr test_atten
jsr test_vols
rts
; Tests each noise volume
test_vols:
loop_n_times test,16
rts
test:
tay
eor #$3F ; x = noise volume
tax
lda vols,y ; y = DMC DAC value
tay
setb $4015,$08 ; enable
setb $400E,0 ; min period
setb $400F,0 ; start
setw temp,700
: lda #0
stx $400C
sta $4011
delay 896-10
lda #$30
sta $400C
sty $4011
delay 896-10-21
dec_tempw
bne :-
rts
vols:
.byte 13,12,11,10,9,9,8,7,6,5,4,4,3,2,1,0
.align 256
; Tests volume 15 over range of DMC DAC, starting
; at high end where it's most attenuated.
test_atten:
setb $4015,$08 ; enable
setb $400C,$3F ; max volume
setb $400E,0 ; min period
setb $400F,0 ; start
wait = 60
ldx #127
ldy #127-13
setb temp,wait
extra = 14-1
@1: delay extra
@2: lda #$30
sta $400C
stx $4011
delay 896-10
lda #$3F
sta $400C
sty $4011
delay 896-10-8-extra
dec temp
bne @1
setb temp,wait
dex
dey
bpl @2
rts

View file

@ -0,0 +1,121 @@
NES Tests Source Code
---------------------
Building with ca65
------------------
To assemble a test ROM with ca65, use the following commands:
ca65 -I common -o test.o source_filename_here.s
ld65 -C nes.cfg test.o -o test.nes
To assemble as an NSF music file:
ca65 -I common -o test.o source_filename_here.s -D BUILD_NSF
ld65 -C nsf.cfg test.o -o test.nsf
Note that some tests might only work when built as a ROM or NSF file,
but not both.
Some tests might include a ROM/NSF that has all the tests combined.
Building such a multi-test is complex and the necessary files aren't
included. Also, tests you build won't print their name if they fail,
since that requires special arrangements due to ca65's inability to
define strings on the command-line.
Shell
-----
Most tests are in a single source file, and make use of several library
source files from common/. This framework provides common services and
reduces code to only that which performs the actual test. Virtually all
tests include "shell.inc" at the beginning, which sets things up and
includes all the appropriate library files.
The reset handler does NES hardware initialization, clears RAM and PPU
nametables, then runs main. Main can exit by returning or jumping to
"exit" with an error code in A. Exit reports the code then goes into an
infinite loop. If the code is 0, it doesn't do anything, otherwise it
reports the code. Code 1 is reported as "Failed", and the rest as "Error
<code>".
Several routines are available to print values and text to the console.
The first time a line of text is completed, the console initializes the
PPU. Most print routines update a running CRC-32 checksum which can be
checked with check_crc. This allows ALL the output to be checked very
easily. If the checksum doesn't match, it is printed, so during
development the code can be run on a NES to get the correct checksum,
which is then typed into the test code. The checksum is also useful when
comparing different outputs; rather than having to examine all the
output, one need only compare checksums.
The default is to build an iNES ROM. Defining BUILD_NSF will build as an
NSF. The other build types aren't supported by the included code, due to
their complexity.
Macros
------
Some macros are used to make common operations more convenient, defined
in common/macros.inc. The left is equivalent to the right:
Macro Equivalent
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
blt bcc
bge bcs
jne label beq skip
jmp label
skip:
etc.
setb addr,byte lda #byte
sta addr
setw addr,word lda #<word
sta addr
lda #>word
sta addr+1
ldxy #value ldx #>value
ldy #<value
incw addr inc addr
bne skip
inc addr+1
skip:
inxy iny ; actual macro differs slightly,
bne skip ; to always take 7 clocks
inx
skip:
zp_byte name .zeropage
name: .res 1
.code
zp_res name,n .zeropage ; if n is omitted, uses 1
name: .res n
.code
bss_res name,n .bss ; if n is omitted, uses 1
name: .res n
.code
nv_res name,n .segment "NVRAM" ; if n is omitted, uses 1
name: .res n
.code
for_loop routine,begin,end,step
calls routine with A set to successive values
from begin through end, with given step
loop_n_times routine,count
calls routine with A from 0 to count-1
"NVRAM" is a section for variables that aren't cleared by the shell.
This is useful for values that are written in a custom reset handler and
later read from main, or values that are saved across resets.
--
Shay Green <gblargg@gmail.com>

View file

@ -0,0 +1,88 @@
; Verifies square DACs and non-linear mixing
;
; Plays two square waves in all totals from 0 to 31.
; Cancels this to silence with inverse wave generated
; using DMC DAC.
.include "vol_shell.inc"
test_main:
setb $4001,$7F ; disable sweep
setb $4005,$7F
setb $4002,0 ; period = 0
setb $4003,0
setb $4006,0
setb $4007,0
delay 5000 ; allow period to settle in
setb $4015,$03
ldx #$6F ; period = 896*2
ldy #$00
stx $4002
stx $4006
sty $4003
sty $4007
delay 175
extra = 27-1
ldx #-1
ldy #0
jmp @first
@1: delay extra
@2: lda dmc,x
sta $4011
delay 896-4-2
lda #127
sta $4011
delay 896-4-5-extra-4
dey
bne @1
@first: inx
lda sq1,x ; update square volumes
sta $4000
lda sq2,x
sta $4004
ldy #80
lda dmc,x
bne @2
rts
.align 256
dmc:
.byte $7F,$7B,$77,$77,$74,$74,$70,$70,$70,$6D,$6D,$6D,$6A,$6A,$6A,$6A
.byte $67,$67,$67,$67,$64,$64,$64,$64,$64,$61,$61,$61,$61,$61,$5E,$5E
.byte $5E,$5E,$5E,$5E,$5C,$5C,$5C,$5C,$5C,$5C,$59,$59,$59,$59,$59,$59
.byte $59,$57,$57,$57,$57,$57,$57,$57,$54,$54,$54,$54,$54,$54,$54,$54
.byte $52,$52,$52,$52,$52,$52,$52,$52,$50,$50,$50,$50,$50,$50,$50,$50
.byte $4E,$4E,$4E,$4E,$4E,$4E,$4E,$4C,$4C,$4C,$4C,$4C,$4C,$4C,$4A,$4A
.byte $4A,$4A,$4A,$4A,$48,$48,$48,$48,$48,$48,$46,$46,$46,$46,$46,$44
.byte $44,$44,$44,$44,$42,$42,$42,$42,$41,$41,$41,$41,$3F,$3F,$3F,$3E
.byte $3E,$3E,$3C,$3C,$3B,$3B,$39,$38,$00
.align 256
sq1:
.byte $B0,$B0,$B0,$B1,$B0,$B1,$B0,$B1,$B2,$B0,$B1,$B2,$B0,$B1,$B2,$B3
.byte $B0,$B1,$B2,$B3,$B0,$B1,$B2,$B3,$B4,$B0,$B1,$B2,$B3,$B4,$B0,$B1
.byte $B2,$B3,$B4,$B5,$B0,$B1,$B2,$B3,$B4,$B5,$B0,$B1,$B2,$B3,$B4,$B5
.byte $B6,$B0,$B1,$B2,$B3,$B4,$B5,$B6,$B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7
.byte $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7,$B1,$B2,$B3,$B4,$B5,$B6,$B7,$B8
.byte $B2,$B3,$B4,$B5,$B6,$B7,$B8,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$B4,$B5
.byte $B6,$B7,$B8,$B9,$B5,$B6,$B7,$B8,$B9,$BA,$B6,$B7,$B8,$B9,$BA,$B7
.byte $B8,$B9,$BA,$BB,$B8,$B9,$BA,$BB,$B9,$BA,$BB,$BC,$BA,$BB,$BC,$BB
.byte $BC,$BD,$BC,$BD,$BD,$BE,$BE,$BF
.align 256
sq2:
.byte $B0,$B1,$B2,$B1,$B3,$B2,$B4,$B3,$B2,$B5,$B4,$B3,$B6,$B5,$B4,$B3
.byte $B7,$B6,$B5,$B4,$B8,$B7,$B6,$B5,$B4,$B9,$B8,$B7,$B6,$B5,$BA,$B9
.byte $B8,$B7,$B6,$B5,$BB,$BA,$B9,$B8,$B7,$B6,$BC,$BB,$BA,$B9,$B8,$B7
.byte $B6,$BD,$BC,$BB,$BA,$B9,$B8,$B7,$BE,$BD,$BC,$BB,$BA,$B9,$B8,$B7
.byte $BF,$BE,$BD,$BC,$BB,$BA,$B9,$B8,$BF,$BE,$BD,$BC,$BB,$BA,$B9,$B8
.byte $BF,$BE,$BD,$BC,$BB,$BA,$B9,$BF,$BE,$BD,$BC,$BB,$BA,$B9,$BF,$BE
.byte $BD,$BC,$BB,$BA,$BF,$BE,$BD,$BC,$BB,$BA,$BF,$BE,$BD,$BC,$BB,$BF
.byte $BE,$BD,$BC,$BB,$BF,$BE,$BD,$BC,$BF,$BE,$BD,$BC,$BF,$BE,$BD,$BF
.byte $BE,$BD,$BF,$BE,$BF,$BE,$BF,$BF

View file

@ -0,0 +1,54 @@
; Verifies triangle DAC and non-linear mixing
;
; Plays triangle wave. Cancels this to silence with inverse
; wave generated using DMC DAC. Scans over range of DMC DAC
; to test non-linearity.
.include "vol_shell.inc"
test_main:
setb $4008,$FF
setb $400A,0
setb $400B,0
delay_msec 20
setb $4015,$04
setb $4009,0
wait = 8
lda #wait
sta temp
sta temp+1
ldy #127-41
extra = 13-1
setb $400A,$37
setb $400B,0
delay 28-extra
ldx #16
@1: delay extra
@2: inx
txa
and #$1F
tax
tya
clc
adc table,x
sta $4011
delay 3
dec_tempw
bne @1
lda #wait
sta temp
sta temp+1
dey
bne @2
rts
.align 32
table:
.byte 0,3,6,8,11,14,17,19,22,25,28,30,33,35,38,41
.byte 41,38,35,33,30,28,25,22,19,17,14,11,8,6,3,0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,129 @@
NES APU Reset Tests
--------------------
These tests verify initial APU state at power, and the effect of reset.
4015_cleared
------------
At power and reset, $4015 is cleared.
2) At power, $4015 should be cleared
3) At reset, $4015 should be cleared
4017_timing
-----------
At power, it is as if $00 were written to $4017,
then a 9-12 clock delay, then execution from address
in reset vector.
At reset, same as above, except last value written
to $4017 is written again, rather than $00.
The delay from when $00 was written to $4017 is
printed. Delay after NES being powered off for a
minute is usually 9.
2) Frame IRQ flag should be set later after power/reset
3) Frame IRQ flag should be set sooner after power/reset
4017_written
------------
At power, $4017 = $00.
At reset, $4017 mode is unchanged, but IRQ inhibit
flag is sometimes cleared.
2) At power, $4017 should be written with $00
3) At reset, $4017 should should be rewritten with last value written
irq_flag_cleared
----------------
At power and reset, IRQ flag is clear.
2) At power, flag should be clear
3) At reset, flag should be clear
len_ctrs_enabled
----------------
At power and reset, length counters are enabled.
2) At power, length counters should be enabled
3) At reset, length counters should be enabled, triangle unaffected
works_immediately
-----------------
At power and reset, $4017, $4015, and length counters work
immediately.
2) At power, writes should work immediately
3) At reset, writes should work immediately
Flashes, clicks, other glitches
-------------------------------
If a test prints "passed", it passed, even if there were some flashes or
odd sounds. Only a test which prints "done" at the end requires that you
watch/listen while it runs in order to determine whether it passed. Such
tests involve things which the CPU cannot directly test.
Alternate output
----------------
Tests generally print information on screen, but also report the final
result audibly, and output text to memory, in case the PPU doesn't work
or there isn't one, as in an NSF or a NES emulator early in development.
After the tests are done, the final result is reported as a series of
beeps (see below). For NSF builds, any important diagnostic bytes are
also reported as beeps, before the final result.
Output at $6000
---------------
All text output is written starting at $6004, with a zero-byte
terminator at the end. As more text is written, the terminator is moved
forward, so an emulator can print the current text at any time.
The test status is written to $6000. $80 means the test is running, $81
means the test needs the reset button pressed, but delayed by at least
100 msec from now. $00-$7F means the test has completed and given that
result code.
To allow an emulator to know when one of these tests is running and the
data at $6000+ is valid, as opposed to some other NES program, $DE $B0
$G1 is written to $6001-$6003.
Audible output
--------------
A byte is reported as a series of tones. The code is in binary, with a
low tone for 0 and a high tone for 1, and with leading zeroes skipped.
The first tone is always a zero. A final code of 0 means passed, 1 means
failure, and 2 or higher indicates a specific reason. See the source
code of the test for more information about the meaning of a test code.
They are found after the set_test macro. For example, the cause of test
code 3 would be found in a line containing set_test 3. Examples:
Tones Binary Decimal Meaning
- - - - - - - - - - - - - - - - - - - -
low 0 0 passed
low high 01 1 failed
low high low 010 2 error 2
NSF versions
------------
Many NSF-based tests require that the NSF player either not interrupt
the init routine with the play routine, or if it does, not interrupt the
play routine again if it hasn't returned yet. This is because many tests
need to run for a while without returning.
NSF versions also make periodic clicks to prevent the NSF player from
thinking the track is silent and thus ending the track before it's done
testing.
--
Shay Green <gblargg@gmail.com>

View file

@ -0,0 +1,60 @@
; At power and reset, $4015 is cleared.
CUSTOM_RESET=1
.include "shell.inc"
.include "run_at_reset.s"
nv_res log
reset:
; Begin mode 0
setb $4017,$00
; Start channels with zero volume
setb $4000,$00
setb $4001,$7F
setb $4002,$FF
setb $4003,$28
setb $4004,$00
setb $4005,$7F
setb $4006,$FF
setb $4007,$28
setb $4008,$7F
setb $400A,$FF
setb $400B,$28
setb $400C,$00
setb $400E,$00
setb $400F,$28
; If any of the low 4 bits of $4015 were set, then
; length counter of that channel would be non-zero,
; and that bit would read back as non-zero here:
lda $4015
sta log
jmp std_reset
main: jsr num_resets
bne first_reset
power: set_test 2,"At power, $4015 should be cleared"
lda log
and #$0F
jne test_failed
jsr prompt_to_reset
setb $4015,$0F
jmp wait_reset
first_reset:
set_test 3,"At reset, $4015 should be cleared"
lda log
and #$0F
jne test_failed
jmp tests_passed

View file

@ -0,0 +1,49 @@
; At power, it is as if $00 were written to $4017,
; then a 9-12 clock delay, then execution from address
; in reset vector.
;
; At reset, same as above, except last value written
; to $4017 is written again, rather than $00.
;
; The delay from when $00 was written to $4017 is
; printed. Delay after NES being powered off for a
; minute is usually 9.
CUSTOM_RESET=1
.include "shell.inc"
.include "run_at_reset.s"
nv_res count
reset: delay 29814-2
ldx #14
: lda $4015
and #$40
bne :+
delay 29831-4-2-2-4-2-3
lda $4015
dex
bne :-
: stx count
jmp std_reset
main: print_str "Delay after effective $4017 write: "
lda count
jsr print_dec
jsr print_newline
set_test 2,"Frame IRQ flag should be set later after power/reset"
lda count
cmp #13
jge test_failed
set_test 3,"Frame IRQ flag should be set sooner after power/reset"
lda count
cmp #6
jlt test_failed
jsr num_resets
jne tests_passed
jsr prompt_to_reset
jmp wait_reset

View file

@ -0,0 +1,73 @@
; At power, $4017 = $00.
; At reset, $4017 mode is unchanged, but IRQ inhibit
; flag is sometimes cleared.
CUSTOM_RESET=1
.include "shell.inc"
.include "run_at_reset.s"
nv_res log,4
reset:
setb $4015,$01
setb $4000,0
setb $4001,$7F
setb $4002,$FF
setb $4003,$28
delay 29831*2-5*6-9-7
lda $4015
sta log+0
lda $4015
sta log+1
delay 14887
lda $4015
sta log+2
lda $4015
sta log+3
jmp std_reset
main: jsr num_resets
bne first_reset
power:
set_test 2,"At power, $4017 should be written with $00"
lda log+0
and #$41
cmp #$41
jne test_failed
lda log+1
and #$01
jne test_failed
jsr prompt_to_reset
setb $4017,$40
jmp wait_reset
first_reset:
set_test 3,"At reset, $4017 should should be rewritten with last value written"
cmp #2
beq second_reset
lda log+0
and #$01
jeq test_failed
lda log+1
and #$01
jne test_failed
jsr prompt_to_reset
setb $4017,$80 ; put in other mode this time
jmp wait_reset
second_reset:
lda log+2
and #$01
jeq test_failed
lda log+3
and #$01
jne test_failed
jmp tests_passed

View file

@ -0,0 +1,92 @@
; Builds program as iNES ROM
; Default is 32K PRG and 8K CHR ROM, NROM (0)
.if 0 ; Options to set before .include "shell.inc":
CHR_RAM=1 ; Use CHR-RAM instead of CHR-ROM
CART_WRAM=1 ; Use mapper that supports 8K WRAM in cart
CUSTOM_MAPPER=n ; Specify mapper number
.endif
.ifndef CUSTOM_MAPPER
.ifdef CART_WRAM
CUSTOM_MAPPER = 2 ; UNROM
.else
CUSTOM_MAPPER = 0 ; NROM
.endif
.endif
;;;; iNES header
.ifndef CUSTOM_HEADER
.segment "HEADER"
.byte $4E,$45,$53,26 ; "NES" EOF
.ifdef CHR_RAM
.byte 2,0 ; 32K PRG, CHR RAM
.else
.byte 2,1 ; 32K PRG, 8K CHR
.endif
.byte CUSTOM_MAPPER*$10+$01 ; vertical mirroring
.endif
.ifndef CUSTOM_VECTORS
.segment "VECTORS"
.word -1,-1,-1, nmi, reset, irq
.endif
;;;; CHR-RAM/ROM
.ifdef CHR_RAM
.define CHARS "CHARS_PRG"
.segment CHARS
ascii_chr:
.segment "CHARS_PRG_ASCII"
.align $200
.incbin "ascii.chr"
ascii_chr_end:
.else
.define CHARS "CHARS"
.segment "CHARS_ASCII"
.align $200
.incbin "ascii.chr"
.res $1800
.endif
.segment CHARS
.res $10,0
;;;; Shell
.ifndef NEED_CONSOLE
NEED_CONSOLE=1
.endif
.segment "CODE"
.res $4000
.include "shell.s"
std_reset:
lda #0
sta PPUCTRL
sta PPUMASK
jmp run_shell
init_runtime:
.ifdef CHR_RAM
load_chr_ram
.endif
rts
post_exit:
jsr set_final_result
jsr play_hex
jmp forever
; This helps devcart recover after running test.
; It is never executed by test ROM.
.segment "LOADER"
.incbin "devcart.bin"
.code
.align 256

Some files were not shown because too many files have changed in this diff Show more