2012-12-30 20:52:47 -08:00
/*
2015-01-01 15:04:46 -08:00
* Copyright 2011 - 2015 Branimir Karadzic . All rights reserved .
2012-12-30 20:52:47 -08:00
* License : http : //www.opensource.org/licenses/BSD-2-Clause
*/
2013-05-23 22:07:54 -07:00
# include "common.h"
2014-05-03 15:18:28 -07:00
# include "bgfx_utils.h"
2013-05-18 22:12:40 -07:00
2013-09-16 21:40:30 -07:00
# include <bx/allocator.h>
2012-12-30 20:52:47 -08:00
# include <bx/string.h>
2013-05-23 22:07:54 -07:00
# include "aviwriter.h"
2012-12-30 20:52:47 -08:00
# include <inttypes.h>
struct PosColorVertex
{
float m_x ;
float m_y ;
float m_z ;
uint32_t m_abgr ;
2014-05-03 15:18:28 -07:00
static void init ( )
{
2014-05-10 20:51:44 -07:00
ms_decl
. begin ( )
. add ( bgfx : : Attrib : : Position , 3 , bgfx : : AttribType : : Float )
. add ( bgfx : : Attrib : : Color0 , 4 , bgfx : : AttribType : : Uint8 , true )
. end ( ) ;
2014-05-03 15:18:28 -07:00
} ;
static bgfx : : VertexDecl ms_decl ;
2012-12-30 20:52:47 -08:00
} ;
2014-05-03 15:18:28 -07:00
bgfx : : VertexDecl PosColorVertex : : ms_decl ;
2012-12-30 20:52:47 -08: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-21 22:05:33 -08: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-30 20:52:47 -08:00
} ;
void saveTga ( const char * _filePath , uint32_t _width , uint32_t _height , uint32_t _srcPitch , const void * _src , bool _grayscale , bool _yflip )
{
FILE * file = fopen ( _filePath , " wb " ) ;
2014-09-19 10:33:13 -07:00
if ( NULL ! = file )
2012-12-30 20:52:47 -08:00
{
uint8_t type = _grayscale ? 3 : 2 ;
uint8_t bpp = _grayscale ? 8 : 32 ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
putc ( type , file ) ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
2014-09-19 10:33:13 -07:00
putc ( 0 , file ) ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
putc ( 0 , file ) ;
2012-12-30 20:52:47 -08:00
putc ( 0 , file ) ;
putc ( _width & 0xff , file ) ;
putc ( ( _width > > 8 ) & 0xff , file ) ;
putc ( _height & 0xff , file ) ;
putc ( ( _height > > 8 ) & 0xff , file ) ;
putc ( bpp , file ) ;
putc ( 32 , file ) ;
uint32_t dstPitch = _width * bpp / 8 ;
if ( _yflip )
{
uint8_t * data = ( uint8_t * ) _src + _srcPitch * _height - _srcPitch ;
for ( uint32_t yy = 0 ; yy < _height ; + + yy )
{
fwrite ( data , dstPitch , 1 , file ) ;
data - = _srcPitch ;
}
}
else
{
uint8_t * data = ( uint8_t * ) _src ;
for ( uint32_t yy = 0 ; yy < _height ; + + yy )
{
fwrite ( data , dstPitch , 1 , file ) ;
data + = _srcPitch ;
}
}
fclose ( file ) ;
}
}
2014-05-03 15:18:28 -07:00
long int fsize ( FILE * _file )
{
long int pos = ftell ( _file ) ;
fseek ( _file , 0L , SEEK_END ) ;
long int size = ftell ( _file ) ;
fseek ( _file , pos , SEEK_SET ) ;
return size ;
}
2012-12-30 20:52:47 -08:00
struct BgfxCallback : public bgfx : : CallbackI
{
virtual ~ BgfxCallback ( )
{
}
virtual void fatal ( bgfx : : Fatal : : Enum _code , const char * _str ) BX_OVERRIDE
{
2012-12-31 18:48:52 -08:00
// Something unexpected happened, inform user and bail out.
2012-12-30 20:52:47 -08:00
dbgPrintf ( " Fatal error: 0x%08x: %s " , _code , _str ) ;
2012-12-31 18:48:52 -08:00
// Must terminate, continuing will cause crash anyway.
2012-12-30 20:52:47 -08:00
abort ( ) ;
}
virtual uint32_t cacheReadSize ( uint64_t _id ) BX_OVERRIDE
{
char filePath [ 256 ] ;
bx : : snprintf ( filePath , sizeof ( filePath ) , " %016 " PRIx64 , _id ) ;
2012-12-31 18:48:52 -08:00
// Use cache id as filename.
2012-12-30 20:52:47 -08:00
FILE * file = fopen ( filePath , " rb " ) ;
if ( NULL ! = file )
{
uint32_t size = fsize ( file ) ;
fclose ( file ) ;
2012-12-31 18:48:52 -08:00
// Return size of shader file.
2012-12-30 20:52:47 -08:00
return size ;
}
2012-12-31 18:48:52 -08:00
// Return 0 if shader is not found.
2012-12-30 20:52:47 -08:00
return 0 ;
}
virtual bool cacheRead ( uint64_t _id , void * _data , uint32_t _size ) BX_OVERRIDE
{
char filePath [ 256 ] ;
2013-01-12 14:25:27 -08:00
bx : : snprintf ( filePath , sizeof ( filePath ) , " temp/%016 " PRIx64 , _id ) ;
2012-12-31 18:48:52 -08:00
// Use cache id as filename.
2012-12-30 20:52:47 -08:00
FILE * file = fopen ( filePath , " rb " ) ;
if ( NULL ! = file )
{
2012-12-31 18:48:52 -08:00
// Read shader.
2012-12-30 20:52:47 -08:00
size_t result = fread ( _data , 1 , _size , file ) ;
fclose ( file ) ;
2012-12-31 18:48:52 -08:00
// Make sure that read size matches requested size.
2012-12-30 20:52:47 -08:00
return result = = _size ;
}
2012-12-31 18:48:52 -08:00
// Shader is not found in cache, needs to be rebuilt.
2012-12-30 20:52:47 -08:00
return false ;
}
virtual void cacheWrite ( uint64_t _id , const void * _data , uint32_t _size ) BX_OVERRIDE
{
char filePath [ 256 ] ;
2013-01-12 14:25:27 -08:00
bx : : snprintf ( filePath , sizeof ( filePath ) , " temp/%016 " PRIx64 , _id ) ;
2012-12-30 20:52:47 -08:00
2012-12-31 18:48:52 -08:00
// Use cache id as filename.
2012-12-30 20:52:47 -08:00
FILE * file = fopen ( filePath , " wb " ) ;
if ( NULL ! = file )
{
2012-12-31 18:48:52 -08:00
// Write shader to cache location.
2012-12-30 20:52:47 -08:00
fwrite ( _data , 1 , _size , file ) ;
fclose ( file ) ;
}
}
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-21 22:51:24 -07:00
char temp [ 1024 ] ;
2012-12-31 18:48:52 -08:00
// Save screen shot as TGA.
2013-08-21 22:51:24 -07:00
bx : : snprintf ( temp , BX_COUNTOF ( temp ) , " %s.mip0.tga " , _filePath ) ;
saveTga ( temp , _width , _height , _pitch , _data , false , _yflip ) ;
uint32_t width = _width ;
uint32_t height = _height ;
uint32_t pitch = _pitch ;
uint8_t * data = ( uint8_t * ) _data ;
// Generate mip maps.
uint32_t mip = 1 ;
for ( ; 2 < = width & & 2 < = height ; + + mip )
{
bx : : snprintf ( temp , BX_COUNTOF ( temp ) , " %s.mip%d.tga " , _filePath , mip ) ;
bgfx : : imageRgba8Downsample2x2 ( width , height , pitch , data , data ) ;
width > > = 1 ;
height > > = 1 ;
pitch = width * 4 ;
saveTga ( temp , width , height , pitch , _data , false , _yflip ) ;
}
if ( width > height )
{
for ( ; 2 < = width ; + + mip )
{
memcpy ( & data [ width * 4 ] , data , width * 4 ) ;
bx : : snprintf ( temp , BX_COUNTOF ( temp ) , " %s.mip%d.tga " , _filePath , mip ) ;
bgfx : : imageRgba8Downsample2x2 ( width , 2 , pitch , data , data ) ;
width > > = 1 ;
pitch = width * 4 ;
saveTga ( temp , width , 2 , pitch , _data , false , _yflip ) ;
}
}
else
{
for ( ; 2 < = height ; + + mip )
{
uint32_t * src = ( uint32_t * ) data ;
for ( uint32_t ii = 0 ; ii < height ; + + ii , src + = 2 )
{
src [ 1 ] = src [ 0 ] ;
}
bx : : snprintf ( temp , BX_COUNTOF ( temp ) , " %s.mip%d.tga " , _filePath , mip ) ;
bgfx : : imageRgba8Downsample2x2 ( 2 , height , 8 , data , data ) ;
height > > = 1 ;
saveTga ( temp , 2 , height , 8 , _data , false , _yflip ) ;
}
}
2012-12-30 20:52:47 -08:00
}
2013-03-25 21:13:54 -07:00
virtual void captureBegin ( uint32_t _width , uint32_t _height , uint32_t /*_pitch*/ , bgfx : : TextureFormat : : Enum /*_format*/ , bool _yflip ) BX_OVERRIDE
2012-12-30 20:52:47 -08:00
{
2014-05-03 15:18:28 -07:00
m_writer = new AviWriter ( entry : : getFileWriter ( ) ) ;
2013-01-12 14:25:27 -08:00
if ( ! m_writer - > open ( " temp/capture.avi " , _width , _height , 60 , _yflip ) )
2012-12-30 20:52:47 -08:00
{
delete m_writer ;
m_writer = NULL ;
}
}
virtual void captureEnd ( ) BX_OVERRIDE
{
if ( NULL ! = m_writer )
{
m_writer - > close ( ) ;
2013-02-10 22:48:13 -08:00
delete m_writer ;
m_writer = NULL ;
2012-12-30 20:52:47 -08:00
}
}
virtual void captureFrame ( const void * _data , uint32_t /*_size*/ ) BX_OVERRIDE
{
if ( NULL ! = m_writer )
{
m_writer - > frame ( _data ) ;
}
}
AviWriter * m_writer ;
} ;
2013-09-16 21:40:30 -07:00
class BgfxAllocator : public bx : : ReallocatorI
{
public :
BgfxAllocator ( )
2013-09-20 22:13:58 -07:00
: m_numBlocks ( 0 )
, m_maxBlocks ( 0 )
2013-09-16 21:40:30 -07:00
{
}
virtual ~ BgfxAllocator ( )
{
}
2014-05-01 10:15:41 -07:00
virtual void * alloc ( size_t _size , size_t _align , const char * _file , uint32_t _line ) BX_OVERRIDE
2013-09-16 21:40:30 -07:00
{
2014-05-01 10:15:41 -07:00
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
{
void * ptr = : : malloc ( _size ) ;
dbgPrintf ( " %s(%d): ALLOC %p of %d byte(s) \n " , _file , _line , ptr , _size ) ;
+ + m_numBlocks ;
m_maxBlocks = bx : : uint32_max ( m_maxBlocks , m_numBlocks ) ;
return ptr ;
}
return bx : : alignedAlloc ( this , _size , _align , _file , _line ) ;
2013-09-16 21:40:30 -07:00
}
2014-05-01 10:15:41 -07:00
virtual void free ( void * _ptr , size_t _align , const char * _file , uint32_t _line ) BX_OVERRIDE
2013-09-16 21:40:30 -07:00
{
2013-09-22 21:40:17 -07:00
if ( NULL ! = _ptr )
{
2014-05-01 10:15:41 -07:00
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
{
dbgPrintf ( " %s(%d): FREE %p \n " , _file , _line , _ptr ) ;
: : free ( _ptr ) ;
- - m_numBlocks ;
}
else
{
bx : : alignedFree ( this , _ptr , _align , _file , _line ) ;
}
2013-09-22 21:40:17 -07:00
}
2013-09-16 21:40:30 -07:00
}
2014-05-01 10:15:41 -07:00
virtual void * realloc ( void * _ptr , size_t _size , size_t _align , const char * _file , uint32_t _line ) BX_OVERRIDE
2013-09-16 21:40:30 -07:00
{
2014-05-01 10:15:41 -07:00
if ( BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT > = _align )
2013-09-20 22:13:58 -07:00
{
2014-05-01 10:15:41 -07:00
void * ptr = : : realloc ( _ptr , _size ) ;
dbgPrintf ( " %s(%d): REALLOC %p (old %p) of %d byte(s) \n " , _file , _line , ptr , _ptr , _size ) ;
if ( NULL = = _ptr )
{
+ + m_numBlocks ;
m_maxBlocks = bx : : uint32_max ( m_maxBlocks , m_numBlocks ) ;
}
return ptr ;
2013-09-20 22:13:58 -07:00
}
2014-05-01 10:15:41 -07:00
return bx : : alignedRealloc ( this , _ptr , _size , _align , _file , _line ) ;
2013-09-16 21:40:30 -07:00
}
2013-09-20 22:13:58 -07:00
void dumpStats ( ) const
{
dbgPrintf ( " Allocator stats: num blocks %d (peak: %d) \n " , m_numBlocks , m_maxBlocks ) ;
}
private :
uint32_t m_numBlocks ;
uint32_t m_maxBlocks ;
2013-09-16 21:40:30 -07:00
} ;
2013-03-25 21:13:54 -07:00
int _main_ ( int /*_argc*/ , char * * /*_argv*/ )
2012-12-30 20:52:47 -08:00
{
BgfxCallback callback ;
2013-09-16 21:40:30 -07:00
BgfxAllocator allocator ;
2012-12-30 20:52:47 -08:00
2013-07-22 21:24:20 -07:00
uint32_t width = 1280 ;
uint32_t height = 720 ;
2014-05-27 20:05:13 -07:00
// Enumerate supported backend renderers.
bgfx : : RendererType : : Enum renderers [ bgfx : : RendererType : : Count ] ;
uint8_t numRenderers = bgfx : : getSupportedRenderers ( renderers ) ;
bgfx : : init (
renderers [ bx : : getHPCounter ( ) % numRenderers ] /* randomize renderer */
2015-03-26 15:04:09 -07:00
, BGFX_PCI_ID_NONE
, 0
2014-05-27 20:05:13 -07:00
, & callback // custom callback handler
, & allocator // custom allocator
) ;
2014-05-01 10:15:41 -07:00
bgfx : : reset ( width , height , BGFX_RESET_CAPTURE | BGFX_RESET_MSAA_X16 ) ;
2012-12-30 20:52:47 -08:00
// Enable debug text.
bgfx : : setDebug ( BGFX_DEBUG_TEXT ) ;
// Set view 0 default viewport.
bgfx : : setViewRect ( 0 , 0 , 0 , 1280 , 720 ) ;
// Set view 0 clear state.
bgfx : : setViewClear ( 0
2015-01-10 21:39:45 -08:00
, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
2012-12-30 20:52:47 -08:00
, 0x303030ff
, 1.0f
, 0
) ;
// Create vertex stream declaration.
2014-05-03 15:18:28 -07:00
PosColorVertex : : init ( ) ;
2012-12-30 20:52:47 -08:00
// Create static vertex buffer.
2014-05-03 15:18:28 -07:00
bgfx : : VertexBufferHandle vbh = bgfx : : createVertexBuffer (
bgfx : : makeRef ( s_cubeVertices , sizeof ( s_cubeVertices ) )
, PosColorVertex : : ms_decl
) ;
2012-12-30 20:52:47 -08:00
// Create static index buffer.
2014-05-03 15:18:28 -07:00
bgfx : : IndexBufferHandle ibh = bgfx : : createIndexBuffer ( bgfx : : makeRef ( s_cubeIndices , sizeof ( s_cubeIndices ) ) ) ;
2012-12-30 20:52:47 -08:00
// Create program from shaders.
2014-05-03 15:18:28 -07:00
bgfx : : ProgramHandle program = loadProgram ( " vs_callback " , " fs_callback " ) ;
2012-12-30 20:52:47 -08:00
float time = 0.0f ;
2014-05-27 20:05:13 -07:00
const bgfx : : RendererType : : Enum rendererType = bgfx : : getRendererType ( ) ;
2012-12-30 20:52:47 -08:00
// 5 second 60Hz video
for ( uint32_t frame = 0 ; frame < 300 ; + + frame )
{
// 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 : : submit ( 0 ) ;
int64_t now = bx : : getHPCounter ( ) ;
static int64_t last = now ;
const int64_t frameTime = now - last ;
last = now ;
const double freq = double ( bx : : getHPFrequency ( ) ) ;
const double toMs = 1000.0 / freq ;
// Use debug font to print information about this example.
bgfx : : dbgTextClear ( ) ;
bgfx : : dbgTextPrintf ( 0 , 1 , 0x4f , " bgfx/examples/07-callback " ) ;
bgfx : : dbgTextPrintf ( 0 , 2 , 0x6f , " Description: Implementing application specific callbacks for taking screen shots, " ) ;
bgfx : : dbgTextPrintf ( 13 , 3 , 0x6f , " caching OpenGL binary shaders, and video capture. " ) ;
bgfx : : dbgTextPrintf ( 0 , 4 , 0x0f , " Frame: % 7.3f[ms] " , double ( frameTime ) * toMs ) ;
2014-05-27 20:05:13 -07:00
bgfx : : dbgTextPrintf ( 2 , 6 , 0x0e , " Supported renderers: " ) ;
for ( uint8_t ii = 0 ; ii < numRenderers ; + + ii )
{
bgfx : : dbgTextPrintf ( 2 , 7 + ii , 0x0c , " [%c] %s "
, renderers [ ii ] = = rendererType ? ' \xfe ' : ' '
, bgfx : : getRendererName ( renderers [ ii ] )
) ;
}
2012-12-30 20:52:47 -08:00
float at [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
float eye [ 3 ] = { 0.0f , 0.0f , - 35.0f } ;
2015-03-26 15:04:09 -07:00
2012-12-30 20:52:47 -08:00
float view [ 16 ] ;
float proj [ 16 ] ;
2014-05-26 19:31:37 -07:00
bx : : mtxLookAt ( view , eye , at ) ;
bx : : mtxProj ( proj , 60.0f , float ( width ) / float ( height ) , 0.1f , 100.0f ) ;
2012-12-30 20:52:47 -08:00
// Set view and projection matrix for view 0.
bgfx : : setViewTransform ( 0 , view , proj ) ;
time + = 1.0f / 60.0f ;
// Submit 11x11 cubes.
for ( uint32_t yy = 0 ; yy < 11 ; + + yy )
{
for ( uint32_t xx = 0 ; xx < 11 - yy ; + + xx )
{
float mtx [ 16 ] ;
2014-05-26 19:31:37 -07:00
bx : : mtxRotateXY ( mtx , time + xx * 0.21f , time + yy * 0.37f ) ;
2012-12-30 20:52:47 -08:00
mtx [ 12 ] = - 15.0f + float ( xx ) * 3.0f ;
mtx [ 13 ] = - 15.0f + float ( yy ) * 3.0f ;
mtx [ 14 ] = 0.0f ;
// Set model matrix for rendering.
bgfx : : setTransform ( mtx ) ;
// Set vertex and fragment shaders.
bgfx : : setProgram ( program ) ;
// Set vertex and index buffer.
bgfx : : setVertexBuffer ( vbh ) ;
bgfx : : setIndexBuffer ( ibh ) ;
// Set render states.
2013-02-21 22:05:33 -08:00
bgfx : : setState ( BGFX_STATE_DEFAULT ) ;
2012-12-30 20:52:47 -08:00
// Submit primitive for rendering to view 0.
bgfx : : submit ( 0 ) ;
}
}
2012-12-31 18:48:52 -08:00
// Take screen shot at frame 150.
2012-12-30 20:52:47 -08:00
if ( 150 = = frame )
{
2013-08-21 22:51:24 -07:00
bgfx : : saveScreenShot ( " temp/frame150 " ) ;
2012-12-30 20:52:47 -08:00
}
2015-03-26 15:04:09 -07:00
// Advance to next frame. Rendering thread will be kicked to
2012-12-30 20:52:47 -08:00
// process submitted rendering primitives.
bgfx : : frame ( ) ;
}
// Cleanup.
bgfx : : destroyIndexBuffer ( ibh ) ;
bgfx : : destroyVertexBuffer ( vbh ) ;
bgfx : : destroyProgram ( program ) ;
// Shutdown bgfx.
bgfx : : shutdown ( ) ;
2013-09-20 22:13:58 -07:00
allocator . dumpStats ( ) ;
2012-12-30 20:52:47 -08:00
return 0 ;
}