Browse Source

examples/common: Cleanup dealing with textures.

Branimir Karadžić 8 years ago
parent
commit
25dd8377d5

+ 14 - 0
examples/32-particles/particles.cpp

@@ -249,9 +249,23 @@ class Particles : public entry::AppI
 
 
 		psInit();
 		psInit();
 
 
+		bgfx::ImageContainer* image = imageLoad(
+			  "textures/particle.ktx"
+			, bgfx::TextureFormat::BGRA8
+			);
+
+		EmitterSpriteHandle sprite = psCreateSprite(
+				  uint16_t(image->m_width)
+				, uint16_t(image->m_height)
+				, image->m_data
+				);
+
+		bgfx::imageFree(image);
+
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_emitter); ++ii)
 		for (uint32_t ii = 0; ii < BX_COUNTOF(m_emitter); ++ii)
 		{
 		{
 			m_emitter[ii].create();
 			m_emitter[ii].create();
+			m_emitter[ii].m_uniforms.m_handle = sprite;
 		}
 		}
 
 
 		imguiCreate();
 		imguiCreate();

+ 45 - 288
examples/common/bgfx_utils.cpp

@@ -19,27 +19,6 @@ namespace stl = tinystl;
 #include "entry/entry.h"
 #include "entry/entry.h"
 #include <ib-compress/indexbufferdecompression.h>
 #include <ib-compress/indexbufferdecompression.h>
 
 
-BX_PRAGMA_DIAGNOSTIC_PUSH()
-BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wtype-limits")
-BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter")
-BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-value")
-BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4100) // error C4100: '' : unreferenced formal parameter
-#if BX_PLATFORM_EMSCRIPTEN
-#	include <compat/ctype.h>
-#endif // BX_PLATFORM_EMSCRIPTEN
-#define MINIZ_NO_STDIO
-#define TINYEXR_IMPLEMENTATION
-#include <tinyexr/tinyexr.h>
-BX_PRAGMA_DIAGNOSTIC_POP()
-
-#define LODEPNG_NO_COMPILE_ENCODER
-#define LODEPNG_NO_COMPILE_DISK
-#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
-#define LODEPNG_NO_COMPILE_ERROR_TEXT
-#define LODEPNG_NO_COMPILE_ALLOCATORS
-#define LODEPNG_NO_COMPILE_CPP
-#include <lodepng/lodepng.h>
-
 #include "bgfx_utils.h"
 #include "bgfx_utils.h"
 
 
 void* load(bx::FileReaderI* _reader, bx::AllocatorI* _allocator, const char* _filePath, uint32_t* _size)
 void* load(bx::FileReaderI* _reader, bx::AllocatorI* _allocator, const char* _filePath, uint32_t* _size)
@@ -167,303 +146,73 @@ bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName)
 	return loadProgram(entry::getFileReader(), _vsName, _fsName);
 	return loadProgram(entry::getFileReader(), _vsName, _fsName);
 }
 }
 
 
