8#include <tinystl/allocator.h>
9#include <tinystl/string.h>
10#include <tinystl/vector.h>
11namespace stl = tinystl;
15#include <bx/commandline.h>
18#include <bx/readerwriter.h>
24#include <bimg/decode.h>
37bx::AllocatorI* getDefaultAllocator()
39 static bx::DefaultAllocator allocator;
43static bx::AllocatorI* g_allocator = getDefaultAllocator();
44typedef bx::StringT<&g_allocator> String;
46class FileReader :
public bx::FileReader
48 typedef bx::FileReader super;
51 virtual bool open(
const bx::FilePath& _filePath, bx::Error* _err)
override
53 return super::open(_filePath, _err);
57class FileWriter :
public bx::FileWriter
59 typedef bx::FileWriter super;
62 virtual bool open(
const bx::FilePath& _filePath,
bool _append, bx::Error* _err)
override
64 return super::open(_filePath, _append, _err);
68bx::AllocatorI* getAllocator()
76void*
load(bx::FileReaderI* _reader, bx::AllocatorI* _allocator,
const bx::FilePath& _filePath, uint32_t* _size)
78 if(bx::open(_reader, _filePath))
80 uint32_t
size = (uint32_t)bx::getSize(_reader);
81 void* data = bx::alloc(_allocator,
size);
82 bx::read(_reader, data,
size, bx::ErrorAssert{});
92 DBG(
"Failed to open: %s.", _filePath);
103void*
load(
const bx::FilePath& _filePath, uint32_t* _size)
105 entry::FileReader reader;
106 return load(&reader, entry::getAllocator(), _filePath, _size);
111 bx::free(entry::getAllocator(), _ptr);
114static const bgfx::Memory*
loadMem(bx::FileReaderI* _reader,
const char* _filePath)
116 if(bx::open(_reader, _filePath))
118 uint32_t
size = (uint32_t)bx::getSize(_reader);
119 const bgfx::Memory* mem = bgfx::alloc(
size + 1);
120 bx::read(_reader, mem->data,
size, bx::ErrorAssert{});
122 mem->data[mem->size - 1] =
'\0';
126 DBG(
"Failed to load %s.", _filePath);
130static void*
loadMem(bx::FileReaderI* _reader, bx::AllocatorI* _allocator,
const bx::FilePath& _filePath, uint32_t* _size)
132 if(bx::open(_reader, _filePath))
134 uint32_t
size = (uint32_t)bx::getSize(_reader);
135 void* data = bx::alloc(_allocator,
size);
136 bx::read(_reader, data,
size, bx::ErrorAssert{});
146 DBG(
"Failed to load %s.", _filePath);
150static bgfx::ShaderHandle
loadShader(bx::FileReaderI* _reader,
const bx::StringView& _name)
152 bx::FilePath filePath(
"shaders/");
154 switch (bgfx::getRendererType() )
156 case bgfx::RendererType::Noop:
157 case bgfx::RendererType::Direct3D11:
158 case bgfx::RendererType::Direct3D12: filePath.join(
"dx11");
break;
159 case bgfx::RendererType::Agc:
160 case bgfx::RendererType::Gnm: filePath.join(
"pssl");
break;
161 case bgfx::RendererType::Metal: filePath.join(
"metal");
break;
162 case bgfx::RendererType::Nvn: filePath.join(
"nvn");
break;
163 case bgfx::RendererType::OpenGL: filePath.join(
"glsl");
break;
164 case bgfx::RendererType::OpenGLES: filePath.join(
"essl");
break;
165 case bgfx::RendererType::Vulkan: filePath.join(
"spirv");
break;
166 case bgfx::RendererType::WebGPU: filePath.join(
"wgsl");
break;
168 case bgfx::RendererType::Count:
169 BX_ASSERT(
false,
"You should not be here!");
174 bx::strCopy(fileName, BX_COUNTOF(fileName), _name);
175 bx::strCat(fileName, BX_COUNTOF(fileName),
".bin");
177 filePath.join(fileName);
179 bgfx::ShaderHandle
handle = bgfx::createShader(
loadMem(_reader, filePath.getCPtr() ) );
180 bgfx::setName(
handle, _name.getPtr(), _name.getLength() );
187 entry::FileReader reader;
193 entry::FileReader reader;
194 bgfx::ShaderHandle
handle = bgfx::createShader(
loadMem(&reader, _filePath.getCPtr() ) );
195 bgfx::setName(
handle, _filePath.getFileName().getPtr(), int32_t(_filePath.getFileName().getLength() ) );
199bgfx::ProgramHandle
loadProgram(bx::FileReaderI* _reader,
const bx::StringView& _vsName,
const bx::StringView& _fsName)
201 bgfx::ShaderHandle vsh =
loadShader(_reader, _vsName);
202 bgfx::ShaderHandle fsh = BGFX_INVALID_HANDLE;
208 return bgfx::createProgram(vsh, fsh,
true );
211bgfx::ProgramHandle
loadProgram(
const bx::StringView& _vsName,
const bx::StringView& _fsName)
213 entry::FileReader reader;
220 bimg::ImageContainer* imageContainer = (bimg::ImageContainer*)_userData;
221 bimg::imageFree(imageContainer);
226 bgfx::TextureInfo* _info,
229 if(NULL == imageContainer)
231 return BGFX_INVALID_HANDLE;
234 const bgfx::Memory* mem = bgfx::makeRef(
235 imageContainer->m_data,
236 imageContainer->m_size,
240 bgfx::TextureInfo info;
241 bgfx::calcTextureSize(
243 uint16_t(imageContainer->m_width),
244 uint16_t(imageContainer->m_height),
245 uint16_t(imageContainer->m_depth),
246 imageContainer->m_cubeMap,
247 1 < imageContainer->m_numMips,
248 imageContainer->m_numLayers,
249 bgfx::TextureFormat::Enum(imageContainer->m_format));
258 if(_preCreate && !_preCreate(info))
260 bimg::imageFree(imageContainer);
261 return BGFX_INVALID_HANDLE;
264 if(imageContainer->m_cubeMap)
266 return bgfx::createTextureCube(
267 uint16_t(imageContainer->m_width),
268 1 < imageContainer->m_numMips,
269 imageContainer->m_numLayers,
270 bgfx::TextureFormat::Enum(imageContainer->m_format),
275 if(1 < imageContainer->m_depth)
277 return bgfx::createTexture3D(
278 uint16_t(imageContainer->m_width),
279 uint16_t(imageContainer->m_height),
280 uint16_t(imageContainer->m_depth),
281 1 < imageContainer->m_numMips,
282 bgfx::TextureFormat::Enum(imageContainer->m_format),
287 if(bgfx::isTextureValid(0,
false, imageContainer->m_numLayers, bgfx::TextureFormat::Enum(imageContainer->m_format), _flags))
289 return bgfx::createTexture2D(
290 uint16_t(imageContainer->m_width),
291 uint16_t(imageContainer->m_height),
292 1 < imageContainer->m_numMips,
293 imageContainer->m_numLayers,
294 bgfx::TextureFormat::Enum(imageContainer->m_format),
299 return BGFX_INVALID_HANDLE;
305auto can_flip_normal_y_format(bimg::TextureFormat::Enum _format) ->
bool
307 if(bimg::isCompressed(_format) || bimg::isFloat(_format))
312 return bimg::getUnpack(_format) !=
nullptr && bimg::getPack(_format) !=
nullptr;
315auto flip_normal_y_mip_ldr(bimg::ImageMip& _mip, bimg::TextureFormat::Enum _format) ->
bool
317 const bimg::UnpackFn unpack = bimg::getUnpack(_format);
318 const bimg::PackFn pack = bimg::getPack(_format);
319 if(
nullptr == unpack ||
nullptr == pack)
324 const uint32_t bpp = bimg::getBitsPerPixel(_format);
325 if(0 == bpp || (bpp % 8) != 0)
330 const uint32_t bytes_per_pixel = bpp / 8;
331 const uint32_t
width = _mip.m_width;
332 const uint32_t
height = _mip.m_height;
333 const uint32_t depth = bx::max<uint32_t>(1, _mip.m_depth);
334 const uint32_t row_stride =
width * bytes_per_pixel;
335 const uint32_t slice_stride = row_stride *
height;
337 uint8_t* slice =
const_cast<uint8_t*
>(_mip.m_data);
338 for(uint32_t zz = 0; zz < depth; ++zz)
340 uint8_t* row = slice + zz * slice_stride;
341 for(uint32_t yy = 0; yy <
height; ++yy)
343 uint8_t* pixel = row;
344 for(uint32_t xx = 0; xx <
width; ++xx)
350 pixel += bytes_per_pixel;
359auto flip_normal_y_all_mips_ldr(bimg::ImageContainer* _image) ->
bool
361 if(!can_flip_normal_y_format(_image->m_format))
366 for(uint8_t mip = 0; mip < _image->m_numMips; ++mip)
368 for(uint16_t layer = 0;
layer < _image->m_numLayers; ++
layer)
370 bimg::ImageMip mipData;
371 if(!bimg::imageGetRawData(*_image, layer, mip, _image->m_data, _image->m_size, mipData))
376 if(!flip_normal_y_mip_ldr(mipData, _image->m_format))
386auto ensure_rgba8_opaque_alpha(bimg::ImageContainer* _image) ->
void
388 if(
nullptr == _image)
393 if(_image->m_format != bimg::TextureFormat::RGBA8)
398 for(uint8_t mip = 0; mip < _image->m_numMips; ++mip)
400 for(uint16_t layer = 0;
layer < _image->m_numLayers; ++
layer)
402 bimg::ImageMip mipData;
403 if(!bimg::imageGetRawData(*_image, layer, mip, _image->m_data, _image->m_size, mipData))
408 const uint32_t
width = mipData.m_width;
409 const uint32_t
height = mipData.m_height;
410 const uint32_t depth = bx::max<uint32_t>(1, mipData.m_depth);
411 const uint32_t row_stride =
width * 4;
412 const uint32_t slice_stride = row_stride *
height;
414 uint8_t* slice =
const_cast<uint8_t*
>(mipData.m_data);
415 for(uint32_t zz = 0; zz < depth; ++zz)
417 uint8_t* row = slice + zz * slice_stride;
418 for(uint32_t yy = 0; yy <
height; ++yy)
420 uint8_t* pixel = row;
421 for(uint32_t xx = 0; xx <
width; ++xx)
446 if(bimg::isCompressed(_image->m_format))
448 bimg::ImageContainer* decoded =
449 bimg::imageConvert(entry::getAllocator(), bimg::TextureFormat::RGBA8, *_image);
455 bimg::imageFree(_image);
459 if(!flip_normal_y_all_mips_ldr(_image))
469 if(
nullptr == _image)
474 if(_image->m_format != bimg::TextureFormat::RGBA8)
476 bimg::ImageContainer* converted =
477 bimg::imageConvert(entry::getAllocator(), bimg::TextureFormat::RGBA8, *_image);
478 if(
nullptr == converted)
483 bimg::imageFree(_image);
487 ensure_rgba8_opaque_alpha(_image);
495 bgfx::TextureInfo* _info,
496 bimg::Orientation::Enum* _orientation,
502 bgfx::TextureHandle
handle = BGFX_INVALID_HANDLE;
506 bx::memSet(_info, 0,
sizeof(*_info) );
507 _info->format = bgfx::TextureFormat::Unknown;
510 if (NULL != _orientation)
512 *_orientation = bimg::Orientation::R0;
516 bx::Error* err = (NULL != _err) ? _err : &localErr;
517 bimg::ImageContainer* imageContainer = bimg::imageParse(entry::getAllocator(), _data, _size, bimg::TextureFormat::Count, err);
518 if(NULL != imageContainer)
520 if(NULL != _orientation)
522 *_orientation = imageContainer->m_orientation;
527 if(bgfx::isValid(
handle) && NULL != _name)
529 bgfx::setName(
handle, _name, int32_t(bx::strLen(_name)));
537 const bx::FilePath& _filePath,
540 bgfx::TextureInfo* _info,
541 bimg::Orientation::Enum* _orientation,
546 bgfx::TextureHandle
handle = BGFX_INVALID_HANDLE;
550 bx::memSet(_info, 0,
sizeof(*_info) );
551 _info->format = bgfx::TextureFormat::Unknown;
554 if (NULL != _orientation)
556 *_orientation = bimg::Orientation::R0;
560 void* data =
load(_reader, entry::getAllocator(), _filePath, &
size);
563 const bx::StringView
name(_filePath);
574 bgfx::TextureInfo* _info,
575 bimg::Orientation::Enum* _orientation,
579 entry::FileReader reader;
580 return loadTexture(&reader, _filePath, _flags, _skip, _info, _orientation, _err, _preCreate);
583bimg::ImageContainer*
imageLoad(
const void* data, uint32_t
size, bgfx::TextureFormat::Enum _dstFormat)
585 return bimg::imageParse(entry::getAllocator(), data,
size, bimg::TextureFormat::Enum(_dstFormat));
588bimg::ImageContainer*
imageLoad(
const bx::FilePath& _filePath, bgfx::TextureFormat::Enum _dstFormat)
590 entry::FileReader reader;
593 void* data =
loadMem(&reader, entry::getAllocator(), _filePath, &
size);
600 return bimg::imageParse(entry::getAllocator(), data,
size, bimg::TextureFormat::Enum(_dstFormat));
603bool imageParseInfo(
const void* _data, uint32_t _size, bimg::ImageContainer& _info, bx::Error* _err)
605 if(_data ==
nullptr || _size == 0)
610 return bimg::imageParseInfo(entry::getAllocator(), _info, _data, _size, _err);
613bool imageParseInfo(
const bx::FilePath& _filePath, bimg::ImageContainer& _info, bx::Error* _err)
616 entry::FileReader reader;
617 void* data =
load(&reader, entry::getAllocator(), _filePath, &
size);
623 const bool parsed = bimg::imageParseInfo(entry::getAllocator(), _info, data,
size, _err);
629 uint16_t _numVertices,
630 bgfx::VertexLayout _layout,
631 const uint16_t* _indices,
632 uint32_t _numIndices)
646 float* tangents =
new float[6 * _numVertices];
647 bx::memSet(tangents, 0, 6 * _numVertices *
sizeof(
float));
653 for(uint32_t ii = 0, num = _numIndices / 3; ii < num; ++ii)
655 const uint16_t*
indices = &_indices[ii * 3];
660 bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _layout, _vertices, i0);
661 bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i0);
663 bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _layout, _vertices, i1);
664 bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i1);
666 bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _layout, _vertices, i2);
667 bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i2);
669 const float bax = v1.m_x - v0.m_x;
670 const float bay = v1.m_y - v0.m_y;
671 const float baz = v1.m_z - v0.m_z;
672 const float bau = v1.m_u - v0.m_u;
673 const float bav = v1.m_v - v0.m_v;
675 const float cax = v2.m_x - v0.m_x;
676 const float cay = v2.m_y - v0.m_y;
677 const float caz = v2.m_z - v0.m_z;
678 const float cau = v2.m_u - v0.m_u;
679 const float cav = v2.m_v - v0.m_v;
681 const float det = (bau * cav - bav * cau);
682 const float invDet = 1.0f / det;
684 const float tx = (bax * cav - cax * bav) * invDet;
685 const float ty = (bay * cav - cay * bav) * invDet;
686 const float tz = (baz * cav - caz * bav) * invDet;
688 const float bx = (cax * bau - bax * cau) * invDet;
689 const float by = (cay * bau - bay * cau) * invDet;
690 const float bz = (caz * bau - baz * cau) * invDet;
692 for(uint32_t jj = 0; jj < 3; ++jj)
694 float* tanu = &tangents[
indices[jj] * 6];
695 float* tanv = &tanu[3];
706 for(uint32_t ii = 0; ii < _numVertices; ++ii)
708 const bx::Vec3 tanu = bx::load<bx::Vec3>(&tangents[ii * 6]);
709 const bx::Vec3 tanv = bx::load<bx::Vec3>(&tangents[ii * 6 + 3]);
712 bgfx::vertexUnpack(nxyzw, bgfx::Attrib::Normal, _layout, _vertices, ii);
714 const bx::Vec3
normal = bx::load<bx::Vec3>(nxyzw);
715 const float ndt = bx::dot(
normal, tanu);
716 const bx::Vec3 nxt = bx::cross(
normal, tanu);
717 const bx::Vec3 tmp = bx::sub(tanu, bx::mul(
normal, ndt));
720 bx::store(tangent, bx::normalize(tmp));
721 tangent[3] = bx::dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
723 bgfx::vertexPack(tangent,
true, bgfx::Attrib::Tangent, _layout, _vertices, ii);
729bool saveToFile(bgfx::ViewId viewId,
const bx::FilePath& _filePath, bgfx::FrameBufferHandle fbo, uint32_t
width, uint32_t
height)
732 auto input_tex = bgfx::getTexture(fbo);
734 auto format = bgfx::TextureFormat::RGBA8;
735 auto bimg_format =
static_cast<bimg::TextureFormat::Enum
>(
format);
739 uint64_t flags = 0 | BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK | BGFX_SAMPLER_U_CLAMP |
740 BGFX_SAMPLER_V_CLAMP;
743 bgfx::TextureInfo info;
748 bgfx::blit(viewId,
blit_tex, 0, 0, input_tex);
752 tinystl::vector<uint8_t>
input(info.storageSize);
755 uint32_t frameNumber = bgfx::readTexture(
blit_tex,
input.data());
759 while(bgfx::frame() != frameNumber)
765 bx::FilePath filePath(_filePath);
767 if(bx::makeAll(filePath.getPath()))
769 bx::FileWriter writer;
770 if(bx::open(&writer, filePath))
773 bimg::imageWritePng(&writer,
776 info.width * (info.bitsPerPixel / 8),
789bool imageSave(
const char* saveAs, bimg::ImageContainer* image)
796 bx::FileWriter writer;
799 if (bx::open(&writer, saveAs,
false, &err))
801 if (!bx::strFindI(saveAs,
"tga").isEmpty())
803 bimg::imageWriteTga(&writer, image->m_width, image->m_height, image->m_width * 4, image->m_data,
false,
false, &err);
805 else if (!bx::strFindI(saveAs,
"ktx").isEmpty())
807 bimg::imageWriteKtx(&writer, *image, image->m_data, image->m_size, &err);
810 else if (!bx::strFindI(saveAs,
"dds").isEmpty())
812 bimg::imageWriteDds(&writer, *image, image->m_data, image->m_size, &err);
815 else if (!bx::strFindI(saveAs,
"png").isEmpty())
817 if (image->m_format != bimg::TextureFormat::RGBA8)
820 auto converted = bimg::imageConvert(entry::getAllocator(), bimg::TextureFormat::RGBA8, *image);
824 bimg::imageGetRawData(*converted, 0, 0, converted->m_data, converted->m_size, mip);
825 bimg::imageWritePng(&writer
830 , converted->m_format
834 bimg::imageFree(converted);
845 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
846 bimg::imageWritePng(&writer
858 else if (!bx::strFindI(saveAs,
"exr").isEmpty())
861 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
862 bimg::imageWriteExr(&writer
872 else if (!bx::strFindI(saveAs,
"hdr").isEmpty())
875 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
876 bimg::imageWriteHdr(&writer
879 , mip.m_width*getBitsPerPixel(mip.m_format)/8
gfx::texture_format format
static const bgfx::Memory * loadMem(bx::FileReaderI *_reader, const char *_filePath)
static bgfx::ShaderHandle loadShader(bx::FileReaderI *_reader, const bx::StringView &_name)
static bgfx::TextureHandle loadTextureFromContainer(bimg::ImageContainer *imageContainer, uint64_t _flags, bgfx::TextureInfo *_info, const TexturePreCreateFn &_preCreate=nullptr)
bool imageParseInfo(const void *_data, uint32_t _size, bimg::ImageContainer &_info, bx::Error *_err)
void calcTangents(void *_vertices, uint16_t _numVertices, bgfx::VertexLayout _layout, const uint16_t *_indices, uint32_t _numIndices)
bimg::ImageContainer * imageLoad(const void *data, uint32_t size, bgfx::TextureFormat::Enum _dstFormat)
bool imageSave(const char *saveAs, bimg::ImageContainer *image)
bool imageFlipTangentSpaceNormalY(bimg::ImageContainer *&_image)
void * load(bx::FileReaderI *_reader, bx::AllocatorI *_allocator, const bx::FilePath &_filePath, uint32_t *_size)
static void imageReleaseCb(void *_ptr, void *_userData)
bool imagePrepareNormalMapBakePng(bimg::ImageContainer *&_image)
Prepare a flipped normal map for PNG bake export (RGBA8, opaque alpha when unused).
bgfx::ProgramHandle loadProgram(bx::FileReaderI *_reader, const bx::StringView &_vsName, const bx::StringView &_fsName)
bool saveToFile(bgfx::ViewId viewId, const bx::FilePath &_filePath, bgfx::FrameBufferHandle fbo, uint32_t width, uint32_t height)
bgfx::TextureHandle loadTexture(const void *_data, uint32_t _size, uint64_t _flags, uint8_t _skip, bgfx::TextureInfo *_info, bimg::Orientation::Enum *_orientation, const char *_name, bx::Error *_err, const TexturePreCreateFn &_preCreate)
std::function< bool(const bgfx::TextureInfo &_info)> TexturePreCreateFn
gfx::texture_handle blit_tex
std::vector< uint32_t > indices