diff --git a/CMakeLists.txt b/CMakeLists.txt index b118ce4ab..dafbb777f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,12 +111,16 @@ find_package(Git) if(GIT_FOUND) message(STATUS "Found GIT: ${GIT_EXECUTABLE}") # Get the current working branch - execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) + execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) # Get the latest abbreviated commit hash of the working branch - execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%ad WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_DATE OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE + GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE + GIT_COMMIT_HASH_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%ad WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE + GIT_COMMIT_DATE OUTPUT_STRIP_TRAILING_WHITESPACE) else() message(STATUS "Unable to find GIT, commit information will not be available") set(GIT_BRANCH "") diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index ccf36a531..21a4202fc 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/DataSpec ${CMAKE_SOURCE_DIR}/Runtime) add_subdirectory(locale) add_subdirectory(icons) +add_subdirectory(badging) atdna(atdna_Space.cpp Space.hpp) atdna(atdna_ResourceBrowser.cpp ResourceBrowser.hpp) @@ -36,6 +37,7 @@ add_executable(urde WIN32 MACOSX_BUNDLE target_link_libraries(urde UrdeLocales UrdeIcons + UrdeBadging RuntimeCommon DNAMP3 DNAMP2 DNAMP1 DNACommon specter specter-fonts freetype ${DATA_SPEC_LIBS} diff --git a/Editor/SplashScreen.cpp b/Editor/SplashScreen.cpp index db4da0aee..2e22a8159 100644 --- a/Editor/SplashScreen.cpp +++ b/Editor/SplashScreen.cpp @@ -1,5 +1,6 @@ #include "SplashScreen.hpp" #include "version.h" +#include "badging/Badging.hpp" namespace urde { @@ -17,6 +18,10 @@ namespace urde #define LINE_WIDTH 2 #define TEXT_MARGIN 10 +#define BADGE_WIDTH 551 +#define BADGE_HEIGHT 217 +#define BADGE_MARGIN 35 + SplashScreen::SplashScreen(ViewManager& vm, specter::ViewResources& res) : ModalWindow(res, vm.rootView(), specter::RectangleConstraint(SPLASH_WIDTH * res.pixelFactor(), @@ -95,6 +100,10 @@ void SplashScreen::updateContentOpacity(float opacity) m_buildInfo.reset(new specter::MultiLineTextView(res, *this, res.m_mainFont, specter::TextView::Alignment::Right)); m_buildInfo->typesetGlyphs(m_buildInfoStr, clearColor); + m_badgeIcon.reset(new specter::IconView(res, *this, GetBadge())); + m_badgeText.reset(new specter::TextView(res, *this, res.m_heading18, specter::TextView::Alignment::Right)); + m_badgeText->typesetGlyphs(BADGE_PHRASE, clearColor); + m_newButt.m_view.reset(new specter::Button(res, *this, &m_newProjBind, m_newString, nullptr, specter::Button::Style::Text)); m_openButt.m_view.reset(new specter::Button(res, *this, &m_openProjBind, m_openString, @@ -110,6 +119,8 @@ void SplashScreen::updateContentOpacity(float opacity) zeus::CColor color = zeus::CColor::lerp(clearColor, res.themeData().uiText(), opacity); m_title->colorGlyphs(color); m_buildInfo->colorGlyphs(color); + m_badgeIcon->setMultiplyColor({1.f, 1.f, 1.f, color.a}); + m_badgeText->colorGlyphs(color); m_newButt.m_view->colorGlyphs(color); m_openButt.m_view->colorGlyphs(color); m_extractButt.m_view->colorGlyphs(color); @@ -226,6 +237,12 @@ void SplashScreen::resized(const boo::SWindowRect& root, const boo::SWindowRect& centerRect.location[0] = root.size[0] / 2 - (SPLASH_WIDTH * pf / 2.0); centerRect.location[1] = root.size[1] / 2 - (SPLASH_HEIGHT * pf / 2.0); + boo::SWindowRect badgeRect = centerRect; + badgeRect.location[0] += LINE_WIDTH * pf; + badgeRect.location[1] += BADGE_MARGIN * pf; + badgeRect.size[0] = BADGE_WIDTH; + badgeRect.size[1] = BADGE_HEIGHT; + boo::SWindowRect textRect = centerRect; textRect.location[0] += TEXT_MARGIN * pf; textRect.location[1] += (SPLASH_HEIGHT - 36) * pf; @@ -236,6 +253,11 @@ void SplashScreen::resized(const boo::SWindowRect& root, const boo::SWindowRect& textRect.location[1] -= 5 * pf; m_buildInfo->resized(root, textRect); + textRect.location[0] = centerRect.location[0] + (SPLASH_WIDTH - TEXT_MARGIN) * pf; + textRect.location[1] = centerRect.location[1] + (BADGE_MARGIN + TEXT_MARGIN) * pf; + m_badgeIcon->resized(root, badgeRect); + m_badgeText->resized(root, textRect); + textRect.size[0] = m_newButt.m_view->nominalWidth(); textRect.size[1] = m_newButt.m_view->nominalHeight(); textRect.location[1] = centerRect.location[1] + 20 * pf; @@ -269,6 +291,8 @@ void SplashScreen::draw(boo::IGraphicsCommandQueue* gfxQ) { m_title->draw(gfxQ); m_buildInfo->draw(gfxQ); + m_badgeIcon->draw(gfxQ); + m_badgeText->draw(gfxQ); m_newButt.m_view->draw(gfxQ); m_openButt.m_view->draw(gfxQ); m_extractButt.m_view->draw(gfxQ); diff --git a/Editor/SplashScreen.hpp b/Editor/SplashScreen.hpp index 002977df5..1229848bb 100644 --- a/Editor/SplashScreen.hpp +++ b/Editor/SplashScreen.hpp @@ -6,6 +6,8 @@ #include #include #include +#include + #include "ViewManager.hpp" namespace urde @@ -22,6 +24,8 @@ class SplashScreen : public specter::ModalWindow std::unique_ptr m_title; std::string m_buildInfoStr; std::unique_ptr m_buildInfo; + std::unique_ptr m_badgeIcon; + std::unique_ptr m_badgeText; std::string m_newString; specter::ViewChild> m_newButt; diff --git a/Editor/ViewManager.cpp b/Editor/ViewManager.cpp index 139caca22..f79ca7be0 100644 --- a/Editor/ViewManager.cpp +++ b/Editor/ViewManager.cpp @@ -6,6 +6,7 @@ #include "locale/locale.hpp" #include "ResourceBrowser.hpp" #include "icons/icons.hpp" +#include "badging/Badging.hpp" #include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/Particle/CElectricDescription.hpp" #include "Runtime/Particle/CSwooshDescription.hpp" @@ -280,6 +281,7 @@ void ViewManager::init(boo::IApplication* app) m_mainCommandQueue = m_mainWindow->getCommandQueue(); m_viewResources.init(m_mainBooFactory, &m_fontCache, &m_themeData, pixelFactor); m_iconsToken = InitializeIcons(m_viewResources); + m_badgeToken = InitializeBadging(m_viewResources); m_viewResources.prepFontCacheAsync(m_mainWindow.get()); specter::RootView* root = SetupRootView(); m_showSplash = true; diff --git a/Editor/ViewManager.hpp b/Editor/ViewManager.hpp index 43dea3341..d232d73fb 100644 --- a/Editor/ViewManager.hpp +++ b/Editor/ViewManager.hpp @@ -31,6 +31,7 @@ class ViewManager : public specter::IViewManager specter::DefaultThemeData m_themeData; specter::ViewResources m_viewResources; boo::GraphicsDataToken m_iconsToken; + boo::GraphicsDataToken m_badgeToken; specter::Translator m_translator; std::unique_ptr m_mainWindow; boo::IGraphicsDataFactory* m_mainBooFactory = nullptr; diff --git a/Editor/badging/Badging.cpp b/Editor/badging/Badging.cpp new file mode 100644 index 000000000..38560ff2d --- /dev/null +++ b/Editor/badging/Badging.cpp @@ -0,0 +1,48 @@ +#include "Badging.hpp" +#include "athena/MemoryReader.hpp" +#include + +extern "C" uint8_t URDE_BADGE[]; +extern "C" size_t URDE_BADGE_SZ; + +namespace urde +{ +static logvisor::Module Log("URDE::badging"); +static specter::Icon g_BadgeIcon; + +boo::GraphicsDataToken InitializeBadging(specter::ViewResources& viewRes) +{ + athena::io::MemoryReader r(URDE_BADGE, URDE_BADGE_SZ); + + size_t fmt = r.readUint32Big(); + if (fmt != 16) + Log.report(logvisor::Fatal, "incorrect icon texture format"); + size_t width = r.readUint16Big(); + size_t height = r.readUint16Big(); + size_t mips = r.readUint32Big(); + size_t decompSz = r.readUint32Big(); + + std::unique_ptr texels(new uint8_t[decompSz]); + uLongf destSz = decompSz; + size_t pos = r.position(); + if (uncompress(texels.get(), &destSz, URDE_BADGE + pos, URDE_BADGE_SZ - pos) != Z_OK) + Log.report(logvisor::Fatal, "unable to decompress badge"); + + return viewRes.m_factory->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool + { + specter::IconAtlas<1, 1> atlas; + + atlas.initializeAtlas(ctx.newStaticTexture(width, height, mips, + boo::TextureFormat::RGBA8, + texels.get(), destSz)); + g_BadgeIcon = atlas.getIcon(0, 0); + return true; + }); +} + +specter::Icon& GetBadge() +{ + return g_BadgeIcon; +} + +} diff --git a/Editor/badging/Badging.hpp b/Editor/badging/Badging.hpp new file mode 100644 index 000000000..ec8753b5f --- /dev/null +++ b/Editor/badging/Badging.hpp @@ -0,0 +1,17 @@ +#ifndef __URDE_BADGING_HPP__ +#define __URDE_BADGING_HPP__ + +#include "specter/ViewResources.hpp" + +namespace urde +{ +boo::GraphicsDataToken InitializeBadging(specter::ViewResources& viewRes); + +specter::Icon& GetBadge(); +} + +#ifndef BADGE_PHRASE +#define BADGE_PHRASE "Prototype" +#endif + +#endif // __URDE_BADGING_HPP__ diff --git a/Editor/badging/CMakeLists.txt b/Editor/badging/CMakeLists.txt new file mode 100644 index 000000000..0b8e14cd1 --- /dev/null +++ b/Editor/badging/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_policy(SET CMP0053 OLD) + + +include_directories(${LIBPNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) +add_executable(packbadge packbadge.c) +target_link_libraries(packbadge ${PNG_LIB} ${ZLIB_LIBRARIES}) + +add_custom_command(OUTPUT badge.bin COMMAND $ + ARGS ${CMAKE_CURRENT_SOURCE_DIR}/badge.png + ${CMAKE_CURRENT_BINARY_DIR}/badge.bin + MAIN_DEPENDENCY badge.png COMMENT "Generating badge.bin") + +bintoc(badge.c ${CMAKE_CURRENT_BINARY_DIR}/badge.bin URDE_BADGE) +add_library(UrdeBadging + badge.c badge.bin + Badging.hpp Badging.cpp) diff --git a/Editor/badging/badge.png b/Editor/badging/badge.png new file mode 100644 index 000000000..925dd90e9 Binary files /dev/null and b/Editor/badging/badge.png differ diff --git a/Editor/badging/packbadge.c b/Editor/badging/packbadge.c new file mode 100644 index 000000000..4a1b84c00 --- /dev/null +++ b/Editor/badging/packbadge.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include + +#if __FreeBSD__ +#include +#endif + +#if _WIN32 +#define _bswap32(v) _byteswap_ulong(v) +#define _bswap16(v) _byteswap_ushort(v) +#define WIN32_LEAN_AND_MEAN +#include +#else +#define _bswap32(v) __builtin_bswap32(v) +#define _bswap16(v) __builtin_bswap16(v) +#endif + +int main(int argc, char* argv[]) +{ + if (argc < 3) + { + fprintf(stderr, "Usage: packbadge \n"); + return 1; + } + + /* Validate input */ + FILE* fp = fopen(argv[1], "rb"); + if (!fp) + { + fprintf(stderr, "'%s' is not able to be opened for reading as a regular file\n", argv[1]); + return 1; + } + + FILE* ofp = fopen(argv[2], "wb"); + if (!ofp) + { + fprintf(stderr, "'%s' is not able to be opened for writing as a regular file\n", argv[2]); + return 1; + } + + size_t decompSz = 0; + int numMips = 1; + + z_stream z = {0}; + size_t rowSz = 0; + uLong rowSzC = 0; + png_bytep row; + png_bytep rowC; + + /* Get PNG data */ + char header[8]; + fread(header, 1, 8, fp); + if (png_sig_cmp((png_const_bytep)header, 0, 8)) + { + fprintf(stderr, "invalid PNG signature in '%s'\n", argv[1]); + fclose(fp); + fclose(ofp); + return 1; + } + + png_structp pngRead = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pngRead) + { + fprintf(stderr, "unable to initialize libpng\n"); + fclose(fp); + fclose(ofp); + return 1; + } + png_infop info = png_create_info_struct(pngRead); + if (!info) + { + fprintf(stderr, "unable to initialize libpng info\n"); + fclose(fp); + fclose(ofp); + return 1; + } + + if (setjmp(png_jmpbuf(pngRead))) + { + fprintf(stderr, "unable to initialize libpng I/O for '%s'\n", argv[1]); + fclose(fp); + fclose(ofp); + return 1; + } + + png_init_io(pngRead, fp); + png_set_sig_bytes(pngRead, 8); + + png_read_info(pngRead, info); + + png_uint_32 width = png_get_image_width(pngRead, info); + png_uint_32 height = png_get_image_height(pngRead, info); + decompSz = width * height * 4; + png_byte colorType = png_get_color_type(pngRead, info); + png_byte bitDepth = png_get_bit_depth(pngRead, info); + + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + { + fprintf(stderr, "'%s' is not in RGBA color mode\n", argv[1]); + fclose(fp); + fclose(ofp); + return 1; + } + + if (bitDepth != 8) + { + fprintf(stderr, "'%s' is not 8 bits-per-channel\n", argv[1]); + fclose(fp); + fclose(ofp); + return 1; + } + + if (setjmp(png_jmpbuf(pngRead))) + { + fprintf(stderr, "unable to read image in '%s'\n", argv[1]); + fclose(fp); + fclose(ofp); + return 1; + } + + uint32_t fmt = _bswap32(16); + uint16_t w = _bswap16(width); + uint16_t h = _bswap16(height); + uint32_t mips = _bswap32(numMips); + uint32_t dsz = _bswap32(decompSz); + fwrite(&fmt, 1, 4, ofp); + fwrite(&w, 1, 2, ofp); + fwrite(&h, 1, 2, ofp); + fwrite(&mips, 1, 4, ofp); + fwrite(&dsz, 1, 4, ofp); + + rowSz = width*4; + rowSzC = compressBound(rowSz); + deflateInit(&z, Z_DEFAULT_COMPRESSION); + + row = malloc(rowSz); + rowC = malloc(rowSzC); + + for (png_uint_32 r=0 ; r