Added rasterized svg support.

--HG--
branch : dev
This commit is contained in:
Martín Lucas Golini
2018-03-17 01:48:23 -03:00
parent ac75530bd5
commit dff099a621
8 changed files with 4558 additions and 86 deletions

View File

@@ -12,6 +12,8 @@ using namespace EE::System;
#include <eepp/graphics/rendermode.hpp>
struct NSVGimage;
namespace EE { namespace System {
class Pack;
class IOStream;
@@ -118,6 +120,13 @@ class EE_API Image {
*/
Image( std::string Path, const unsigned int& forceChannels = 0 );
/** Load a compressed image from memory
* @param imageData The image data
* @param imageDataSize The image size
* @param forceChannels Number of channels to use for the image, default 0 means that it use the default image channels.
*/
Image( const Uint8* imageData, const unsigned int& imageDataSize, const unsigned int& forceChannels = 0 );
/** Load an image from pack
* @param Pack The pack file to use to load the image.
* @param FilePackPath The path of the file inside the pack file.
@@ -239,6 +248,8 @@ class EE_API Image {
void allocate( const Uint32& size, Color DefaultColor = Color(0,0,0,0), bool memsetData = true );
void loadFromPack( Pack * Pack, const std::string& FilePackPath );
void svgLoad( NSVGimage * image );
};
}}

View File

@@ -1,3 +1,4 @@
../../src/eepp/graphics/stbi_iocb.hpp
../../src/tools/uieditor/uieditor.cpp
../../include/eepp/scene.hpp
../../include/eepp/scene/actions/close.hpp

View File

@@ -3,13 +3,20 @@
#include <eepp/system/log.hpp>
#include <eepp/system/pack.hpp>
#include <eepp/system/packmanager.hpp>
#include <eepp/graphics/pixeldensity.hpp>
#include <SOIL2/src/SOIL2/image_helper.h>
#include <SOIL2/src/SOIL2/stb_image.h>
#include <SOIL2/src/SOIL2/SOIL2.h>
#include <jpeg-compressor/jpge.h>
#include <eepp/graphics/stbi_iocb.hpp>
#include <imageresampler/resampler.h>
#include <algorithm>
#define NANOSVG_IMPLEMENTATION
#include <nanosvg/nanosvg.h>
#define NANOSVGRAST_IMPLEMENTATION
#include <nanosvg/nanosvgrast.h>
namespace EE { namespace Graphics {
static const char * get_resampler_name( Image::ResamplerFilter filter ) {
@@ -150,6 +157,37 @@ static unsigned char * resample_image( unsigned char* pSrc_image, int src_width,
return dst_image;
}
static bool svg_test( const std::string& path ) {
return FileSystem::fileExtension( path ) == "svg";
}
static bool svg_test_from_memory( const Uint8 * imageData, const unsigned int & imageDataSize ) {
return imageDataSize > 5 && (
( imageData[0] == '<' && imageData[1] == 's' && imageData[2] == 'v' && imageData[3] == 'g' ) ||
( imageData[0] == '<' && imageData[1] == '?' && imageData[2] == 'x' && imageData[3] == 'm' && imageData[4] == 'l' )
);
}
static bool svg_test_from_stream( IOStream& stream ) {
if ( stream.isOpen() ) {
std::string str;
str.resize( 5 );
stream.seek( 0 );
stream.read( (char*)&str[0], 5 );
String::toLowerInPlace( str );
if ( ( str[0] == '<' && str[1] == 's' && str[2] == 'v' && str[3] == 'g' ) ||
( str[0] == '<' && str[1] == '?' && str[2] == 'x' && str[3] == 'm' && str[4] == 'l' ) ) {
return true;
}
}
return false;
}
Uint32 Image::sJpegQuality = 85;
Uint32 Image::jpegQuality() {
@@ -221,7 +259,7 @@ bool Image::getInfo( const std::string& path, int * width, int * height, int * c
}
bool Image::isImage( const std::string& path ) {
return STBI_unknown != stbi_test( path.c_str() );
return STBI_unknown != stbi_test( path.c_str() ) || svg_test( path );
}
bool Image::isImageExtension( const std::string& path ) {
@@ -238,7 +276,8 @@ bool Image::isImageExtension( const std::string& path ) {
Ext == "hdr" ||
Ext == "pic" ||
Ext == "pvr" ||
Ext == "pkm"
Ext == "pkm" ||
Ext == "svg"
);
}
@@ -332,6 +371,8 @@ Image::Image( std::string Path, const unsigned int& forceChannels ) :
mSize = mWidth * mHeight * mChannels;
mLoadedFromStbi = true;
} else if ( svg_test( Path ) ) {
svgLoad( nsvgParseFromFile( Path.c_str(), "px", 96.0f ) );
} else if ( PackManager::instance()->isFallbackToPacksActive() && NULL != ( tPack = PackManager::instance()->exists( Path ) ) ) {
loadFromPack( tPack, Path );
} else {
@@ -345,6 +386,45 @@ Image::Image( std::string Path, const unsigned int& forceChannels ) :
}
}
Image::Image( const Uint8 * imageData, const unsigned int & imageDataSize, const unsigned int & forceChannels ) :
mPixels(NULL),
mWidth(0),
mHeight(0),
mChannels(forceChannels),
mSize(0),
mAvoidFree(false),
mLoadedFromStbi(false)
{
int w, h, c;
Uint8 * data = stbi_load_from_memory( imageData, imageDataSize, &w, &h, &c, mChannels );
if ( NULL != data ) {
mPixels = data;
mWidth = (unsigned int)w;
mHeight = (unsigned int)h;
if ( STBI_default == mChannels )
mChannels = (unsigned int)c;
mSize = mWidth * mHeight * mChannels;
mLoadedFromStbi = true;
} else if ( svg_test_from_memory( imageData, imageDataSize ) ) {
SafeDataPointer data( imageDataSize + 1 );
memcpy( data.data, imageData, imageDataSize );
data.data[imageDataSize] = '\0';
svgLoad( nsvgParse( (char*)data.data, "px", 96.0f ) );
} else {
std::string reason = ".";
if ( NULL != stbi_failure_reason() ) {
reason = ", reason: " + std::string( stbi_failure_reason() );
}
eePRINTL( "Failed to load image from memory. Reason: %s", reason.c_str() );
}
}
Image::Image( Pack * Pack, std::string FilePackPath, const unsigned int& forceChannels ) :
mPixels(NULL),
mWidth(0),
@@ -367,12 +447,13 @@ Image::Image( IOStream & stream, const unsigned int& forceChannels ) :
mLoadedFromStbi(false)
{
if ( stream.isOpen() ) {
SafeDataPointer PData( stream.getSize() );
stream.read( (char*)PData.data, PData.size );
stbi_io_callbacks callbacks;
callbacks.read = &IOCb::read;
callbacks.skip = &IOCb::skip;
callbacks.eof = &IOCb::eof;
int w, h, c;
Uint8 * data = stbi_load_from_memory( PData.data, PData.size, &w, &h, &c, mChannels );
Uint8 * data = stbi_load_from_callbacks( &callbacks, &stream, &w, &h, &c, mChannels );
if ( NULL != data ) {
mPixels = data;
@@ -385,6 +466,15 @@ Image::Image( IOStream & stream, const unsigned int& forceChannels ) :
mSize = mWidth * mHeight * mChannels;
mLoadedFromStbi = true;
} else if ( svg_test_from_stream( stream ) ) {
SafeDataPointer data( stream.getSize() + 1 );
stream.seek( 0 );
stream.read( (char*)data.data, data.size - 1 );
data.data[data.size - 1] = '\0';
svgLoad( nsvgParse( (char*)data.data, "px", 96.0f ) );
} else {
eePRINTL( "Failed to load image. Reason: %s", stbi_failure_reason() );
}
@@ -398,6 +488,37 @@ Image::~Image() {
clearCache();
}
void Image::svgLoad( NSVGimage * image ) {
if (image == NULL)
return;
NSVGrasterizer *rast = NULL;
unsigned char* img = NULL;
int w, h;
w = (int)image->width * PixelDensity::getPixelDensity();
h = (int)image->height * PixelDensity::getPixelDensity();
rast = nsvgCreateRasterizer();
if (rast != NULL) {
img = (unsigned char*)malloc(w*h*4);
if (img != NULL) {
nsvgRasterize(rast, image, 0, 0, PixelDensity::getPixelDensity(), img, w, h, w * 4);
mPixels = img;
mWidth = w;
mHeight = h;
mChannels = 4;
mLoadedFromStbi = true;
}
}
nsvgDeleteRasterizer(rast);
nsvgDelete(image);
}
void Image::loadFromPack( Pack * Pack, const std::string& FilePackPath ) {
if ( NULL != Pack && Pack->isOpen() && -1 != Pack->exists( FilePackPath ) ) {
SafeDataPointer PData;
@@ -418,6 +539,11 @@ void Image::loadFromPack( Pack * Pack, const std::string& FilePackPath ) {
mSize = mWidth * mHeight * mChannels;
mLoadedFromStbi = true;
} else if ( svg_test_from_memory( PData.data, PData.size ) ) {
SafeDataPointer data( PData.size + 1 );
memcpy( data.data, PData.data, PData.size );
data.data[PData.size] = '\0';
svgLoad( nsvgParse( (char*)data.data, "px", 96.0f ) );
} else {
eePRINTL( "Failed to load image %s. Reason: %s", FilePackPath.c_str(), stbi_failure_reason() );
}

View File

@@ -0,0 +1,29 @@
#ifndef EE_STBI_IOCB_HPP
#define EE_STBI_IOCB_HPP
#include <eepp/system/iostream.hpp>
using namespace EE::System;
namespace IOCb
{
// stb_image callbacks that operate on a IOStream
static inline int read(void* user, char* data, int size)
{
IOStream * stream = static_cast<IOStream*>(user);
return static_cast<int>(stream->read(data, size));
}
static inline void skip(void* user, int size)
{
IOStream * stream = static_cast<IOStream*>(user);
stream->seek(stream->tell() + size);
}
static inline int eof(void* user)
{
IOStream* stream = static_cast<IOStream*>(user);
return stream->tell() >= stream->getSize();
}
}
#endif

View File

@@ -9,7 +9,7 @@
#include <eepp/system/filesystem.hpp>
#include <SOIL2/src/SOIL2/stb_image.h>
#include <SOIL2/src/SOIL2/SOIL2.h>
#include <jpeg-compressor/jpgd.h>
#include <eepp/graphics/stbi_iocb.hpp>
using namespace EE::Window;
#define TEX_LT_PATH (1)
@@ -20,46 +20,6 @@ using namespace EE::Window;
namespace EE { namespace Graphics {
namespace IOCb
{
// stb_image callbacks that operate on a IOStream
int read(void* user, char* data, int size)
{
IOStream * stream = static_cast<IOStream*>(user);
return static_cast<int>(stream->read(data, size));
}
void skip(void* user, int size)
{
IOStream * stream = static_cast<IOStream*>(user);
stream->seek(stream->tell() + size);
}
int eof(void* user)
{
IOStream* stream = static_cast<IOStream*>(user);
return stream->tell() >= stream->getSize();
}
}
namespace jpeg
{
class jpeg_decoder_stream_steam : public jpgd::jpeg_decoder_stream {
public:
IOStream * mStream;
jpeg_decoder_stream_steam( IOStream * stream ) :
mStream( stream )
{}
virtual ~jpeg_decoder_stream_steam() {}
virtual int read(jpgd::uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) {
return mStream->read( (char*)pBuf, max_bytes_to_read );
}
};
}
TextureLoader::TextureLoader( IOStream& Stream,
const bool& Mipmap,
const Texture::ClampMode& ClampMode,
@@ -282,19 +242,9 @@ void TextureLoader::loadFromFile() {
mSize = FileSystem::fileSize( mFilepath );
}
mPixels = stbi_load( mFilepath.c_str(), &mImgWidth, &mImgHeight, &mChannels, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
}
if ( NULL == mPixels ) {
eePRINTL( "Filed to load: %s. Reason: %s", mFilepath.c_str(), stbi_failure_reason() );
if ( STBI_jpeg == mImgType ) {
mPixels = jpgd::decompress_jpeg_image_from_file( mFilepath.c_str(), &mImgWidth, &mImgHeight, &mChannels, 3 );
if ( NULL != mPixels ) {
eePRINTL( "Loaded: %s using jpeg-compressor.", mFilepath.c_str() );
}
}
Image image( mFilepath, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
image.avoidFreeImage( true );
mPixels = image.getPixels(); mImgWidth = image.getWidth(); mImgHeight = image.getHeight(); mChannels = image.getChannels();
}
} else if ( PackManager::instance()->isFallbackToPacksActive() ) {
mPack = PackManager::instance()->exists( mFilepath );
@@ -339,19 +289,9 @@ void TextureLoader::loadFromMemory() {
stbi__pkm_info_from_memory( mPixels, mSize, &mImgWidth, &mImgHeight, &mChannels );
mIsCompressed = mDirectUpload = true;
} else {
mPixels = stbi_load_from_memory( mImagePtr, mSize, &mImgWidth, &mImgHeight, &mChannels, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
}
if ( NULL == mPixels ) {
eePRINTL( "Filed to load image from memory. Reason: %s", stbi_failure_reason() );
if ( STBI_jpeg == mImgType ) {
mPixels = jpgd::decompress_jpeg_image_from_memory( mImagePtr, mSize, &mImgWidth, &mImgHeight, &mChannels, 3 );
if ( NULL != mPixels ) {
eePRINTL( "Loaded: image using jpeg-compressor." );
}
}
Image image( mImagePtr, mSize, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
image.avoidFreeImage( true );
mPixels = image.getPixels(); mImgWidth = image.getWidth(); mImgHeight = image.getHeight(); mChannels = image.getChannels();
}
}
@@ -396,20 +336,13 @@ void TextureLoader::loadFromStream() {
mIsCompressed = mDirectUpload = true;
} else {
mStream->seek( 0 );
mPixels = stbi_load_from_callbacks( &callbacks, mStream, &mImgWidth, &mImgHeight, &mChannels, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
Image image( *mStream, ( NULL != mColorKey ) ? STBI_rgb_alpha : STBI_default );
image.avoidFreeImage( true );
mPixels = image.getPixels(); mImgWidth = image.getWidth(); mImgHeight = image.getHeight(); mChannels = image.getChannels();
mStream->seek( 0 );
}
if ( NULL == mPixels ) {
eePRINTL( stbi_failure_reason() );
if ( STBI_jpeg == mImgType ) {
jpeg::jpeg_decoder_stream_steam stream( mStream );
mPixels = jpgd::decompress_jpeg_image_from_stream( &stream, &mImgWidth, &mImgHeight, &mChannels, 3 );
mStream->seek( 0 );
}
}
}
}

View File

@@ -44,7 +44,7 @@ ios_size IOStreamZip::write( const char * data, ios_size size ) {
}
ios_size IOStreamZip::seek( ios_size position ) {
if ( isOpen() ) {
if ( isOpen() && mPos != position ) {
zip_fclose( mFile );
struct zip_stat zs;

2925
src/thirdparty/nanosvg/nanosvg.h vendored Normal file

File diff suppressed because it is too large Load Diff

1447
src/thirdparty/nanosvg/nanosvgrast.h vendored Normal file

File diff suppressed because it is too large Load Diff