SVG support (#4306)
* first version of svg support * merge some nanosvg pr * look for svg icons first * bug fix * scale svg depends on screen size * use irrlicht headers to get screen size * finish isALoadableFileFormat for svg * delete dynamically allocated memory * fix wrong delete * only rescale icons, due to size settings in stkskin.xml depends on the size of the image file * check svg in FileManager::getAsset * fix large icon in list
This commit is contained in:
parent
fa8665a360
commit
4694223c03
@ -126,6 +126,7 @@ source/Irrlicht/CImage.cpp
|
||||
source/Irrlicht/CImageLoaderBMP.cpp
|
||||
source/Irrlicht/CImageLoaderJPG.cpp
|
||||
source/Irrlicht/CImageLoaderPNG.cpp
|
||||
source/Irrlicht/CImageLoaderSVG.cpp
|
||||
source/Irrlicht/CImageWriterBMP.cpp
|
||||
source/Irrlicht/CImageWriterJPG.cpp
|
||||
source/Irrlicht/CImageWriterPNG.cpp
|
||||
@ -255,6 +256,7 @@ source/Irrlicht/CImage.h
|
||||
source/Irrlicht/CImageLoaderBMP.h
|
||||
source/Irrlicht/CImageLoaderJPG.h
|
||||
source/Irrlicht/CImageLoaderPNG.h
|
||||
source/Irrlicht/CImageLoaderSVG.h
|
||||
source/Irrlicht/CImageWriterBMP.h
|
||||
source/Irrlicht/CImageWriterJPG.h
|
||||
source/Irrlicht/CImageWriterPNG.h
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const = 0;
|
||||
virtual core::dimension2du getImageSize(io::IReadFile* file) const { return core::dimension2du(0, 0); }
|
||||
virtual bool supportThreadedLoading() const { return false; }
|
||||
|
||||
virtual void setScreenSize(const core::dimension2d<u32> &screen_size) {};
|
||||
};
|
||||
|
||||
|
||||
|
151
lib/irrlicht/source/Irrlicht/CImageLoaderSVG.cpp
Normal file
151
lib/irrlicht/source/Irrlicht/CImageLoaderSVG.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
// This file is modified by riso from CImageLoaderJPG.h
|
||||
// nanosvg as parser and rasterizer for SVG files.
|
||||
// The nanosvg headers are based on those in SDL2_image-2.0.5
|
||||
|
||||
#include "CImageLoaderSVG.h"
|
||||
|
||||
|
||||
#include "IReadFile.h"
|
||||
#include "CImage.h"
|
||||
#include "os.h"
|
||||
#include "irrString.h"
|
||||
#include "CNullDriver.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
|
||||
//! constructor
|
||||
CImageLoaderSVG::CImageLoaderSVG()
|
||||
{
|
||||
}
|
||||
|
||||
//! set the screen size
|
||||
void CImageLoaderSVG::setScreenSize(const core::dimension2d<u32> &screen_size)
|
||||
{
|
||||
ScreenSize = screen_size;
|
||||
}
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
bool CImageLoaderSVG::isALoadableFileExtension(const io::path& filename) const
|
||||
{
|
||||
return core::hasFileExtension ( filename, "svg" );
|
||||
}
|
||||
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
bool CImageLoaderSVG::isALoadableFileFormat(io::IReadFile* file) const
|
||||
{
|
||||
// read first 4095 characters, check if can find "<svg"
|
||||
// this implementation refers IMG_isSVG() in SDL2_Image
|
||||
long filesize = file->getSize();
|
||||
long cropsize = filesize < 4095L ? filesize : 4095L;
|
||||
char* data = new char[cropsize+1];
|
||||
|
||||
int readsize = file->read(data,cropsize);
|
||||
data[cropsize] = '\0';
|
||||
if( (long)readsize != cropsize) {
|
||||
os::Printer::log("Couldn't read SVG image file", file->getFileName(), ELL_ERROR);
|
||||
delete[] data;
|
||||
return 0;
|
||||
}
|
||||
// check if can find "<svg" in the file
|
||||
if ( strstr(data, "<svg") )
|
||||
{
|
||||
delete[] data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! creates a surface from the file
|
||||
IImage* CImageLoaderSVG::loadImage(io::IReadFile* file, bool skip_checking) const
|
||||
{
|
||||
// check IMG_LoadSVG_RW
|
||||
struct NSVGimage *img = 0;
|
||||
struct NSVGrasterizer *rasterizer = 0;
|
||||
video::IImage* image = 0;
|
||||
int w, h;
|
||||
|
||||
// read all the characters in the svg file to data
|
||||
long filesize = file->getSize();
|
||||
char* data = new char[filesize+1];
|
||||
int readsize = file->read(data,filesize);
|
||||
data[filesize] = '\0';
|
||||
|
||||
if( (long)readsize != filesize) {
|
||||
os::Printer::log("Couldn't read SVG image file", file->getFileName(), ELL_ERROR);
|
||||
delete[] data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// parse the svg image
|
||||
img = nsvgParse(data, "px", 96);
|
||||
if ( !img ) {
|
||||
os::Printer::log("Couldn't parse SVG image", ELL_ERROR);
|
||||
delete[] data;
|
||||
return 0;
|
||||
}
|
||||
delete[] data;
|
||||
|
||||
rasterizer = nsvgCreateRasterizer();
|
||||
if ( !rasterizer ) {
|
||||
os::Printer::log("Couldn't create SVG rasterizer", ELL_ERROR);
|
||||
nsvgDelete( img );
|
||||
return 0;
|
||||
}
|
||||
|
||||
float scale =1.0f;
|
||||
// only rescale the icons
|
||||
if ( strstr(file->getFileName().c_str(),"gui/icons/") )
|
||||
{
|
||||
// determine scaling based on screen size
|
||||
float screen_height = ScreenSize.Height;
|
||||
float desired_icon_size = 0.21*screen_height + 30.0f; // phenomenological
|
||||
scale = desired_icon_size/img->height;
|
||||
}
|
||||
|
||||
// create surface
|
||||
w = (int)(img->width*scale);
|
||||
h = (int)(img->height*scale);
|
||||
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(w, h));
|
||||
if ( !image ) {
|
||||
os::Printer::log("LOAD SVG: create image struct failure", file->getFileName(), ELL_ERROR);
|
||||
nsvgDeleteRasterizer( rasterizer );
|
||||
nsvgDelete( img );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// rasterization
|
||||
nsvgRasterize(rasterizer, img, 0.0f, 0.0f, scale, (unsigned char *)image->lock(), (int)image->getDimension().Width, (int)image->getDimension().Height, (int)image->getPitch());
|
||||
|
||||
if (image)
|
||||
image->unlock();
|
||||
// clean up
|
||||
nsvgDeleteRasterizer( rasterizer );
|
||||
nsvgDelete( img );
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
//! creates a loader which is able to load svg images
|
||||
IImageLoader* createImageLoaderSVG()
|
||||
{
|
||||
return new CImageLoaderSVG();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
|
64
lib/irrlicht/source/Irrlicht/CImageLoaderSVG.h
Normal file
64
lib/irrlicht/source/Irrlicht/CImageLoaderSVG.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||||
// This file is part of the "Irrlicht Engine".
|
||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||||
// This file is modified by riso from CImageLoaderJPG.h
|
||||
// nanosvg as parser and rasterizer for SVG files.
|
||||
// The nanosvg headers are based on those in SDL2_image-2.0.5
|
||||
|
||||
#ifndef __C_IMAGE_LOADER_SVG_H_INCLUDED__
|
||||
#define __C_IMAGE_LOADER_SVG_H_INCLUDED__
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#include "IImageLoader.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "nanosvgrast.h"
|
||||
|
||||
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video
|
||||
{
|
||||
|
||||
/*!
|
||||
Surface Loader for SVG images
|
||||
*/
|
||||
class CImageLoaderSVG : public IImageLoader
|
||||
{
|
||||
public:
|
||||
|
||||
//! constructor
|
||||
CImageLoaderSVG();
|
||||
|
||||
// set the screen size, used to determine scaling
|
||||
virtual void setScreenSize(const core::dimension2d<u32> &screen_size);
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
//! based on the file extension (e.g. ".tga")
|
||||
virtual bool isALoadableFileExtension(const io::path& filename) const;
|
||||
|
||||
//! returns true if the file maybe is able to be loaded by this class
|
||||
virtual bool isALoadableFileFormat(io::IReadFile* file) const;
|
||||
|
||||
//! creates a surface from the file
|
||||
virtual IImage* loadImage(io::IReadFile* file, bool skip_checking = false) const;
|
||||
|
||||
private:
|
||||
core::dimension2d<u32> ScreenSize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // end namespace video
|
||||
} // end namespace irr
|
||||
|
||||
#endif
|
||||
|
@ -58,6 +58,9 @@ IImageLoader* createImageLoaderPPM();
|
||||
//! creates a loader which is able to load rgb images
|
||||
IImageLoader* createImageLoaderRGB();
|
||||
|
||||
//! creates a loader which is able to load svg images
|
||||
IImageLoader* createImageLoaderSVG();
|
||||
|
||||
|
||||
//! creates a writer which is able to save bmp images
|
||||
IImageWriter* createImageWriterBMP();
|
||||
@ -131,6 +134,8 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& scre
|
||||
#ifdef _IRR_COMPILE_WITH_BMP_LOADER_
|
||||
SurfaceLoader.push_back(video::createImageLoaderBMP());
|
||||
#endif
|
||||
SurfaceLoader.push_back(video::createImageLoaderSVG());
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_JPG_WRITER_
|
||||
SurfaceWriter.push_back(video::createImageWriterJPG());
|
||||
#endif
|
||||
@ -1298,6 +1303,8 @@ IImage* CNullDriver::createImageFromFile(io::IReadFile* file, video::IImageLoade
|
||||
*loader = SurfaceLoader[i];
|
||||
return 0;
|
||||
}
|
||||
// pass screen size to ImageLoaderSVG. For other formats (BMP,JPG,PNG), setScreenSize() does nothing
|
||||
SurfaceLoader[i]->setScreenSize(getCurrentRenderTargetSize());
|
||||
// reset file position which might have changed due to previous loadImage calls
|
||||
file->seek(0);
|
||||
image = SurfaceLoader[i]->loadImage(file);
|
||||
@ -1318,6 +1325,8 @@ IImage* CNullDriver::createImageFromFile(io::IReadFile* file, video::IImageLoade
|
||||
*loader = SurfaceLoader[i];
|
||||
return 0;
|
||||
}
|
||||
// pass screen size to ImageLoaderSVG. For other formats (BMP,JPG,PNG), setScreenSize() does nothing
|
||||
SurfaceLoader[i]->setScreenSize(getCurrentRenderTargetSize());
|
||||
file->seek(0);
|
||||
image = SurfaceLoader[i]->loadImage(file);
|
||||
if (image)
|
||||
|
3088
lib/irrlicht/source/Irrlicht/nanosvg.h
Normal file
3088
lib/irrlicht/source/Irrlicht/nanosvg.h
Normal file
File diff suppressed because it is too large
Load Diff
1466
lib/irrlicht/source/Irrlicht/nanosvgrast.h
Normal file
1466
lib/irrlicht/source/Irrlicht/nanosvgrast.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -2888,22 +2888,37 @@ bool Skin::hasFont() const
|
||||
* icon. */
|
||||
std::string Skin::getThemedIcon(const std::string& relative_path) const
|
||||
{
|
||||
if (!SkinConfig::m_icon_theme ||
|
||||
relative_path.find("gui/icons/") == std::string::npos)
|
||||
// First check if an svg icon is available
|
||||
const std::vector<std::string> ext {".svg", ".png"};
|
||||
// get the path without extension
|
||||
const std::string path_no_extension = StringUtils::removeExtension(relative_path);
|
||||
// loop the file extensions: svg first
|
||||
for(auto s : ext)
|
||||
{
|
||||
return file_manager->getAsset(relative_path);
|
||||
}
|
||||
std::string relative_path2 = path_no_extension + s;
|
||||
if (!SkinConfig::m_icon_theme ||
|
||||
relative_path2.find("gui/icons/") == std::string::npos)
|
||||
{
|
||||
std::string tmp_path = file_manager->getAsset(relative_path2);
|
||||
if (file_manager->fileExists(tmp_path))
|
||||
{
|
||||
return tmp_path;
|
||||
}
|
||||
}
|
||||
|
||||
if (relative_path.find(SkinConfig::m_data_path) != std::string::npos &&
|
||||
file_manager->fileExists(relative_path))
|
||||
{
|
||||
// Absolute path given
|
||||
return relative_path;
|
||||
}
|
||||
if (relative_path2.find(SkinConfig::m_data_path) != std::string::npos &&
|
||||
file_manager->fileExists(relative_path2))
|
||||
{
|
||||
// Absolute path given
|
||||
return relative_path2;
|
||||
}
|
||||
|
||||
std::string test_path = SkinConfig::m_data_path + "data/" + relative_path;
|
||||
if (file_manager->fileExists(test_path))
|
||||
return test_path;
|
||||
else
|
||||
return file_manager->getAsset(relative_path);
|
||||
std::string test_path = SkinConfig::m_data_path + "data/" + relative_path2;
|
||||
if (file_manager->fileExists(test_path))
|
||||
{
|
||||
return test_path;
|
||||
}
|
||||
}
|
||||
// if nothing found, return the bundled one
|
||||
return file_manager->getAsset(relative_path);
|
||||
} // getThemedIcon
|
||||
|
@ -787,10 +787,14 @@ std::string FileManager::getAsset(FileManager::AssetType type,
|
||||
{
|
||||
if (type == GUI_ICON && GUIEngine::getSkin()->hasIconTheme())
|
||||
{
|
||||
const std::string test_path = GUIEngine::getSkin()->getDataPath() +
|
||||
"data/gui/icons/" + name;
|
||||
if (fileExists(test_path))
|
||||
return test_path;
|
||||
// remove the extension to check both .svg and .png
|
||||
const std::string test_path = StringUtils::removeExtension
|
||||
(GUIEngine::getSkin()->getDataPath() + "data/gui/icons/" + name);
|
||||
// first check if there is an SVG version
|
||||
if (fileExists(test_path + ".svg"))
|
||||
return test_path + ".svg";
|
||||
else if (fileExists(test_path + ".png"))
|
||||
return test_path + ".png";
|
||||
else
|
||||
return m_subdir_name[type] + name;
|
||||
}
|
||||
|
@ -158,6 +158,7 @@ void AddonsScreen::init()
|
||||
m_icon_height = GUIEngine::getFontHeight() * 2;
|
||||
// 128 is the height of the image file
|
||||
m_icon_bank->setScale((float)GUIEngine::getFontHeight() / 72.0f);
|
||||
m_icon_bank->setTargetIconSize(128,128);
|
||||
w_list->setIcons(m_icon_bank, (int)(m_icon_height));
|
||||
|
||||
m_type = "kart";
|
||||
|
@ -148,6 +148,7 @@ void NetworkingLobby::loadedFromFile()
|
||||
m_icon_bank->addTextureAsSprite(icon_6);
|
||||
|
||||
m_icon_bank->setScale((float)GUIEngine::getFontHeight() / 96.0f);
|
||||
m_icon_bank->setTargetIconSize(128, 128);
|
||||
} // loadedFromFile
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -75,6 +75,7 @@ void OptionsScreenInput::loadedFromFile()
|
||||
// scale icons depending on font height
|
||||
const float scale = GUIEngine::getFontHeight() / 72.0f;
|
||||
m_icon_bank->setScale(scale);
|
||||
m_icon_bank->setTargetIconSize(128, 128);
|
||||
} // loadFromFile
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user