-typedef unsigned char stbi_uc;
-extern "C" stbi_uc* stbi_load_from_memory(stbi_uc const* _buffer, int _len, int* _x, int* _y, int* _comp, int _req_comp);
-extern "C" void stbi_image_free(void* _ptr);
-extern void lodepng_free(void* _ptr);
-
-static void exrRelease(void* _ptr)
+static void imageReleaseCb(void* _ptr, void* _userData)
 {
 {
-	BX_FREE(entry::getAllocator(), _ptr);
+	BX_UNUSED(_ptr);
+	bgfx::ImageContainer* imageContainer = (bgfx::ImageContainer*)_userData;
+	bgfx::imageFree(imageContainer);
 }
 }
 
 
 bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, uint32_t _flags, uint8_t _skip, bgfx::TextureInfo* _info)
 bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, uint32_t _flags, uint8_t _skip, bgfx::TextureInfo* _info)
 {
 {
-	if (NULL != bx::stristr(_filePath, ".dds")
-	||  NULL != bx::stristr(_filePath, ".pvr")
-	||  NULL != bx::stristr(_filePath, ".ktx") )
-	{
-		const bgfx::Memory* mem = loadMem(_reader, _filePath);
-		if (NULL != mem)
-		{
-			return bgfx::createTexture(mem, _flags, _skip, _info);
-		}
-
-		bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
-		DBG("Failed to load %s.", _filePath);
-		return handle;
-	}
-
+	BX_UNUSED(_skip);
 	bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
 	bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
-	bx::AllocatorI* allocator = entry::getAllocator();
 
 
-	uint32_t size = 0;
-	void* data = loadMem(_reader, allocator, _filePath, &size);
+	uint32_t size;
+	void* data = load(_reader, entry::getAllocator(), _filePath, &size);
 	if (NULL != data)
 	if (NULL != data)
 	{
 	{
-		bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
-		uint32_t bpp = 32;
-
-		uint32_t width  = 0;
-		uint32_t height = 0;
-
-		typedef void (*ReleaseFn)(void* _ptr);
-		ReleaseFn release = stbi_image_free;
+		bgfx::ImageContainer* imageContainer = bgfx::imageParse(entry::getAllocator(), data, size);
 
 
-		uint8_t* out = NULL;
-		static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
-
-		if (0 == bx::memCmp(data, pngMagic, sizeof(pngMagic) ) )
+		if (NULL != imageContainer)
 		{
 		{
-			release = lodepng_free;
-
-			unsigned error;
-			LodePNGState state;
-			lodepng_state_init(&state);
-			state.decoder.color_convert = 0;
-			error = lodepng_decode(&out, &width, &height, &state, (uint8_t*)data, size);
-
-			if (0 == error)
-			{
-				switch (state.info_raw.bitdepth)
-				{
-				case 8:
-					switch (state.info_raw.colortype)
-					{
-					case LCT_GREY:
-						format = bgfx::TextureFormat::R8;
-						bpp    = 8;
-						break;
-
-					case LCT_GREY_ALPHA:
-						format = bgfx::TextureFormat::RG8;
-						bpp    = 16;
-						break;
-
-					case LCT_RGB:
-						format = bgfx::TextureFormat::RGB8;
-						bpp    = 24;
-						break;
-
-					case LCT_RGBA:
-						format = bgfx::TextureFormat::RGBA8;
-						bpp    = 32;
-						break;
-
-					case LCT_PALETTE:
-						format = bgfx::TextureFormat::R8;
-						bpp    = 8;
-						break;
-					}
-					break;
-
-				case 16:
-					switch (state.info_raw.colortype)
-					{
-					case LCT_GREY:
-						for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
-						{
-							uint16_t* rgba = (uint16_t*)out + ii*4;
-							rgba[0] = bx::toHostEndian(rgba[0], false);
-						}
-						format = bgfx::TextureFormat::R16;
-						bpp    = 16;
-						break;
-
-					case LCT_GREY_ALPHA:
-						for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
-						{
-							uint16_t* rgba = (uint16_t*)out + ii*4;
-							rgba[0] = bx::toHostEndian(rgba[0], false);
-							rgba[1] = bx::toHostEndian(rgba[1], false);
-						}
-						format = bgfx::TextureFormat::R16;
-						bpp    = 16;
-						break;
-
-					case LCT_RGBA:
-						for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
-						{
-							uint16_t* rgba = (uint16_t*)out + ii*4;
-							rgba[0] = bx::toHostEndian(rgba[0], false);
-							rgba[1] = bx::toHostEndian(rgba[1], false);
-							rgba[2] = bx::toHostEndian(rgba[2], false);
-							rgba[3] = bx::toHostEndian(rgba[3], false);
-						}
-						format = bgfx::TextureFormat::RGBA16;
-						bpp    = 64;
-						break;
-
-					case LCT_RGB:
-					case LCT_PALETTE:
-						break;
-					}
-					break;
-
-				default:
-					break;
-				}
-			}
+			const bgfx::Memory* mem = bgfx::makeRef(
+					  imageContainer->m_data
+					, imageContainer->m_size
+					, imageReleaseCb
+					, imageContainer
+					);
+			unload(data);
 
 
-			lodepng_state_cleanup(&state);
-		}
-		else
-		{
-			EXRVersion exrVersion;
-			int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)data, size);
-			if (TINYEXR_SUCCESS == result)
+			if (imageContainer->m_cubeMap)
 			{
 			{
-				const char* err = NULL;
-				EXRHeader exrHeader;
-				result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)data, size, &err);
-				if (TINYEXR_SUCCESS == result)
-				{
-					EXRImage exrImage;
-					InitEXRImage(&exrImage);
-
-					result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)data, size, &err);
-					if (TINYEXR_SUCCESS == result)
-					{
-						uint8_t idxR = UINT8_MAX;
-						uint8_t idxG = UINT8_MAX;
-						uint8_t idxB = UINT8_MAX;
-						uint8_t idxA = UINT8_MAX;
-						for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
-						{
-							const EXRChannelInfo& channel = exrHeader.channels[ii];
-							if (UINT8_MAX == idxR
-							&&  0 == bx::strncmp(channel.name, "R") )
-							{
-								idxR = ii;
-							}
-							else if (UINT8_MAX == idxG
-								 &&  0 == bx::strncmp(channel.name, "G") )
-							{
-								idxG = ii;
-							}
-							else if (UINT8_MAX == idxB
-								 &&  0 == bx::strncmp(channel.name, "B") )
-							{
-								idxB = ii;
-							}
-							else if (UINT8_MAX == idxA
-								 &&  0 == bx::strncmp(channel.name, "A") )
-							{
-								idxA = ii;
-							}
-						}
-
-						if (UINT8_MAX != idxR)
-						{
-							const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
-
-							uint32_t srcBpp = 32;
-							uint32_t dstBpp = asFloat ? 32 : 16;
-							format = asFloat ? bgfx::TextureFormat::R32F : bgfx::TextureFormat::R16F;
-							uint32_t stepR = 1;
-							uint32_t stepG = 0;
-							uint32_t stepB = 0;
-							uint32_t stepA = 0;
-
-							if (UINT8_MAX != idxG)
-							{
-								srcBpp += 32;
-								dstBpp = asFloat ? 64 : 32;
-								format = asFloat ? bgfx::TextureFormat::RG32F : bgfx::TextureFormat::RG16F;
-								stepG  = 1;
-							}
-
-							if (UINT8_MAX != idxB)
-							{
-								srcBpp += 32;
-								dstBpp = asFloat ? 128 : 64;
-								format = asFloat ? bgfx::TextureFormat::RGBA32F : bgfx::TextureFormat::RGBA16F;
-								stepB  = 1;
-							}
-
-							if (UINT8_MAX != idxA)
-							{
-								srcBpp += 32;
-								dstBpp = asFloat ? 128 : 64;
-								format = asFloat ? bgfx::TextureFormat::RGBA32F : bgfx::TextureFormat::RGBA16F;
-								stepA  = 1;
-							}
-
-							release = exrRelease;
-							out = (uint8_t*)BX_ALLOC(allocator, exrImage.width * exrImage.height * dstBpp/8);
-
-							const float zero = 0.0f;
-							const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
-							const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
-							const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
-							const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
-
-							const uint32_t bytesPerPixel = dstBpp/8;
-							for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
-							{
-								float rgba[4] =
-								{
-									*srcR,
-									*srcG,
-									*srcB,
-									*srcA,
-								};
-								bx::memCopy(&out[ii * bytesPerPixel], rgba, bytesPerPixel);
-
-								srcR += stepR;
-								srcG += stepG;
-								srcB += stepB;
-								srcA += stepA;
-							}
-						}
-
-						FreeEXRImage(&exrImage);
-					}
-
-					FreeEXRHeader(&exrHeader);
-				}
+				handle = bgfx::createTextureCube(
+					  uint16_t(imageContainer->m_width)
+					, 1 < imageContainer->m_numMips
+					, imageContainer->m_numLayers
+					, imageContainer->m_format
+					, _flags
+					, mem
+					);
 			}
 			}
 			else
 			else
 			{
 			{
-				int comp = 0;
-				out = stbi_load_from_memory( (uint8_t*)data, size, (int*)&width, (int*)&height, &comp, 4);
+				handle = bgfx::createTexture2D(
+					  uint16_t(imageContainer->m_width)
+					, uint16_t(imageContainer->m_height)
+					, 1 < imageContainer->m_numMips
+					, imageContainer->m_numLayers
+					, imageContainer->m_format
+					, _flags
+					, mem
+					);
 			}
 			}
