2012-12-31 08:52:47 +04:00
/*
2017-01-01 11:18:41 +03:00
* Copyright 2011 - 2017 Branimir Karadzic . All rights reserved .
2016-01-01 11:11:04 +03:00
* License : https : //github.com/bkaradzic/bgfx#license-bsd-2-clause
2012-12-31 08:52:47 +04:00
*/
2013-05-24 09:07:54 +04:00
# include "common.h"
2014-05-04 02:18:28 +04:00
# include "bgfx_utils.h"
2013-05-19 09:12:40 +04:00
2013-09-17 08:40:30 +04:00
# include <bx/allocator.h>
2012-12-31 08:52:47 +04:00
# include <bx/string.h>
2016-12-09 07:45:01 +03:00
# include <bx/crtimpl.h>
2013-05-24 09:07:54 +04:00
# include "aviwriter.h"
2012-12-31 08:52:47 +04:00
# include <inttypes.h>
2017-06-26 07:44:04 +03:00
namespace
{
2012-12-31 08:52:47 +04:00
struct PosColorVertex
{
float m_x ;
float m_y ;
float m_z ;
uint32_t m_abgr ;
2014-05-04 02:18:28 +04:00
static void init ( )
{
2014-05-11 07:51:44 +04:00
ms_decl
. begin ( )
. add ( bgfx : : Attrib : : Position , 3 , bgfx : : AttribType : : Float )
. add ( bgfx : : Attrib : : Color0 , 4 , bgfx : : AttribType : : Uint8 , true )
. end ( ) ;
2014-05-04 02:18:28 +04:00
} ;
static bgfx : : VertexDecl ms_decl ;
2012-12-31 08:52:47 +04:00
} ;
2014-05-04 02:18:28 +04:00
bgfx : : VertexDecl PosColorVertex : : ms_decl ;
2012-12-31 08:52:47 +04:00
static PosColorVertex s_cubeVertices [ 8 ] =
{
{ - 1.0f , 1.0f , 1.0f , 0xff000000 } ,
{ 1.0f , 1.0f , 1.0f , 0xff0000ff } ,
{ - 1.0f , - 1.0f , 1.0f , 0xff00ff00 } ,
{ 1.0f , - 1.0f , 1.0f , 0xff00ffff } ,
{ - 1.0f , 1.0f , - 1.0f , 0xffff0000 } ,
{ 1.0f , 1.0f , - 1.0f , 0xffff00ff } ,
{ - 1.0f , - 1.0f , - 1.0f , 0xffffff00 } ,
{ 1.0f , - 1.0f , - 1.0f , 0xffffffff } ,
} ;
static const uint16_t s_cubeIndices [ 36 ] =
{
2013-02-22 10:05:33 +04:00
0 , 1 , 2 , // 0
1 , 3 , 2 ,
4 , 6 , 5 , // 2
5 , 6 , 7 ,
0 , 2 , 4 , // 4
4 , 2 , 6 ,
1 , 5 , 3 , // 6
5 , 7 , 3 ,
0 , 4 , 1 , // 8
4 , 5 , 1 ,
2 , 3 , 6 , // 10
6 , 3 , 7 ,
2012-12-31 08:52:47 +04:00
} ;
2016-12-09 07:45:01 +03:00
void imageWriteTga ( bx : : WriterI * _writer , uint32_t _width , uint32_t _height , uint32_t _pitch , const void * _src , bool _grayscale , bool _yflip , bx : : Error * _err )
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
BX_ERROR_SCOPE ( _err ) ;
uint8_t type = _grayscale ? 3 : 2 ;
uint8_t bpp = _grayscale ? 8 : 32 ;
uint8_t header [ 18 ] = { } ;
header [ 2 ] = type ;
header [ 12 ] = _width & 0xff ;
header [ 13 ] = ( _width > > 8 ) & 0xff ;
header [ 14 ] = _height & 0xff ;
header [ 15 ] = ( _height > > 8 ) & 0xff ;
header [ 16 ] = bpp ;
header [ 17 ] = 32 ;
bx : : write ( _writer , header , sizeof ( header ) , _err ) ;
uint32_t dstPitch = _width * bpp / 8 ;
if ( _yflip )
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
uint8_t * data = ( uint8_t * ) _src + _pitch * _height - _pitch ;
for ( uint32_t yy = 0 ; yy < _height ; + + yy )
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
bx : : write ( _writer , data , dstPitch , _err ) ;
data - = _pitch ;
2012-12-31 08:52:47 +04:00
}
2016-12-09 07:45:01 +03:00
}
else if ( _pitch = = dstPitch )
{
bx : : write ( _writer , _src , _height * _pitch , _err ) ;
}
else
{
uint8_t * data = ( uint8_t * ) _src ;
for ( uint32_t yy = 0 ; yy < _height ; + + yy )
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
bx : : write ( _writer , data , dstPitch , _err ) ;
data + = _pitch ;
2012-12-31 08:52:47 +04:00
}
}
}
2016-12-09 07:45:01 +03:00
void saveTga ( const char * _filePath , uint32_t _width , uint32_t _height , uint32_t _srcPitch , const void * _src , bool _grayscale , bool _yflip )
2014-05-04 02:18:28 +04:00
{
2017-06-12 07:01:38 +03:00
bx : : FileWriter writer ;
2016-12-09 07:45:01 +03:00
bx : : Error err ;
if ( bx : : open ( & writer , _filePath , false , & err ) )
{
imageWriteTga ( & writer , _width , _height , _srcPitch , _src , _grayscale , _yflip , & err ) ;
bx : : close ( & writer ) ;
}
2014-05-04 02:18:28 +04:00
}
2012-12-31 08:52:47 +04:00
struct BgfxCallback : public bgfx : : CallbackI
{
virtual ~ BgfxCallback ( )
{
}
virtual void fatal ( bgfx : : Fatal : : Enum _code , const char * _str ) BX_OVERRIDE
{
2013-01-01 06:48:52 +04:00
// Something unexpected happened, inform user and bail out.
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " Fatal error: 0x%08x: %s " , _code , _str ) ;
2013-01-01 06:48:52 +04:00
// Must terminate, continuing will cause crash anyway.
2012-12-31 08:52:47 +04:00
abort ( ) ;
}
2015-07-25 04:02:17 +03:00
virtual void traceVargs ( const char * _filePath , uint16_t _line , const char * _format , va_list _argList ) BX_OVERRIDE
2015-07-17 03:39:02 +03:00
{
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " %s (%d): " , _filePath , _line ) ;
bx : : debugPrintfVargs ( _format , _argList ) ;
2015-07-17 03:39:02 +03:00
}
2012-12-31 08:52:47 +04:00
virtual uint32_t cacheReadSize ( uint64_t _id ) BX_OVERRIDE
{
char filePath [ 256 ] ;
2015-06-14 20:03:59 +03:00
bx : : snprintf ( filePath , sizeof ( filePath ) , " temp/%016 " PRIx64 , _id ) ;
2013-01-01 06:48:52 +04:00
// Use cache id as filename.
2016-12-09 07:45:01 +03:00
bx : : FileReaderI * reader = entry : : getFileReader ( ) ;
bx : : Error err ;
if ( bx : : open ( reader , filePath , & err ) )
2012-12-31 08:52:47 +04:00
{
2016-12-23 03:18:44 +03:00
uint32_t size = ( uint32_t ) bx : : getSize ( reader ) ;
2016-12-09 07:45:01 +03:00
bx : : close ( reader ) ;
2013-01-01 06:48:52 +04:00
// Return size of shader file.
2012-12-31 08:52:47 +04:00
return size ;
}
2013-01-01 06:48:52 +04:00
// Return 0 if shader is not found.
2012-12-31 08:52:47 +04:00
return 0 ;
}
virtual bool cacheRead ( uint64_t _id , void * _data , uint32_t _size ) BX_OVERRIDE
{
char filePath [ 256 ] ;
2013-01-13 02:25:27 +04:00
bx : : snprintf ( filePath , sizeof ( filePath ) , " temp/%016 " PRIx64 , _id ) ;
2013-01-01 06:48:52 +04:00
// Use cache id as filename.
2016-12-09 07:45:01 +03:00
bx : : FileReaderI * reader = entry : : getFileReader ( ) ;
bx : : Error err ;
if ( bx : : open ( reader , filePath , & err ) )
2012-12-31 08:52:47 +04:00
{
2013-01-01 06:48:52 +04:00
// Read shader.
2016-12-09 07:45:01 +03:00
uint32_t result = bx : : read ( reader , _data , _size , & err ) ;
bx : : close ( reader ) ;
2013-01-01 06:48:52 +04:00
// Make sure that read size matches requested size.
2012-12-31 08:52:47 +04:00
return result = = _size ;
}
2013-01-01 06:48:52 +04:00
// Shader is not found in cache, needs to be rebuilt.
2012-12-31 08:52:47 +04:00
return false ;
}
virtual void cacheWrite ( uint64_t _id , const void * _data , uint32_t _size ) BX_OVERRIDE
{
char filePath [ 256 ] ;
2013-01-13 02:25:27 +04:00
bx : : snprintf ( filePath , sizeof ( filePath ) , " temp/%016 " PRIx64 , _id ) ;
2012-12-31 08:52:47 +04:00
2013-01-01 06:48:52 +04:00
// Use cache id as filename.
2016-12-09 07:45:01 +03:00
bx : : FileWriterI * writer = entry : : getFileWriter ( ) ;
bx : : Error err ;
if ( bx : : open ( writer , filePath , false , & err ) )
2012-12-31 08:52:47 +04:00
{
2013-01-01 06:48:52 +04:00
// Write shader to cache location.
2016-12-09 07:45:01 +03:00
bx : : write ( writer , _data , _size , & err ) ;
bx : : close ( writer ) ;
2012-12-31 08:52:47 +04:00
}
}
virtual void screenShot ( const char * _filePath , uint32_t _width , uint32_t _height , uint32_t _pitch , const void * _data , uint32_t /*_size*/ , bool _yflip ) BX_OVERRIDE
{
2013-08-22 09:51:24 +04:00
char temp [ 1024 ] ;
2013-01-01 06:48:52 +04:00
// Save screen shot as TGA.
2016-12-09 07:45:01 +03:00
bx : : snprintf ( temp , BX_COUNTOF ( temp ) , " %s.tga " , _filePath ) ;
2013-08-22 09:51:24 +04:00
saveTga ( temp , _width , _height , _pitch , _data , false , _yflip ) ;
2012-12-31 08:52:47 +04:00
}
2013-03-26 08:13:54 +04:00
virtual void captureBegin ( uint32_t _width , uint32_t _height , uint32_t /*_pitch*/ , bgfx : : TextureFormat : : Enum /*_format*/ , bool _yflip ) BX_OVERRIDE
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
m_writer = BX_NEW ( entry : : getAllocator ( ) , AviWriter ) ( entry : : getFileWriter ( ) ) ;
2013-01-13 02:25:27 +04:00
if ( ! m_writer - > open ( " temp/capture.avi " , _width , _height , 60 , _yflip ) )
2012-12-31 08:52:47 +04:00
{
2016-12-09 07:45:01 +03:00
BX_DELETE ( entry : : getAllocator ( ) , m_writer ) ;
2012-12-31 08:52:47 +04:00
m_writer = NULL ;
}
}
virtual void captureEnd ( ) BX_OVERRIDE
{
if ( NULL ! = m_writer )
{
m_writer - > close ( ) ;
2016-12-09 07:45:01 +03:00
BX_DELETE ( entry : : getAllocator ( ) , m_writer ) ;
2013-02-11 10:48:13 +04:00
m_writer = NULL ;
2012-12-31 08:52:47 +04:00
}
}
virtual void captureFrame ( const void * _data , uint32_t /*_size*/ ) BX_OVERRIDE
{
if ( NULL ! = m_writer )
{
m_writer - > frame ( _data ) ;
}
}
AviWriter * m_writer ;
} ;
2015-11-07 09:03:06 +03:00
class BgfxAllocator : public bx : : AllocatorI
2013-09-17 08:40:30 +04:00
{
public :
BgfxAllocator ( )
2013-09-21 09:13:58 +04:00
: m_numBlocks ( 0 )
, m_maxBlocks ( 0 )
2013-09-17 08:40:30 +04:00
{
}
virtual ~ BgfxAllocator ( )
{
}
2015-11-07 09:03:06 +03:00
virtual void * realloc ( void * _ptr , size_t _size , size_t _align , const char * _file , uint32_t _line ) BX_OVERRIDE
2013-09-17 08:40:30 +04:00
{
2015-11-07 09:03:06 +03:00
if ( 0 = = _size )
2014-05-01 21:15:41 +04:00
{
2015-11-07 09:03:06 +03:00
if ( NULL ! = _ptr )
{
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
{
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " %s(%d): FREE %p \n " , _file , _line , _ptr ) ;
2015-11-07 09:03:06 +03:00
: : free ( _ptr ) ;
- - m_numBlocks ;
}
else
{
bx : : alignedFree ( this , _ptr , _align , _file , _line ) ;
}
}
2013-09-17 08:40:30 +04:00
2015-11-07 09:03:06 +03:00
return NULL ;
}
else if ( NULL = = _ptr )
2013-09-23 08:40:17 +04:00
{
2014-05-01 21:15:41 +04:00
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
{
2015-11-07 09:03:06 +03:00
void * ptr = : : malloc ( _size ) ;
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " %s(%d): ALLOC %p of %d byte(s) \n " , _file , _line , ptr , _size ) ;
2015-11-07 09:03:06 +03:00
+ + m_numBlocks ;
m_maxBlocks = bx : : uint32_max ( m_maxBlocks , m_numBlocks ) ;
return ptr ;
2014-05-01 21:15:41 +04:00
}
2015-11-07 09:03:06 +03:00
return bx : : alignedAlloc ( this , _size , _align , _file , _line ) ;
2013-09-23 08:40:17 +04:00
}
2013-09-17 08:40:30 +04:00
2014-05-01 21:15:41 +04:00
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
2013-09-21 09:13:58 +04:00
{
2014-05-01 21:15:41 +04:00
void * ptr = : : realloc ( _ptr , _size ) ;
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " %s(%d): REALLOC %p (old %p) of %d byte(s) \n " , _file , _line , ptr , _ptr , _size ) ;
2014-05-01 21:15:41 +04:00
if ( NULL = = _ptr )
{
+ + m_numBlocks ;
m_maxBlocks = bx : : uint32_max ( m_maxBlocks , m_numBlocks ) ;
}
return ptr ;
2013-09-21 09:13:58 +04:00
}
2014-05-01 21:15:41 +04:00
return bx : : alignedRealloc ( this , _ptr , _size , _align , _file , _line ) ;
2013-09-17 08:40:30 +04:00
}
2013-09-21 09:13:58 +04:00
void dumpStats ( ) const
{
2017-01-21 02:06:51 +03:00
bx : : debugPrintf ( " Allocator stats: num blocks %d (peak: %d) \n " , m_numBlocks , m_maxBlocks ) ;
2013-09-21 09:13:58 +04:00
}
private :
uint32_t m_numBlocks ;
uint32_t m_maxBlocks ;
2013-09-17 08:40:30 +04:00
} ;
2017-06-16 23:10:37 +03:00
class ExampleCallback : public entry : : AppI
2012-12-31 08:52:47 +04:00
{
2017-06-26 07:44:04 +03:00
public :
ExampleCallback ( const char * _name , const char * _description )
: entry : : AppI ( _name , _description )
{
}
2017-06-16 23:10:37 +03:00
void init ( int _argc , char * * _argv ) BX_OVERRIDE
2012-12-31 08:52:47 +04:00
{
2017-06-16 23:10:37 +03:00
Args args ( _argc , _argv ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
m_width = 1280 ;
m_height = 720 ;
2017-06-17 04:46:21 +03:00
2017-06-26 07:44:04 +03:00
bgfx : : init (
args . m_type
, args . m_pciId
, 0
, & m_callback // custom callback handler
, & m_allocator // custom allocator
) ;
2017-06-16 23:10:37 +03:00
bgfx : : reset ( m_width , m_height , BGFX_RESET_CAPTURE | BGFX_RESET_MSAA_X16 ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Enable debug text.
bgfx : : setDebug ( BGFX_DEBUG_TEXT ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set view 0 default viewport.
bgfx : : setViewRect ( 0 , 0 , 0 , 1280 , 720 ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set view 0 clear state.
bgfx : : setViewClear ( 0
, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
, 0x303030ff
, 1.0f
, 0
) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Create vertex stream declaration.
PosColorVertex : : init ( ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Create static vertex buffer.
m_vbh = bgfx : : createVertexBuffer (
bgfx : : makeRef ( s_cubeVertices , sizeof ( s_cubeVertices ) )
, PosColorVertex : : ms_decl
) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Create static index buffer.
m_ibh = bgfx : : createIndexBuffer ( bgfx : : makeRef ( s_cubeIndices , sizeof ( s_cubeIndices ) ) ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Create program from shaders.
m_program = loadProgram ( " vs_callback " , " fs_callback " ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
m_time = 0.0f ;
m_frame = 0 ;
}
2012-12-31 08:52:47 +04:00
2017-06-16 23:10:37 +03:00
virtual int shutdown ( ) BX_OVERRIDE
{
// Cleanup.
bgfx : : destroyIndexBuffer ( m_ibh ) ;
bgfx : : destroyVertexBuffer ( m_vbh ) ;
bgfx : : destroyProgram ( m_program ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Shutdown bgfx.
bgfx : : shutdown ( ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
m_allocator . dumpStats ( ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
return 0 ;
}
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
bool update ( ) BX_OVERRIDE
{
// 5 second 60Hz video
2017-06-26 07:44:04 +03:00
if ( m_frame < 300 )
2012-12-31 08:52:47 +04:00
{
2017-06-16 23:10:37 +03:00
+ + m_frame ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// This dummy draw call is here to make sure that view 0 is cleared
// if no other draw calls are submitted to view 0.
bgfx : : touch ( 0 ) ;
2017-06-17 04:46:21 +03:00
2017-06-26 07:44:04 +03:00
float at [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
2017-06-16 23:10:37 +03:00
float eye [ 3 ] = { 0.0f , 0.0f , - 35.0f } ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
float view [ 16 ] ;
float proj [ 16 ] ;
bx : : mtxLookAt ( view , eye , at ) ;
bx : : mtxProj ( proj , 60.0f , float ( m_width ) / float ( m_height ) , 0.1f , 100.0f , bgfx : : getCaps ( ) - > homogeneousDepth ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set view and projection matrix for view 0.
bgfx : : setViewTransform ( 0 , view , proj ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
m_time + = 1.0f / 60.0f ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Submit 11x11 cubes.
for ( uint32_t yy = 0 ; yy < 11 ; + + yy )
{
for ( uint32_t xx = 0 ; xx < 11 - yy ; + + xx )
{
float mtx [ 16 ] ;
bx : : mtxRotateXY ( mtx , m_time + xx * 0.21f , m_time + yy * 0.37f ) ;
mtx [ 12 ] = - 15.0f + float ( xx ) * 3.0f ;
mtx [ 13 ] = - 15.0f + float ( yy ) * 3.0f ;
mtx [ 14 ] = 0.0f ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set model matrix for rendering.
bgfx : : setTransform ( mtx ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set vertex and index buffer.
bgfx : : setVertexBuffer ( 0 , m_vbh ) ;
bgfx : : setIndexBuffer ( m_ibh ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Set render states.
bgfx : : setState ( BGFX_STATE_DEFAULT ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Submit primitive for rendering to view 0.
bgfx : : submit ( 0 , m_program ) ;
}
}
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Take screen shot at frame 150.
if ( 150 = = m_frame )
{
bgfx : : FrameBufferHandle fbh = BGFX_INVALID_HANDLE ;
bgfx : : requestScreenShot ( fbh , " temp/frame150 " ) ;
}
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
bgfx : : frame ( ) ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
return true ;
2012-12-31 08:52:47 +04:00
}
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
return false ;
2012-12-31 08:52:47 +04:00
}
2017-06-16 23:10:37 +03:00
BgfxCallback m_callback ;
BgfxAllocator m_allocator ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
uint32_t m_width ;
uint32_t m_height ;
2017-06-17 04:46:21 +03:00
2017-06-16 23:10:37 +03:00
bgfx : : VertexBufferHandle m_vbh ;
bgfx : : IndexBufferHandle m_ibh ;
bgfx : : ProgramHandle m_program ;
float m_time ;
uint32_t m_frame ;
} ;
2012-12-31 08:52:47 +04:00
2017-06-26 07:44:04 +03:00
} // namespace
2013-09-21 09:13:58 +04:00
2017-06-26 07:44:04 +03:00
ENTRY_IMPLEMENT_MAIN ( ExampleCallback , " 07-callback " , " Implementing application specific callbacks for taking screen shots, caching OpenGL binary shaders, and video capture. " ) ;