diff --git a/Content/Documentation/WickedEngine-Documentation.md b/Content/Documentation/WickedEngine-Documentation.md index 0a70cabf7..ef0e43127 100644 --- a/Content/Documentation/WickedEngine-Documentation.md +++ b/Content/Documentation/WickedEngine-Documentation.md @@ -302,6 +302,7 @@ Calls Render for the active RenderPath and wakes up scripts that are waiting for Calls Compose for the active RenderPath Note: the splash_screen texture of the application can be created before application is initialized, in this case this texture will be shown as a full screen image (with cropping, if necessary) while the engine initialization hasn't finished. The splash_screen texture will be also created automatically if a splash_screen.png file is found in the working directory. If a splash screen is not used, then the intialization logging screen will be shown at startup. +Warning: if you load a splash screen yourself with the resource manager, note that mipmaps will not be generated while the engine is not yet initialized. You can use the Application::splash_screen_subresource to specify which mipmap to use for the image by using the GraphicsDevice::CreateSubresource() method. This will be handled automatically if you use the default splash_screen.png file. ### RenderPath [[Header]](../../WickedEngine/wiRenderPath.h) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index c1354b0cf..456837318 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -5243,6 +5243,13 @@ Texture EditorComponent::CreateThumbnail(Texture texture, uint32_t target_width, current_height *= 4; } + // It is invalid top create texture above 16K resolution, so force downsize if this happens: + while (current_width > 16384 || current_height > 16384) + { + current_width /= 2; + current_height /= 2; + } + // Crop target: { TextureDesc desc = thumbnail.desc; diff --git a/Editor/ProjectCreatorWindow.cpp b/Editor/ProjectCreatorWindow.cpp index 72ec160c4..6e006382e 100644 --- a/Editor/ProjectCreatorWindow.cpp +++ b/Editor/ProjectCreatorWindow.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "ProjectCreatorWindow.h" +#include "Utility/win32ico.h" + using namespace wi::ecs; using namespace wi::scene; @@ -217,6 +219,10 @@ end) { wi::helper::saveTextureToFile(iconResource.GetTexture(), directory + "icon.png"); wi::helper::saveTextureToFile(iconResource.GetTexture(), directory + "icon.ico"); + + //wi::vector cursordata; + //wi::helper::CreateCursorFromTexture(iconResource.GetTexture(), 4, 4, cursordata); + //wi::helper::FileWrite(directory + "cursor.cur", cursordata.data(), cursordata.size()); } if (thumbnailResource.IsValid()) { @@ -287,38 +293,6 @@ end) { wi::graphics::Texture tex = iconResource.GetTexture(); - struct ICONDIR - { - uint16_t idReserved; // Reserved (must be 0) - uint16_t idType; // Resource Type (1 for icon) - uint16_t idCount; // Number of images - }; - struct ICONDIRENTRY - { - uint8_t bWidth; // Width, in pixels - uint8_t bHeight; // Height, in pixels - uint8_t bColorCount; // Number of colors (0 if >= 8bpp) - uint8_t bReserved; // Reserved (must be 0) - uint16_t wPlanes; // Color Planes - uint16_t wBitCount; // Bits per pixel - uint32_t dwBytesInRes; // Size of image data - uint32_t dwImageOffset;// Offset to image data - }; - struct BITMAPINFOHEADER - { - uint32_t biSize; // Size of this header - int32_t biWidth; // Width in pixels - int32_t biHeight; // Height in pixels (doubled for icon) - uint16_t biPlanes; // Number of color planes - uint16_t biBitCount; // Bits per pixel - uint32_t biCompression;// Compression method - uint32_t biSizeImage; // Size of image data - int32_t biXPelsPerMeter; // Horizontal resolution - int32_t biYPelsPerMeter; // Vertical resolution - uint32_t biClrUsed; // Colors used - uint32_t biClrImportant; // Important colors - }; - const int resolutions[] = {128,64,32}; for (int res : resolutions) @@ -326,9 +300,9 @@ end) const uint32_t pixelCount = res * res; const uint32_t rgbDataSize = pixelCount * 4; // 32-bit RGBA const uint32_t maskSize = ((res + 7) / 8) * res; // 1-bit mask, padded to byte - const uint32_t bmpInfoHeaderSize = sizeof(BITMAPINFOHEADER); + const uint32_t bmpInfoHeaderSize = sizeof(ico::BITMAPINFOHEADER); - BITMAPINFOHEADER bmpHeader = { + ico::BITMAPINFOHEADER bmpHeader = { bmpInfoHeaderSize, // Size of header int32_t(res), // Width int32_t(res * 2), // Height (doubled for XOR + AND mask) @@ -354,7 +328,7 @@ end) if (wi::helper::saveTextureToMemoryFile(editor->CreateThumbnail(tex, res, res, false), "ico", iconfiledata)) // note: individual mip thumbnails at this point! { // replace the BMP header and data part: - std::copy(iconfiledata.begin() + sizeof(ICONDIR) + sizeof(ICONDIRENTRY), iconfiledata.end(), it); + std::copy(iconfiledata.begin() + sizeof(ico::ICONDIR) + sizeof(ico::ICONDIRENTRY), iconfiledata.end(), it); wilog("\tOverwritten Win32 icon at %d * %d resolution", res, res); } } diff --git a/WickedEngine/Utility/win32ico.h b/WickedEngine/Utility/win32ico.h new file mode 100644 index 000000000..c00ba4719 --- /dev/null +++ b/WickedEngine/Utility/win32ico.h @@ -0,0 +1,45 @@ +#ifndef WIN32_ICO_H +#define WIN32_ICO_H + +// ICO image format is for storing multiple images in a single file with max 256 dimension, to be used with icons and cursors +// Structure: +// ICONDIR +// ICONDIRENTRY * imageCount +// (BITMAPINFOHEADER, BGRA pixel data, opacity bitmask) * imageCount + +namespace ico +{ + struct ICONDIR + { + unsigned short idReserved; // Reserved (must be 0) + unsigned short idType; // Resource Type (1 for icon, 2 for cursor) + unsigned short idCount; // Number of images + }; + struct ICONDIRENTRY + { + unsigned char bWidth; // Width, in pixels + unsigned char bHeight; // Height, in pixels + unsigned char bColorCount; // Number of colors (0 if >= 8bpp) + unsigned char bReserved; // Reserved (must be 0) + unsigned short wPlanes; // Color Planes | hotspotX for cursor + unsigned short wBitCount; // Bits per pixel | hotspotY for cursor + unsigned int dwBytesInRes; // Size of image data + unsigned int dwImageOffset; // Offset to image data + }; + struct BITMAPINFOHEADER + { + unsigned int biSize; // Size of this header + int biWidth; // Width in pixels + int biHeight; // Height in pixels (doubled for icon) + unsigned short biPlanes; // Number of color planes + unsigned short biBitCount; // Bits per pixel + unsigned int biCompression; // Compression method + unsigned int biSizeImage; // Size of image data + int biXPelsPerMeter; // Horizontal resolution + int biYPelsPerMeter; // Vertical resolution + unsigned int biClrUsed; // Colors used + unsigned int biClrImportant; // Important colors + }; +} + +#endif // WIN32_ICO_H diff --git a/WickedEngine/WickedEngine_SOURCE.vcxitems b/WickedEngine/WickedEngine_SOURCE.vcxitems index 8144e2018..1b42b3ab0 100644 --- a/WickedEngine/WickedEngine_SOURCE.vcxitems +++ b/WickedEngine/WickedEngine_SOURCE.vcxitems @@ -317,6 +317,7 @@ + diff --git a/WickedEngine/WickedEngine_SOURCE.vcxitems.filters b/WickedEngine/WickedEngine_SOURCE.vcxitems.filters index f1d9e12be..7c8701c20 100644 --- a/WickedEngine/WickedEngine_SOURCE.vcxitems.filters +++ b/WickedEngine/WickedEngine_SOURCE.vcxitems.filters @@ -1395,6 +1395,9 @@ ENGINE\Scripting\LuaBindings + + UTILITY + diff --git a/WickedEngine/wiApplication.cpp b/WickedEngine/wiApplication.cpp index 3848d6516..83d9a8b99 100644 --- a/WickedEngine/wiApplication.cpp +++ b/WickedEngine/wiApplication.cpp @@ -159,6 +159,7 @@ namespace wi if (resource.IsValid()) { splash_screen = resource.GetTexture(); + splash_screen_subresource = graphicsDevice->CreateSubresource(&splash_screen, SubresourceType::SRV, 0, 1, 0, 1); // only first mip! mipgen is not initialized at this point... } } } @@ -190,6 +191,7 @@ namespace wi { fx.enableLinearOutputMapping(9); } + fx.image_subresource = splash_screen_subresource; wi::image::Draw(&splash_screen, fx, cmd); } } diff --git a/WickedEngine/wiApplication.h b/WickedEngine/wiApplication.h index 262472f64..a98db7def 100644 --- a/WickedEngine/wiApplication.h +++ b/WickedEngine/wiApplication.h @@ -52,7 +52,9 @@ namespace wi wi::graphics::SwapChain swapChain; wi::Canvas canvas; wi::platform::window_type window; + wi::graphics::Texture splash_screen; + int splash_screen_subresource = -1; // Runs the main engine loop void Run(); diff --git a/WickedEngine/wiHelper.cpp b/WickedEngine/wiHelper.cpp index 052713501..f883471b6 100644 --- a/WickedEngine/wiHelper.cpp +++ b/WickedEngine/wiHelper.cpp @@ -11,6 +11,7 @@ #include "Utility/stb_image_write.h" #include "Utility/zstd/zstd.h" #include "Utility/portable-file-dialogs.h" +#include "Utility/win32ico.h" #include #include @@ -677,43 +678,11 @@ namespace wi::helper if (!extension.compare("ICO")) { - struct ICONDIR - { - uint16_t idReserved; // Reserved (must be 0) - uint16_t idType; // Resource Type (1 for icon) - uint16_t idCount; // Number of images - }; - struct ICONDIRENTRY - { - uint8_t bWidth; // Width, in pixels - uint8_t bHeight; // Height, in pixels - uint8_t bColorCount; // Number of colors (0 if >= 8bpp) - uint8_t bReserved; // Reserved (must be 0) - uint16_t wPlanes; // Color Planes - uint16_t wBitCount; // Bits per pixel - uint32_t dwBytesInRes; // Size of image data - uint32_t dwImageOffset;// Offset to image data - }; - struct BITMAPINFOHEADER - { - uint32_t biSize; // Size of this header - int32_t biWidth; // Width in pixels - int32_t biHeight; // Height in pixels (doubled for icon) - uint16_t biPlanes; // Number of color planes - uint16_t biBitCount; // Bits per pixel - uint32_t biCompression;// Compression method - uint32_t biSizeImage; // Size of image data - int32_t biXPelsPerMeter; // Horizontal resolution - int32_t biYPelsPerMeter; // Vertical resolution - uint32_t biClrUsed; // Colors used - uint32_t biClrImportant; // Important colors - }; - const uint32_t minsize = 32; - size_t filesize = sizeof(ICONDIR); + size_t filesize = sizeof(ico::ICONDIR); - ICONDIR icondir = { 0,1,0 }; + ico::ICONDIR icondir = { 0,1,0 }; for (auto& mip : mips) { @@ -722,7 +691,7 @@ namespace wi::helper if (mip.width < minsize || mip.height < minsize) break; icondir.idCount++; - filesize += sizeof(ICONDIRENTRY); + filesize += sizeof(ico::ICONDIRENTRY); } if (icondir.idCount < 1) @@ -742,15 +711,15 @@ namespace wi::helper const uint32_t pixelCount = mip.width * mip.height; const uint32_t rgbDataSize = pixelCount * 4; // 32-bit RGBA const uint32_t maskSize = ((mip.width + 7) / 8) * mip.height; // 1-bit mask, padded to byte - const uint32_t imageDataSize = sizeof(BITMAPINFOHEADER) + rgbDataSize + maskSize; + const uint32_t imageDataSize = sizeof(ico::BITMAPINFOHEADER) + rgbDataSize + maskSize; filesize += imageDataSize; } filedata.resize(filesize); uint8_t* ptr = filedata.data(); - std::memcpy(ptr, &icondir, sizeof(ICONDIR)); - ptr += sizeof(ICONDIR); + std::memcpy(ptr, &icondir, sizeof(ico::ICONDIR)); + ptr += sizeof(ico::ICONDIR); for (auto& mip : mips) { @@ -762,9 +731,9 @@ namespace wi::helper const uint32_t pixelCount = mip.width * mip.height; const uint32_t rgbDataSize = pixelCount * 4; // 32-bit RGBA const uint32_t maskSize = ((mip.width + 7) / 8) * mip.height; // 1-bit mask, padded to byte - const uint32_t imageDataSize = sizeof(BITMAPINFOHEADER) + rgbDataSize + maskSize; + const uint32_t imageDataSize = sizeof(ico::BITMAPINFOHEADER) + rgbDataSize + maskSize; - ICONDIRENTRY iconEntry = { + ico::ICONDIRENTRY iconEntry = { static_cast(mip.width > 255 ? 0 : mip.width), // Width (0 for 256+) static_cast(mip.height > 255 ? 0 : mip.height), // Height (0 for 256+) 0, // Color count (0 for 32-bit) @@ -774,8 +743,8 @@ namespace wi::helper imageDataSize, // Size of image data imageDataOffset // Offset to image data }; - std::memcpy(ptr, &iconEntry, sizeof(ICONDIRENTRY)); - ptr += sizeof(ICONDIRENTRY); + std::memcpy(ptr, &iconEntry, sizeof(ico::ICONDIRENTRY)); + ptr += sizeof(ico::ICONDIRENTRY); imageDataOffset += imageDataSize; } @@ -790,8 +759,8 @@ namespace wi::helper const uint32_t rgbDataSize = pixelCount * 4; // 32-bit RGBA const uint32_t maskSize = ((mip.width + 7) / 8) * mip.height; // 1-bit mask, padded to byte - BITMAPINFOHEADER bmpHeader = { - sizeof(BITMAPINFOHEADER), // Size of header + ico::BITMAPINFOHEADER bmpHeader = { + sizeof(ico::BITMAPINFOHEADER), // Size of header int32_t(mip.width), // Width int32_t(mip.height * 2), // Height (doubled for XOR + AND mask) 1, // Planes @@ -803,8 +772,8 @@ namespace wi::helper 0, // Colors used 0 // Important colors }; - std::memcpy(ptr, &bmpHeader, sizeof(BITMAPINFOHEADER)); - ptr += sizeof(BITMAPINFOHEADER); + std::memcpy(ptr, &bmpHeader, sizeof(ico::BITMAPINFOHEADER)); + ptr += sizeof(ico::BITMAPINFOHEADER); // Convert RGBA to BGRA and write XOR mask (flipped vertically) for (uint32_t y = mip.height; y > 0; --y) @@ -839,11 +808,6 @@ namespace wi::helper } *ptr++ = maskByte; } - // Pad to 32-bit boundary - while ((ptr - filedata.data() - sizeof(ICONDIR) - sizeof(ICONDIRENTRY) - sizeof(BITMAPINFOHEADER) - rgbDataSize) % 4 != 0) - { - *ptr++ = 0; - } } } @@ -977,6 +941,28 @@ namespace wi::helper return success; } + bool CreateCursorFromTexture(const wi::graphics::Texture& texture, int hotspotX, int hotspotY, wi::vector& data) + { + if (!saveTextureToMemoryFile(texture, "ico", data)) + return false; + + // rewrite ICO structure for CUR structure: + ico::ICONDIR* icondir = (ico::ICONDIR*)data.data(); + icondir->idType = 2; + + uint32_t baseWidth = texture.desc.width; + uint32_t baseHeight = texture.desc.height; + + for (uint16_t i = 0; i < icondir->idCount; ++i) + { + ico::ICONDIRENTRY* icondirentry = (ico::ICONDIRENTRY*)(data.data() + sizeof(ico::ICONDIR)) + i; + icondirentry->wPlanes = (uint16_t)hotspotX / (baseWidth / icondirentry->bWidth); + icondirentry->wBitCount = (uint16_t)hotspotY / (baseHeight / icondirentry->bHeight); + } + + return true; + } + std::string getCurrentDateTimeAsString() { time_t t = std::time(nullptr); diff --git a/WickedEngine/wiHelper.h b/WickedEngine/wiHelper.h index cecbaa217..5633993ee 100644 --- a/WickedEngine/wiHelper.h +++ b/WickedEngine/wiHelper.h @@ -66,6 +66,9 @@ namespace wi::helper // Download buffer from GPU into CPU memory bool saveBufferToMemory(const wi::graphics::GPUBuffer& buffer, wi::vector& data); + // Creates cursor data from texture. If successful, the file data is returned in the data argument + bool CreateCursorFromTexture(const wi::graphics::Texture& texture, int hotspotX, int hotspotY, wi::vector& data); + std::string getCurrentDateTimeAsString(); void SplitPath(const std::string& fullPath, std::string& dir, std::string& fileName); diff --git a/WickedEngine/wiInput.cpp b/WickedEngine/wiInput.cpp index 8a12351b3..5d833e940 100644 --- a/WickedEngine/wiInput.cpp +++ b/WickedEngine/wiInput.cpp @@ -16,6 +16,7 @@ #ifdef SDL2 #include +#include "Utility/win32ico.h" #endif // SDL2 #ifdef PLATFORM_PS5 @@ -829,6 +830,55 @@ namespace wi::input cursor_table[cursor] = LoadCursorFromFile(wfilename); #endif // PLATFORM_WINDOWS_DESKTOP +#ifdef SDL2 + // In SDL extract the raw color data from win32 .CUR file and use SDL to create cursor: + wi::vector data; + if (wi::helper::FileRead(filename, data)) + { + // Extract only the first image data: + ico::ICONDIRENTRY* icondirentry = (ico::ICONDIRENTRY*)(data.data() + sizeof(ico::ICONDIR)); + + int hotspotX = icondirentry->wPlanes; + int hotspotY = icondirentry->wBitCount; + + uint8_t* pixeldata = (data.data() + icondirentry->dwImageOffset + sizeof(ico::BITMAPINFOHEADER)); + + const uint32_t width = icondirentry->bWidth; + const uint32_t height = icondirentry->bHeight; + + // Convert BGRA to ARGB and flip vertically + wi::vector colors; + colors.reserve(width * height); + for (uint32_t y = height; y > 0; --y) + { + uint8_t* src = pixeldata + (y - 1) * width * 4; + for (uint32_t x = 0; x < width; ++x) + { + colors.push_back(wi::Color(src[3], src[2], src[1], src[0])); + src += 4; + } + } + + SDL_Surface* surface = SDL_CreateRGBSurfaceFrom( + colors.data(), + width, + height, + 4 * 8, + 4 * width, + 0x0000ff00, + 0x00ff0000, + 0xff000000, + 0x000000ff + ); + + if (surface != nullptr) + { + cursor_table[cursor] = SDL_CreateColorCursor(surface, hotspotX, hotspotY); + SDL_FreeSurface(surface); + } + } +#endif // SDL2 + // refresh in case we set the current one: cursor_next = cursor_current; cursor_current = CURSOR_COUNT; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 5824e56a0..f37fbde84 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 789; + const int revision = 790; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);