-		}
-
-		BX_FREE(allocator, data);
-
-		if (NULL != out)
-		{
-			handle = bgfx::createTexture2D(
-				  uint16_t(width)
-				, uint16_t(height)
-				, false
-				, 1
-				, format
-				, _flags
-				, bgfx::copy(out, width*height*bpp/8)
-				);
-			release(out);
 
 
 			if (NULL != _info)
 			if (NULL != _info)
 			{
 			{
 				bgfx::calcTextureSize(
 				bgfx::calcTextureSize(
 					  *_info
 					  *_info
-					, uint16_t(width)
-					, uint16_t(height)
+					, uint16_t(imageContainer->m_width)
+					, uint16_t(imageContainer->m_height)
 					, 0
 					, 0
 					, false
 					, false
 					, false
 					, false
 					, 1
 					, 1
-					, format
+					, imageContainer->m_format
 					);
 					);
 			}
 			}
 		}
 		}
 	}
 	}
-	else
-	{
-		DBG("Failed to load %s.", _filePath);
-	}
 
 
 	return handle;
 	return handle;
 }
 }
@@ -473,6 +222,14 @@ bgfx::TextureHandle loadTexture(const char* _name, uint32_t _flags, uint8_t _ski
 	return loadTexture(entry::getFileReader(), _name, _flags, _skip, _info);
 	return loadTexture(entry::getFileReader(), _name, _flags, _skip, _info);
 }
 }
 
 
+bgfx::ImageContainer* imageLoad(const char* _filePath, bgfx::TextureFormat::Enum _dstFormat)
+{
+	uint32_t size = 0;
+	void* data = loadMem(entry::getFileReader(), entry::getAllocator(), _filePath, &size);
+
+	return bgfx::imageParse(entry::getAllocator(), data, size, _dstFormat);
+}
+
 void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
 void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
 {
 {
 	struct PosTexcoord
 	struct PosTexcoord

+ 26 - 0
examples/common/bgfx_utils.h

@@ -7,12 +7,27 @@
 #define BGFX_UTILS_H_HEADER_GUARD
 #define BGFX_UTILS_H_HEADER_GUARD
 
 
 #include <bgfx/bgfx.h>
 #include <bgfx/bgfx.h>
+#include "image.h"
 
 
+///
 void* load(const char* _filePath, uint32_t* _size = NULL);
 void* load(const char* _filePath, uint32_t* _size = NULL);
+
+///
 void unload(void* _ptr);
 void unload(void* _ptr);
+
+///
 bgfx::ShaderHandle loadShader(const char* _name);
 bgfx::ShaderHandle loadShader(const char* _name);
+
+///
 bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName);
 bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName);
+
+///
 bgfx::TextureHandle loadTexture(const char* _name, uint32_t _flags = BGFX_TEXTURE_NONE, uint8_t _skip = 0, bgfx::TextureInfo* _info = NULL);
 bgfx::TextureHandle loadTexture(const char* _name, uint32_t _flags = BGFX_TEXTURE_NONE, uint8_t _skip = 0, bgfx::TextureInfo* _info = NULL);
+
+///
+bgfx::ImageContainer* imageLoad(const char* _filePath, bgfx::TextureFormat::Enum _dstFormat);
+
+///
 void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices);
 void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices);
 
 
 /// Returns true if both internal transient index and vertex buffer have
 /// Returns true if both internal transient index and vertex buffer have
@@ -29,6 +44,7 @@ inline bool checkAvailTransientBuffers(uint32_t _numVertices, const bgfx::Vertex
 		;
 		;
 }
 }
 
 
