diff --git a/data/gui.xml b/data/gui.xml index fbc1a44b9..29ff8d768 100644 --- a/data/gui.xml +++ b/data/gui.xml @@ -21,7 +21,6 @@ - @@ -510,6 +509,9 @@ + + + diff --git a/data/strings/en.ini b/data/strings/en.ini index 8959434fb..d03409ae1 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -400,6 +400,7 @@ SavePalette = Save Palette Screenshot = Screenshot Screenshot_Open = Take & Open Screenshot Screenshot_Save = Take & Save Screenshot +Screenshot_Steam = Take & Add Screenshot to Steam Screenshot_sRGB = (sRGB Color Profile) Screenshot_DisplayCS = (Display Color Profile) Scroll = Scroll {0} diff --git a/src/app/commands/screenshot.cpp b/src/app/commands/screenshot.cpp index 84f09f9e7..2af92ce97 100644 --- a/src/app/commands/screenshot.cpp +++ b/src/app/commands/screenshot.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2019 Igara Studio S.A. +// Copyright (C) 2019-2020 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -17,15 +17,23 @@ #include "app/file/file.h" #include "app/i18n/strings.h" #include "app/resource_finder.h" +#include "base/buffer.h" #include "base/fs.h" #include "doc/cel.h" #include "doc/color.h" +#include "doc/image_impl.h" #include "doc/layer.h" #include "doc/sprite.h" #include "fmt/format.h" #include "os/display.h" #include "os/surface.h" +#include "ui/alert.h" #include "ui/manager.h" +#include "ui/scale.h" + +#ifdef ENABLE_STEAM + #include "steam/steam.h" +#endif namespace app { @@ -34,6 +42,9 @@ using namespace ui; struct ScreenshotParams : public NewParams { Param save { this, false, "save" }; Param srgb { this, true, "srgb" }; +#ifdef ENABLE_STEAM + Param steam { this, false, "steam" }; +#endif }; class ScreenshotCommand : public CommandWithNewParams { @@ -85,9 +96,11 @@ void ScreenshotCommand::onExecute(Context* ctx) doc::Cel* cel = spr->firstLayer()->cel(0); doc::Image* img = cel->image(); + const int w = img->width(); + const int h = img->height(); - for (int y=0; yheight(); ++y) { - for (int x=0; xwidth(); ++x) { + for (int y=0; ygetPixel(x, y); img->putPixel(x, y, doc::rgba(gfx::getr(c), @@ -103,6 +116,34 @@ void ScreenshotCommand::onExecute(Context* ctx) if (params().srgb()) cmd::convert_color_profile(spr, gfx::ColorSpace::MakeSRGB()); + if (params().steam()) { +#ifdef ENABLE_STEAM + if (auto steamAPI = steam::SteamAPI::instance()) { + // Get image again (cmd::convert_color_profile() might have changed it) + img = cel->image(); + + const int scale = display->scale(); + base::buffer rgbBuffer(3*w*h*scale*scale); + int c = 0; + doc::LockImageBits bits(img); + for (int y=0; y(img, x, y); + for (int j=0; jwriteScreenshot(&rgbBuffer[0], rgbBuffer.size(), w*scale, h*scale)) + return; + } +#endif + } + if (params().save()) { save_document(ctx, doc.get()); } @@ -115,7 +156,9 @@ void ScreenshotCommand::onExecute(Context* ctx) std::string ScreenshotCommand::onGetFriendlyName() const { std::string name; - if (params().save()) + if (params().steam()) + name = Strings::commands_Screenshot_Steam(); + else if (params().save()) name = Strings::commands_Screenshot_Save(); else name = Strings::commands_Screenshot_Open(); diff --git a/src/steam/LICENSE.txt b/src/steam/LICENSE.txt index 9a182c0f3..aed3f772b 100644 --- a/src/steam/LICENSE.txt +++ b/src/steam/LICENSE.txt @@ -1,3 +1,4 @@ +Copyright (c) 2020 Igara Studio S.A. Copyright (c) 2016 David Capello Permission is hereby granted, free of charge, to any person obtaining diff --git a/src/steam/steam.cpp b/src/steam/steam.cpp index 3b9e2b5ce..0ecd0e94c 100644 --- a/src/steam/steam.cpp +++ b/src/steam/steam.cpp @@ -1,4 +1,5 @@ // Aseprite Steam Wrapper +// Copyright (c) 2020 Igara Studio S.A. // Copyright (c) 2016 David Capello // // This file is released under the terms of the MIT license. @@ -12,13 +13,22 @@ #include "base/dll.h" #include "base/fs.h" +#include "base/ints.h" #include "base/log.h" #include "base/string.h" namespace steam { -typedef bool (*SteamAPI_Init_Func)(); -typedef void (*SteamAPI_Shutdown_Func)(); +typedef uint32_t ScreenshotHandle; +typedef void* ISteamScreenshots; + +// Steam main API +typedef bool __cdecl (*SteamAPI_Init_Func)(); +typedef void __cdecl (*SteamAPI_Shutdown_Func)(); + +// ISteamScreenshots +typedef ISteamScreenshots* __cdecl (*SteamAPI_SteamScreenshots_v003_Func)(); +typedef ScreenshotHandle __cdecl (*SteamAPI_ISteamScreenshots_WriteScreenshot_Func)(ISteamScreenshots*, void*, uint32_t, int, int); #ifdef _WIN32 #ifdef _WIN64 @@ -32,9 +42,11 @@ typedef void (*SteamAPI_Shutdown_Func)(); #define STEAM_API_DLL_FILENAME "libsteam_api.so" #endif +#define GETPROC(name) base::get_dll_proc(m_steamLib, #name) + class SteamAPI::Impl { public: - Impl() : m_initialized(false) { + Impl() { m_steamLib = base::load_dll( base::join_path(base::get_file_path(base::get_app_path()), STEAM_API_DLL_FILENAME)); @@ -43,18 +55,19 @@ public: return; } - auto SteamAPI_Init = base::get_dll_proc(m_steamLib, "SteamAPI_Init"); + auto SteamAPI_Init = GETPROC(SteamAPI_Init); if (!SteamAPI_Init) { LOG("STEAM: SteamAPI_Init not found...\n"); return; } + // Call SteamAPI_Init() to connect to Steam if (!SteamAPI_Init()) { LOG("STEAM: Steam is not initialized...\n"); return; } - LOG("STEAM: Steam initialized...\n"); + LOG("STEAM: Steam initialized\n"); m_initialized = true; } @@ -62,7 +75,7 @@ public: if (!m_steamLib) return; - auto SteamAPI_Shutdown = base::get_dll_proc(m_steamLib, "SteamAPI_Shutdown"); + auto SteamAPI_Shutdown = GETPROC(SteamAPI_Shutdown); if (SteamAPI_Shutdown) { LOG("STEAM: Steam shutdown...\n"); SteamAPI_Shutdown(); @@ -75,19 +88,55 @@ public: return m_initialized; } + bool writeScreenshot(void* rgbBuffer, + uint32_t sizeInBytes, + int width, int height) { + if (!m_initialized) + return false; + + auto SteamScreenshots = GETPROC(SteamAPI_SteamScreenshots_v003); + auto WriteScreenshot = GETPROC(SteamAPI_ISteamScreenshots_WriteScreenshot); + if (!SteamScreenshots || !WriteScreenshot) { + LOG("STEAM: Error getting Steam Screenshot API functions\n"); + return false; + } + + auto screenshots = SteamScreenshots(); + if (!screenshots) { + LOG("STEAM: Error getting Steam Screenshot API instance\n"); + return false; + } + + WriteScreenshot(screenshots, rgbBuffer, sizeInBytes, width, height); + return true; + } + private: - base::dll m_steamLib; - bool m_initialized; + bool m_initialized = false; + base::dll m_steamLib = nullptr; }; +SteamAPI* g_instance = nullptr; + +// static +SteamAPI* SteamAPI::instance() +{ + return g_instance; +} + SteamAPI::SteamAPI() : m_impl(new Impl) { + ASSERT(g_instance == nullptr); + g_instance = this; } SteamAPI::~SteamAPI() { delete m_impl; + + ASSERT(g_instance == this); + g_instance = nullptr; } bool SteamAPI::initialized() const @@ -95,4 +144,11 @@ bool SteamAPI::initialized() const return m_impl->initialized(); } +bool SteamAPI::writeScreenshot(void* rgbBuffer, + uint32_t sizeInBytes, + int width, int height) +{ + return m_impl->writeScreenshot(rgbBuffer, sizeInBytes, width, height); +} + } // namespace steam diff --git a/src/steam/steam.h b/src/steam/steam.h index 236682c5a..664e211f1 100644 --- a/src/steam/steam.h +++ b/src/steam/steam.h @@ -1,4 +1,5 @@ // Aseprite Steam Wrapper +// Copyright (c) 2020 Igara Studio S.A. // Copyright (c) 2016 David Capello // // This file is released under the terms of the MIT license. @@ -12,11 +13,17 @@ namespace steam { class SteamAPI { public: + static SteamAPI* instance(); + SteamAPI(); ~SteamAPI(); bool initialized() const; + bool writeScreenshot(void* rgbBuffer, + uint32_t sizeInBytes, + int width, int height); + private: class Impl; Impl* m_impl;