Unravel Engine C++ Reference
Loading...
Searching...
No Matches
bgfx_utils.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011-2023 Branimir Karadzic. All rights reserved.
3 * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
4 */
5
6#include "common.h"
7
8#include <tinystl/allocator.h>
9#include <tinystl/string.h>
10#include <tinystl/vector.h>
11namespace stl = tinystl;
12
13#include "entry/entry.h"
14#include <bgfx/bgfx.h>
15#include <bx/commandline.h>
16#include <bx/endian.h>
17#include <bx/math.h>
18#include <bx/readerwriter.h>
19#include <bx/string.h>
20
21#include "bgfx_utils.h"
22
23#include <bimg/decode.h>
24
25#include <bgfx/bgfx.h>
26#include <bx/bx.h>
27#include <bx/file.h>
28#include <bx/sort.h>
29
30#include <time.h>
31namespace entry
32{
33namespace
34{
35
36bx::AllocatorI* getDefaultAllocator()
37{
38 static bx::DefaultAllocator allocator;
39 return &allocator;
40}
41
42static bx::AllocatorI* g_allocator = getDefaultAllocator();
43typedef bx::StringT<&g_allocator> String;
44
45class FileReader : public bx::FileReader
46{
47 typedef bx::FileReader super;
48
49public:
50 virtual bool open(const bx::FilePath& _filePath, bx::Error* _err) override
51 {
52 return super::open(_filePath, _err);
53 }
54};
55
56class FileWriter : public bx::FileWriter
57{
58 typedef bx::FileWriter super;
59
60public:
61 virtual bool open(const bx::FilePath& _filePath, bool _append, bx::Error* _err) override
62 {
63 return super::open(_filePath, _append, _err);
64 }
65};
66
67bx::AllocatorI* getAllocator()
68{
69 return g_allocator;
70}
71
72} // namespace
73} // namespace entry
74
75void* load(bx::FileReaderI* _reader, bx::AllocatorI* _allocator, const char* _filePath, uint32_t* _size)
76{
77 if(bx::open(_reader, _filePath))
78 {
79 uint32_t size = (uint32_t)bx::getSize(_reader);
80 void* data = bx::alloc(_allocator, size);
81 bx::read(_reader, data, size, bx::ErrorAssert{});
82 bx::close(_reader);
83 if(NULL != _size)
84 {
85 *_size = size;
86 }
87 return data;
88 }
89 else
90 {
91 DBG("Failed to open: %s.", _filePath);
92 }
93
94 if(NULL != _size)
95 {
96 *_size = 0;
97 }
98
99 return NULL;
100}
101
102void* load(const char* _filePath, uint32_t* _size)
103{
104 entry::FileReader reader;
105 return load(&reader, entry::getAllocator(), _filePath, _size);
106}
107
108void unload(void* _ptr)
109{
110 bx::free(entry::getAllocator(), _ptr);
111}
112
113static const bgfx::Memory* loadMem(bx::FileReaderI* _reader, const char* _filePath)
114{
115 if(bx::open(_reader, _filePath))
116 {
117 uint32_t size = (uint32_t)bx::getSize(_reader);
118 const bgfx::Memory* mem = bgfx::alloc(size + 1);
119 bx::read(_reader, mem->data, size, bx::ErrorAssert{});
120 bx::close(_reader);
121 mem->data[mem->size - 1] = '\0';
122 return mem;
123 }
124
125 DBG("Failed to load %s.", _filePath);
126 return NULL;
127}
128
129static void* loadMem(bx::FileReaderI* _reader, bx::AllocatorI* _allocator, const char* _filePath, uint32_t* _size)
130{
131 if(bx::open(_reader, _filePath))
132 {
133 uint32_t size = (uint32_t)bx::getSize(_reader);
134 void* data = bx::alloc(_allocator, size);
135 bx::read(_reader, data, size, bx::ErrorAssert{});
136 bx::close(_reader);
137
138 if(NULL != _size)
139 {
140 *_size = size;
141 }
142 return data;
143 }
144
145 DBG("Failed to load %s.", _filePath);
146 return NULL;
147}
148
149static bgfx::ShaderHandle loadShader(bx::FileReaderI* _reader, const char* _name)
150{
151 char filePath[512];
152
153 const char* shaderPath = "???";
154
155 switch(bgfx::getRendererType())
156 {
157 case bgfx::RendererType::Noop:
158 case bgfx::RendererType::Direct3D11:
159 case bgfx::RendererType::Direct3D12:
160 shaderPath = "shaders/dx11/";
161 break;
162 case bgfx::RendererType::Agc:
163 case bgfx::RendererType::Gnm:
164 shaderPath = "shaders/pssl/";
165 break;
166 case bgfx::RendererType::Metal:
167 shaderPath = "shaders/metal/";
168 break;
169 case bgfx::RendererType::Nvn:
170 shaderPath = "shaders/nvn/";
171 break;
172 case bgfx::RendererType::OpenGL:
173 shaderPath = "shaders/glsl/";
174 break;
175 case bgfx::RendererType::OpenGLES:
176 shaderPath = "shaders/essl/";
177 break;
178 case bgfx::RendererType::Vulkan:
179 shaderPath = "shaders/spirv/";
180 break;
181
182 case bgfx::RendererType::Count:
183 BX_ASSERT(false, "You should not be here!");
184 break;
185 }
186
187 bx::strCopy(filePath, BX_COUNTOF(filePath), shaderPath);
188 bx::strCat(filePath, BX_COUNTOF(filePath), _name);
189 bx::strCat(filePath, BX_COUNTOF(filePath), ".bin");
190
191 bgfx::ShaderHandle handle = bgfx::createShader(loadMem(_reader, filePath));
192 bgfx::setName(handle, _name);
193
194 return handle;
195}
196
197bgfx::ShaderHandle loadShader(const char* _name)
198{
199 entry::FileReader reader;
200 return loadShader(&reader, _name);
201}
202
203bgfx::ProgramHandle loadProgram(bx::FileReaderI* _reader, const char* _vsName, const char* _fsName)
204{
205 bgfx::ShaderHandle vsh = loadShader(_reader, _vsName);
206 bgfx::ShaderHandle fsh = BGFX_INVALID_HANDLE;
207 if(NULL != _fsName)
208 {
209 fsh = loadShader(_reader, _fsName);
210 }
211
212 return bgfx::createProgram(vsh, fsh, true /* destroy shaders when program is destroyed */);
213}
214
215bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName)
216{
217 entry::FileReader reader;
218 return loadProgram(&reader, _vsName, _fsName);
219}
220
221static void imageReleaseCb(void* _ptr, void* _userData)
222{
223 BX_UNUSED(_ptr);
224 bimg::ImageContainer* imageContainer = (bimg::ImageContainer*)_userData;
225 bimg::imageFree(imageContainer);
226}
227
228bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader,
229 const char* _filePath,
230 uint64_t _flags,
231 uint8_t _skip,
232 bgfx::TextureInfo* _info,
233 bimg::Orientation::Enum* _orientation)
234{
235 BX_UNUSED(_skip);
236 bgfx::TextureHandle handle = BGFX_INVALID_HANDLE;
237
238 uint32_t size;
239 void* data = load(_reader, entry::getAllocator(), _filePath, &size);
240 if (NULL != data)
241 {
242 bimg::ImageContainer* imageContainer = bimg::imageParse(entry::getAllocator(), data, size);
243
244 if (NULL != imageContainer)
245 {
246 if (NULL != _orientation)
247 {
248 *_orientation = imageContainer->m_orientation;
249 }
250
251 const bgfx::Memory* mem = bgfx::makeRef(
252 imageContainer->m_data
253 , imageContainer->m_size
254 , imageReleaseCb
255 , imageContainer
256 );
257 unload(data);
258
259 if (NULL != _info)
260 {
261 bgfx::calcTextureSize(
262 *_info
263 , uint16_t(imageContainer->m_width)
264 , uint16_t(imageContainer->m_height)
265 , uint16_t(imageContainer->m_depth)
266 , imageContainer->m_cubeMap
267 , 1 < imageContainer->m_numMips
268 , imageContainer->m_numLayers
269 , bgfx::TextureFormat::Enum(imageContainer->m_format)
270 );
271 }
272
273 if (imageContainer->m_cubeMap)
274 {
275 handle = bgfx::createTextureCube(
276 uint16_t(imageContainer->m_width)
277 , 1 < imageContainer->m_numMips
278 , imageContainer->m_numLayers
279 , bgfx::TextureFormat::Enum(imageContainer->m_format)
280 , _flags
281 , mem
282 );
283 }
284 else if (1 < imageContainer->m_depth)
285 {
286 handle = bgfx::createTexture3D(
287 uint16_t(imageContainer->m_width)
288 , uint16_t(imageContainer->m_height)
289 , uint16_t(imageContainer->m_depth)
290 , 1 < imageContainer->m_numMips
291 , bgfx::TextureFormat::Enum(imageContainer->m_format)
292 , _flags
293 , mem
294 );
295 }
296 else if (bgfx::isTextureValid(0, false, imageContainer->m_numLayers, bgfx::TextureFormat::Enum(imageContainer->m_format), _flags) )
297 {
298 handle = bgfx::createTexture2D(
299 uint16_t(imageContainer->m_width)
300 , uint16_t(imageContainer->m_height)
301 , 1 < imageContainer->m_numMips
302 , imageContainer->m_numLayers
303 , bgfx::TextureFormat::Enum(imageContainer->m_format)
304 , _flags
305 , mem
306 );
307 }
308
309 if (bgfx::isValid(handle) )
310 {
311 const bx::StringView name(_filePath);
312 bgfx::setName(handle, name.getPtr(), name.getLength() );
313 }
314 }
315 }
316
317 return handle;
318}
319
320bgfx::TextureHandle loadTexture(const char* _name,
321 uint64_t _flags,
322 uint8_t _skip,
323 bgfx::TextureInfo* _info,
324 bimg::Orientation::Enum* _orientation)
325{
326 entry::FileReader reader;
327 return loadTexture(&reader, _name, _flags, _skip, _info, _orientation);
328}
329
330bimg::ImageContainer* imageLoad(const void* data, uint32_t size, bgfx::TextureFormat::Enum _dstFormat)
331{
332 return bimg::imageParse(entry::getAllocator(), data, size, bimg::TextureFormat::Enum(_dstFormat));
333}
334
335bimg::ImageContainer* imageLoad(const char* _filePath, bgfx::TextureFormat::Enum _dstFormat)
336{
337 entry::FileReader reader;
338
339 uint32_t size = 0;
340 void* data = loadMem(&reader, entry::getAllocator(), _filePath, &size);
341
342 return bimg::imageParse(entry::getAllocator(), data, size, bimg::TextureFormat::Enum(_dstFormat));
343}
344
345void calcTangents(void* _vertices,
346 uint16_t _numVertices,
347 bgfx::VertexLayout _layout,
348 const uint16_t* _indices,
349 uint32_t _numIndices)
350{
351 struct PosTexcoord
352 {
353 float m_x;
354 float m_y;
355 float m_z;
356 float m_pad0;
357 float m_u;
358 float m_v;
359 float m_pad1;
360 float m_pad2;
361 };
362
363 float* tangents = new float[6 * _numVertices];
364 bx::memSet(tangents, 0, 6 * _numVertices * sizeof(float));
365
366 PosTexcoord v0;
367 PosTexcoord v1;
368 PosTexcoord v2;
369
370 for(uint32_t ii = 0, num = _numIndices / 3; ii < num; ++ii)
371 {
372 const uint16_t* indices = &_indices[ii * 3];
373 uint32_t i0 = indices[0];
374 uint32_t i1 = indices[1];
375 uint32_t i2 = indices[2];
376
377 bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _layout, _vertices, i0);
378 bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i0);
379
380 bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _layout, _vertices, i1);
381 bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i1);
382
383 bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _layout, _vertices, i2);
384 bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i2);
385
386 const float bax = v1.m_x - v0.m_x;
387 const float bay = v1.m_y - v0.m_y;
388 const float baz = v1.m_z - v0.m_z;
389 const float bau = v1.m_u - v0.m_u;
390 const float bav = v1.m_v - v0.m_v;
391
392 const float cax = v2.m_x - v0.m_x;
393 const float cay = v2.m_y - v0.m_y;
394 const float caz = v2.m_z - v0.m_z;
395 const float cau = v2.m_u - v0.m_u;
396 const float cav = v2.m_v - v0.m_v;
397
398 const float det = (bau * cav - bav * cau);
399 const float invDet = 1.0f / det;
400
401 const float tx = (bax * cav - cax * bav) * invDet;
402 const float ty = (bay * cav - cay * bav) * invDet;
403 const float tz = (baz * cav - caz * bav) * invDet;
404
405 const float bx = (cax * bau - bax * cau) * invDet;
406 const float by = (cay * bau - bay * cau) * invDet;
407 const float bz = (caz * bau - baz * cau) * invDet;
408
409 for(uint32_t jj = 0; jj < 3; ++jj)
410 {
411 float* tanu = &tangents[indices[jj] * 6];
412 float* tanv = &tanu[3];
413 tanu[0] += tx;
414 tanu[1] += ty;
415 tanu[2] += tz;
416
417 tanv[0] += bx;
418 tanv[1] += by;
419 tanv[2] += bz;
420 }
421 }
422
423 for(uint32_t ii = 0; ii < _numVertices; ++ii)
424 {
425 const bx::Vec3 tanu = bx::load<bx::Vec3>(&tangents[ii * 6]);
426 const bx::Vec3 tanv = bx::load<bx::Vec3>(&tangents[ii * 6 + 3]);
427
428 float nxyzw[4];
429 bgfx::vertexUnpack(nxyzw, bgfx::Attrib::Normal, _layout, _vertices, ii);
430
431 const bx::Vec3 normal = bx::load<bx::Vec3>(nxyzw);
432 const float ndt = bx::dot(normal, tanu);
433 const bx::Vec3 nxt = bx::cross(normal, tanu);
434 const bx::Vec3 tmp = bx::sub(tanu, bx::mul(normal, ndt));
435
436 float tangent[4];
437 bx::store(tangent, bx::normalize(tmp));
438 tangent[3] = bx::dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
439
440 bgfx::vertexPack(tangent, true, bgfx::Attrib::Tangent, _layout, _vertices, ii);
441 }
442
443 delete[] tangents;
444}
445
446bool saveToFile(bgfx::ViewId viewId, const char* _filePath, bgfx::FrameBufferHandle fbo, uint32_t width, uint32_t height)
447{
448
449 auto input_tex = bgfx::getTexture(fbo);
450 // formats have one to one mapping
451 auto format = bgfx::TextureFormat::RGBA8;
452 auto bimg_format = static_cast<bimg::TextureFormat::Enum>(format);
453
454 bool result = false;
455
456 uint64_t flags = 0 | BGFX_TEXTURE_BLIT_DST | BGFX_TEXTURE_READ_BACK | BGFX_SAMPLER_U_CLAMP |
457 BGFX_SAMPLER_V_CLAMP;
458 auto blit_tex = bgfx::createTexture2D(width, height, false, 1, format, flags, nullptr);
459
460 bgfx::TextureInfo info;
461 bgfx::calcTextureSize(info, width, height, 1, false, false, 1, format);
462
463 // Blit and read
464 bgfx::touch(viewId);
465 bgfx::blit(viewId, blit_tex, 0, 0, input_tex);
466
467 // Allocate memory for the texture data
468
469 tinystl::vector<uint8_t> input(info.storageSize);
470
471 // Read the frame buffer data
472 uint32_t frameNumber = bgfx::readTexture(blit_tex, input.data());
473
474
475 // Wait until the data is available (frameNumber indicates when)
476 while(bgfx::frame() != frameNumber)
477 {
478 // You can perform other tasks here if needed
479 break;
480 }
481
482 bx::FilePath filePath(_filePath);
483
484 if(bx::makeAll(filePath.getPath()))
485 {
486 bx::FileWriter writer;
487 if(bx::open(&writer, filePath))
488 {
489 bx::Error err;
490 bimg::imageWritePng(&writer,
491 info.width,
492 info.height,
493 info.width * (info.bitsPerPixel / 8),
494 input.data(),
495 bimg_format,
496 false,
497 &err);
498 result = true;
499 bx::close(&writer);
500 }
501 }
502
503 return result;
504}
505
506bool imageSave(const char* saveAs, bimg::ImageContainer* image)
507{
508 if (!image)
509 {
510 return false;
511 }
512 // Write the image to file based on its extension
513 bx::FileWriter writer;
514 bx::Error err;
515
516 if (bx::open(&writer, saveAs, false, &err))
517 {
518 if (!bx::strFindI(saveAs, "tga").isEmpty())
519 {
520 bimg::imageWriteTga(&writer, image->m_width, image->m_height, image->m_width * 4, image->m_data, false, false, &err);
521 }
522 else if (!bx::strFindI(saveAs, "ktx").isEmpty())
523 {
524 bimg::imageWriteKtx(&writer, *image, image->m_data, image->m_size, &err);
525
526 }
527 else if (!bx::strFindI(saveAs, "dds").isEmpty())
528 {
529 bimg::imageWriteDds(&writer, *image, image->m_data, image->m_size, &err);
530
531 }
532 else if (!bx::strFindI(saveAs, "png").isEmpty())
533 {
534 if (image->m_format != bimg::TextureFormat::RGBA8)
535 {
536
537 auto converted = bimg::imageConvert(entry::getAllocator(), bimg::TextureFormat::RGBA8, *image);
538 if(converted)
539 {
540 bimg::ImageMip mip;
541 bimg::imageGetRawData(*converted, 0, 0, converted->m_data, converted->m_size, mip);
542 bimg::imageWritePng(&writer
543 , mip.m_width
544 , mip.m_height
545 , mip.m_width*4
546 , mip.m_data
547 , converted->m_format
548 , false
549 , &err
550 );
551 bimg::imageFree(converted);
552 }
553 else
554 {
555 //err.setError(bx::ErrorResult())
556 }
557 //help("Incompatible image texture format. image PNG format must be RGBA8.", err);
558 }
559 else
560 {
561 bimg::ImageMip mip;
562 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
563 bimg::imageWritePng(&writer
564 , mip.m_width
565 , mip.m_height
566 , mip.m_width*4
567 , mip.m_data
568 , image->m_format
569 , false
570 , &err
571 );
572 }
573
574 }
575 else if (!bx::strFindI(saveAs, "exr").isEmpty())
576 {
577 bimg::ImageMip mip;
578 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
579 bimg::imageWriteExr(&writer
580 , mip.m_width
581 , mip.m_height
582 , mip.m_width*8
583 , mip.m_data
584 , image->m_format
585 , false
586 , &err
587 );
588 }
589 else if (!bx::strFindI(saveAs, "hdr").isEmpty())
590 {
591 bimg::ImageMip mip;
592 bimg::imageGetRawData(*image, 0, 0, image->m_data, image->m_size, mip);
593 bimg::imageWriteHdr(&writer
594 , mip.m_width
595 , mip.m_height
596 , mip.m_width*getBitsPerPixel(mip.m_format)/8
597 , mip.m_data
598 , image->m_format
599 , false
600 , &err
601 );
602 }
603
604
605 bx::close(&writer);
606 }
607
608 return err.isOk();
609
610}
void calcTangents(void *_vertices, uint16_t _numVertices, bgfx::VertexLayout _layout, const uint16_t *_indices, uint32_t _numIndices)
bgfx::ProgramHandle loadProgram(bx::FileReaderI *_reader, const char *_vsName, const char *_fsName)
bimg::ImageContainer * imageLoad(const void *data, uint32_t size, bgfx::TextureFormat::Enum _dstFormat)
bool imageSave(const char *saveAs, bimg::ImageContainer *image)
void unload(void *_ptr)
bgfx::TextureHandle loadTexture(bx::FileReaderI *_reader, const char *_filePath, uint64_t _flags, uint8_t _skip, bgfx::TextureInfo *_info, bimg::Orientation::Enum *_orientation)
bool saveToFile(bgfx::ViewId viewId, const char *_filePath, bgfx::FrameBufferHandle fbo, uint32_t width, uint32_t height)
void * load(bx::FileReaderI *_reader, bx::AllocatorI *_allocator, const char *_filePath, uint32_t *_size)
btVector3 normal
#define DBG(_format,...)
Definition dbg.h:14
std::string name
Definition hub.cpp:27
Definition imgui.h:25
gfx::uniform_handle handle
Definition uniform.cpp:9