+///
 struct MeshState
 struct MeshState
 {
 {
 	struct Texture
 	struct Texture
@@ -48,15 +64,25 @@ struct MeshState
 
 
 struct Mesh;
 struct Mesh;
 
 
+///
 Mesh* meshLoad(const char* _filePath);
 Mesh* meshLoad(const char* _filePath);
+
+///
 void meshUnload(Mesh* _mesh);
 void meshUnload(Mesh* _mesh);
 
 
+///
 MeshState* meshStateCreate();
 MeshState* meshStateCreate();
+
+///
 void meshStateDestroy(MeshState* _meshState);
 void meshStateDestroy(MeshState* _meshState);
 
 
+///
 void meshSubmit(const Mesh* _mesh, uint8_t _id, bgfx::ProgramHandle _program, const float* _mtx, uint64_t _state = BGFX_STATE_MASK);
 void meshSubmit(const Mesh* _mesh, uint8_t _id, bgfx::ProgramHandle _program, const float* _mtx, uint64_t _state = BGFX_STATE_MASK);
+
+///
 void meshSubmit(const Mesh* _mesh, const MeshState*const* _state, uint8_t _numPasses, const float* _mtx, uint16_t _numMatrices = 1);
 void meshSubmit(const Mesh* _mesh, const MeshState*const* _state, uint8_t _numPasses, const float* _mtx, uint16_t _numMatrices = 1);
 
 
+///
 struct Args
 struct Args
 {
 {
 	Args(int _argc, char** _argv);
 	Args(int _argc, char** _argv);

+ 394 - 0
examples/common/image.cpp

@@ -0,0 +1,394 @@
+/*
+ * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#include "entry/dbg.h"
+
+#include <bgfx/bgfx.h>
+#include <bx/allocator.h>
+#include <bx/endian.h>
+#include <bx/readerwriter.h>
+#include "bgfx_utils.h"
+
+BX_PRAGMA_DIAGNOSTIC_PUSH()
+BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wtype-limits")
+BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter")
+BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-value")
+BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4100) // error C4100: '' : unreferenced formal parameter
+#if BX_PLATFORM_EMSCRIPTEN
+#	include <compat/ctype.h>
+#endif // BX_PLATFORM_EMSCRIPTEN
+#define MINIZ_NO_STDIO
+#define TINYEXR_IMPLEMENTATION
+#include <tinyexr/tinyexr.h>
+BX_PRAGMA_DIAGNOSTIC_POP()
+
+#define LODEPNG_NO_COMPILE_ENCODER
+#define LODEPNG_NO_COMPILE_DISK
+#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
+#define LODEPNG_NO_COMPILE_ERROR_TEXT
+#define LODEPNG_NO_COMPILE_ALLOCATORS
+#define LODEPNG_NO_COMPILE_CPP
+#include <lodepng/lodepng.h>
+
+typedef unsigned char stbi_uc;
+extern "C" stbi_uc* stbi_load_from_memory(stbi_uc const* _buffer, int _len, int* _x, int* _y, int* _comp, int _req_comp);
+extern "C" void stbi_image_free(void* _ptr);
+extern void lodepng_free(void* _ptr);
+
+namespace bgfx
+{
+	struct ImageMip
+	{
+		TextureFormat::Enum m_format;
+		uint32_t m_width;
+		uint32_t m_height;
+		uint32_t m_blockSize;
+		uint32_t m_size;
+		uint8_t  m_bpp;
+		bool     m_hasAlpha;
+		const uint8_t* m_data;
+	};
+
+	uint32_t imageGetSize(
+		  TextureInfo* _info
+		, uint16_t _width
+		, uint16_t _height
+		, uint16_t _depth
+		, bool _cubeMap
+		, bool _hasMips
+		, uint16_t _numLayers
+		, TextureFormat::Enum _format
+		);
+
+	///
+	ImageContainer* imageParseBgfx(bx::AllocatorI* _allocator, const void* _src, uint32_t _size);
+
+	///
+	bool imageConvert(
+		  void* _dst
+		, TextureFormat::Enum _dstFormat
+		, const void* _src
+		, TextureFormat::Enum _srcFormat
+		, uint32_t _width
+		, uint32_t _height
+		);
+
+	///
+	ImageContainer* imageConvert(
+		  bx::AllocatorI* _allocator
+		, TextureFormat::Enum _dstFormat
+		, const ImageContainer& _input
+		);
+
+} // namespace bgfx
+
+namespace bgfx
+{
+	static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
+	{
+		static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
+
+		if (0 == bx::memCmp(_data, pngMagic, sizeof(pngMagic) ) )
+		{
+			return NULL;
+		}
+
+		bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
+		uint32_t width  = 0;
+		uint32_t height = 0;
+
+		unsigned error;
+		LodePNGState state;
+		lodepng_state_init(&state);
+		state.decoder.color_convert = 0;
+
+		uint8_t* data = NULL;
+		error = lodepng_decode(&data, &width, &height, &state, (uint8_t*)_data, _size);
+
+		if (0 == error)
+		{
+			switch (state.info_raw.bitdepth)
+			{
+				case 8:
+					switch (state.info_raw.colortype)
+					{
+						case LCT_GREY:
+							format = bgfx::TextureFormat::R8;
+							break;
+
+						case LCT_GREY_ALPHA:
+							format = bgfx::TextureFormat::RG8;
+							break;
+
+						case LCT_RGB:
+							format = bgfx::TextureFormat::RGB8;
+							break;
+
+						case LCT_RGBA:
+							format = bgfx::TextureFormat::RGBA8;
+							break;
+
+						case LCT_PALETTE:
+							break;
+					}
+					break;
+
+				case 16:
+					switch (state.info_raw.colortype)
+					{
+						case LCT_GREY:
+							for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
+							{
+								uint16_t* rgba = (uint16_t*)data + ii;
+								rgba[0] = bx::toHostEndian(rgba[0], false);
+							}
+							format = bgfx::TextureFormat::R16;
+							break;
+
+						case LCT_GREY_ALPHA:
+							for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
+							{
+								uint16_t* rgba = (uint16_t*)data + ii*2;
+								rgba[0] = bx::toHostEndian(rgba[0], false);
+								rgba[1] = bx::toHostEndian(rgba[1], false);
+							}
+							format = bgfx::TextureFormat::RG16;
+							break;
+
+						case LCT_RGBA:
+							for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
+							{
+								uint16_t* rgba = (uint16_t*)data + ii*4;
+								rgba[0] = bx::toHostEndian(rgba[0], false);
+								rgba[1] = bx::toHostEndian(rgba[1], false);
+								rgba[2] = bx::toHostEndian(rgba[2], false);
+								rgba[3] = bx::toHostEndian(rgba[3], false);
+							}
+							format = bgfx::TextureFormat::RGBA16;
+							break;
+
+						case LCT_RGB:
+						case LCT_PALETTE:
+							break;
+					}
+					break;
+
+				default:
+					break;
+			}
+		}
+
+		lodepng_state_cleanup(&state);
+
+		ImageContainer* output = imageAlloc(_allocator
+			, format
+			, uint16_t(width)
+			, uint16_t(height)
+			, 0
+			, 1
+			, false
+			, false
+			, data
+			);
+		lodepng_free(data);
+
+		return output;
+	}
+
+	static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
+	{
+		EXRVersion exrVersion;
+		int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
+		if (TINYEXR_SUCCESS != result)
+		{
+			return NULL;
+		}
+
+		bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
+		uint32_t width  = 0;
+		uint32_t height = 0;
+
+		uint8_t* data = NULL;
+		const char* err = NULL;
+		EXRHeader exrHeader;
+		result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)_data, _size, &err);
+		if (TINYEXR_SUCCESS == result)
+		{
+			EXRImage exrImage;
+			InitEXRImage(&exrImage);
+
+			result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)_data, _size, &err);
+			if (TINYEXR_SUCCESS == result)
+			{
+				uint8_t idxR = UINT8_MAX;
+				uint8_t idxG = UINT8_MAX;
+				uint8_t idxB = UINT8_MAX;
+				uint8_t idxA = UINT8_MAX;
+				for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
+				{
+					const EXRChannelInfo& channel = exrHeader.channels[ii];
+					if (UINT8_MAX == idxR
+					&&  0 == bx::strncmp(channel.name, "R") )
+					{
+						idxR = ii;
+					}
+					else if (UINT8_MAX == idxG
+					&&  0 == bx::strncmp(channel.name, "G") )
+					{
+						idxG = ii;
+					}
+					else if (UINT8_MAX == idxB
+					&&  0 == bx::strncmp(channel.name, "B") )
+					{
+						idxB = ii;
+					}
+					else if (UINT8_MAX == idxA
+					&&  0 == bx::strncmp(channel.name, "A") )
+					{
+						idxA = ii;
+					}
+				}
+
+				if (UINT8_MAX != idxR)
+				{
+					const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
+					uint32_t srcBpp = 32;
+					uint32_t dstBpp = asFloat ? 32 : 16;
+					format = asFloat ? TextureFormat::R32F : TextureFormat::R16F;
+					uint32_t stepR = 1;
+					uint32_t stepG = 0;
+					uint32_t stepB = 0;
+					uint32_t stepA = 0;
+
+					if (UINT8_MAX != idxG)
+					{
+						srcBpp += 32;
+						dstBpp = asFloat ? 64 : 32;
+						format = asFloat ? TextureFormat::RG32F : TextureFormat::RG16F;
+						stepG  = 1;
+					}
+
+					if (UINT8_MAX != idxB)
+					{
+						srcBpp += 32;
+						dstBpp = asFloat ? 128 : 64;
+						format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
+						stepB  = 1;
+					}
+
+					if (UINT8_MAX != idxA)
+					{
+						srcBpp += 32;
+						dstBpp = asFloat ? 128 : 64;
+						format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
+						stepA  = 1;
+					}
+
+					data = (uint8_t*)BX_ALLOC(_allocator, exrImage.width * exrImage.height * dstBpp/8);
+
+					const float  zero = 0.0f;
+					const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
+					const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
+					const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
+					const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
+
+					const uint32_t bytesPerPixel = dstBpp/8;
+					for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
+					{
+						float rgba[4] =
+						{
+							*srcR,
+							*srcG,
+							*srcB,
+							*srcA,
+						};
+						bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
+
+						srcR += stepR;
+						srcG += stepG;
+						srcB += stepB;
+						srcA += stepA;
+					}
+				}
+
+				FreeEXRImage(&exrImage);
+			}
+
+			FreeEXRHeader(&exrHeader);
+		}
+
+		ImageContainer* output = imageAlloc(_allocator
+			, format
+			, uint16_t(width)
+			, uint16_t(height)
+			, 0
+			, 1
+			, false
+			, false
+			, data
+			);
+		BX_FREE(_allocator, data);
+
+		return output;
+	}
+
+	static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
+	{
+		TextureFormat::Enum format = TextureFormat::RGBA8;
+		uint32_t width  = 0;
+		uint32_t height = 0;
+
+		int comp = 0;
+		void* data = stbi_load_from_memory( (uint8_t*)_data, _size, (int*)&width, (int*)&height, &comp, 4);
+
+		if (NULL != data)
+		{
+			return NULL;
+		}
+
+		ImageContainer* output = imageAlloc(_allocator
+			, format
+			, uint16_t(width)
+			, uint16_t(height)
+			, 0
+			, 1
+			, false
+			, false
+			, data
+			);
+		stbi_image_free(data);
+
+		return output;
+	}
+
+	ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat)
+	{
+		ImageContainer* input = imageParseBgfx    (_allocator, _data, _size)        ;
+		input = NULL == input ? imageParseLodePng (_allocator, _data, _size) : input;
+		input = NULL == input ? imageParseTinyExr (_allocator, _data, _size) : input;
+		input = NULL == input ? imageParseStbImage(_allocator, _data, _size) : input;
+
+		if (NULL == input)
+		{
+			return NULL;
+		}
+
+		_dstFormat = TextureFormat::Count == _dstFormat
+			? input->m_format
+			: _dstFormat
+			;
+
+		if (_dstFormat == input->m_format)
+		{
+			return input;
+		}
+
+		ImageContainer* output = imageConvert(_allocator, _dstFormat, *input);
+		imageFree(input);
+
+		return output;
+	}
+
+} // namespace bgfx

+ 62 - 0
examples/common/image.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
+ * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
+ */
+
+#ifndef IMAGE_H_HEADER_GUARD
+#define IMAGE_H_HEADER_GUARD
+
+namespace bgfx
+{
+	///
+	struct ImageContainer
+	{
+		bx::AllocatorI* m_allocator;
+		void*           m_data;
+
+		TextureFormat::Enum m_format;
+
+		uint32_t m_size;
+		uint32_t m_offset;
+		uint32_t m_width;
+		uint32_t m_height;
+		uint32_t m_depth;
+		uint16_t m_numLayers;
+		uint8_t  m_numMips;
+		bool     m_hasAlpha;
+		bool     m_cubeMap;
+		bool     m_ktx;
+		bool     m_ktxLE;
+		bool     m_srgb;
+	};
+
+	///
+	ImageContainer* imageParse(
+		  bx::AllocatorI* _allocator
+		, const void* _data
+		, uint32_t _size
+		, TextureFormat::Enum _dstFormat = TextureFormat::Count
+		);
+
+	///
+	ImageContainer* imageAlloc(
+		  bx::AllocatorI* _allocator
+		, TextureFormat::Enum _format
+		, uint16_t _width
+		, uint16_t _height
+		, uint16_t _depth
+		, uint16_t _numLayers
+		, bool _cubeMap
+		, bool _hasMips
+		, const void* _data = NULL
+		);
+
+	///
+	void imageFree(ImageContainer* _imageContainer);
+
+	/// Converts format to string.
+	const char* getName(TextureFormat::Enum _format);
+
+} // namespace bgfx
+
+#endif // IMAGE_H_HEADER_GUARD

+ 115 - 14
examples/common/ps/particle_system.cpp

@@ -8,6 +8,7 @@
 
 
 #include "particle_system.h"
 #include "particle_system.h"
 #include "../bgfx_utils.h"
 #include "../bgfx_utils.h"
+#include "../packrect.h"
 
 
 #include <bx/easing.h>
 #include <bx/easing.h>
 #include <bx/crtimpl.h>
 #include <bx/crtimpl.h>
@@ -183,6 +184,49 @@ namespace ps
 			;
 			;
 	}
 	}
 
 
+#define SPRITE_TEXTURE_SIZE 1024
+	template<uint16_t MaxHandlesT = 256, uint16_t TextureSizeT = 1024>
+	struct SpriteT
+	{
+		SpriteT()
+			: m_ra(TextureSizeT, TextureSizeT)
+		{
+		}
+
+		EmitterSpriteHandle create(uint16_t _width, uint16_t _height)
+		{
+			EmitterSpriteHandle handle = { bx::HandleAlloc::invalid };
+
+			if (m_handleAlloc.getNumHandles() < m_handleAlloc.getMaxHandles() )
+			{
+				Pack2D pack;
+				if (m_ra.find(_width, _height, pack) )
+				{
+					handle.idx = m_handleAlloc.alloc();
+					m_pack[handle.idx] = pack;
+				}
+			}
+
+			return handle;
+		}
+
+		void destroy(EmitterSpriteHandle _sprite)
+		{
+			const Pack2D& pack = m_pack[_sprite.idx];
+			m_ra.clear(pack);
+			m_handleAlloc.free(_sprite.idx);
+		}
+
+		const Pack2D& get(EmitterSpriteHandle _sprite) const
+		{
+			return m_pack[_sprite.idx];
+		}
+
+		bx::HandleAllocT<MaxHandlesT> m_handleAlloc;
+		Pack2D                        m_pack[MaxHandlesT];
+		RectPack2DT<256>              m_ra;
+	};
+
 	struct Emitter
 	struct Emitter
 	{
 	{
 		void create(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles);
 		void create(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles);
@@ -322,7 +366,7 @@ namespace ps
 			}
 			}
 		}
 		}
 
 
