mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-06-04 20:46:29 +03:00
Added rasterized svg support.
--HG-- branch : dev
This commit is contained in:
@@ -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 );
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() );
|
||||
}
|
||||
|
||||
29
src/eepp/graphics/stbi_iocb.hpp
Normal file
29
src/eepp/graphics/stbi_iocb.hpp
Normal 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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
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
1447
src/thirdparty/nanosvg/nanosvgrast.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user