2013-10-18 01:55:43 -04:00
/*
2014-01-13 17:45:18 -05:00
* Copyright 2013 - 2014 Dario Manesku . All rights reserved .
2013-10-18 01:55:43 -04:00
* License : http : //www.opensource.org/licenses/BSD-2-Clause
*/
2013-12-24 01:36:30 -05:00
# include <stdio.h>
# include <string.h>
# include <string>
# include <vector>
# include <unordered_map>
# include <map>
2013-10-18 01:55:43 -04:00
namespace std { namespace tr1 { } }
using namespace std : : tr1 ;
# include "common.h"
# include <bgfx.h>
# include <bx/timer.h>
# include <bx/readerwriter.h>
2013-11-13 11:53:44 -05:00
# include <bx/allocator.h>
2013-11-20 14:28:12 -05:00
# include <bx/hash.h>
2013-11-12 16:18:14 -05:00
# include <bx/float4_t.h>
2013-10-18 01:55:43 -04:00
# include "entry/entry.h"
2014-01-30 12:20:06 -05:00
# include "entry/camera.h"
2013-10-18 01:55:43 -04:00
# include "fpumath.h"
# include "imgui/imgui.h"
2013-11-12 16:18:14 -05:00
# define SV_USE_SIMD 1
2013-10-24 17:36:16 -04:00
# define MAX_INSTANCE_COUNT 25
# define MAX_LIGHTS_COUNT 5
2013-11-12 16:20:50 -05:00
# define VIEWID_RANGE1_PASS0 1
2013-10-20 14:34:28 -04:00
# define VIEWID_RANGE1_RT_PASS1 2
# define VIEWID_RANGE15_PASS2 3
# define VIEWID_RANGE1_PASS3 20
2013-10-18 01:55:43 -04:00
uint32_t packUint32 ( uint8_t _x , uint8_t _y , uint8_t _z , uint8_t _w )
{
union
{
uint32_t ui32 ;
uint8_t arr [ 4 ] ;
} un ;
un . arr [ 0 ] = _x ;
un . arr [ 1 ] = _y ;
un . arr [ 2 ] = _z ;
un . arr [ 3 ] = _w ;
return un . ui32 ;
}
uint32_t packF4u ( float _x , float _y = 0.0f , float _z = 0.0f , float _w = 0.0f )
{
const uint8_t xx = uint8_t ( _x * 127.0f + 128.0f ) ;
const uint8_t yy = uint8_t ( _y * 127.0f + 128.0f ) ;
const uint8_t zz = uint8_t ( _z * 127.0f + 128.0f ) ;
const uint8_t ww = uint8_t ( _w * 127.0f + 128.0f ) ;
return packUint32 ( xx , yy , zz , ww ) ;
}
struct PosNormalTexcoordVertex
{
float m_x ;
float m_y ;
float m_z ;
uint32_t m_normal ;
float m_u ;
float m_v ;
} ;
static const float s_texcoord = 50.0f ;
static const uint32_t s_numHPlaneVertices = 4 ;
static PosNormalTexcoordVertex s_hplaneVertices [ s_numHPlaneVertices ] =
{
{ - 1.0f , 0.0f , 1.0f , packF4u ( 0.0f , 1.0f , 0.0f ) , s_texcoord , s_texcoord } ,
{ 1.0f , 0.0f , 1.0f , packF4u ( 0.0f , 1.0f , 0.0f ) , s_texcoord , 0.0f } ,
{ - 1.0f , 0.0f , - 1.0f , packF4u ( 0.0f , 1.0f , 0.0f ) , 0.0f , s_texcoord } ,
{ 1.0f , 0.0f , - 1.0f , packF4u ( 0.0f , 1.0f , 0.0f ) , 0.0f , 0.0f } ,
} ;
static const uint32_t s_numVPlaneVertices = 4 ;
static PosNormalTexcoordVertex s_vplaneVertices [ s_numVPlaneVertices ] =
{
{ - 1.0f , 1.0f , 0.0f , packF4u ( 0.0f , 0.0f , - 1.0f ) , 1.0f , 1.0f } ,
{ 1.0f , 1.0f , 0.0f , packF4u ( 0.0f , 0.0f , - 1.0f ) , 1.0f , 0.0f } ,
{ - 1.0f , - 1.0f , 0.0f , packF4u ( 0.0f , 0.0f , - 1.0f ) , 0.0f , 1.0f } ,
{ 1.0f , - 1.0f , 0.0f , packF4u ( 0.0f , 0.0f , - 1.0f ) , 0.0f , 0.0f } ,
} ;
static const uint32_t s_numPlaneIndices = 6 ;
static const uint16_t s_planeIndices [ s_numPlaneIndices ] =
{
0 , 1 , 2 ,
1 , 3 , 2 ,
} ;
static const char * s_shaderPath = NULL ;
static bool s_flipV = false ;
2014-02-14 02:14:49 -05:00
static float s_texelHalf = 0.0f ;
2013-10-18 01:55:43 -04:00
static uint32_t s_viewMask = 0 ;
static bgfx : : UniformHandle u_texColor ;
static bgfx : : UniformHandle u_texStencil ;
2014-02-06 02:07:11 -05:00
static bgfx : : FrameBufferHandle s_stencilFb ;
2013-10-18 01:55:43 -04:00
inline uint32_t uint32_max ( uint32_t _a , uint32_t _b )
{
return _a > _b ? _a : _b ;
}
static void shaderFilePath ( char * _out , const char * _name )
{
strcpy ( _out , s_shaderPath ) ;
strcat ( _out , _name ) ;
strcat ( _out , " .bin " ) ;
}
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 ;
}
static const bgfx : : Memory * load ( const char * _filePath )
{
FILE * file = fopen ( _filePath , " rb " ) ;
if ( NULL ! = file )
{
uint32_t size = ( uint32_t ) fsize ( file ) ;
const bgfx : : Memory * mem = bgfx : : alloc ( size + 1 ) ;
size_t ignore = fread ( mem - > data , 1 , size , file ) ;
BX_UNUSED ( ignore ) ;
fclose ( file ) ;
mem - > data [ mem - > size - 1 ] = ' \0 ' ;
return mem ;
}
return NULL ;
}
static const bgfx : : Memory * loadShader ( const char * _name )
{
char filePath [ 512 ] ;
shaderFilePath ( filePath , _name ) ;
return load ( filePath ) ;
}
static const bgfx : : Memory * loadTexture ( const char * _name )
{
char filePath [ 512 ] ;
strcpy ( filePath , " textures/ " ) ;
strcat ( filePath , _name ) ;
return load ( filePath ) ;
}
static bgfx : : ProgramHandle loadProgram ( const char * _vsName , const char * _fsName )
{
const bgfx : : Memory * mem ;
// Load vertex shader.
mem = loadShader ( _vsName ) ;
bgfx : : VertexShaderHandle vsh = bgfx : : createVertexShader ( mem ) ;
// Load fragment shader.
mem = loadShader ( _fsName ) ;
bgfx : : FragmentShaderHandle fsh = bgfx : : createFragmentShader ( mem ) ;
// Create program from shaders.
bgfx : : ProgramHandle program = bgfx : : createProgram ( vsh , fsh ) ;
// We can destroy vertex and fragment shader here since
// their reference is kept inside bgfx after calling createProgram.
// Vertex and fragment shader will be destroyed once program is
// destroyed.
bgfx : : destroyVertexShader ( vsh ) ;
bgfx : : destroyFragmentShader ( fsh ) ;
return program ;
}
void mtxScaleRotateTranslate ( float * _result
2013-10-20 14:34:28 -04:00
, const float _scaleX
, const float _scaleY
, const float _scaleZ
, const float _rotX
, const float _rotY
, const float _rotZ
, const float _translateX
, const float _translateY
, const float _translateZ
)
2013-10-18 01:55:43 -04:00
{
float mtxRotateTranslate [ 16 ] ;
float mtxScale [ 16 ] ;
mtxRotateXYZ ( mtxRotateTranslate , _rotX , _rotY , _rotZ ) ;
mtxRotateTranslate [ 12 ] = _translateX ;
mtxRotateTranslate [ 13 ] = _translateY ;
mtxRotateTranslate [ 14 ] = _translateZ ;
2013-10-20 14:34:28 -04:00
memset ( mtxScale , 0 , 16 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
mtxScale [ 0 ] = _scaleX ;
mtxScale [ 5 ] = _scaleY ;
mtxScale [ 10 ] = _scaleZ ;
mtxScale [ 15 ] = 1.0f ;
mtxMul ( _result , mtxScale , mtxRotateTranslate ) ;
}
void mtxBillboard ( float * __restrict _result
2013-10-20 14:34:28 -04:00
, const float * __restrict _view
, const float * __restrict _pos
, const float * __restrict _scale
)
2013-10-18 01:55:43 -04:00
{
_result [ 0 ] = _view [ 0 ] * _scale [ 0 ] ;
_result [ 1 ] = _view [ 4 ] * _scale [ 0 ] ;
_result [ 2 ] = _view [ 8 ] * _scale [ 0 ] ;
_result [ 3 ] = 0.0f ;
_result [ 4 ] = _view [ 1 ] * _scale [ 1 ] ;
_result [ 5 ] = _view [ 5 ] * _scale [ 1 ] ;
_result [ 6 ] = _view [ 9 ] * _scale [ 1 ] ;
_result [ 7 ] = 0.0f ;
_result [ 8 ] = _view [ 2 ] * _scale [ 2 ] ;
_result [ 9 ] = _view [ 6 ] * _scale [ 2 ] ;
_result [ 10 ] = _view [ 10 ] * _scale [ 2 ] ;
_result [ 11 ] = 0.0f ;
_result [ 12 ] = _pos [ 0 ] ;
_result [ 13 ] = _pos [ 1 ] ;
_result [ 14 ] = _pos [ 2 ] ;
_result [ 15 ] = 1.0f ;
}
void planeNormal ( float * __restrict _result
2013-10-20 14:34:28 -04:00
, const float * __restrict _v0
, const float * __restrict _v1
, const float * __restrict _v2
)
2013-10-18 01:55:43 -04:00
{
float vec0 [ 3 ] , vec1 [ 3 ] ;
float cross [ 3 ] ;
vec0 [ 0 ] = _v1 [ 0 ] - _v0 [ 0 ] ;
vec0 [ 1 ] = _v1 [ 1 ] - _v0 [ 1 ] ;
vec0 [ 2 ] = _v1 [ 2 ] - _v0 [ 2 ] ;
vec1 [ 0 ] = _v2 [ 0 ] - _v1 [ 0 ] ;
vec1 [ 1 ] = _v2 [ 1 ] - _v1 [ 1 ] ;
vec1 [ 2 ] = _v2 [ 2 ] - _v1 [ 2 ] ;
vec3Cross ( cross , vec0 , vec1 ) ;
vec3Norm ( _result , cross ) ;
_result [ 3 ] = - vec3Dot ( _result , _v0 ) ;
}
struct Uniforms
{
void init ( )
{
m_params . m_ambientPass = 1.0f ;
m_params . m_lightningPass = 1.0f ;
2014-02-14 02:14:49 -05:00
m_params . m_texelHalf = 0.0f ;
2013-10-18 01:55:43 -04:00
m_ambient [ 0 ] = 0.05f ;
m_ambient [ 1 ] = 0.05f ;
m_ambient [ 2 ] = 0.05f ;
m_ambient [ 3 ] = 0.0f ; //unused
m_diffuse [ 0 ] = 0.8f ;
m_diffuse [ 1 ] = 0.8f ;
m_diffuse [ 2 ] = 0.8f ;
m_diffuse [ 3 ] = 0.0f ; //unused
m_specular_shininess [ 0 ] = 1.0f ;
m_specular_shininess [ 1 ] = 1.0f ;
m_specular_shininess [ 2 ] = 1.0f ;
m_specular_shininess [ 3 ] = 25.0f ; //shininess
2013-10-20 14:34:28 -04:00
m_fog [ 0 ] = 0.0f ; //color
m_fog [ 1 ] = 0.0f ;
m_fog [ 2 ] = 0.0f ;
2013-10-18 01:55:43 -04:00
m_fog [ 3 ] = 0.0055f ; //density
m_color [ 0 ] = 1.0f ;
m_color [ 1 ] = 1.0f ;
m_color [ 2 ] = 1.0f ;
m_color [ 3 ] = 1.0f ;
m_time = 0.0f ;
m_flipV = float ( s_flipV ) * 2.0f - 1.0f ;
m_lightPosRadius [ 0 ] = 0.0f ;
m_lightPosRadius [ 1 ] = 0.0f ;
m_lightPosRadius [ 2 ] = 0.0f ;
m_lightPosRadius [ 3 ] = 1.0f ;
m_lightRgbInnerR [ 0 ] = 0.0f ;
m_lightRgbInnerR [ 1 ] = 0.0f ;
m_lightRgbInnerR [ 2 ] = 0.0f ;
m_lightRgbInnerR [ 3 ] = 1.0f ;
m_virtualLightPos_extrusionDist [ 0 ] = 0.0f ;
m_virtualLightPos_extrusionDist [ 1 ] = 0.0f ;
m_virtualLightPos_extrusionDist [ 2 ] = 0.0f ;
m_virtualLightPos_extrusionDist [ 3 ] = 100.0f ;
u_params = bgfx : : createUniform ( " u_params " , bgfx : : UniformType : : Uniform4fv ) ;
u_svparams = bgfx : : createUniform ( " u_svparams " , bgfx : : UniformType : : Uniform4fv ) ;
u_ambient = bgfx : : createUniform ( " u_ambient " , bgfx : : UniformType : : Uniform4fv ) ;
u_diffuse = bgfx : : createUniform ( " u_diffuse " , bgfx : : UniformType : : Uniform4fv ) ;
u_specular_shininess = bgfx : : createUniform ( " u_specular_shininess " , bgfx : : UniformType : : Uniform4fv ) ;
u_fog = bgfx : : createUniform ( " u_fog " , bgfx : : UniformType : : Uniform4fv ) ;
u_color = bgfx : : createUniform ( " u_color " , bgfx : : UniformType : : Uniform4fv ) ;
u_time = bgfx : : createUniform ( " u_time " , bgfx : : UniformType : : Uniform1f ) ;
u_flipV = bgfx : : createUniform ( " u_flipV " , bgfx : : UniformType : : Uniform1f ) ;
u_lightPosRadius = bgfx : : createUniform ( " u_lightPosRadius " , bgfx : : UniformType : : Uniform4fv ) ;
u_lightRgbInnerR = bgfx : : createUniform ( " u_lightRgbInnerR " , bgfx : : UniformType : : Uniform4fv ) ;
u_virtualLightPos_extrusionDist = bgfx : : createUniform ( " u_virtualLightPos_extrusionDist " , bgfx : : UniformType : : Uniform4fv ) ;
}
//call this once at initialization
void submitConstUniforms ( )
{
bgfx : : setUniform ( u_ambient , & m_ambient ) ;
bgfx : : setUniform ( u_diffuse , & m_diffuse ) ;
bgfx : : setUniform ( u_specular_shininess , & m_specular_shininess ) ;
bgfx : : setUniform ( u_fog , & m_fog ) ;
bgfx : : setUniform ( u_flipV , & m_flipV ) ;
}
//call this once per frame
void submitPerFrameUniforms ( )
{
bgfx : : setUniform ( u_time , & m_time ) ;
}
//call this before each draw call
void submitPerDrawUniforms ( )
{
bgfx : : setUniform ( u_params , & m_params ) ;
bgfx : : setUniform ( u_svparams , & m_svparams ) ;
bgfx : : setUniform ( u_color , & m_color ) ;
bgfx : : setUniform ( u_lightPosRadius , & m_lightPosRadius ) ;
bgfx : : setUniform ( u_lightRgbInnerR , & m_lightRgbInnerR ) ;
bgfx : : setUniform ( u_virtualLightPos_extrusionDist , & m_virtualLightPos_extrusionDist ) ;
}
void destroy ( )
{
bgfx : : destroyUniform ( u_params ) ;
bgfx : : destroyUniform ( u_svparams ) ;
bgfx : : destroyUniform ( u_ambient ) ;
bgfx : : destroyUniform ( u_diffuse ) ;
bgfx : : destroyUniform ( u_specular_shininess ) ;
bgfx : : destroyUniform ( u_fog ) ;
bgfx : : destroyUniform ( u_color ) ;
bgfx : : destroyUniform ( u_time ) ;
bgfx : : destroyUniform ( u_flipV ) ;
bgfx : : destroyUniform ( u_lightPosRadius ) ;
bgfx : : destroyUniform ( u_lightRgbInnerR ) ;
bgfx : : destroyUniform ( u_virtualLightPos_extrusionDist ) ;
}
2013-10-20 14:34:28 -04:00
struct Params
2013-10-18 01:55:43 -04:00
{
float m_ambientPass ;
float m_lightningPass ;
2014-02-14 02:14:49 -05:00
float m_texelHalf ;
float m_unused00 ;
2013-10-20 14:34:28 -04:00
} ;
2013-11-12 16:20:50 -05:00
2013-10-20 14:34:28 -04:00
struct SvParams
2013-10-18 01:55:43 -04:00
{
float m_useStencilTex ;
float m_dfail ;
2014-02-14 02:14:49 -05:00
float m_unused10 ;
float m_unused11 ;
2013-10-20 14:34:28 -04:00
} ;
Params m_params ;
SvParams m_svparams ;
2013-10-18 01:55:43 -04:00
float m_ambient [ 4 ] ;
float m_diffuse [ 4 ] ;
float m_specular_shininess [ 4 ] ;
float m_fog [ 4 ] ;
float m_color [ 4 ] ;
float m_time ;
float m_flipV ;
float m_lightPosRadius [ 4 ] ;
float m_lightRgbInnerR [ 4 ] ;
float m_virtualLightPos_extrusionDist [ 4 ] ;
/**
* u_params . x - u_ambientPass
* u_params . y - u_lightningPass
2014-02-14 02:14:49 -05:00
* u_params . z - u_texelHalf
* u_params . w - unused
2013-10-18 01:55:43 -04:00
* u_svparams . x - u_useStencilTex
* u_svparams . y - u_dfail
* u_svparams . z - unused
* u_svparams . w - unused
*/
bgfx : : UniformHandle u_params ;
bgfx : : UniformHandle u_svparams ;
bgfx : : UniformHandle u_ambient ;
bgfx : : UniformHandle u_diffuse ;
bgfx : : UniformHandle u_specular_shininess ;
bgfx : : UniformHandle u_fog ;
bgfx : : UniformHandle u_color ;
bgfx : : UniformHandle u_time ;
bgfx : : UniformHandle u_flipV ;
bgfx : : UniformHandle u_lightPosRadius ;
bgfx : : UniformHandle u_lightRgbInnerR ;
bgfx : : UniformHandle u_virtualLightPos_extrusionDist ;
} ;
2013-10-20 14:34:28 -04:00
static Uniforms s_uniforms ;
2013-10-18 01:55:43 -04:00
struct RenderState
{
enum Enum
{
ShadowVolume_UsingStencilTexture_DrawAmbient = 0 ,
ShadowVolume_UsingStencilTexture_BuildDepth ,
ShadowVolume_UsingStencilTexture_CraftStencil_DepthPass ,
ShadowVolume_UsingStencilTexture_CraftStencil_DepthFail ,
ShadowVolume_UsingStencilTexture_DrawDiffuse ,
ShadowVolume_UsingStencilBuffer_DrawAmbient ,
ShadowVolume_UsingStencilBuffer_CraftStencil_DepthPass ,
ShadowVolume_UsingStencilBuffer_CraftStencil_DepthFail ,
ShadowVolume_UsingStencilBuffer_DrawDiffuse ,
Custom_Default ,
Custom_BlendLightTexture ,
Custom_DrawPlaneBottom ,
Custom_DrawShadowVolume_Lines ,
Count
} ;
uint64_t m_state ;
uint32_t m_blendFactorRgba ;
uint32_t m_fstencil ;
uint32_t m_bstencil ;
} ;
static void setRenderState ( const RenderState & _renderState )
{
bgfx : : setStencil ( _renderState . m_fstencil , _renderState . m_bstencil ) ;
bgfx : : setState ( _renderState . m_state , _renderState . m_blendFactorRgba ) ;
}
static RenderState s_renderStates [ RenderState : : Count ] =
{
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilTexture_DrawAmbient
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilTexture_BuildDepth
2013-10-18 01:55:43 -04:00
BGFX_STATE_DEPTH_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilTexture_CraftStencil_DepthPass
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE )
| BGFX_STATE_DEPTH_TEST_LEQUAL
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilTexture_CraftStencil_DepthFail
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE )
| BGFX_STATE_DEPTH_TEST_GEQUAL
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
} ,
{ // ShadowVolume_UsingStencilTexture_DrawDiffuse
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE )
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_EQUAL
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilBuffer_DrawAmbient
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilBuffer_CraftStencil_DepthPass
2013-10-18 01:55:43 -04:00
BGFX_STATE_DEPTH_TEST_LEQUAL
2013-10-20 14:34:28 -04:00
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_TEST_ALWAYS
2013-11-12 16:20:50 -05:00
| BGFX_STENCIL_FUNC_REF ( 1 )
2013-10-20 14:34:28 -04:00
| BGFX_STENCIL_FUNC_RMASK ( 0xff )
| BGFX_STENCIL_OP_FAIL_S_KEEP
| BGFX_STENCIL_OP_FAIL_Z_KEEP
| BGFX_STENCIL_OP_PASS_Z_DECR
, BGFX_STENCIL_TEST_ALWAYS
2013-11-12 16:20:50 -05:00
| BGFX_STENCIL_FUNC_REF ( 1 )
2013-10-20 14:34:28 -04:00
| BGFX_STENCIL_FUNC_RMASK ( 0xff )
| BGFX_STENCIL_OP_FAIL_S_KEEP
| BGFX_STENCIL_OP_FAIL_Z_KEEP
| BGFX_STENCIL_OP_PASS_Z_INCR
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilBuffer_CraftStencil_DepthFail
2013-10-18 01:55:43 -04:00
BGFX_STATE_DEPTH_TEST_LEQUAL
2013-10-20 14:34:28 -04:00
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_TEST_ALWAYS
2013-11-12 16:20:50 -05:00
| BGFX_STENCIL_FUNC_REF ( 1 )
2013-10-20 14:34:28 -04:00
| BGFX_STENCIL_FUNC_RMASK ( 0xff )
| BGFX_STENCIL_OP_FAIL_S_KEEP
| BGFX_STENCIL_OP_FAIL_Z_INCR
| BGFX_STENCIL_OP_PASS_Z_KEEP
, BGFX_STENCIL_TEST_ALWAYS
2013-11-12 16:20:50 -05:00
| BGFX_STENCIL_FUNC_REF ( 1 )
2013-10-20 14:34:28 -04:00
| BGFX_STENCIL_FUNC_RMASK ( 0xff )
| BGFX_STENCIL_OP_FAIL_S_KEEP
| BGFX_STENCIL_OP_FAIL_Z_DECR
| BGFX_STENCIL_OP_PASS_Z_KEEP
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // ShadowVolume_UsingStencilBuffer_DrawDiffuse
BGFX_STATE_RGB_WRITE
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE )
| BGFX_STATE_DEPTH_TEST_EQUAL
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_TEST_EQUAL
| BGFX_STENCIL_FUNC_REF ( 0 )
| BGFX_STENCIL_FUNC_RMASK ( 0xff )
| BGFX_STENCIL_OP_FAIL_S_KEEP
| BGFX_STENCIL_OP_FAIL_Z_KEEP
| BGFX_STENCIL_OP_PASS_Z_KEEP
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // Custom_Default
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // Custom_BlendLightTexture
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_SRC_COLOR , BGFX_STATE_BLEND_INV_SRC_COLOR )
| BGFX_STATE_CULL_CCW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // Custom_DrawPlaneBottom
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_ALPHA_WRITE
| BGFX_STATE_DEPTH_WRITE
| BGFX_STATE_CULL_CW
| BGFX_STATE_MSAA
, UINT32_MAX
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
} ,
2013-10-20 14:34:28 -04:00
{ // Custom_DrawShadowVolume_Lines
2013-10-18 01:55:43 -04:00
BGFX_STATE_RGB_WRITE
2013-10-20 14:34:28 -04:00
| BGFX_STATE_DEPTH_TEST_LESS
| BGFX_STATE_BLEND_FUNC ( BGFX_STATE_BLEND_FACTOR , BGFX_STATE_BLEND_SRC_ALPHA )
| BGFX_STATE_PT_LINES
| BGFX_STATE_MSAA
, 0x0f0f0fff
, BGFX_STENCIL_NONE
, BGFX_STENCIL_NONE
2013-10-18 01:55:43 -04:00
}
} ;
struct ViewState
{
2013-10-28 21:35:47 -04:00
ViewState ( uint32_t _width = 1280 , uint32_t _height = 720 )
2013-10-18 01:55:43 -04:00
: m_width ( _width )
, m_height ( _height )
2013-10-20 14:34:28 -04:00
{
}
2013-10-18 01:55:43 -04:00
uint32_t m_width ;
uint32_t m_height ;
2013-10-20 22:30:58 -04:00
float m_view [ 16 ] ;
float m_proj [ 16 ] ;
2013-10-18 01:55:43 -04:00
} ;
struct ClearValues
{
uint32_t m_clearRgba ;
float m_clearDepth ;
uint8_t m_clearStencil ;
} ;
void submit ( uint8_t _id , int32_t _depth = 0 )
{
bgfx : : submit ( _id , _depth ) ;
2013-10-20 14:34:28 -04:00
// Keep track of submited view ids.
2013-10-18 01:55:43 -04:00
s_viewMask | = 1 < < _id ;
}
void submitMask ( uint32_t _viewMask , int32_t _depth = 0 )
{
bgfx : : submitMask ( _viewMask , _depth ) ;
2013-10-20 14:34:28 -04:00
// Keep track of submited view ids.
2013-10-18 01:55:43 -04:00
s_viewMask | = _viewMask ;
}
struct Aabb
{
float m_min [ 3 ] ;
float m_max [ 3 ] ;
} ;
struct Obb
{
float m_mtx [ 16 ] ;
} ;
struct Sphere
{
float m_center [ 3 ] ;
float m_radius ;
} ;
struct Primitive
{
uint32_t m_startIndex ;
uint32_t m_numIndices ;
uint32_t m_startVertex ;
uint32_t m_numVertices ;
Sphere m_sphere ;
Aabb m_aabb ;
Obb m_obb ;
} ;
typedef std : : vector < Primitive > PrimitiveArray ;
struct Face
{
uint16_t m_i [ 3 ] ;
float m_plane [ 4 ] ;
} ;
typedef std : : vector < Face > FaceArray ;
struct Edge
{
2013-11-12 16:18:14 -05:00
bool m_faceReverseOrder [ 2 ] ;
2013-10-18 01:55:43 -04:00
uint8_t m_faceIndex ;
2013-11-20 14:28:12 -05:00
uint16_t m_i0 , m_i1 ;
2013-10-18 01:55:43 -04:00
} ;
2013-11-13 11:53:44 -05:00
struct Plane
{
float m_plane [ 4 ] ;
} ;
2013-10-18 01:55:43 -04:00
struct HalfEdge
{
# define INVALID_EDGE_INDEX UINT16_MAX
uint16_t m_secondIndex ;
bool m_marked ;
} ;
struct HalfEdges
{
HalfEdges ( )
: m_data ( )
, m_offsets ( )
, m_endPtr ( )
2013-10-20 14:34:28 -04:00
{
}
2013-10-18 01:55:43 -04:00
void init ( uint16_t * _indices , uint32_t _numIndices )
{
2013-10-20 14:34:28 -04:00
m_data = ( HalfEdge * ) malloc ( 2 * _numIndices * sizeof ( HalfEdge ) ) ;
2013-10-18 01:55:43 -04:00
2013-10-18 12:53:06 -04:00
std : : unordered_map < uint16_t , std : : vector < uint16_t > > edges ;
2013-10-18 01:55:43 -04:00
for ( uint32_t ii = 0 ; ii < _numIndices ; ii + = 3 )
{
uint16_t idx0 = _indices [ ii ] ;
uint16_t idx1 = _indices [ ii + 1 ] ;
uint16_t idx2 = _indices [ ii + 2 ] ;
edges [ idx0 ] . push_back ( idx1 ) ;
edges [ idx1 ] . push_back ( idx2 ) ;
edges [ idx2 ] . push_back ( idx0 ) ;
}
2013-10-19 02:45:34 -04:00
uint32_t numRows = ( uint32_t ) edges . size ( ) ;
2013-10-20 14:34:28 -04:00
m_offsets = ( uint32_t * ) malloc ( numRows * sizeof ( uint32_t ) ) ;
2013-10-18 01:55:43 -04:00
HalfEdge * he = m_data ;
for ( uint32_t ii = 0 ; ii < numRows ; + + ii )
{
m_offsets [ ii ] = uint32_t ( he - m_data ) ;
std : : vector < uint16_t > & row = edges [ ii ] ;
2013-10-19 02:45:34 -04:00
for ( uint32_t jj = 0 , end = ( uint32_t ) row . size ( ) ; jj < end ; + + jj )
2013-10-18 01:55:43 -04:00
{
he - > m_secondIndex = row [ jj ] ;
he - > m_marked = false ;
+ + he ;
}
he - > m_secondIndex = INVALID_EDGE_INDEX ;
+ + he ;
}
he - > m_secondIndex = 0 ;
m_endPtr = he ;
}
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
void destroy ( )
{
free ( m_data ) ;
m_data = NULL ;
free ( m_offsets ) ;
m_offsets = NULL ;
}
void mark ( uint16_t _firstIndex , uint16_t _secondIndex )
{
HalfEdge * ptr = & m_data [ m_offsets [ _firstIndex ] ] ;
while ( INVALID_EDGE_INDEX ! = ptr - > m_secondIndex )
{
if ( ptr - > m_secondIndex = = _secondIndex )
{
ptr - > m_marked = true ;
break ;
}
+ + ptr ;
}
}
bool unmark ( uint16_t _firstIndex , uint16_t _secondIndex )
{
bool ret = false ;
HalfEdge * ptr = & m_data [ m_offsets [ _firstIndex ] ] ;
while ( INVALID_EDGE_INDEX ! = ptr - > m_secondIndex )
{
if ( ptr - > m_secondIndex = = _secondIndex & & ptr - > m_marked )
{
ptr - > m_marked = false ;
ret = true ;
break ;
}
+ + ptr ;
}
return ret ;
}
2013-10-20 14:34:28 -04:00
inline HalfEdge * begin ( ) const
{
return m_data ;
}
inline HalfEdge * end ( ) const
{
return m_endPtr ;
}
2013-10-18 01:55:43 -04:00
HalfEdge * m_data ;
uint32_t * m_offsets ;
HalfEdge * m_endPtr ;
} ;
2013-11-20 14:28:12 -05:00
struct WeldedVertex
{
uint16_t m_v ;
bool m_welded ;
} ;
inline float sqLength ( const float _a [ 3 ] , const float _b [ 3 ] )
{
const float xx = _a [ 0 ] - _b [ 0 ] ;
const float yy = _a [ 1 ] - _b [ 1 ] ;
const float zz = _a [ 2 ] - _b [ 2 ] ;
return xx * xx + yy * yy + zz * zz ;
}
uint16_t weldVertices ( WeldedVertex * _output , const bgfx : : VertexDecl & _decl , const void * _data , uint16_t _num , float _epsilon )
{
const uint32_t hashSize = bx : : uint32_nextpow2 ( _num ) ;
const uint32_t hashMask = hashSize - 1 ;
const float epsilonSq = _epsilon * _epsilon ;
uint32_t numVertices = 0 ;
const uint32_t size = sizeof ( uint16_t ) * ( hashSize + _num ) ;
uint16_t * hashTable = ( uint16_t * ) alloca ( size ) ;
memset ( hashTable , 0xff , size ) ;
uint16_t * next = hashTable + hashSize ;
for ( uint32_t ii = 0 ; ii < _num ; + + ii )
{
float pos [ 4 ] ;
vertexUnpack ( pos , bgfx : : Attrib : : Position , _decl , _data , ii ) ;
uint32_t hashValue = bx : : hashMurmur2A ( pos , 3 * sizeof ( float ) ) & hashMask ;
uint16_t offset = hashTable [ hashValue ] ;
for ( ; UINT16_MAX ! = offset ; offset = next [ offset ] )
{
float test [ 4 ] ;
vertexUnpack ( test , bgfx : : Attrib : : Position , _decl , _data , _output [ offset ] . m_v ) ;
if ( sqLength ( test , pos ) < epsilonSq )
{
_output [ ii ] . m_v = _output [ offset ] . m_v ;
_output [ ii ] . m_welded = true ;
break ;
}
}
if ( UINT16_MAX = = offset )
{
_output [ ii ] . m_v = ii ;
_output [ ii ] . m_welded = false ;
next [ ii ] = hashTable [ hashValue ] ;
hashTable [ hashValue ] = ii ;
numVertices + + ;
}
}
return numVertices ;
}
2013-10-18 01:55:43 -04:00
struct Group
{
Group ( )
{
reset ( ) ;
}
void reset ( )
{
m_vbh . idx = bgfx : : invalidHandle ;
m_ibh . idx = bgfx : : invalidHandle ;
m_numVertices = 0 ;
m_vertices = NULL ;
m_numIndices = 0 ;
m_indices = NULL ;
2013-11-12 16:18:14 -05:00
m_numEdges = 0 ;
m_edges = NULL ;
2013-11-13 11:53:44 -05:00
m_edgePlanesUnalignedPtr = NULL ;
2013-10-18 01:55:43 -04:00
m_prims . clear ( ) ;
}
2013-11-12 16:18:14 -05:00
typedef struct { float f [ 6 ] ; } f6_t ;
2013-11-17 20:57:39 -05:00
struct EdgeAndPlane
2013-11-12 16:18:14 -05:00
{
2013-11-20 14:28:12 -05:00
EdgeAndPlane ( uint16_t _i0 , uint16_t _i1 )
2013-11-17 20:57:39 -05:00
: m_faceIndex ( 0 )
2013-11-20 14:28:12 -05:00
, m_i0 ( _i0 )
, m_i1 ( _i1 )
2013-11-12 16:18:14 -05:00
{
}
2013-11-17 20:57:39 -05:00
bool m_faceReverseOrder [ 2 ] ;
uint8_t m_faceIndex ;
2013-11-20 14:28:12 -05:00
uint16_t m_i0 , m_i1 ;
2013-11-17 20:57:39 -05:00
Plane m_plane [ 2 ] ;
2013-11-12 16:18:14 -05:00
} ;
2013-11-20 14:28:12 -05:00
void fillStructures ( const bgfx : : VertexDecl & _decl )
2013-10-18 01:55:43 -04:00
{
2013-11-20 14:28:12 -05:00
uint16_t stride = _decl . getStride ( ) ;
2013-10-18 01:55:43 -04:00
m_faces . clear ( ) ;
m_halfEdges . destroy ( ) ;
2013-11-20 14:28:12 -05:00
//Init halfedges.
2013-10-18 01:55:43 -04:00
m_halfEdges . init ( m_indices , m_numIndices ) ;
2013-11-20 14:28:12 -05:00
//Init faces and edges.
2013-11-12 16:18:14 -05:00
m_faces . reserve ( m_numIndices / 3 ) ; //1 face = 3 indices
m_edges = ( Edge * ) malloc ( m_numIndices * sizeof ( Edge ) ) ; //1 triangle = 3 indices = 3 edges.
2013-11-13 11:53:44 -05:00
m_edgePlanesUnalignedPtr = ( Plane * ) malloc ( m_numIndices * sizeof ( Plane ) + 15 ) ;
m_edgePlanes = ( Plane * ) bx : : alignPtr ( m_edgePlanesUnalignedPtr , 0 , 16 ) ;
2013-11-20 14:28:12 -05:00
typedef std : : map < std : : pair < uint16_t , uint16_t > , EdgeAndPlane > EdgeMap ;
2013-11-12 16:18:14 -05:00
EdgeMap edgeMap ;
2013-10-18 01:55:43 -04:00
2013-11-20 14:28:12 -05:00
//Get unique indices.
WeldedVertex * uniqueVertices = ( WeldedVertex * ) malloc ( m_numVertices * sizeof ( WeldedVertex ) ) ;
: : weldVertices ( uniqueVertices , _decl , m_vertices , m_numVertices , 0.0001f ) ;
uint16_t * uniqueIndices = ( uint16_t * ) malloc ( m_numIndices * sizeof ( uint16_t ) ) ;
for ( uint32_t ii = 0 ; ii < m_numIndices ; + + ii )
2013-11-13 11:53:44 -05:00
{
2013-11-20 14:28:12 -05:00
uint16_t index = m_indices [ ii ] ;
if ( uniqueVertices [ index ] . m_welded )
2013-11-13 11:53:44 -05:00
{
2013-11-20 14:28:12 -05:00
uniqueIndices [ ii ] = uniqueVertices [ index ] . m_v ;
2013-11-13 11:53:44 -05:00
}
2013-11-20 14:28:12 -05:00
else
{
uniqueIndices [ ii ] = index ;
}
}
free ( uniqueVertices ) ;
2013-10-18 01:55:43 -04:00
for ( uint32_t ii = 0 , size = m_numIndices / 3 ; ii < size ; + + ii )
{
const uint16_t * indices = & m_indices [ ii * 3 ] ;
const uint16_t i0 = indices [ 0 ] ;
const uint16_t i1 = indices [ 1 ] ;
const uint16_t i2 = indices [ 2 ] ;
2013-11-20 14:28:12 -05:00
const float * v0 = ( float * ) & m_vertices [ i0 * stride ] ;
const float * v1 = ( float * ) & m_vertices [ i1 * stride ] ;
const float * v2 = ( float * ) & m_vertices [ i2 * stride ] ;
2013-10-18 01:55:43 -04:00
float plane [ 4 ] ;
planeNormal ( plane , v0 , v2 , v1 ) ;
Face face ;
face . m_i [ 0 ] = i0 ;
face . m_i [ 1 ] = i1 ;
face . m_i [ 2 ] = i2 ;
2013-10-20 14:34:28 -04:00
memcpy ( face . m_plane , plane , 4 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
m_faces . push_back ( face ) ;
2013-11-20 14:28:12 -05:00
//Use unique indices for EdgeMap.
const uint16_t * uindices = & uniqueIndices [ ii * 3 ] ;
const uint16_t ui0 = uindices [ 0 ] ;
const uint16_t ui1 = uindices [ 1 ] ;
const uint16_t ui2 = uindices [ 2 ] ;
const uint16_t triangleEdge [ 3 ] [ 2 ] =
2013-10-18 01:55:43 -04:00
{
2013-11-20 14:28:12 -05:00
{ ui0 , ui1 } ,
{ ui1 , ui2 } ,
{ ui2 , ui0 } ,
2013-10-18 01:55:43 -04:00
} ;
for ( uint8_t jj = 0 ; jj < 3 ; + + jj )
2013-11-12 16:18:14 -05:00
{
2013-11-20 14:28:12 -05:00
const uint16_t ui0 = triangleEdge [ jj ] [ 0 ] ;
const uint16_t ui1 = triangleEdge [ jj ] [ 1 ] ;
std : : pair < uint16_t , uint16_t > key = std : : make_pair ( ui0 , ui1 ) ;
std : : pair < uint16_t , uint16_t > keyInv = std : : make_pair ( ui1 , ui0 ) ;
2013-11-12 16:18:14 -05:00
EdgeMap : : iterator iter = edgeMap . find ( keyInv ) ;
if ( iter ! = edgeMap . end ( ) )
2013-10-18 01:55:43 -04:00
{
2013-11-13 11:53:44 -05:00
EdgeAndPlane & ep = iter - > second ;
memcpy ( ep . m_plane [ ep . m_faceIndex ] . m_plane , plane , 4 * sizeof ( float ) ) ;
ep . m_faceReverseOrder [ ep . m_faceIndex ] = true ;
2013-10-18 01:55:43 -04:00
}
else
{
2013-11-20 14:28:12 -05:00
std : : pair < EdgeMap : : iterator , bool > result = edgeMap . insert ( std : : make_pair ( key , EdgeAndPlane ( ui0 , ui1 ) ) ) ;
2013-11-13 11:53:44 -05:00
EdgeAndPlane & ep = result . first - > second ;
memcpy ( ep . m_plane [ ep . m_faceIndex ] . m_plane , plane , 4 * sizeof ( float ) ) ;
ep . m_faceReverseOrder [ ep . m_faceIndex ] = false ;
ep . m_faceIndex + + ;
2013-10-18 01:55:43 -04:00
}
}
2013-11-12 16:18:14 -05:00
}
2013-10-18 01:55:43 -04:00
2013-11-20 14:28:12 -05:00
free ( uniqueIndices ) ;
2013-11-13 11:53:44 -05:00
uint32_t index = 0 ;
2013-11-12 16:18:14 -05:00
for ( EdgeMap : : const_iterator iter = edgeMap . begin ( ) , end = edgeMap . end ( ) ; iter ! = end ; + + iter )
{
2013-11-13 11:53:44 -05:00
Edge * edge = & m_edges [ m_numEdges ] ;
Plane * plane = & m_edgePlanes [ index ] ;
memcpy ( edge , iter - > second . m_faceReverseOrder , sizeof ( Edge ) ) ;
memcpy ( plane , iter - > second . m_plane , 2 * sizeof ( Plane ) ) ;
m_numEdges + + ;
index + = 2 ;
2013-10-18 01:55:43 -04:00
}
}
void unload ( )
{
bgfx : : destroyVertexBuffer ( m_vbh ) ;
if ( bgfx : : invalidHandle ! = m_ibh . idx )
{
bgfx : : destroyIndexBuffer ( m_ibh ) ;
}
free ( m_vertices ) ;
m_vertices = NULL ;
free ( m_indices ) ;
m_indices = NULL ;
2013-11-12 16:18:14 -05:00
free ( m_edges ) ;
m_edges = NULL ;
2013-11-13 11:53:44 -05:00
free ( m_edgePlanesUnalignedPtr ) ;
m_edgePlanesUnalignedPtr = NULL ;
2013-10-18 01:55:43 -04:00
m_halfEdges . destroy ( ) ;
}
bgfx : : VertexBufferHandle m_vbh ;
bgfx : : IndexBufferHandle m_ibh ;
uint16_t m_numVertices ;
uint8_t * m_vertices ;
uint32_t m_numIndices ;
uint16_t * m_indices ;
Sphere m_sphere ;
Aabb m_aabb ;
Obb m_obb ;
PrimitiveArray m_prims ;
2013-11-12 16:18:14 -05:00
uint32_t m_numEdges ;
Edge * m_edges ;
2013-11-13 11:53:44 -05:00
Plane * m_edgePlanesUnalignedPtr ;
Plane * m_edgePlanes ;
2013-10-18 01:55:43 -04:00
FaceArray m_faces ;
HalfEdges m_halfEdges ;
} ;
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
typedef std : : vector < Group > GroupArray ;
struct Mesh
{
void load ( const void * _vertices , uint32_t _numVertices , const bgfx : : VertexDecl _decl , const uint16_t * _indices , uint32_t _numIndices )
{
Group group ;
const bgfx : : Memory * mem ;
uint32_t size ;
//vertices
group . m_numVertices = _numVertices ;
size = _numVertices * _decl . getStride ( ) ;
group . m_vertices = ( uint8_t * ) malloc ( size ) ;
memcpy ( group . m_vertices , _vertices , size ) ;
mem = bgfx : : makeRef ( group . m_vertices , size ) ;
group . m_vbh = bgfx : : createVertexBuffer ( mem , _decl ) ;
//indices
group . m_numIndices = _numIndices ;
size = _numIndices * 2 ;
group . m_indices = ( uint16_t * ) malloc ( size ) ;
memcpy ( group . m_indices , _indices , size ) ;
mem = bgfx : : makeRef ( group . m_indices , size ) ;
group . m_ibh = bgfx : : createIndexBuffer ( mem ) ;
m_groups . push_back ( group ) ;
}
void load ( const char * _filePath )
{
# define BGFX_CHUNK_MAGIC_VB BX_MAKEFOURCC('V', 'B', ' ', 0x0)
# define BGFX_CHUNK_MAGIC_IB BX_MAKEFOURCC('I', 'B', ' ', 0x0)
# define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0)
bx : : CrtFileReader reader ;
reader . open ( _filePath ) ;
Group group ;
uint32_t chunk ;
while ( 4 = = bx : : read ( & reader , chunk ) )
{
switch ( chunk )
{
2013-10-20 14:34:28 -04:00
case BGFX_CHUNK_MAGIC_VB :
{
bx : : read ( & reader , group . m_sphere ) ;
bx : : read ( & reader , group . m_aabb ) ;
bx : : read ( & reader , group . m_obb ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
bx : : read ( & reader , m_decl ) ;
uint16_t stride = m_decl . getStride ( ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
bx : : read ( & reader , group . m_numVertices ) ;
const uint32_t size = group . m_numVertices * stride ;
group . m_vertices = ( uint8_t * ) malloc ( size ) ;
bx : : read ( & reader , group . m_vertices , size ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
const bgfx : : Memory * mem = bgfx : : makeRef ( group . m_vertices , size ) ;
group . m_vbh = bgfx : : createVertexBuffer ( mem , m_decl ) ;
}
break ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
case BGFX_CHUNK_MAGIC_IB :
{
bx : : read ( & reader , group . m_numIndices ) ;
const uint32_t size = group . m_numIndices * 2 ;
group . m_indices = ( uint16_t * ) malloc ( size ) ;
bx : : read ( & reader , group . m_indices , size ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
const bgfx : : Memory * mem = bgfx : : makeRef ( group . m_indices , size ) ;
group . m_ibh = bgfx : : createIndexBuffer ( mem ) ;
}
break ;
case BGFX_CHUNK_MAGIC_PRI :
{
uint16_t len ;
bx : : read ( & reader , len ) ;
std : : string material ;
material . resize ( len ) ;
bx : : read ( & reader , const_cast < char * > ( material . c_str ( ) ) , len ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
uint16_t num ;
bx : : read ( & reader , num ) ;
for ( uint32_t ii = 0 ; ii < num ; + + ii )
2013-10-18 01:55:43 -04:00
{
bx : : read ( & reader , len ) ;
2013-10-20 14:34:28 -04:00
std : : string name ;
name . resize ( len ) ;
bx : : read ( & reader , const_cast < char * > ( name . c_str ( ) ) , len ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
Primitive prim ;
bx : : read ( & reader , prim . m_startIndex ) ;
bx : : read ( & reader , prim . m_numIndices ) ;
bx : : read ( & reader , prim . m_startVertex ) ;
bx : : read ( & reader , prim . m_numVertices ) ;
bx : : read ( & reader , prim . m_sphere ) ;
bx : : read ( & reader , prim . m_aabb ) ;
bx : : read ( & reader , prim . m_obb ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
group . m_prims . push_back ( prim ) ;
2013-10-18 01:55:43 -04:00
}
2013-10-20 14:34:28 -04:00
m_groups . push_back ( group ) ;
group . reset ( ) ;
}
break ;
default :
DBG ( " %08x at %d " , chunk , reader . seek ( ) ) ;
break ;
2013-10-18 01:55:43 -04:00
}
}
reader . close ( ) ;
for ( GroupArray : : iterator it = m_groups . begin ( ) , itEnd = m_groups . end ( ) ; it ! = itEnd ; + + it )
{
2013-11-20 14:28:12 -05:00
it - > fillStructures ( m_decl ) ;
2013-10-18 01:55:43 -04:00
}
}
void unload ( )
{
for ( GroupArray : : iterator it = m_groups . begin ( ) , itEnd = m_groups . end ( ) ; it ! = itEnd ; + + it )
{
it - > unload ( ) ;
}
m_groups . clear ( ) ;
}
bgfx : : VertexDecl m_decl ;
GroupArray m_groups ;
} ;
struct Model
{
Model ( )
2013-11-12 16:20:50 -05:00
{
2013-10-18 01:55:43 -04:00
m_program . idx = bgfx : : invalidHandle ;
m_texture . idx = bgfx : : invalidHandle ;
}
void load ( const void * _vertices , uint32_t _numVertices , const bgfx : : VertexDecl _decl , const uint16_t * _indices , uint32_t _numIndices )
{
m_mesh . load ( _vertices , _numVertices , _decl , _indices , _numIndices ) ;
}
void load ( const char * _meshFilePath )
{
m_mesh . load ( _meshFilePath ) ;
}
void unload ( )
{
m_mesh . unload ( ) ;
}
void submit ( uint8_t _viewId , float * _mtx , const RenderState & _renderState )
{
for ( GroupArray : : const_iterator it = m_mesh . m_groups . begin ( ) , itEnd = m_mesh . m_groups . end ( ) ; it ! = itEnd ; + + it )
{
const Group & group = * it ;
// Set uniforms
s_uniforms . submitPerDrawUniforms ( ) ;
// Set program
BX_CHECK ( bgfx : : invalidHandle ! = m_program , " Error, program is not set. " ) ;
bgfx : : setProgram ( m_program ) ;
// Set transform
bgfx : : setTransform ( _mtx ) ;
// Set buffers
bgfx : : setIndexBuffer ( group . m_ibh ) ;
bgfx : : setVertexBuffer ( group . m_vbh ) ;
// Set textures
if ( bgfx : : invalidHandle ! = m_texture . idx )
{
bgfx : : setTexture ( 0 , u_texColor , m_texture ) ;
}
2014-02-06 02:07:11 -05:00
bgfx : : setTexture ( 7 , u_texStencil , s_stencilFb ) ;
2013-10-18 01:55:43 -04:00
// Apply render state
: : setRenderState ( _renderState ) ;
// Submit
: : submit ( _viewId ) ;
}
}
Mesh m_mesh ;
bgfx : : ProgramHandle m_program ;
bgfx : : TextureHandle m_texture ;
} ;
struct Instance
{
Instance ( )
: m_svExtrusionDistance ( 150.0f )
2013-11-12 16:20:50 -05:00
{
2013-10-18 01:55:43 -04:00
m_color [ 0 ] = 1.0f ;
m_color [ 1 ] = 1.0f ;
m_color [ 2 ] = 1.0f ;
}
void submit ( uint8_t _viewId , const RenderState & _renderState )
{
2013-10-20 14:34:28 -04:00
memcpy ( s_uniforms . m_color , m_color , 3 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
float mtx [ 16 ] ;
mtxScaleRotateTranslate ( mtx
2013-10-20 14:34:28 -04:00
, m_scale [ 0 ]
, m_scale [ 1 ]
, m_scale [ 2 ]
, m_rotation [ 0 ]
, m_rotation [ 1 ]
, m_rotation [ 2 ]
, m_pos [ 0 ]
, m_pos [ 1 ]
, m_pos [ 2 ]
) ;
2013-10-18 01:55:43 -04:00
BX_CHECK ( NULL ! = m_model , " Instance model cannot be NULL! " ) ;
m_model - > submit ( _viewId , mtx , _renderState ) ;
}
float m_scale [ 3 ] ;
float m_rotation [ 3 ] ;
float m_pos [ 3 ] ;
float m_color [ 3 ] ;
float m_svExtrusionDistance ;
Model * m_model ;
} ;
2013-11-09 13:06:06 -05:00
# define SV_INSTANCE_MEM_SIZE (1500 << 10)
# define SV_INSTANCE_COUNT ( (25 > MAX_INSTANCE_COUNT) ? 25 : MAX_INSTANCE_COUNT)
# define SV_PAGE_SIZE (SV_INSTANCE_MEM_SIZE * SV_INSTANCE_COUNT * MAX_LIGHTS_COUNT)
2013-10-23 20:02:10 -04:00
struct ShadowVolumeAllocator
{
ShadowVolumeAllocator ( )
{
2013-11-09 13:06:06 -05:00
m_mem = ( uint8_t * ) malloc ( SV_PAGE_SIZE * 2 ) ;
2013-10-23 20:02:10 -04:00
m_ptr = m_mem ;
m_firstPage = true ;
}
~ ShadowVolumeAllocator ( )
{
free ( m_mem ) ;
}
void * alloc ( uint32_t _size )
{
void * ret = ( void * ) m_ptr ;
m_ptr + = _size ;
2013-11-09 13:06:06 -05:00
BX_CHECK ( m_ptr - m_mem < ( m_firstPage ? SV_PAGE_SIZE : 2 * SV_PAGE_SIZE ) , " Buffer overflow! " ) ;
2013-10-23 20:02:10 -04:00
return ret ;
}
void swap ( )
{
2013-11-09 13:06:06 -05:00
m_ptr = m_firstPage ? m_mem + SV_PAGE_SIZE : m_mem ;
2013-10-23 20:02:10 -04:00
m_firstPage = ! m_firstPage ;
}
uint8_t * m_mem ;
uint8_t * m_ptr ;
bool m_firstPage ;
} ;
static ShadowVolumeAllocator s_svAllocator ;
2013-10-18 01:55:43 -04:00
struct ShadowVolumeImpl
{
enum Enum
{
DepthPass ,
DepthFail ,
} ;
} ;
struct ShadowVolumeAlgorithm
{
enum Enum
{
FaceBased ,
EdgeBased ,
} ;
} ;
struct ShadowVolume
{
bgfx : : VertexBufferHandle m_vbSides ;
bgfx : : IndexBufferHandle m_ibSides ;
bgfx : : IndexBufferHandle m_ibFrontCap ;
bgfx : : IndexBufferHandle m_ibBackCap ;
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
uint32_t m_numVertices ;
uint32_t m_numIndices ;
const float * m_mtx ;
const float * m_lightPos ;
bool m_cap ;
} ;
2013-10-30 01:44:41 -04:00
void shadowVolumeLightTransform ( float * __restrict _outLightPos
, const float * __restrict _scale
, const float * __restrict _rotate
, const float * __restrict _translate
, const float * __restrict _lightPos // world pos
)
2013-10-18 01:55:43 -04:00
{
2013-10-20 16:11:41 -04:00
/**
2013-10-18 01:55:43 -04:00
* Instead of transforming all the vertices , transform light instead :
* mtx = pivotTranslate - > rotateZYX - > invScale
* light = mtx * origin
*/
2013-10-20 14:34:28 -04:00
float pivot [ 16 ] ;
mtxTranslate ( pivot
, _lightPos [ 0 ] - _translate [ 0 ]
, _lightPos [ 1 ] - _translate [ 1 ]
, _lightPos [ 2 ] - _translate [ 2 ]
) ;
float mzyx [ 16 ] ;
mtxRotateZYX ( mzyx
, - _rotate [ 0 ]
, - _rotate [ 1 ]
, - _rotate [ 2 ]
) ;
float invScale [ 16 ] ;
mtxScale ( invScale
, 1.0f / _scale [ 0 ]
, 1.0f / _scale [ 1 ]
, 1.0f / _scale [ 2 ]
) ;
float tmp0 [ 16 ] ;
mtxMul ( tmp0 , pivot , mzyx ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
float mtx [ 16 ] ;
mtxMul ( mtx , tmp0 , invScale ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
float origin [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
2013-10-30 01:44:41 -04:00
vec3MulMtx ( _outLightPos , origin , mtx ) ;
2013-10-18 01:55:43 -04:00
}
void shadowVolumeCreate ( ShadowVolume & _shadowVolume
2013-10-20 14:34:28 -04:00
, Group & _group
, uint16_t _stride
, const float * _mtx
, const float * _light // in model space
, ShadowVolumeImpl : : Enum _impl = ShadowVolumeImpl : : DepthPass
, ShadowVolumeAlgorithm : : Enum _algo = ShadowVolumeAlgorithm : : FaceBased
, bool _textureAsStencil = false
)
2013-10-18 01:55:43 -04:00
{
2013-11-13 11:53:44 -05:00
const uint8_t * vertices = _group . m_vertices ;
const FaceArray & faces = _group . m_faces ;
const Edge * edges = _group . m_edges ;
const Plane * edgePlanes = _group . m_edgePlanes ;
const uint32_t numEdges = _group . m_numEdges ;
HalfEdges & halfEdges = _group . m_halfEdges ;
2013-10-18 01:55:43 -04:00
struct VertexData
{
2013-10-20 14:34:28 -04:00
VertexData ( )
{
}
2013-10-18 01:55:43 -04:00
VertexData ( const float * _v3 , float _extrude = 0.0f , float _k = 1.0f )
{
2013-10-20 14:34:28 -04:00
memcpy ( m_v , _v3 , 3 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
m_extrude = _extrude ;
m_k = _k ;
}
float m_v [ 3 ] ;
2013-10-20 14:34:28 -04:00
float m_extrude ;
float m_k ;
2013-10-18 01:55:43 -04:00
} ;
2013-10-24 16:56:13 -04:00
bool cap = ( ShadowVolumeImpl : : DepthFail = = _impl ) ;
2013-11-12 16:20:50 -05:00
VertexData * verticesSide = ( VertexData * ) s_svAllocator . alloc ( 20000 * sizeof ( VertexData ) ) ;
uint16_t * indicesSide = ( uint16_t * ) s_svAllocator . alloc ( 20000 * 3 * sizeof ( uint16_t ) ) ;
2013-10-24 16:56:13 -04:00
uint16_t * indicesFrontCap = 0 ;
uint16_t * indicesBackCap = 0 ;
if ( cap )
{
indicesFrontCap = ( uint16_t * ) s_svAllocator . alloc ( 80000 * 3 * sizeof ( uint16_t ) ) ;
indicesBackCap = ( uint16_t * ) s_svAllocator . alloc ( 80000 * 3 * sizeof ( uint16_t ) ) ;
}
2013-10-18 01:55:43 -04:00
2013-10-21 16:32:42 -04:00
uint32_t vsideI = 0 ;
uint32_t sideI = 0 ;
uint32_t frontCapI = 0 ;
uint32_t backCapI = 0 ;
2013-10-18 01:55:43 -04:00
uint16_t indexSide = 0 ;
2013-10-20 14:34:28 -04:00
if ( ShadowVolumeAlgorithm : : FaceBased = = _algo )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
for ( FaceArray : : const_iterator iter = faces . begin ( ) , end = faces . end ( ) ; iter ! = end ; + + iter )
{
const Face & face = * iter ;
bool frontFacing = false ;
float f = vec3Dot ( face . m_plane , _light ) + face . m_plane [ 3 ] ;
if ( f > 0.0f )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
frontFacing = true ;
2013-11-12 16:20:50 -05:00
uint16_t triangleEdges [ 3 ] [ 2 ] =
2013-10-18 01:55:43 -04:00
{
2013-10-21 16:32:42 -04:00
{ face . m_i [ 0 ] , face . m_i [ 1 ] } ,
{ face . m_i [ 1 ] , face . m_i [ 2 ] } ,
{ face . m_i [ 2 ] , face . m_i [ 0 ] } ,
2013-10-20 14:34:28 -04:00
} ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
for ( uint8_t ii = 0 ; ii < 3 ; + + ii )
{
uint16_t first = triangleEdges [ ii ] [ 0 ] ;
uint16_t second = triangleEdges [ ii ] [ 1 ] ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( ! halfEdges . unmark ( second , first ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
halfEdges . mark ( first , second ) ;
2013-10-18 01:55:43 -04:00
}
}
2013-10-20 14:34:28 -04:00
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( cap )
{
if ( frontFacing )
2013-10-18 01:55:43 -04:00
{
2013-10-21 16:32:42 -04:00
indicesFrontCap [ frontCapI + + ] = face . m_i [ 0 ] ;
indicesFrontCap [ frontCapI + + ] = face . m_i [ 1 ] ;
indicesFrontCap [ frontCapI + + ] = face . m_i [ 2 ] ;
2013-10-20 14:34:28 -04:00
}
else
{
2013-10-21 16:32:42 -04:00
indicesBackCap [ backCapI + + ] = face . m_i [ 0 ] ;
indicesBackCap [ backCapI + + ] = face . m_i [ 1 ] ;
indicesBackCap [ backCapI + + ] = face . m_i [ 2 ] ;
2013-10-20 14:34:28 -04:00
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
/**
* if ' _useFrontFacingFacesAsBackCap ' is needed , implement it as such :
*
* bool condition0 = frontFacing & & _useFrontFacingFacesAsBackCap ;
* bool condition1 = ! frontFacing & & ! _useFrontFacingFacesAsBackCap ;
* if ( condition0 | | condition1 )
* {
2013-10-21 16:32:42 -04:00
* indicesBackCap [ backCapI + + ] = face . m_i [ 0 ] ;
* indicesBackCap [ backCapI + + ] = face . m_i [ 1 + condition0 ] ;
* indicesBackCap [ backCapI + + ] = face . m_i [ 2 - condition0 ] ;
2013-10-20 14:34:28 -04:00
* }
*/
}
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
// Fill side arrays.
uint16_t firstIndex = 0 ;
HalfEdge * he = halfEdges . begin ( ) ;
while ( halfEdges . end ( ) ! = he )
{
if ( he - > m_marked )
{
he - > m_marked = false ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
const float * v0 = ( float * ) & vertices [ firstIndex * _stride ] ;
const float * v1 = ( float * ) & vertices [ he - > m_secondIndex * _stride ] ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
verticesSide [ vsideI + + ] = VertexData ( v0 , 0.0f ) ;
verticesSide [ vsideI + + ] = VertexData ( v0 , 1.0f ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 0.0f ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 1.0f ) ;
2013-10-18 01:55:43 -04:00
2013-10-21 16:32:42 -04:00
indicesSide [ sideI + + ] = indexSide + 0 ;
indicesSide [ sideI + + ] = indexSide + 1 ;
indicesSide [ sideI + + ] = indexSide + 2 ;
indicesSide [ sideI + + ] = indexSide + 2 ;
indicesSide [ sideI + + ] = indexSide + 1 ;
indicesSide [ sideI + + ] = indexSide + 3 ;
2013-10-20 14:34:28 -04:00
indexSide + = 4 ;
2013-10-18 01:55:43 -04:00
}
2013-10-20 14:34:28 -04:00
+ + he ;
if ( INVALID_EDGE_INDEX = = he - > m_secondIndex )
{
+ + he ;
+ + firstIndex ;
}
}
}
else // ShadowVolumeAlgorithm::EdgeBased:
{
2013-11-12 16:18:14 -05:00
uint32_t ii = 0 ;
2013-10-20 14:34:28 -04:00
2013-11-12 16:18:14 -05:00
# if SV_USE_SIMD
2013-11-13 11:53:44 -05:00
uint32_t numEdgesRounded = numEdges & ( ~ 0x1 ) ;
2013-11-12 16:18:14 -05:00
using namespace bx ;
2013-11-03 05:16:51 -05:00
2013-11-12 16:18:14 -05:00
const float4_t lx = float4_splat ( _light [ 0 ] ) ;
const float4_t ly = float4_splat ( _light [ 1 ] ) ;
const float4_t lz = float4_splat ( _light [ 2 ] ) ;
for ( ; ii < numEdgesRounded ; ii + = 2 )
{
const Edge & edge0 = edges [ ii ] ;
const Edge & edge1 = edges [ ii + 1 ] ;
2013-11-13 11:53:44 -05:00
const Plane * edgePlane0 = & edgePlanes [ ii * 2 ] ;
const Plane * edgePlane1 = & edgePlanes [ ii * 2 + 2 ] ;
2013-11-12 16:18:14 -05:00
const float4_t reverse = float4_ild ( edge0 . m_faceReverseOrder [ 0 ]
, edge1 . m_faceReverseOrder [ 0 ]
, edge0 . m_faceReverseOrder [ 1 ]
, edge1 . m_faceReverseOrder [ 1 ]
) ;
2013-11-13 11:53:44 -05:00
const float4_t v0 = float4_ld ( edgePlane0 [ 0 ] . m_plane ) ;
const float4_t v1 = float4_ld ( edgePlane1 [ 0 ] . m_plane ) ;
const float4_t v2 = float4_ld ( edgePlane0 [ 1 ] . m_plane ) ;
const float4_t v3 = float4_ld ( edgePlane1 [ 1 ] . m_plane ) ;
2013-11-12 16:18:14 -05:00
const float4_t xxyy0 = float4_shuf_xAyB ( v0 , v2 ) ;
const float4_t zzww0 = float4_shuf_zCwD ( v0 , v2 ) ;
const float4_t xxyy1 = float4_shuf_xAyB ( v1 , v3 ) ;
const float4_t zzww1 = float4_shuf_zCwD ( v1 , v3 ) ;
const float4_t vX = float4_shuf_xAyB ( xxyy0 , xxyy1 ) ;
const float4_t vY = float4_shuf_zCwD ( xxyy0 , xxyy1 ) ;
const float4_t vZ = float4_shuf_xAyB ( zzww0 , zzww1 ) ;
const float4_t vW = float4_shuf_zCwD ( zzww0 , zzww1 ) ;
const float4_t r0 = float4_mul ( vX , lx ) ;
const float4_t r1 = float4_mul ( vY , ly ) ;
const float4_t r2 = float4_mul ( vZ , lz ) ;
const float4_t dot = float4_add ( r0 , float4_add ( r1 , r2 ) ) ;
const float4_t f = float4_add ( dot , vW ) ;
2013-11-13 13:11:34 -05:00
const float4_t zero = float4_zero ( ) ;
const float4_t mask = float4_cmpgt ( f , zero ) ;
const float4_t onef = float4_splat ( 1.0f ) ;
const float4_t tmp0 = float4_and ( mask , onef ) ;
2013-11-12 16:18:14 -05:00
const float4_t tmp1 = float4_ftoi ( tmp0 ) ;
const float4_t tmp2 = float4_xor ( tmp1 , reverse ) ;
const float4_t tmp3 = float4_sll ( tmp2 , 1 ) ;
2013-11-13 13:11:34 -05:00
const float4_t onei = float4_isplat ( 1 ) ;
const float4_t tmp4 = float4_isub ( tmp3 , onei ) ;
2013-11-12 16:18:14 -05:00
BX_ALIGN_STRUCT_16 ( int32_t res [ 4 ] ) ;
float4_st ( & res , tmp4 ) ;
for ( uint16_t jj = 0 ; jj < 2 ; + + jj )
{
int16_t k = res [ jj ] + res [ jj + 2 ] ;
if ( k ! = 0 )
2013-10-18 01:55:43 -04:00
{
2013-11-20 14:28:12 -05:00
float * v0 = ( float * ) & vertices [ edges [ ii + jj ] . m_i0 * _stride ] ;
float * v1 = ( float * ) & vertices [ edges [ ii + jj ] . m_i1 * _stride ] ;
verticesSide [ vsideI + + ] = VertexData ( v0 , 0.0f , float ( k ) ) ;
verticesSide [ vsideI + + ] = VertexData ( v0 , 1.0f , float ( k ) ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 0.0f , float ( k ) ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 1.0f , float ( k ) ) ;
2013-11-12 16:18:14 -05:00
k = _textureAsStencil ? 1 : k ;
uint16_t winding = uint16_t ( k > 0 ) ;
for ( uint8_t ii = 0 , end = abs ( k ) ; ii < end ; + + ii )
{
indicesSide [ sideI + + ] = indexSide ;
indicesSide [ sideI + + ] = indexSide + 2 - winding ;
indicesSide [ sideI + + ] = indexSide + 1 + winding ;
indicesSide [ sideI + + ] = indexSide + 2 ;
indicesSide [ sideI + + ] = indexSide + 3 - winding * 2 ;
indicesSide [ sideI + + ] = indexSide + 1 + winding * 2 ;
}
indexSide + = 4 ;
2013-10-20 14:34:28 -04:00
}
}
2013-11-12 16:18:14 -05:00
}
# endif
2013-10-18 01:55:43 -04:00
2013-11-12 16:18:14 -05:00
for ( ; ii < numEdges ; + + ii )
{
const Edge & edge = edges [ ii ] ;
2013-11-13 11:53:44 -05:00
const Plane * edgePlane = & edgePlanes [ ii * 2 ] ;
2013-10-18 01:55:43 -04:00
2013-11-13 11:53:44 -05:00
int16_t s0 = ( ( vec3Dot ( edgePlane [ 0 ] . m_plane , _light ) + edgePlane [ 0 ] . m_plane [ 3 ] ) > 0.0f ) ^ edge . m_faceReverseOrder [ 0 ] ;
int16_t s1 = ( ( vec3Dot ( edgePlane [ 1 ] . m_plane , _light ) + edgePlane [ 1 ] . m_plane [ 3 ] ) > 0.0f ) ^ edge . m_faceReverseOrder [ 1 ] ;
2013-11-12 16:18:14 -05:00
int16_t k = ( ( s0 + s1 ) < < 1 ) - 2 ;
2013-10-18 01:55:43 -04:00
2013-11-12 16:18:14 -05:00
if ( k ! = 0 )
2013-10-20 14:34:28 -04:00
{
2013-11-20 14:28:12 -05:00
float * v0 = ( float * ) & vertices [ edge . m_i0 * _stride ] ;
float * v1 = ( float * ) & vertices [ edge . m_i1 * _stride ] ;
verticesSide [ vsideI + + ] = VertexData ( v0 , 0.0f , k ) ;
verticesSide [ vsideI + + ] = VertexData ( v0 , 1.0f , k ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 0.0f , k ) ;
verticesSide [ vsideI + + ] = VertexData ( v1 , 1.0f , k ) ;
2013-11-12 16:18:14 -05:00
k = _textureAsStencil ? 1 : k ;
uint16_t winding = uint16_t ( k > 0 ) ;
for ( uint8_t ii = 0 , end = abs ( k ) ; ii < end ; + + ii )
{
indicesSide [ sideI + + ] = indexSide ;
indicesSide [ sideI + + ] = indexSide + 2 - winding ;
indicesSide [ sideI + + ] = indexSide + 1 + winding ;
2013-10-21 16:32:42 -04:00
2013-11-12 16:18:14 -05:00
indicesSide [ sideI + + ] = indexSide + 2 ;
indicesSide [ sideI + + ] = indexSide + 3 - winding * 2 ;
indicesSide [ sideI + + ] = indexSide + 1 + winding * 2 ;
}
2013-10-18 01:55:43 -04:00
2013-11-12 16:18:14 -05:00
indexSide + = 4 ;
}
2013-10-20 14:34:28 -04:00
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( cap )
{
// This could/should be done on GPU!
for ( FaceArray : : const_iterator iter = faces . begin ( ) , end = faces . end ( ) ; iter ! = end ; + + iter )
{
const Face & face = * iter ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
float f = vec3Dot ( face . m_plane , _light ) + face . m_plane [ 3 ] ;
2013-11-12 16:20:50 -05:00
bool frontFacing = ( f > 0.0f ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
for ( uint8_t ii = 0 , end = 1 + uint8_t ( ! _textureAsStencil ) ; ii < end ; + + ii )
{
if ( frontFacing )
{
2013-10-21 16:32:42 -04:00
indicesFrontCap [ frontCapI + + ] = face . m_i [ 0 ] ;
indicesFrontCap [ frontCapI + + ] = face . m_i [ 1 ] ;
indicesFrontCap [ frontCapI + + ] = face . m_i [ 2 ] ;
2013-10-20 14:34:28 -04:00
}
else
{
2013-10-21 16:32:42 -04:00
indicesBackCap [ backCapI + + ] = face . m_i [ 0 ] ;
indicesBackCap [ backCapI + + ] = face . m_i [ 1 ] ;
indicesBackCap [ backCapI + + ] = face . m_i [ 2 ] ;
2013-10-18 01:55:43 -04:00
}
}
}
2013-10-20 14:34:28 -04:00
}
2013-10-18 01:55:43 -04:00
}
bgfx : : VertexDecl decl ;
decl . begin ( ) ;
decl . add ( bgfx : : Attrib : : Position , 3 , bgfx : : AttribType : : Float ) ;
decl . add ( bgfx : : Attrib : : TexCoord0 , 2 , bgfx : : AttribType : : Float ) ;
decl . end ( ) ;
//fill the structure
_shadowVolume . m_numVertices = vsideI ;
_shadowVolume . m_numIndices = sideI + frontCapI + backCapI ;
_shadowVolume . m_mtx = _mtx ;
_shadowVolume . m_lightPos = _light ;
_shadowVolume . m_cap = cap ;
const bgfx : : Memory * mem ;
//sides
uint32_t vsize = vsideI * 5 * sizeof ( float ) ;
2013-10-21 16:32:42 -04:00
uint32_t isize = sideI * sizeof ( uint16_t ) ;
2013-10-18 01:55:43 -04:00
2013-10-23 20:02:10 -04:00
mem = bgfx : : makeRef ( verticesSide , vsize ) ;
2013-10-18 01:55:43 -04:00
_shadowVolume . m_vbSides = bgfx : : createVertexBuffer ( mem , decl ) ;
2013-10-23 20:02:10 -04:00
mem = bgfx : : makeRef ( indicesSide , isize ) ;
2013-10-18 01:55:43 -04:00
_shadowVolume . m_ibSides = bgfx : : createIndexBuffer ( mem ) ;
// bgfx::destroy*Buffer doesn't actually destroy buffers now.
// Instead, these bgfx::destroy*Buffer commands get queued to be executed after the end of the next frame.
bgfx : : destroyVertexBuffer ( _shadowVolume . m_vbSides ) ;
bgfx : : destroyIndexBuffer ( _shadowVolume . m_ibSides ) ;
if ( cap )
{
//front cap
2013-10-21 16:32:42 -04:00
isize = frontCapI * sizeof ( uint16_t ) ;
2013-10-23 20:02:10 -04:00
mem = bgfx : : makeRef ( indicesFrontCap , isize ) ;
2013-10-18 01:55:43 -04:00
_shadowVolume . m_ibFrontCap = bgfx : : createIndexBuffer ( mem ) ;
//gets destroyed after the end of the next frame
bgfx : : destroyIndexBuffer ( _shadowVolume . m_ibFrontCap ) ;
//back cap
2013-10-21 16:32:42 -04:00
isize = backCapI * sizeof ( uint16_t ) ;
2013-10-23 20:02:10 -04:00
mem = bgfx : : makeRef ( indicesBackCap , isize ) ;
2013-10-18 01:55:43 -04:00
_shadowVolume . m_ibBackCap = bgfx : : createIndexBuffer ( mem ) ;
//gets destroyed after the end of the next frame
bgfx : : destroyIndexBuffer ( _shadowVolume . m_ibBackCap ) ;
}
}
void createNearClipVolume ( float * __restrict _outPlanes24f
2013-10-20 14:34:28 -04:00
, float * __restrict _lightPos
, float * __restrict _view
, float _fovy
, float _aspect
, float _near
)
2013-10-18 01:55:43 -04:00
{
float ( * volumePlanes ) [ 4 ] = ( float ( * ) [ 4 ] ) _outPlanes24f ;
float mtxViewInv [ 16 ] ;
float mtxViewTrans [ 16 ] ;
mtxInverse ( mtxViewInv , _view ) ;
mtxTranspose ( mtxViewTrans , _view ) ;
float lightPosV [ 4 ] ;
vec4MulMtx ( lightPosV , _lightPos , _view ) ;
const float delta = 0.1f ;
float nearNormal [ 4 ] = { 0.0f , 0.0f , 1.0f , _near } ;
float d = vec3Dot ( lightPosV , nearNormal ) + lightPosV [ 3 ] * nearNormal [ 3 ] ;
// Light is:
// 1.0f - in front of near plane
// 0.0f - on the near plane
// -1.0f - behind near plane
2013-10-20 14:34:28 -04:00
float lightSide = float ( ( d > delta ) - ( d < - delta ) ) ;
2013-10-18 01:55:43 -04:00
float t = tanf ( _fovy * ( ( float ) M_PI / 180.0f ) * 0.5f ) * _near ;
float b = - t ;
float r = t * _aspect ;
float l = - r ;
float cornersV [ 4 ] [ 3 ] =
{
{ r , t , _near } ,
{ l , t , _near } ,
{ l , b , _near } ,
{ r , b , _near } ,
} ;
float corners [ 4 ] [ 3 ] ;
vec3MulMtx ( corners [ 0 ] , cornersV [ 0 ] , mtxViewInv ) ;
vec3MulMtx ( corners [ 1 ] , cornersV [ 1 ] , mtxViewInv ) ;
vec3MulMtx ( corners [ 2 ] , cornersV [ 2 ] , mtxViewInv ) ;
vec3MulMtx ( corners [ 3 ] , cornersV [ 3 ] , mtxViewInv ) ;
float planeNormals [ 4 ] [ 3 ] ;
for ( uint8_t ii = 0 ; ii < 4 ; + + ii )
{
float * normal = planeNormals [ ii ] ;
float * plane = volumePlanes [ ii ] ;
float planeVec [ 3 ] ;
vec3Sub ( planeVec , corners [ ii ] , corners [ ( ii - 1 ) % 4 ] ) ;
float light [ 3 ] ;
float tmp [ 3 ] ;
vec3Mul ( tmp , corners [ ii ] , _lightPos [ 3 ] ) ;
vec3Sub ( light , _lightPos , tmp ) ;
vec3Cross ( normal , planeVec , light ) ;
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
normal [ 0 ] * = lightSide ;
normal [ 1 ] * = lightSide ;
normal [ 2 ] * = lightSide ;
2013-10-20 14:34:28 -04:00
float lenInv = 1.0f / sqrtf ( vec3Dot ( normal , normal ) ) ;
2013-10-18 01:55:43 -04:00
plane [ 0 ] = normal [ 0 ] * lenInv ;
plane [ 1 ] = normal [ 1 ] * lenInv ;
plane [ 2 ] = normal [ 2 ] * lenInv ;
plane [ 3 ] = - vec3Dot ( normal , corners [ ii ] ) * lenInv ;
}
float nearPlaneV [ 4 ] =
{
2013-11-12 16:20:50 -05:00
0.0f * lightSide ,
0.0f * lightSide ,
1.0f * lightSide ,
_near * lightSide ,
2013-10-18 01:55:43 -04:00
} ;
vec4MulMtx ( volumePlanes [ 4 ] , nearPlaneV , mtxViewTrans ) ;
float * lightPlane = volumePlanes [ 5 ] ;
float lightPlaneNormal [ 3 ] = { 0.0f , 0.0f , - _near * lightSide } ;
float tmp [ 3 ] ;
vec3MulMtx ( tmp , lightPlaneNormal , mtxViewInv ) ;
vec3Sub ( lightPlaneNormal , tmp , _lightPos ) ;
2013-10-20 14:34:28 -04:00
float lenInv = 1.0f / sqrtf ( vec3Dot ( lightPlaneNormal , lightPlaneNormal ) ) ;
2013-10-18 01:55:43 -04:00
lightPlane [ 0 ] = lightPlaneNormal [ 0 ] * lenInv ;
lightPlane [ 1 ] = lightPlaneNormal [ 1 ] * lenInv ;
lightPlane [ 2 ] = lightPlaneNormal [ 2 ] * lenInv ;
lightPlane [ 3 ] = - vec3Dot ( lightPlaneNormal , _lightPos ) * lenInv ;
}
bool clipTest ( const float * _planes , uint8_t _planeNum , const Mesh & _mesh , const float * _scale , const float * _translate )
{
float ( * volumePlanes ) [ 4 ] = ( float ( * ) [ 4 ] ) _planes ;
2013-11-17 23:42:29 -05:00
float scale = fmaxf ( fmaxf ( _scale [ 0 ] , _scale [ 1 ] ) , _scale [ 2 ] ) ;
2013-10-18 01:55:43 -04:00
const GroupArray & groups = _mesh . m_groups ;
for ( GroupArray : : const_iterator it = groups . begin ( ) , itEnd = groups . end ( ) ; it ! = itEnd ; + + it )
{
const Group & group = * it ;
Sphere sphere = group . m_sphere ;
sphere . m_center [ 0 ] = sphere . m_center [ 0 ] * scale + _translate [ 0 ] ;
sphere . m_center [ 1 ] = sphere . m_center [ 1 ] * scale + _translate [ 1 ] ;
sphere . m_center [ 2 ] = sphere . m_center [ 2 ] * scale + _translate [ 2 ] ;
sphere . m_radius * = ( scale + 0.4f ) ;
bool isInside = true ;
for ( uint8_t ii = 0 ; ii < _planeNum ; + + ii )
{
const float * plane = volumePlanes [ ii ] ;
float positiveSide = vec3Dot ( plane , sphere . m_center ) + plane [ 3 ] + sphere . m_radius ;
if ( positiveSide < 0.0f )
{
isInside = false ;
break ;
}
}
2013-11-12 16:20:50 -05:00
if ( isInside )
2013-10-18 01:55:43 -04:00
{
2013-11-12 16:20:50 -05:00
return true ;
2013-10-18 01:55:43 -04:00
}
}
return false ;
}
int _main_ ( int /*_argc*/ , char * * /*_argv*/ )
{
ViewState viewState ( 1280 , 720 ) ;
ClearValues clearValues = { 0x00000000 , 1.0f , 0 } ;
uint32_t debug = BGFX_DEBUG_TEXT ;
uint32_t reset = BGFX_RESET_VSYNC ;
bgfx : : init ( ) ;
bgfx : : reset ( viewState . m_width , viewState . m_height , reset ) ;
// Enable debug text.
bgfx : : setDebug ( debug ) ;
// Setup root path for binary shaders. Shader binaries are different
// for each renderer.
switch ( bgfx : : getRendererType ( ) )
{
2013-10-20 14:34:28 -04:00
default :
case bgfx : : RendererType : : Direct3D9 :
s_shaderPath = " shaders/dx9/ " ;
2014-02-14 02:14:49 -05:00
s_texelHalf = 0.5f ;
2013-10-20 14:34:28 -04:00
break ;
case bgfx : : RendererType : : Direct3D11 :
s_shaderPath = " shaders/dx11/ " ;
break ;
case bgfx : : RendererType : : OpenGL :
s_shaderPath = " shaders/glsl/ " ;
2014-02-14 02:14:49 -05:00
s_flipV = true ;
2013-10-20 14:34:28 -04:00
break ;
case bgfx : : RendererType : : OpenGLES2 :
case bgfx : : RendererType : : OpenGLES3 :
s_shaderPath = " shaders/gles/ " ;
2014-02-14 02:14:49 -05:00
s_flipV = true ;
2013-10-20 14:34:28 -04:00
break ;
2013-10-18 01:55:43 -04:00
}
// Imgui
FILE * file = fopen ( " font/droidsans.ttf " , " rb " ) ;
uint32_t size = ( uint32_t ) fsize ( file ) ;
void * data = malloc ( size ) ;
size_t ignore = fread ( data , 1 , size , file ) ;
BX_UNUSED ( ignore ) ;
fclose ( file ) ;
2014-02-25 23:19:13 -05:00
2013-10-18 01:55:43 -04:00
imguiCreate ( data , size ) ;
2014-02-25 23:19:13 -05:00
free ( data ) ;
2013-10-18 01:55:43 -04:00
bgfx : : VertexDecl PosNormalTexcoordDecl ;
PosNormalTexcoordDecl . begin ( ) ;
PosNormalTexcoordDecl . add ( bgfx : : Attrib : : Position , 3 , bgfx : : AttribType : : Float ) ;
PosNormalTexcoordDecl . add ( bgfx : : Attrib : : Normal , 4 , bgfx : : AttribType : : Uint8 , true , true ) ;
PosNormalTexcoordDecl . add ( bgfx : : Attrib : : TexCoord0 , 2 , bgfx : : AttribType : : Float ) ;
PosNormalTexcoordDecl . end ( ) ;
s_uniforms . init ( ) ;
s_uniforms . submitConstUniforms ( ) ;
const bgfx : : Memory * mem ;
mem = loadTexture ( " figure-rgba.dds " ) ;
bgfx : : TextureHandle figureTex = bgfx : : createTexture ( mem ) ;
mem = loadTexture ( " flare.dds " ) ;
bgfx : : TextureHandle flareTex = bgfx : : createTexture ( mem ) ;
mem = loadTexture ( " fieldstone-rgba.dds " ) ;
bgfx : : TextureHandle fieldstoneTex = bgfx : : createTexture ( mem ) ;
2014-02-06 02:07:11 -05:00
bgfx : : TextureHandle fbtextures [ ] =
{
bgfx : : createTexture2D ( viewState . m_width , viewState . m_height , 1 , bgfx : : TextureFormat : : BGRA8 , BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_RT ) ,
2014-03-09 20:57:24 -04:00
bgfx : : createTexture2D ( viewState . m_width , viewState . m_height , 1 , bgfx : : TextureFormat : : D16 , BGFX_TEXTURE_RT_BUFFER_ONLY ) ,
2014-02-06 02:07:11 -05:00
} ;
s_stencilFb = bgfx : : createFrameBuffer ( BX_COUNTOF ( fbtextures ) , fbtextures , true ) ;
2013-10-18 01:55:43 -04:00
2013-10-23 20:45:58 -04:00
u_texColor = bgfx : : createUniform ( " u_texColor " , bgfx : : UniformType : : Uniform1iv ) ;
u_texStencil = bgfx : : createUniform ( " u_texStencil " , bgfx : : UniformType : : Uniform1iv ) ;
2013-10-18 01:55:43 -04:00
bgfx : : ProgramHandle programTextureLightning = loadProgram ( " vs_shadowvolume_texture_lightning " , " fs_shadowvolume_texture_lightning " ) ;
bgfx : : ProgramHandle programColorLightning = loadProgram ( " vs_shadowvolume_color_lightning " , " fs_shadowvolume_color_lightning " ) ;
bgfx : : ProgramHandle programColorTexture = loadProgram ( " vs_shadowvolume_color_texture " , " fs_shadowvolume_color_texture " ) ;
bgfx : : ProgramHandle programTexture = loadProgram ( " vs_shadowvolume_texture " , " fs_shadowvolume_texture " ) ;
2013-11-12 16:20:50 -05:00
bgfx : : ProgramHandle programBackBlank = loadProgram ( " vs_shadowvolume_svback " , " fs_shadowvolume_svbackblank " ) ;
bgfx : : ProgramHandle programSideBlank = loadProgram ( " vs_shadowvolume_svside " , " fs_shadowvolume_svsideblank " ) ;
bgfx : : ProgramHandle programFrontBlank = loadProgram ( " vs_shadowvolume_svfront " , " fs_shadowvolume_svfrontblank " ) ;
2013-10-18 01:55:43 -04:00
2013-11-12 16:20:50 -05:00
bgfx : : ProgramHandle programBackColor = loadProgram ( " vs_shadowvolume_svback " , " fs_shadowvolume_svbackcolor " ) ;
bgfx : : ProgramHandle programSideColor = loadProgram ( " vs_shadowvolume_svside " , " fs_shadowvolume_svsidecolor " ) ;
bgfx : : ProgramHandle programFrontColor = loadProgram ( " vs_shadowvolume_svfront " , " fs_shadowvolume_svfrontcolor " ) ;
2013-10-18 01:55:43 -04:00
2013-11-12 16:20:50 -05:00
bgfx : : ProgramHandle programSideTex = loadProgram ( " vs_shadowvolume_svside " , " fs_shadowvolume_svsidetex " ) ;
bgfx : : ProgramHandle programBackTex1 = loadProgram ( " vs_shadowvolume_svback " , " fs_shadowvolume_svbacktex1 " ) ;
bgfx : : ProgramHandle programBackTex2 = loadProgram ( " vs_shadowvolume_svback " , " fs_shadowvolume_svbacktex2 " ) ;
bgfx : : ProgramHandle programFrontTex1 = loadProgram ( " vs_shadowvolume_svfront " , " fs_shadowvolume_svfronttex1 " ) ;
bgfx : : ProgramHandle programFrontTex2 = loadProgram ( " vs_shadowvolume_svfront " , " fs_shadowvolume_svfronttex2 " ) ;
2013-10-18 01:55:43 -04:00
struct ShadowVolumeProgramType
{
enum Enum
{
Blank = 0 ,
Color ,
Tex1 ,
Tex2 ,
Count
} ;
} ;
struct ShadowVolumePart
{
enum Enum
{
Back = 0 ,
Side ,
Front ,
Count
} ;
} ;
bgfx : : ProgramHandle svProgs [ ShadowVolumeProgramType : : Count ] [ ShadowVolumePart : : Count ] =
2013-11-12 16:20:50 -05:00
{
2013-11-18 01:26:15 -05:00
{ programBackBlank , programSideBlank , programFrontBlank } , // Blank
{ programBackColor , programSideColor , programFrontColor } , // Color
{ programBackTex1 , programSideTex , programFrontTex1 } , // Tex1
{ programBackTex2 , programSideTex , programFrontTex2 } , // Tex2
2013-10-18 01:55:43 -04:00
} ;
Model bunnyLowPolyModel ;
Model bunnyHighPolyModel ;
Model columnModel ;
Model platformModel ;
Model cubeModel ;
Model hplaneFieldModel ;
Model hplaneFigureModel ;
Model vplaneModel ;
bunnyHighPolyModel . load ( " meshes/bunny_patched.bin " ) ;
bunnyHighPolyModel . m_program = programColorLightning ;
bunnyLowPolyModel . load ( " meshes/bunny_decimated.bin " ) ;
bunnyLowPolyModel . m_program = programColorLightning ;
columnModel . load ( " meshes/column.bin " ) ;
columnModel . m_program = programColorLightning ;
platformModel . load ( " meshes/platform.bin " ) ;
platformModel . m_program = programTextureLightning ;
platformModel . m_texture = figureTex ;
cubeModel . load ( " meshes/cube.bin " ) ;
cubeModel . m_program = programTextureLightning ;
cubeModel . m_texture = figureTex ;
hplaneFieldModel . load ( s_hplaneVertices , s_numHPlaneVertices , PosNormalTexcoordDecl , s_planeIndices , s_numPlaneIndices ) ;
hplaneFieldModel . m_program = programTextureLightning ;
hplaneFieldModel . m_texture = fieldstoneTex ;
hplaneFigureModel . load ( s_hplaneVertices , s_numHPlaneVertices , PosNormalTexcoordDecl , s_planeIndices , s_numPlaneIndices ) ;
hplaneFigureModel . m_program = programTextureLightning ;
hplaneFigureModel . m_texture = figureTex ;
vplaneModel . load ( s_vplaneVertices , s_numVPlaneVertices , PosNormalTexcoordDecl , s_planeIndices , s_numPlaneIndices ) ;
vplaneModel . m_program = programColorTexture ;
vplaneModel . m_texture = flareTex ;
2013-10-21 14:09:46 -04:00
// Setup lights.
2013-10-24 17:36:16 -04:00
const float rgbInnerR [ MAX_LIGHTS_COUNT ] [ 4 ] =
2013-10-18 01:55:43 -04:00
{
{ 1.0f , 0.7f , 0.2f , 0.0f } , //yellow
{ 0.7f , 0.2f , 1.0f , 0.0f } , //purple
{ 0.2f , 1.0f , 0.7f , 0.0f } , //cyan
{ 1.0f , 0.4f , 0.2f , 0.0f } , //orange
{ 0.7f , 0.7f , 0.7f , 0.0f } , //white
} ;
2013-10-24 17:36:16 -04:00
float lightRgbInnerR [ MAX_LIGHTS_COUNT ] [ 4 ] ;
for ( uint8_t ii = 0 , jj = 0 ; ii < MAX_LIGHTS_COUNT ; + + ii , + + jj )
2013-10-18 01:55:43 -04:00
{
2013-10-24 17:36:16 -04:00
const uint8_t index = jj % MAX_LIGHTS_COUNT ;
2013-10-18 01:55:43 -04:00
lightRgbInnerR [ ii ] [ 0 ] = rgbInnerR [ index ] [ 0 ] ;
lightRgbInnerR [ ii ] [ 1 ] = rgbInnerR [ index ] [ 1 ] ;
lightRgbInnerR [ ii ] [ 2 ] = rgbInnerR [ index ] [ 2 ] ;
lightRgbInnerR [ ii ] [ 3 ] = rgbInnerR [ index ] [ 3 ] ;
}
int64_t profTime = 0 ;
int64_t timeOffset = bx : : getHPCounter ( ) ;
2013-11-12 16:20:50 -05:00
uint32_t numShadowVolumeVertices = 0 ;
2013-10-18 01:55:43 -04:00
uint32_t numShadowVolumeIndices = 0 ;
uint32_t oldWidth = 0 ;
uint32_t oldHeight = 0 ;
2013-10-20 14:34:28 -04:00
// Imgui.
bool settings_showHelp = false ;
bool settings_updateLights = true ;
bool settings_updateScene = true ;
bool settings_mixedSvImpl = true ;
2014-03-09 20:57:24 -04:00
bool settings_useStencilTexture = false ;
2013-10-20 14:34:28 -04:00
bool settings_drawShadowVolumes = false ;
float settings_numLights = 1.0f ;
float settings_instanceCount = 9.0f ;
2013-11-12 16:20:50 -05:00
ShadowVolumeImpl : : Enum settings_shadowVolumeImpl = ShadowVolumeImpl : : DepthFail ;
ShadowVolumeAlgorithm : : Enum settings_shadowVolumeAlgorithm = ShadowVolumeAlgorithm : : EdgeBased ;
2013-10-20 14:34:28 -04:00
int32_t scrollAreaRight = 0 ;
const char * titles [ 2 ] =
{
" Scene 0 " ,
" Scene 1 " ,
} ;
enum LightPattern
{
LightPattern0 = 0 ,
LightPattern1
} ;
enum MeshChoice
{
BunnyHighPoly = 0 ,
BunnyLowPoly
} ;
enum Scene
{
Scene0 = 0 ,
Scene1 ,
SceneCount
} ;
LightPattern lightPattern = LightPattern0 ;
MeshChoice currentMesh = BunnyLowPoly ;
Scene currentScene = Scene0 ;
2014-01-30 12:20:06 -05:00
// Set view and projection matrices.
const float fov = 60.0f ;
const float aspect = float ( viewState . m_width ) / float ( viewState . m_height ) ;
const float nearPlane = 1.0f ;
const float farPlane = 1000.0f ;
mtxProj ( viewState . m_proj , fov , aspect , nearPlane , farPlane ) ;
float initialPos [ 3 ] = { 3.0f , 20.0f , - 58.0f } ;
cameraSetPosition ( initialPos ) ;
cameraSetVerticalAngle ( - 0.25f ) ;
2014-01-30 13:44:37 -05:00
cameraUpdate ( 0.0f ) ;
2014-01-30 12:20:06 -05:00
cameraGetViewMtx ( viewState . m_view ) ;
2013-10-18 01:55:43 -04:00
entry : : MouseState mouseState ;
while ( ! entry : : processEvents ( viewState . m_width , viewState . m_height , debug , reset , & mouseState ) )
{
2014-01-30 12:20:06 -05:00
// Respond properly on resize.
2013-10-18 01:55:43 -04:00
if ( oldWidth ! = viewState . m_width
2013-11-18 01:26:15 -05:00
| | oldHeight ! = viewState . m_height )
2013-10-18 01:55:43 -04:00
{
oldWidth = viewState . m_width ;
oldHeight = viewState . m_height ;
2014-02-06 02:07:11 -05:00
bgfx : : destroyFrameBuffer ( s_stencilFb ) ;
2013-10-18 01:55:43 -04:00
2014-02-06 02:07:11 -05:00
fbtextures [ 0 ] = bgfx : : createTexture2D ( viewState . m_width , viewState . m_height , 1 , bgfx : : TextureFormat : : BGRA8 , BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_RT ) ;
2014-03-09 20:57:24 -04:00
fbtextures [ 1 ] = bgfx : : createTexture2D ( viewState . m_width , viewState . m_height , 1 , bgfx : : TextureFormat : : D16 , BGFX_TEXTURE_RT_BUFFER_ONLY ) ;
2014-02-06 02:07:11 -05:00
s_stencilFb = bgfx : : createFrameBuffer ( BX_COUNTOF ( fbtextures ) , fbtextures , true ) ;
2013-10-18 01:55:43 -04:00
}
2014-01-30 12:20:06 -05:00
// Time.
2013-10-18 01:55:43 -04:00
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 ;
float time = ( float ) ( ( now - timeOffset ) / double ( bx : : getHPFrequency ( ) ) ) ;
const float deltaTime = float ( frameTime / freq ) ;
s_uniforms . m_time = time ;
2014-01-30 12:20:06 -05:00
// Update camera.
cameraUpdate ( deltaTime ) ;
cameraGetViewMtx ( viewState . m_view ) ;
2013-10-20 14:34:28 -04:00
imguiBeginFrame ( mouseState . m_mx
, mouseState . m_my
, ( mouseState . m_buttons [ entry : : MouseButton : : Left ] ? IMGUI_MBUT_LEFT : 0 )
| ( mouseState . m_buttons [ entry : : MouseButton : : Right ] ? IMGUI_MBUT_RIGHT : 0 )
, 0
, viewState . m_width
, viewState . m_height
) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
imguiBeginScrollArea ( " Settings " , viewState . m_width - 256 - 10 , 10 , 256 , 700 , & scrollAreaRight ) ;
if ( imguiCheck ( titles [ Scene0 ] , Scene0 = = currentScene ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
currentScene = Scene0 ;
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( titles [ Scene1 ] , Scene1 = = currentScene ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
currentScene = Scene1 ;
}
2013-10-18 01:55:43 -04:00
2013-10-24 17:36:16 -04:00
imguiSlider ( " Lights " , & settings_numLights , 1.0f , float ( MAX_LIGHTS_COUNT ) , 1.0f ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Update lights " , settings_updateLights ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
settings_updateLights = ! settings_updateLights ;
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
imguiIndent ( ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Light pattern 0 " , LightPattern0 = = lightPattern , settings_updateLights ) )
{
lightPattern = LightPattern0 ;
}
if ( imguiCheck ( " Light pattern 1 " , LightPattern1 = = lightPattern , settings_updateLights ) )
{
lightPattern = LightPattern1 ;
}
2013-10-18 01:55:43 -04:00
imguiUnindent ( ) ;
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Update scene " , settings_updateScene , Scene0 = = currentScene ) )
{
settings_updateScene = ! settings_updateScene ;
}
2013-10-18 01:55:43 -04:00
imguiSeparatorLine ( ) ;
imguiLabel ( " Stencil buffer implementation: " ) ;
settings_shadowVolumeImpl = ( imguiCheck ( " Depth fail " , ShadowVolumeImpl : : DepthFail = = settings_shadowVolumeImpl , ! settings_mixedSvImpl ) ? ShadowVolumeImpl : : DepthFail : settings_shadowVolumeImpl ) ;
settings_shadowVolumeImpl = ( imguiCheck ( " Depth pass " , ShadowVolumeImpl : : DepthPass = = settings_shadowVolumeImpl , ! settings_mixedSvImpl ) ? ShadowVolumeImpl : : DepthPass : settings_shadowVolumeImpl ) ;
settings_mixedSvImpl = ( imguiCheck ( " Mixed " , settings_mixedSvImpl ) ? ! settings_mixedSvImpl : settings_mixedSvImpl ) ;
imguiLabel ( " Shadow volume implementation: " ) ;
settings_shadowVolumeAlgorithm = ( imguiCheck ( " Face based impl. " , ShadowVolumeAlgorithm : : FaceBased = = settings_shadowVolumeAlgorithm ) ? ShadowVolumeAlgorithm : : FaceBased : settings_shadowVolumeAlgorithm ) ;
settings_shadowVolumeAlgorithm = ( imguiCheck ( " Edge based impl. " , ShadowVolumeAlgorithm : : EdgeBased = = settings_shadowVolumeAlgorithm ) ? ShadowVolumeAlgorithm : : EdgeBased : settings_shadowVolumeAlgorithm ) ;
imguiLabel ( " Stencil: " ) ;
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Use stencil buffer " , ! settings_useStencilTexture ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
if ( settings_useStencilTexture )
{
settings_useStencilTexture = false ;
}
2013-10-18 01:55:43 -04:00
}
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Use texture as stencil " , settings_useStencilTexture ) )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
if ( ! settings_useStencilTexture )
{
settings_useStencilTexture = true ;
}
2013-10-18 01:55:43 -04:00
}
imguiSeparatorLine ( ) ;
imguiLabel ( " Mesh: " ) ;
2013-10-20 14:34:28 -04:00
if ( imguiCheck ( " Bunny - high poly " , BunnyHighPoly = = currentMesh ) )
{
currentMesh = BunnyHighPoly ;
}
if ( imguiCheck ( " Bunny - low poly " , BunnyLowPoly = = currentMesh ) )
{
currentMesh = BunnyLowPoly ;
}
if ( Scene1 = = currentScene )
{
2013-10-24 17:36:16 -04:00
imguiSlider ( " Instance count " , & settings_instanceCount , 1.0f , float ( MAX_INSTANCE_COUNT ) , 1.0f ) ;
2013-10-20 14:34:28 -04:00
}
2013-10-18 01:55:43 -04:00
imguiLabel ( " CPU Time: %7.1f [ms] " , double ( profTime ) * toMs ) ;
imguiLabel ( " Volume Vertices: %5.uk " , numShadowVolumeVertices / 1000 ) ;
imguiLabel ( " Volume Indices: %6.uk " , numShadowVolumeIndices / 1000 ) ;
2013-11-12 16:20:50 -05:00
numShadowVolumeVertices = 0 ;
numShadowVolumeIndices = 0 ;
2013-10-18 01:55:43 -04:00
imguiSeparatorLine ( ) ;
2013-10-20 14:34:28 -04:00
settings_drawShadowVolumes = imguiCheck ( " Draw Shadow Volumes " , settings_drawShadowVolumes )
? ! settings_drawShadowVolumes
: settings_drawShadowVolumes
;
2013-10-18 01:55:43 -04:00
imguiIndent ( ) ;
imguiUnindent ( ) ;
imguiEndScrollArea ( ) ;
static int32_t scrollAreaLeft = 0 ;
imguiBeginScrollArea ( " Show help: " , 10 , viewState . m_height - 77 - 10 , 120 , 77 , & scrollAreaLeft ) ;
2013-10-20 14:34:28 -04:00
settings_showHelp = imguiButton ( settings_showHelp ? " ON " : " OFF " )
? ! settings_showHelp
: settings_showHelp
;
2013-10-18 01:55:43 -04:00
imguiEndScrollArea ( ) ;
imguiEndFrame ( ) ;
//update settings
s_uniforms . m_params . m_ambientPass = 1.0f ;
s_uniforms . m_params . m_lightningPass = 1.0f ;
2014-02-14 02:14:49 -05:00
s_uniforms . m_params . m_texelHalf = s_texelHalf ;
2013-10-18 01:55:43 -04:00
s_uniforms . m_svparams . m_useStencilTex = float ( settings_useStencilTexture ) ;
s_uniforms . submitPerFrameUniforms ( ) ;
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
//set picked bunny model
Model * bunnyModel = BunnyLowPoly = = currentMesh ? & bunnyLowPolyModel : & bunnyHighPolyModel ;
//update time accumulators
static float sceneTimeAccumulator = 0.0f ;
if ( settings_updateScene )
{
sceneTimeAccumulator + = deltaTime ;
}
static float lightTimeAccumulator = 0.0f ;
if ( settings_updateLights )
{
lightTimeAccumulator + = deltaTime ;
}
//setup light positions
2013-10-24 17:36:16 -04:00
float lightPosRadius [ MAX_LIGHTS_COUNT ] [ 4 ] ;
2013-10-20 16:11:41 -04:00
if ( LightPattern0 = = lightPattern )
2013-10-18 01:55:43 -04:00
{
2013-10-20 14:34:28 -04:00
for ( uint8_t ii = 0 ; ii < settings_numLights ; + + ii )
{
lightPosRadius [ ii ] [ 0 ] = cos ( 2.0f * float ( M_PI ) / settings_numLights * float ( ii ) + lightTimeAccumulator * 1.1f + 3.0f ) * 20.0f ;
lightPosRadius [ ii ] [ 1 ] = 20.0f ;
lightPosRadius [ ii ] [ 2 ] = sin ( 2.0f * float ( M_PI ) / settings_numLights * float ( ii ) + lightTimeAccumulator * 1.1f + 3.0f ) * 20.0f ;
lightPosRadius [ ii ] [ 3 ] = 20.0f ;
}
2013-10-20 16:11:41 -04:00
}
else
{
2013-10-20 14:34:28 -04:00
for ( uint8_t ii = 0 ; ii < settings_numLights ; + + ii )
{
lightPosRadius [ ii ] [ 0 ] = cos ( float ( ii ) * 2.0f / settings_numLights + lightTimeAccumulator * 1.3f + float ( M_PI ) ) * 40.0f ;
lightPosRadius [ ii ] [ 1 ] = 20.0f ;
lightPosRadius [ ii ] [ 2 ] = sin ( float ( ii ) * 2.0f / settings_numLights + lightTimeAccumulator * 1.3f + float ( M_PI ) ) * 40.0f ;
lightPosRadius [ ii ] [ 3 ] = 20.0f ;
}
2013-10-18 01:55:43 -04:00
}
//use debug font to print information about this example.
bgfx : : dbgTextClear ( ) ;
bgfx : : dbgTextPrintf ( 0 , 1 , 0x4f , " bgfx/examples/14-shadowvolumes " ) ;
bgfx : : dbgTextPrintf ( 0 , 2 , 0x6f , " Description: Shadow volumes. " ) ;
bgfx : : dbgTextPrintf ( 0 , 3 , 0x0f , " Frame: % 7.3f[ms] " , double ( frameTime ) * toMs ) ;
2013-10-20 14:34:28 -04:00
2013-10-18 01:55:43 -04:00
if ( settings_showHelp )
{
uint8_t row = 5 ;
bgfx : : dbgTextPrintf ( 3 , row + + , 0x0f , " Stencil buffer implementation: " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Depth fail - Robust, but slower than 'Depth pass'. Requires computing and drawing of shadow volume caps. " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Depth pass - Faster, but not stable. Shadows are wrong when camera is in the shadow. " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Mixed - 'Depth pass' where possible, 'Depth fail' where necessary. Best of both words. " ) ;
row + + ;
bgfx : : dbgTextPrintf ( 3 , row + + , 0x0f , " Shadow volume implementation: " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Face Based - Slower. Works fine with either stencil buffer or texture as stencil. " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Edge Based - Faster, but requires +2 incr/decr on stencil buffer. To avoid massive redraw, use RGBA texture as stencil. " ) ;
row + + ;
bgfx : : dbgTextPrintf ( 3 , row + + , 0x0f , " Stencil: " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Stencil buffer - Faster, but capable only of +1 incr. " ) ;
bgfx : : dbgTextPrintf ( 8 , row + + , 0x0f , " Texture as stencil - Slower, but capable of +2 incr. " ) ;
2013-11-12 16:20:50 -05:00
}
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
// Setup instances
2013-10-18 01:55:43 -04:00
Instance shadowCasters [ SceneCount ] [ 60 ] ;
uint16_t shadowCastersCount [ SceneCount ] ;
for ( uint8_t ii = 0 ; ii < SceneCount ; + + ii )
{
shadowCastersCount [ ii ] = 0 ;
}
Instance shadowReceivers [ SceneCount ] [ 10 ] ;
uint16_t shadowReceiversCount [ SceneCount ] ;
for ( uint8_t ii = 0 ; ii < SceneCount ; + + ii )
{
shadowReceiversCount [ ii ] = 0 ;
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Bunny
2013-10-18 01:55:43 -04:00
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 5.0f ;
inst . m_scale [ 1 ] = 5.0f ;
inst . m_scale [ 2 ] = 5.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = float ( 4.0f - sceneTimeAccumulator * 0.7f ) ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = 0.0f ;
inst . m_pos [ 1 ] = 10.0f ;
inst . m_pos [ 2 ] = 0.0f ;
inst . m_color [ 0 ] = 0.68f ;
inst . m_color [ 1 ] = 0.65f ;
inst . m_color [ 2 ] = 0.60f ;
inst . m_model = bunnyModel ;
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Cubes top.
2013-10-18 01:55:43 -04:00
const uint8_t numCubesTop = 9 ;
for ( uint16_t ii = 0 ; ii < numCubesTop ; + + ii )
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 1.0f ;
inst . m_scale [ 1 ] = 1.0f ;
inst . m_scale [ 2 ] = 1.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = sin ( ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f ) * 13.0f ;
inst . m_pos [ 1 ] = 6.0f ;
inst . m_pos [ 2 ] = cos ( ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f ) * 13.0f ;
inst . m_model = & cubeModel ;
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Cubes bottom.
2013-10-18 01:55:43 -04:00
const uint8_t numCubesBottom = 9 ;
for ( uint16_t ii = 0 ; ii < numCubesBottom ; + + ii )
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 1.0f ;
inst . m_scale [ 1 ] = 1.0f ;
inst . m_scale [ 2 ] = 1.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = sin ( ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f ) * 13.0f ;
inst . m_pos [ 1 ] = 22.0f ;
inst . m_pos [ 2 ] = cos ( ii * 2.0f + 13.0f + sceneTimeAccumulator * 1.1f ) * 13.0f ;
inst . m_model = & cubeModel ;
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Columns.
2013-10-18 01:55:43 -04:00
const float dist = 16.0f ;
const float columnPositions [ 4 ] [ 3 ] =
{
{ dist , 3.3f , dist } ,
{ - dist , 3.3f , dist } ,
{ dist , 3.3f , - dist } ,
{ - dist , 3.3f , - dist } ,
} ;
for ( uint8_t ii = 0 ; ii < 4 ; + + ii )
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 1.5f ;
inst . m_scale [ 1 ] = 1.5f ;
inst . m_scale [ 2 ] = 1.5f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 1.57f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = columnPositions [ ii ] [ 0 ] ;
inst . m_pos [ 1 ] = columnPositions [ ii ] [ 1 ] ;
inst . m_pos [ 2 ] = columnPositions [ ii ] [ 2 ] ;
inst . m_color [ 0 ] = 0.25f ;
inst . m_color [ 1 ] = 0.25f ;
inst . m_color [ 2 ] = 0.25f ;
inst . m_model = & columnModel ;
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Ceiling.
2013-10-18 01:55:43 -04:00
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 21.0f ;
inst . m_scale [ 1 ] = 21.0f ;
inst . m_scale [ 2 ] = 21.0f ;
inst . m_rotation [ 0 ] = float ( M_PI ) ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = 0.0f ;
inst . m_pos [ 1 ] = 28.2f ;
inst . m_pos [ 2 ] = 0.0f ;
inst . m_model = & platformModel ;
inst . m_svExtrusionDistance = 2.0f ; //prevent culling on tight view frustum
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow casters - Platform.
2013-10-18 01:55:43 -04:00
{
Instance & inst = shadowCasters [ Scene0 ] [ shadowCastersCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 24.0f ;
inst . m_scale [ 1 ] = 24.0f ;
inst . m_scale [ 2 ] = 24.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = 0.0f ;
inst . m_pos [ 1 ] = 0.0f ;
inst . m_pos [ 2 ] = 0.0f ;
inst . m_model = & platformModel ;
inst . m_svExtrusionDistance = 2.0f ; //prevent culling on tight view frustum
}
2013-10-20 14:34:28 -04:00
// Scene 0 - shadow receivers - Floor.
2013-10-18 01:55:43 -04:00
{
Instance & inst = shadowReceivers [ Scene0 ] [ shadowReceiversCount [ Scene0 ] + + ] ;
inst . m_scale [ 0 ] = 500.0f ;
inst . m_scale [ 1 ] = 500.0f ;
inst . m_scale [ 2 ] = 500.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = 0.0f ;
inst . m_pos [ 1 ] = 0.0f ;
inst . m_pos [ 2 ] = 0.0f ;
inst . m_model = & hplaneFieldModel ;
}
2013-10-20 14:34:28 -04:00
// Scene 1 - shadow casters - Bunny instances
2013-10-18 01:55:43 -04:00
{
2013-10-20 16:11:41 -04:00
enum Direction
{
2013-10-21 15:46:27 -04:00
Left = 0x0 ,
Down = 0x1 ,
Right = 0x2 ,
Up = 0x3 ,
2013-10-20 16:11:41 -04:00
} ;
2013-10-21 15:46:27 -04:00
const uint8_t directionMask = 0x3 ;
2013-10-18 01:55:43 -04:00
2013-10-20 16:11:41 -04:00
uint8_t currentDirection = Left ;
float currX = 0.0f ;
float currY = 0.0f ;
const float stepX = 20.0f ;
const float stepY = 20.0f ;
uint8_t stateStep = 0 ;
2013-10-21 15:46:27 -04:00
uint8_t stateChange = 1 ;
2013-10-18 01:55:43 -04:00
2013-10-20 16:11:41 -04:00
for ( uint8_t ii = 0 ; ii < settings_instanceCount ; + + ii )
2013-10-18 01:55:43 -04:00
{
2013-10-20 16:11:41 -04:00
Instance & inst = shadowCasters [ Scene1 ] [ shadowCastersCount [ Scene1 ] + + ] ;
inst . m_scale [ 0 ] = 5.0f ;
inst . m_scale [ 1 ] = 5.0f ;
inst . m_scale [ 2 ] = 5.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = float ( M_PI ) ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = currX ;
inst . m_pos [ 1 ] = 0.0f ;
inst . m_pos [ 2 ] = currY ;
inst . m_model = bunnyModel ;
2013-10-21 15:46:27 -04:00
+ + stateStep ;
if ( stateStep > = ( ( stateChange & ~ 0x1 ) > > 1 ) )
2013-10-20 16:11:41 -04:00
{
2013-10-26 13:22:08 -04:00
currentDirection = ( currentDirection + 1 ) & directionMask ;
2013-10-20 16:11:41 -04:00
stateStep = 0 ;
2013-10-21 15:46:27 -04:00
+ + stateChange ;
2013-10-20 16:11:41 -04:00
}
switch ( currentDirection )
{
case Left : currX - = stepX ; break ;
case Down : currY - = stepY ; break ;
case Right : currX + = stepX ; break ;
case Up : currY + = stepY ; break ;
}
2013-10-18 01:55:43 -04:00
}
}
2013-10-20 14:34:28 -04:00
// Scene 1 - shadow receivers - Floor.
2013-10-18 01:55:43 -04:00
{
Instance & inst = shadowReceivers [ Scene1 ] [ shadowReceiversCount [ Scene1 ] + + ] ;
inst . m_scale [ 0 ] = 500.0f ;
inst . m_scale [ 1 ] = 500.0f ;
inst . m_scale [ 2 ] = 500.0f ;
inst . m_rotation [ 0 ] = 0.0f ;
inst . m_rotation [ 1 ] = 0.0f ;
inst . m_rotation [ 2 ] = 0.0f ;
inst . m_pos [ 0 ] = 0.0f ;
inst . m_pos [ 1 ] = 0.0f ;
inst . m_pos [ 2 ] = 0.0f ;
inst . m_model = & hplaneFigureModel ;
}
2013-10-20 14:34:28 -04:00
// Make sure at the beginning everything gets cleared.
2013-10-21 14:09:46 -04:00
bgfx : : setViewClear ( 0
, BGFX_CLEAR_COLOR_BIT
| BGFX_CLEAR_DEPTH_BIT
| BGFX_CLEAR_STENCIL_BIT
, clearValues . m_clearRgba
, clearValues . m_clearDepth
, clearValues . m_clearStencil
) ;
2013-10-18 01:55:43 -04:00
: : submit ( 0 ) ;
2013-10-20 14:34:28 -04:00
// Draw ambient only.
2013-10-18 01:55:43 -04:00
s_uniforms . m_params . m_ambientPass = 1.0f ;
s_uniforms . m_params . m_lightningPass = 0.0f ;
s_uniforms . m_color [ 0 ] = 1.0f ;
s_uniforms . m_color [ 1 ] = 1.0f ;
s_uniforms . m_color [ 2 ] = 1.0f ;
const RenderState & drawAmbient = ( settings_useStencilTexture ?
2013-10-20 14:34:28 -04:00
s_renderStates [ RenderState : : ShadowVolume_UsingStencilTexture_DrawAmbient ] :
s_renderStates [ RenderState : : ShadowVolume_UsingStencilBuffer_DrawAmbient ] ) ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
// Draw shadow casters.
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 ; ii < shadowCastersCount [ currentScene ] ; + + ii )
{
shadowCasters [ currentScene ] [ ii ] . submit ( VIEWID_RANGE1_PASS0 , drawAmbient ) ;
}
2013-10-20 14:34:28 -04:00
// Draw shadow receivers.
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 ; ii < shadowReceiversCount [ currentScene ] ; + + ii )
{
shadowReceivers [ currentScene ] [ ii ] . submit ( VIEWID_RANGE1_PASS0 , drawAmbient ) ;
}
2013-10-20 14:34:28 -04:00
// Using stencil texture requires rendering to separate render target. first pass is building depth buffer.
2013-10-18 01:55:43 -04:00
if ( settings_useStencilTexture )
{
2013-10-21 14:09:46 -04:00
bgfx : : setViewClear ( VIEWID_RANGE1_RT_PASS1 , BGFX_CLEAR_DEPTH_BIT , 0x00000000 , 1.0f , 0 ) ;
2014-02-06 02:07:11 -05:00
bgfx : : setViewFrameBuffer ( VIEWID_RANGE1_RT_PASS1 , s_stencilFb ) ;
2013-10-18 01:55:43 -04:00
2013-11-12 16:20:50 -05:00
const RenderState & renderState = s_renderStates [ RenderState : : ShadowVolume_UsingStencilTexture_BuildDepth ] ;
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 ; ii < shadowCastersCount [ currentScene ] ; + + ii )
{
shadowCasters [ currentScene ] [ ii ] . submit ( VIEWID_RANGE1_RT_PASS1 , renderState ) ;
}
for ( uint8_t ii = 0 ; ii < shadowReceiversCount [ currentScene ] ; + + ii )
{
shadowReceivers [ currentScene ] [ ii ] . submit ( VIEWID_RANGE1_RT_PASS1 , renderState ) ;
}
}
profTime = bx : : getHPCounter ( ) ;
/**
2013-11-12 16:20:50 -05:00
* For each light :
2013-10-20 16:11:41 -04:00
* 1. Compute and draw shadow volume to stencil buffer
* 2. Draw diffuse with stencil test
*/
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 , viewId = VIEWID_RANGE15_PASS2 ; ii < settings_numLights ; + + ii , + + viewId )
{
const float * lightPos = lightPosRadius [ ii ] ;
2013-10-20 14:34:28 -04:00
memcpy ( s_uniforms . m_lightPosRadius , lightPosRadius [ ii ] , 4 * sizeof ( float ) ) ;
memcpy ( s_uniforms . m_lightRgbInnerR , lightRgbInnerR [ ii ] , 3 * sizeof ( float ) ) ;
memcpy ( s_uniforms . m_color , lightRgbInnerR [ ii ] , 3 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
if ( settings_useStencilTexture )
{
2014-02-06 02:07:11 -05:00
bgfx : : setViewFrameBuffer ( viewId , s_stencilFb ) ;
2013-10-21 14:09:46 -04:00
bgfx : : setViewClear ( viewId
, BGFX_CLEAR_COLOR_BIT
, 0x00000000
, 1.0f
, 0
) ;
2013-10-18 01:55:43 -04:00
}
else
{
2014-02-06 02:07:11 -05:00
const bgfx : : FrameBufferHandle invalid = BGFX_INVALID_HANDLE ;
bgfx : : setViewFrameBuffer ( viewId , invalid ) ;
2013-10-21 14:09:46 -04:00
bgfx : : setViewClear ( viewId
, BGFX_CLEAR_STENCIL_BIT
, clearValues . m_clearRgba
, clearValues . m_clearDepth
, clearValues . m_clearStencil
) ;
2013-10-18 01:55:43 -04:00
}
2013-10-20 14:34:28 -04:00
// Create near clip volume for current light.
2013-10-20 16:11:41 -04:00
float nearClipVolume [ 6 * 4 ] = { } ;
2013-10-18 01:55:43 -04:00
float pointLight [ 4 ] ;
if ( settings_mixedSvImpl )
{
pointLight [ 0 ] = lightPos [ 0 ] ;
pointLight [ 1 ] = lightPos [ 1 ] ;
pointLight [ 2 ] = lightPos [ 2 ] ;
pointLight [ 3 ] = 1.0f ;
2013-10-21 14:15:52 -04:00
createNearClipVolume ( nearClipVolume , pointLight , viewState . m_view , fov , aspect , nearPlane ) ;
2013-10-18 01:55:43 -04:00
}
for ( uint8_t jj = 0 ; jj < shadowCastersCount [ currentScene ] ; + + jj )
{
const Instance & instance = shadowCasters [ currentScene ] [ jj ] ;
Model * model = instance . m_model ;
2013-11-12 16:20:50 -05:00
ShadowVolumeImpl : : Enum shadowVolumeImpl = settings_shadowVolumeImpl ;
2013-10-18 01:55:43 -04:00
if ( settings_mixedSvImpl )
2013-11-12 16:20:50 -05:00
{
2013-10-20 14:34:28 -04:00
// If instance is inside near clip volume, depth fail must be used, else depth pass is fine.
2013-10-18 01:55:43 -04:00
bool isInsideVolume = clipTest ( nearClipVolume , 6 , model - > m_mesh , instance . m_scale , instance . m_pos ) ;
shadowVolumeImpl = ( isInsideVolume ? ShadowVolumeImpl : : DepthFail : ShadowVolumeImpl : : DepthPass ) ;
}
2013-11-12 16:20:50 -05:00
s_uniforms . m_svparams . m_dfail = float ( ShadowVolumeImpl : : DepthFail = = shadowVolumeImpl ) ;
2013-10-18 01:55:43 -04:00
2013-10-30 01:44:41 -04:00
// Compute virtual light position for shadow volume generation.
2013-10-18 01:55:43 -04:00
float transformedLightPos [ 3 ] ;
2013-10-30 01:44:41 -04:00
shadowVolumeLightTransform ( transformedLightPos
2013-10-20 14:34:28 -04:00
, instance . m_scale
, instance . m_rotation
, instance . m_pos
, lightPos
) ;
// Set virtual light pos.
memcpy ( s_uniforms . m_virtualLightPos_extrusionDist , transformedLightPos , 3 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
s_uniforms . m_virtualLightPos_extrusionDist [ 3 ] = instance . m_svExtrusionDistance ;
2013-10-30 01:44:41 -04:00
// Compute transform for shadow volume.
float shadowVolumeMtx [ 16 ] ;
mtxScaleRotateTranslate ( shadowVolumeMtx
, instance . m_scale [ 0 ]
, instance . m_scale [ 1 ]
, instance . m_scale [ 2 ]
, instance . m_rotation [ 0 ]
, instance . m_rotation [ 1 ]
, instance . m_rotation [ 2 ]
, instance . m_pos [ 0 ]
, instance . m_pos [ 1 ]
, instance . m_pos [ 2 ]
) ;
2013-10-18 01:55:43 -04:00
GroupArray & groups = model - > m_mesh . m_groups ;
const uint16_t stride = model - > m_mesh . m_decl . getStride ( ) ;
for ( GroupArray : : iterator it = groups . begin ( ) , itEnd = groups . end ( ) ; it ! = itEnd ; + + it )
{
Group & group = * it ;
2013-10-20 14:34:28 -04:00
// Create shadow volume.
2013-10-18 01:55:43 -04:00
ShadowVolume shadowVolume ;
shadowVolumeCreate ( shadowVolume
2013-10-20 14:34:28 -04:00
, group
, stride
, shadowVolumeMtx
, transformedLightPos
, shadowVolumeImpl
, settings_shadowVolumeAlgorithm
, settings_useStencilTexture
) ;
2013-10-18 01:55:43 -04:00
numShadowVolumeVertices + = shadowVolume . m_numVertices ;
numShadowVolumeIndices + = shadowVolume . m_numIndices ;
2013-10-20 14:34:28 -04:00
ShadowVolumeProgramType : : Enum programIndex = ShadowVolumeProgramType : : Blank ;
2013-10-18 01:55:43 -04:00
RenderState : : Enum renderStateIndex ;
if ( settings_useStencilTexture )
{
2013-10-20 14:34:28 -04:00
renderStateIndex = ShadowVolumeImpl : : DepthFail = = shadowVolumeImpl
? RenderState : : ShadowVolume_UsingStencilTexture_CraftStencil_DepthFail
: RenderState : : ShadowVolume_UsingStencilTexture_CraftStencil_DepthPass
;
2013-11-12 16:20:50 -05:00
programIndex = ShadowVolumeAlgorithm : : FaceBased = = settings_shadowVolumeAlgorithm
2013-10-20 14:34:28 -04:00
? ShadowVolumeProgramType : : Tex1
: ShadowVolumeProgramType : : Tex2
;
2013-10-18 01:55:43 -04:00
}
else
{
2013-10-20 14:34:28 -04:00
renderStateIndex = ShadowVolumeImpl : : DepthFail = = shadowVolumeImpl
? RenderState : : ShadowVolume_UsingStencilBuffer_CraftStencil_DepthFail
: RenderState : : ShadowVolume_UsingStencilBuffer_CraftStencil_DepthPass
;
2013-10-18 01:55:43 -04:00
}
const RenderState & renderStateCraftStencil = s_renderStates [ renderStateIndex ] ;
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ programIndex ] [ ShadowVolumePart : : Side ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( shadowVolume . m_vbSides ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibSides ) ;
: : setRenderState ( renderStateCraftStencil ) ;
: : submit ( viewId ) ;
if ( shadowVolume . m_cap )
{
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ programIndex ] [ ShadowVolumePart : : Front ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( group . m_vbh ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibFrontCap ) ;
: : setRenderState ( renderStateCraftStencil ) ;
: : submit ( viewId ) ;
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ programIndex ] [ ShadowVolumePart : : Back ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( group . m_vbh ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibBackCap ) ;
: : setRenderState ( renderStateCraftStencil ) ;
: : submit ( viewId ) ;
}
if ( settings_drawShadowVolumes )
{
const RenderState & renderState = s_renderStates [ RenderState : : Custom_DrawShadowVolume_Lines ] ;
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ ShadowVolumeProgramType : : Color ] [ ShadowVolumePart : : Side ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( shadowVolume . m_vbSides ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibSides ) ;
: : setRenderState ( renderState ) ;
: : submit ( VIEWID_RANGE1_PASS3 ) ;
if ( shadowVolume . m_cap )
{
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ ShadowVolumeProgramType : : Color ] [ ShadowVolumePart : : Front ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( group . m_vbh ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibFrontCap ) ;
: : setRenderState ( renderState ) ;
: : submit ( VIEWID_RANGE1_PASS3 ) ;
s_uniforms . submitPerDrawUniforms ( ) ;
bgfx : : setProgram ( svProgs [ ShadowVolumeProgramType : : Color ] [ ShadowVolumePart : : Back ] ) ;
bgfx : : setTransform ( shadowVolumeMtx ) ;
bgfx : : setVertexBuffer ( group . m_vbh ) ;
bgfx : : setIndexBuffer ( shadowVolume . m_ibBackCap ) ;
: : setRenderState ( renderState ) ;
: : submit ( VIEWID_RANGE1_PASS3 ) ;
}
}
}
}
2013-10-20 14:34:28 -04:00
// Draw diffuse only.
2013-10-18 01:55:43 -04:00
s_uniforms . m_params . m_ambientPass = 0.0f ;
s_uniforms . m_params . m_lightningPass = 1.0f ;
2013-10-20 16:11:41 -04:00
RenderState & drawDiffuse = settings_useStencilTexture
? s_renderStates [ RenderState : : ShadowVolume_UsingStencilTexture_DrawDiffuse ]
: s_renderStates [ RenderState : : ShadowVolume_UsingStencilBuffer_DrawDiffuse ]
;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
// If using stencil texture, viewId is set to render target. Incr it to render to default back buffer.
2013-10-18 01:55:43 -04:00
viewId + = uint8_t ( settings_useStencilTexture ) ;
2013-10-20 14:34:28 -04:00
// Draw shadow casters.
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 ; ii < shadowCastersCount [ currentScene ] ; + + ii )
{
shadowCasters [ currentScene ] [ ii ] . submit ( viewId , drawDiffuse ) ;
}
2013-10-20 14:34:28 -04:00
// Draw shadow receivers.
2013-10-18 01:55:43 -04:00
for ( uint8_t ii = 0 ; ii < shadowReceiversCount [ currentScene ] ; + + ii )
{
shadowReceivers [ currentScene ] [ ii ] . submit ( viewId , drawDiffuse ) ;
}
}
2013-11-12 16:20:50 -05:00
profTime = bx : : getHPCounter ( ) - profTime ;
2013-10-18 01:55:43 -04:00
2013-10-20 14:34:28 -04:00
// Lights.
2013-10-18 01:55:43 -04:00
const float lightScale [ 3 ] = { 1.5f , 1.5f , 1.5f } ;
for ( uint8_t ii = 0 ; ii < settings_numLights ; + + ii )
{
2013-10-20 14:34:28 -04:00
memcpy ( s_uniforms . m_color , lightRgbInnerR [ ii ] , 3 * sizeof ( float ) ) ;
2013-10-18 01:55:43 -04:00
float lightMtx [ 16 ] ;
mtxBillboard ( lightMtx , viewState . m_view , lightPosRadius [ ii ] , lightScale ) ;
vplaneModel . submit ( VIEWID_RANGE1_PASS3 , lightMtx , s_renderStates [ RenderState : : Custom_BlendLightTexture ] ) ;
}
2013-10-20 14:34:28 -04:00
// Setup view rect and transform for all used views.
2013-10-20 22:30:58 -04:00
bgfx : : setViewRectMask ( s_viewMask , 0 , 0 , viewState . m_width , viewState . m_height ) ;
bgfx : : setViewTransformMask ( s_viewMask , viewState . m_view , viewState . m_proj ) ;
2013-10-18 01:55:43 -04:00
s_viewMask = 0 ;
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
bgfx : : frame ( ) ;
2013-10-23 20:02:10 -04:00
// Swap memory pages.
s_svAllocator . swap ( ) ;
2013-10-21 14:09:46 -04:00
// Reset clear values.
bgfx : : setViewClearMask ( UINT32_MAX
, BGFX_CLEAR_NONE
, clearValues . m_clearRgba
, clearValues . m_clearDepth
, clearValues . m_clearStencil
) ;
2013-10-18 01:55:43 -04:00
}
// Cleanup
bunnyLowPolyModel . unload ( ) ;
bunnyHighPolyModel . unload ( ) ;
columnModel . unload ( ) ;
cubeModel . unload ( ) ;
platformModel . unload ( ) ;
hplaneFieldModel . unload ( ) ;
hplaneFigureModel . unload ( ) ;
vplaneModel . unload ( ) ;
s_uniforms . destroy ( ) ;
bgfx : : destroyUniform ( u_texColor ) ;
bgfx : : destroyUniform ( u_texStencil ) ;
2014-02-06 02:07:11 -05:00
bgfx : : destroyFrameBuffer ( s_stencilFb ) ;
2013-10-18 01:55:43 -04:00
bgfx : : destroyTexture ( figureTex ) ;
bgfx : : destroyTexture ( fieldstoneTex ) ;
bgfx : : destroyTexture ( flareTex ) ;
bgfx : : destroyProgram ( programTextureLightning ) ;
bgfx : : destroyProgram ( programColorLightning ) ;
bgfx : : destroyProgram ( programColorTexture ) ;
bgfx : : destroyProgram ( programTexture ) ;
bgfx : : destroyProgram ( programBackBlank ) ;
bgfx : : destroyProgram ( programSideBlank ) ;
bgfx : : destroyProgram ( programFrontBlank ) ;
bgfx : : destroyProgram ( programBackColor ) ;
bgfx : : destroyProgram ( programSideColor ) ;
bgfx : : destroyProgram ( programFrontColor ) ;
bgfx : : destroyProgram ( programSideTex ) ;
bgfx : : destroyProgram ( programBackTex1 ) ;
bgfx : : destroyProgram ( programBackTex2 ) ;
bgfx : : destroyProgram ( programFrontTex1 ) ;
bgfx : : destroyProgram ( programFrontTex2 ) ;
imguiDestroy ( ) ;
// Shutdown bgfx.
bgfx : : shutdown ( ) ;
return 0 ;
}