-		uint32_t render(const float* _mtxView, const float* _eye, uint32_t _first, uint32_t _max, ParticleSort* _outSort, PosColorTexCoord0Vertex* _outVertices)
+		uint32_t render(const float _uv[4], const float* _mtxView, const float* _eye, uint32_t _first, uint32_t _max, ParticleSort* _outSort, PosColorTexCoord0Vertex* _outVertices)
 		{
 		{
 			bx::EaseFn easeRgba  = s_easeFunc[m_uniforms.m_easeRgba];
 			bx::EaseFn easeRgba  = s_easeFunc[m_uniforms.m_easeRgba];
 			bx::EaseFn easePos   = s_easeFunc[m_uniforms.m_easePos];
 			bx::EaseFn easePos   = s_easeFunc[m_uniforms.m_easePos];
@@ -385,8 +429,8 @@ namespace ps
 				bx::vec3Sub(&vertex->m_x, tmp, vdir);
 				bx::vec3Sub(&vertex->m_x, tmp, vdir);
 				aabbExpand(aabb, &vertex->m_x);
 				aabbExpand(aabb, &vertex->m_x);
 				vertex->m_abgr  = abgr;
 				vertex->m_abgr  = abgr;
-				vertex->m_u     = 0.0f;
-				vertex->m_v     = 0.0f;
+				vertex->m_u     = _uv[0];
+				vertex->m_v     = _uv[1];
 				vertex->m_blend = blend;
 				vertex->m_blend = blend;
 				++vertex;
 				++vertex;
 
 
@@ -394,8 +438,8 @@ namespace ps
 				bx::vec3Sub(&vertex->m_x, tmp, vdir);
 				bx::vec3Sub(&vertex->m_x, tmp, vdir);
 				aabbExpand(aabb, &vertex->m_x);
 				aabbExpand(aabb, &vertex->m_x);
 				vertex->m_abgr  = abgr;
 				vertex->m_abgr  = abgr;
-				vertex->m_u     = 1.0f;
-				vertex->m_v     = 0.0f;
+				vertex->m_u     = _uv[2];
+				vertex->m_v     = _uv[1];
 				vertex->m_blend = blend;
 				vertex->m_blend = blend;
 				++vertex;
 				++vertex;
 
 
@@ -403,8 +447,8 @@ namespace ps
 				bx::vec3Add(&vertex->m_x, tmp, vdir);
 				bx::vec3Add(&vertex->m_x, tmp, vdir);
 				aabbExpand(aabb, &vertex->m_x);
 				aabbExpand(aabb, &vertex->m_x);
 				vertex->m_abgr  = abgr;
 				vertex->m_abgr  = abgr;
-				vertex->m_u     = 1.0f;
-				vertex->m_v     = 1.0f;
+				vertex->m_u     = _uv[2];
+				vertex->m_v     = _uv[3];
 				vertex->m_blend = blend;
 				vertex->m_blend = blend;
 				++vertex;
 				++vertex;
 
 
@@ -412,8 +456,8 @@ namespace ps
 				bx::vec3Add(&vertex->m_x, tmp, vdir);
 				bx::vec3Add(&vertex->m_x, tmp, vdir);
 				aabbExpand(aabb, &vertex->m_x);
 				aabbExpand(aabb, &vertex->m_x);
 				vertex->m_abgr  = abgr;
 				vertex->m_abgr  = abgr;
-				vertex->m_u     = 0.0f;
-				vertex->m_v     = 1.0f;
+				vertex->m_u     = _uv[0];
+				vertex->m_v     = _uv[3];
 				vertex->m_blend = blend;
 				vertex->m_blend = blend;
 				++vertex;
 				++vertex;
 			}
 			}
