diff --git a/Submodules/UIKit/CMakeLists.txt b/Submodules/UIKit/CMakeLists.txt index f03546a..06f28b9 100644 --- a/Submodules/UIKit/CMakeLists.txt +++ b/Submodules/UIKit/CMakeLists.txt @@ -98,6 +98,39 @@ if (APPLE) lib/platforms/apple/ios/SkiaCtx_ios.mm ) endif () +elseif (PLATFORM_SWITCH) + target_sources(UIKit PRIVATE + lib/platforms/SkiaCtx_sdlBase.cpp + lib/platforms/switch/SkiaCtx_switch.cpp + ) + + find_package(PkgConfig REQUIRED) + pkg_check_modules(SDL2 REQUIRED sdl2) + message(STATUS "SDL2 Path: \"${SDL2_INCLUDE_DIRS}\"") + target_link_libraries(${PROJECT_NAME} PRIVATE ${SDL2_LIBRARIES}) + target_include_directories(${PROJECT_NAME} PUBLIC ${SDL2_INCLUDE_DIRS}) + + # GPU + target_link_libraries(UIKit PUBLIC EGL glapi GLESv2 drm_nouveau nx) + + + target_link_libraries(UIKit PUBLIC + ${EXTERN_PATH}/skia/out/horizon/libskia.a + ${EXTERN_PATH}/skia/out/horizon/libskparagraph.a + ${EXTERN_PATH}/skia/out/horizon/libskshaper.a + ${EXTERN_PATH}/skia/out/horizon/libskunicode_core.a + ${EXTERN_PATH}/skia/out/horizon/libskunicode_icu.a + ${EXTERN_PATH}/skia/out/horizon/libicu.a + ${EXTERN_PATH}/skia/out/horizon/libskcms.a + freetype + expat + jpeg + png + bz2 + z + + + ) endif () target_include_directories(UIKit PUBLIC @@ -118,4 +151,4 @@ if (APPLE) list(APPEND platform_libs "-framework Foundation" "-framework VideoToolbox" "-framework AVKit" "-framework MetalKit" "-framework CoreText") endif () -target_link_libraries(UIKit PRIVATE ${platform_libs}) \ No newline at end of file +target_link_libraries(UIKit PUBLIC ${platform_libs}) \ No newline at end of file diff --git a/Submodules/UIKit/include/UIEvent.h b/Submodules/UIKit/include/UIEvent.h index d71d2f6..8bd953b 100644 --- a/Submodules/UIKit/include/UIEvent.h +++ b/Submodules/UIKit/include/UIEvent.h @@ -2,6 +2,8 @@ #include #include +#include +#include namespace NXKit { diff --git a/Submodules/UIKit/include/platforms/switch/SkiaCtx_switch.h b/Submodules/UIKit/include/platforms/switch/SkiaCtx_switch.h new file mode 100644 index 0000000..6165d91 --- /dev/null +++ b/Submodules/UIKit/include/platforms/switch/SkiaCtx_switch.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include + +namespace NXKit { + +class SkiaCtx_switch: public SkiaCtx_sdlBase { +public: + SkiaCtx_switch(); + + sk_sp getBackbufferSurface() override; +// float getScaleFactor() override; + sk_sp directContext() override { return context; } + + + virtual void swapBuffers() override; + + virtual NXSize getSize() override; + + virtual float getScaleFactor() override; + +private: + SDL_Window *window = nullptr; + + sk_sp context; + sk_sp surface; + + void initContext(); +}; + +} diff --git a/Submodules/UIKit/lib/CABasicAnimation.cpp b/Submodules/UIKit/lib/CABasicAnimation.cpp index 7c381f1..baf6edb 100644 --- a/Submodules/UIKit/lib/CABasicAnimation.cpp +++ b/Submodules/UIKit/lib/CABasicAnimation.cpp @@ -1,4 +1,5 @@ #include +#include using namespace NXKit; diff --git a/Submodules/UIKit/lib/CADisplayLink.cpp b/Submodules/UIKit/lib/CADisplayLink.cpp index 26074f0..4dcbeab 100644 --- a/Submodules/UIKit/lib/CADisplayLink.cpp +++ b/Submodules/UIKit/lib/CADisplayLink.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace NXKit { std::vector CADisplayLink::activeLinks; @@ -18,4 +19,4 @@ namespace NXKit { isRunning = false; activeLinks.erase(std::remove(activeLinks.begin(), activeLinks.end(), this), activeLinks.end()); } -} \ No newline at end of file +} diff --git a/Submodules/UIKit/lib/Geometry.cpp b/Submodules/UIKit/lib/Geometry.cpp index 3f1d144..c872497 100644 --- a/Submodules/UIKit/lib/Geometry.cpp +++ b/Submodules/UIKit/lib/Geometry.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "NXAffineTransform.h" #include "NXTransform3D.h" diff --git a/Submodules/UIKit/lib/NXData.cpp b/Submodules/UIKit/lib/NXData.cpp index dc4f624..8d9c3dd 100644 --- a/Submodules/UIKit/lib/NXData.cpp +++ b/Submodules/UIKit/lib/NXData.cpp @@ -1,5 +1,5 @@ #include -//#include +#include #include //#ifdef USE_LIBROMFS @@ -45,7 +45,7 @@ std::shared_ptr NXData::fromPath(const std::string& path) { fileReader->close(fileReader); if (bytesRead == fileSize) { - return make_shared(buffer, fileSize, true); + return new_shared(buffer, fileSize, true); } else { delete[] buffer; return nullptr; diff --git a/Submodules/UIKit/lib/UIGestureRecognizer.cpp b/Submodules/UIKit/lib/UIGestureRecognizer.cpp index eacfb1b..4eb32c3 100644 --- a/Submodules/UIKit/lib/UIGestureRecognizer.cpp +++ b/Submodules/UIKit/lib/UIGestureRecognizer.cpp @@ -2,6 +2,8 @@ #include #include +#include + namespace NXKit { UIGestureRecognizer::UIGestureRecognizer(std::function)> onStateChanged): diff --git a/Submodules/UIKit/lib/platforms/SkiaCtx_sdlBase.cpp b/Submodules/UIKit/lib/platforms/SkiaCtx_sdlBase.cpp index 9d9d783..ee97f04 100644 --- a/Submodules/UIKit/lib/platforms/SkiaCtx_sdlBase.cpp +++ b/Submodules/UIKit/lib/platforms/SkiaCtx_sdlBase.cpp @@ -8,7 +8,17 @@ SkiaCtx_sdlBase::SkiaCtx_sdlBase() SDL_Init(SDL_INIT_EVERYTHING); Uint32 flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; -#ifdef USE_GLES +#ifdef __SWITCH__ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + + flags |= SDL_WINDOW_OPENGL; +#elif defined(USE_GLES) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); diff --git a/Submodules/UIKit/lib/platforms/switch/SkiaCtx_switch.cpp b/Submodules/UIKit/lib/platforms/switch/SkiaCtx_switch.cpp new file mode 100644 index 0000000..7a3d26b --- /dev/null +++ b/Submodules/UIKit/lib/platforms/switch/SkiaCtx_switch.cpp @@ -0,0 +1,213 @@ +#include + +#include "include/core/SkColorSpace.h" +#include +#include "include/gpu/ganesh/gl/GrGLDirectContext.h" +#include "include/gpu/ganesh/gl/GrGLInterface.h" +#include "include/gpu/ganesh/gl/GrGLBackendSurface.h" +#include "include/gpu/ganesh/gl/ios/GrGLMakeIOSInterface.h" +#include "include/gpu/ganesh/SkSurfaceGanesh.h" +#include "include/gpu/ganesh/GrDirectContext.h" +#include "include/gpu/ganesh/GrBackendSurface.h" +#include "include/gpu/ganesh/gl/GrGLAssembleInterface.h" +#include "include/gpu/ganesh/gl/GrGLInterface.h" +#include "include/private/base/SkTemplates.h" + +#include "include/gpu/ganesh/gl/egl/GrGLMakeEGLInterface.h" +#include "include/ports/SkFontMgr_empty.h" + +#include + + +// Include the main libnx system header, for Switch development +#include + +#include +#include +#include + +using namespace NXKit; + +static EGLDisplay s_display; +static EGLContext s_context; +static EGLSurface s_surface; + +static bool initEgl(NWindow* win) +{ + // Connect to the EGL default display + s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!s_display) + { + // LTRACEF("Could not connect to display! error: %d", eglGetError()); + goto _fail0; + } + + // Initialize the EGL display connection + eglInitialize(s_display, nullptr, nullptr); + + // Select OpenGL (Core) as the desired graphics API + if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) + { + // LTRACEF("Could not set API! error: %d", eglGetError()); + goto _fail1; + } + + // Get an appropriate EGL framebuffer configuration + EGLConfig config; + EGLint numConfigs; + static const EGLint framebufferAttributeList[] = + { + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + eglChooseConfig(s_display, framebufferAttributeList, &config, 1, &numConfigs); + if (numConfigs == 0) + { + // LTRACEF("No config found! error: %d", eglGetError()); + goto _fail1; + } + + // Create an EGL window surface + s_surface = eglCreateWindowSurface(s_display, config, win, nullptr); + if (!s_surface) + { + // LTRACEF("Surface creation failed! error: %d", eglGetError()); + goto _fail1; + } + + // Create an EGL rendering context + static const EGLint contextAttributeList[] = + { + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_MAJOR_VERSION_KHR, 4, + EGL_CONTEXT_MINOR_VERSION_KHR, 3, + EGL_NONE + }; + s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, contextAttributeList); + if (!s_context) + { + // LTRACEF("Context creation failed! error: %d", eglGetError()); + goto _fail2; + } + + // Connect the context to the surface + eglMakeCurrent(s_display, s_surface, s_surface, s_context); + return true; + +_fail2: + eglDestroySurface(s_display, s_surface); + s_surface = nullptr; +_fail1: + eglTerminate(s_display); + s_display = nullptr; +_fail0: + return false; +} + +static void deinitEgl() +{ + if (s_display) + { + eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (s_context) + { + eglDestroyContext(s_display, s_context); + s_context = nullptr; + } + if (s_surface) + { + eglDestroySurface(s_display, s_surface); + s_surface = nullptr; + } + eglTerminate(s_display); + s_display = nullptr; + } +} + +SkiaCtx_switch::SkiaCtx_switch() { + if (!initEgl(nwindowGetDefault())) + exit(1); + + + SDL_Init(SDL_INIT_EVERYTHING); + // Uint32 flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; + + // SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + // SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + // SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + // SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + // SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + // SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); + // SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + + // flags |= SDL_WINDOW_OPENGL; + // window = SDL_CreateWindow("Window", 12, 12, 1280, 720, flags); + // auto context = SDL_GL_CreateContext(window); + // SDL_GL_MakeCurrent(window, context); + + SkGraphics::Init(); + initContext(); + + // fontMgr = SkFontMgr_New_Custom_Empty(); +} + +void SkiaCtx_switch::initContext() { + auto interface = GrGLInterfaces::MakeEGL(); + auto ctx = GrDirectContexts::MakeGL(interface); +} + +//float SkiaCtx_switch::getScaleFactor() { +// return NSApplication.sharedApplication.keyWindow.backingScaleFactor; +//} + +sk_sp SkiaCtx_switch::getBackbufferSurface() { + auto size = getSize(); + if (_size.width == size.width && _size.height == size.height && surface != nullptr) { return surface; } + + _size = size; + + GrGLFramebufferInfo framebuffer_info; + framebuffer_info.fFormat = GL_RGBA8; + framebuffer_info.fFBOID = 0; + auto scaleFactor = getScaleFactor(); + GrBackendRenderTarget target = GrBackendRenderTargets::MakeGL(size.width * scaleFactor, + size.height * scaleFactor, + 0, 8, + framebuffer_info); + + SkSurfaceProps props; + + glViewport(0, 0, _size.width * scaleFactor, _size.height * scaleFactor); + surface = SkSurfaces::WrapBackendRenderTarget(context.get(), target, + kBottomLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, + nullptr, &props); + + return surface; +} + +std::unique_ptr NXKit::MakeSkiaCtx() { + return std::make_unique(); +} + +bool NXKit::platformRunLoop(std::function loop) { + return loop(); +} + +void SkiaCtx_switch::swapBuffers() { + eglSwapBuffers(s_display, s_surface); +} + +NXSize SkiaCtx_switch::getSize() { + return { 1280, 720 }; +} + +float SkiaCtx_switch::getScaleFactor() { + return 1; +} + diff --git a/Submodules/cmake/toolchain.cmake b/Submodules/cmake/toolchain.cmake index 6208612..fdf4dd9 100644 --- a/Submodules/cmake/toolchain.cmake +++ b/Submodules/cmake/toolchain.cmake @@ -69,7 +69,7 @@ if (PLATFORM_DESKTOP) set(CMAKE_TOOLCHAIN_FILE ${EXTERN_PATH}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE PATH "vcpkg toolchain file") elseif (PLATFORM_IOS) - message("Building for iOS") + message(STATUS "building for iOS") add_definitions( -DPLATFORM_IOS ) set(DEPLOYMENT_TARGET "15.0") @@ -81,6 +81,20 @@ elseif (PLATFORM_IOS) set(CMAKE_TOOLCHAIN_FILE ${EXTERN_PATH}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE PATH "vcpkg toolchain file") set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE ${EXTERN_PATH}/cmake/ios.toolchain.cmake CACHE PATH "ios toolchain file") set(CMAKE_XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2") # iphone, ipad +elseif (PLATFORM_SWITCH) + message(STATUS "building for SWITCH") + set(USE_GLES ON) + if (NOT DEFINED ENV{DEVKITPRO}) + message(FATAL_ERROR "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") + endif () + add_definitions( -DPLATFORM_SWITCH ) + set(DEVKITPRO $ENV{DEVKITPRO} CACHE BOOL "DEVKITPRO") + set(__SWITCH__ ON) + set(USE_SYSTEM_SDL ON) + set(CMAKE_C_FLAGS "-I${DEVKITPRO}/libnx/include -I${DEVKITPRO}/portlibs/switch/include -D__SWITCH__") + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + include(${DEVKITPRO}/cmake/Switch.cmake REQUIRED) + # message("${DEVKITPRO}/portlibs/switch/include") endif () if (USE_GLES) @@ -154,6 +168,13 @@ function(setup_project) set_target_properties(${PROJECT_NAME} PROPERTIES XCODE_EMBED_FRAMEWORKS ${EXTERN_PATH}/angle/ios/MetalANGLE.framework ) + elseif (PLATFORM_SWITCH) + add_custom_target(${PROJECT_NAME}.nro DEPENDS ${PROJECT_NAME} + COMMAND ${NX_NACPTOOL_EXE} --create "${PROJECT_NAME}" "${PROJECT_AUTHOR}" "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_ALTER}" ${PROJECT_NAME}.nacp --titleid=${PROJECT_TITLEID} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_RESOURCES} ${CMAKE_BINARY_DIR}/resources +# COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/resources/font + COMMAND ${NX_ELF2NRO_EXE} ${PROJECT_NAME}.elf ${PROJECT_NAME}.nro --icon=${PROJECT_ICON} --nacp=${PROJECT_NAME}.nacp + ) endif () # Include Submodules