@@ -466,7 +510,13 @@ namespace ps
 			m_num = 0;
 			m_num = 0;
 
 
 			s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1);
 			s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Int1);
-			m_particleTexture = loadTexture("textures/particle.ktx");
+			m_texture  = bgfx::createTexture2D(
+				  SPRITE_TEXTURE_SIZE
+				, SPRITE_TEXTURE_SIZE
+				, false
+				, 1
+				, bgfx::TextureFormat::BGRA8
+				);
 
 
 			bgfx::RendererType::Enum type = bgfx::getRendererType();
 			bgfx::RendererType::Enum type = bgfx::getRendererType();
 			m_particleProgram = bgfx::createProgram(
 			m_particleProgram = bgfx::createProgram(
@@ -479,7 +529,7 @@ namespace ps
 		void shutdown()
 		void shutdown()
 		{
 		{
 			bgfx::destroyProgram(m_particleProgram);
 			bgfx::destroyProgram(m_particleProgram);
-			bgfx::destroyTexture(m_particleTexture);
+			bgfx::destroyTexture(m_texture);
 			bgfx::destroyUniform(s_texColor);
 			bgfx::destroyUniform(s_texColor);
 
 
 			bx::destroyHandleAlloc(m_allocator, m_emitterAlloc);
 			bx::destroyHandleAlloc(m_allocator, m_emitterAlloc);
@@ -488,6 +538,33 @@ namespace ps
 			m_allocator = NULL;
 			m_allocator = NULL;
 		}
 		}
 
 
+		EmitterSpriteHandle createSprite(uint16_t _width, uint16_t _height, const void* _data)
+		{
+			EmitterSpriteHandle handle = m_sprite.create(_width, _height);
+
+			if (isValid(handle) )
+			{
+				const Pack2D& pack = m_sprite.get(handle);
+				bgfx::updateTexture2D(
+						m_texture
+						, 0
+						, 0
+						, pack.m_x
+						, pack.m_y
+						, pack.m_width
+						, pack.m_height
+						, bgfx::copy(_data, pack.m_width*pack.m_height*4)
+						);
+			}
+
+			return handle;
+		}
+
+		void destroy(EmitterSpriteHandle _handle)
+		{
+			m_sprite.destroy(_handle);
+		}
+
 		void update(float _dt)
 		void update(float _dt)
 		{
 		{
 			uint32_t numParticles = 0;
 			uint32_t numParticles = 0;
@@ -535,7 +612,18 @@ namespace ps
 					{
 					{
 						const uint16_t idx = m_emitterAlloc->getHandleAt(ii);
 						const uint16_t idx = m_emitterAlloc->getHandleAt(ii);
 						Emitter& emitter = m_emitter[idx];
 						Emitter& emitter = m_emitter[idx];
-						pos += emitter.render(_mtxView, _eye, pos, max, particleSort, vertices);
+
+						const Pack2D& pack = m_sprite.get(emitter.m_uniforms.m_handle);
+						const float invTextureSize = 1.0f/SPRITE_TEXTURE_SIZE;
+						const float uv[4] =
+						{
+							 pack.m_x                  * invTextureSize,
+							 pack.m_y                  * invTextureSize,
+							(pack.m_x + pack.m_width ) * invTextureSize,
+							(pack.m_y + pack.m_height) * invTextureSize,
+						};
+
+						pos += emitter.render(uv, _mtxView, _eye, pos, max, particleSort, vertices);
 					}
 					}
 
 
 					qsort(particleSort
 					qsort(particleSort
@@ -569,7 +657,7 @@ namespace ps
 						);
 						);
 					bgfx::setVertexBuffer(&tvb);
 					bgfx::setVertexBuffer(&tvb);
 					bgfx::setIndexBuffer(&tib);
 					bgfx::setIndexBuffer(&tib);
-					bgfx::setTexture(0, s_texColor, m_particleTexture);
+					bgfx::setTexture(0, s_texColor, m_texture);
 					bgfx::submit(_view, m_particleProgram);
 					bgfx::submit(_view, m_particleProgram);
 				}
 				}
 			}
 			}
@@ -631,8 +719,11 @@ namespace ps
 		bx::HandleAlloc* m_emitterAlloc;
 		bx::HandleAlloc* m_emitterAlloc;
 		Emitter* m_emitter;
 		Emitter* m_emitter;
 
 
+		typedef SpriteT<256, SPRITE_TEXTURE_SIZE> Sprite;
+		Sprite m_sprite;
+
 		bgfx::UniformHandle s_texColor;
 		bgfx::UniformHandle s_texColor;
-		bgfx::TextureHandle m_particleTexture;
+		bgfx::TextureHandle m_texture;
 		bgfx::ProgramHandle m_particleProgram;
 		bgfx::ProgramHandle m_particleProgram;
 
 
 		uint32_t m_num;
 		uint32_t m_num;
@@ -672,6 +763,16 @@ void psShutdown()
 	s_ctx.shutdown();
 	s_ctx.shutdown();
 }
 }
 
 
+EmitterSpriteHandle psCreateSprite(uint16_t _width, uint16_t _height, const void* _data)
+{
+	return s_ctx.createSprite(_width, _height, _data);
+}
+
+void psDestroy(EmitterSpriteHandle _handle)
+{
+	s_ctx.destroy(_handle);
+}
+
 EmitterHandle psCreateEmitter(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles)
 EmitterHandle psCreateEmitter(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles)
 {
 {
 	return s_ctx.createEmitter(_shape, _direction, _maxParticles);
 	return s_ctx.createEmitter(_shape, _direction, _maxParticles);

+ 17 - 2
examples/common/ps/particle_system.h

@@ -12,6 +12,15 @@
 
 
 #include "../bounds.h"
 #include "../bounds.h"
 
 
+struct EmitterHandle       { uint16_t idx; };
+struct EmitterSpriteHandle { uint16_t idx; };
+
+template<typename Ty>
+inline bool isValid(Ty _handle)
+{
+	return _handle.idx != UINT16_MAX;
+}
+
 struct EmitterShape
 struct EmitterShape
 {
 {
 	enum Enum
 	enum Enum
@@ -60,9 +69,9 @@ struct EmitterUniforms
 	bx::Easing::Enum m_easeRgba;
 	bx::Easing::Enum m_easeRgba;
 	bx::Easing::Enum m_easeBlend;
 	bx::Easing::Enum m_easeBlend;
 	bx::Easing::Enum m_easeScale;
 	bx::Easing::Enum m_easeScale;
-};
 
 
-struct EmitterHandle { uint16_t idx; };
+	EmitterSpriteHandle m_handle;
+};
 
 
 ///
 ///
 void psInit(uint16_t _maxEmitters = 64, bx::AllocatorI* _allocator = NULL);
 void psInit(uint16_t _maxEmitters = 64, bx::AllocatorI* _allocator = NULL);
@@ -70,6 +79,12 @@ void psInit(uint16_t _maxEmitters = 64, bx::AllocatorI* _allocator = NULL);
 ///
 ///
 void psShutdown();
 void psShutdown();
 
 
+///
+EmitterSpriteHandle psCreateSprite(uint16_t _width, uint16_t _height, const void* _data);
+
+///
+void psDestroy(EmitterSpriteHandle _handle);
+
 ///
 ///
 EmitterHandle psCreateEmitter(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles);
 EmitterHandle psCreateEmitter(EmitterShape::Enum _shape, EmitterDirection::Enum _direction, uint32_t _maxParticles);
 
 

+ 0 - 1
scripts/texturev.lua

@@ -11,7 +11,6 @@ project ("texturev")
 		path.join(BGFX_DIR, "examples/common"),
 		path.join(BGFX_DIR, "examples/common"),
 		path.join(MODULE_DIR, "include"),
 		path.join(MODULE_DIR, "include"),
 		path.join(MODULE_DIR, "3rdparty"),
 		path.join(MODULE_DIR, "3rdparty"),
-		path.join(MODULE_DIR, "src"),
 	}
 	}
 
 
 	files {
 	files {

+ 9 - 4
src/image.cpp

@@ -858,7 +858,7 @@ namespace bgfx
 			, 1 < _input.m_numMips
 			, 1 < _input.m_numMips
 			);
 			);
 
 
-		const uint8_t bpp = getBitsPerPixel(_dstFormat);
+		const uint8_t  bpp = getBitsPerPixel(_dstFormat);
 		const uint16_t numSides = _input.m_numLayers * (_input.m_cubeMap ? 6 : 1);
 		const uint16_t numSides = _input.m_numLayers * (_input.m_cubeMap ? 6 : 1);
 
 
 		uint8_t* dst = (uint8_t*)output->m_data	;
 		uint8_t* dst = (uint8_t*)output->m_data	;
@@ -906,7 +906,7 @@ namespace bgfx
 			, imageContainer.m_numLayers
 			, imageContainer.m_numLayers
 			, imageContainer.m_cubeMap
 			, imageContainer.m_cubeMap
 			, 1 < imageContainer.m_numMips
 			, 1 < imageContainer.m_numMips
-			, _src
+			, (uint8_t*)_src + imageContainer.m_offset
 			);
 			);
 
 
 		return output;
 		return output;
@@ -1712,10 +1712,10 @@ namespace bgfx
 		const uint8_t numMips = _hasMips ? imageGetNumMips(_format, _width, _height) : 1;
 		const uint8_t numMips = _hasMips ? imageGetNumMips(_format, _width, _height) : 1;
 		uint32_t size = imageGetSize(NULL, _width, _height, _depth, _cubeMap, _hasMips, _numLayers, _format);
 		uint32_t size = imageGetSize(NULL, _width, _height, _depth, _cubeMap, _hasMips, _numLayers, _format);
 
 
-		ImageContainer* imageContainer = (ImageContainer*)BX_ALLOC(_allocator, (NULL != _data ? 0 : size) + sizeof(ImageContainer) );
+		ImageContainer* imageContainer = (ImageContainer*)BX_ALLOC(_allocator, size + sizeof(ImageContainer) );
 
 
 		imageContainer->m_allocator = _allocator;
 		imageContainer->m_allocator = _allocator;
-		imageContainer->m_data      = NULL != _data ? const_cast<void*>(_data) : imageContainer + 1;
+		imageContainer->m_data      = imageContainer + 1;
 		imageContainer->m_format    = _format;
 		imageContainer->m_format    = _format;
 		imageContainer->m_size      = size;
 		imageContainer->m_size      = size;
 		imageContainer->m_offset    = 0;
 		imageContainer->m_offset    = 0;
@@ -1730,6 +1730,11 @@ namespace bgfx
 		imageContainer->m_ktxLE     = false;
 		imageContainer->m_ktxLE     = false;
 		imageContainer->m_srgb      = false;
 		imageContainer->m_srgb      = false;
 
 
+		if (NULL != _data)
+		{
+			bx::memCopy(imageContainer->m_data, _data, imageContainer->m_size);
+		}
+
 		return imageContainer;
 		return imageContainer;
 	}
 	}