@@ -25,25 +25,83 @@ drawPass_t::~drawPass_t( void )
{
}

//--------------------------------------------------------------

lightSampler_t::lightSampler_t( void )
: fbo( 0 )
{}

lightSampler_t::~lightSampler_t( void )
{
if ( fbo )
{
GL_CHECK( glDeleteFramebuffers( 1, &fbo ) );
}
}

void lightSampler_t::Elevate( const glm::vec3& min, const glm::vec3& max )
{
GLint viewport[4];
GL_CHECK( glGetIntegerv( GL_VIEWPORT, viewport ) );

float w = ( float ) viewport[ 2 ];
float h = ( float ) viewport[ 3 ];

w *= 3.0f;
h *= 3.0f;

camera.SetClipTransform( glm::ortho< float >( -w, w, -h, h, 0.0f, 10000000.0f ) );

glm::vec3 eye( ( min + max ) * 0.5f );

eye.y += ( max.y - min.y ) * 0.3f;

// Transform the upper left most point in view, the upper right most point in view,
// and the lower right most point in view to view space.

// Project these points on z = 0. If the distance from the upper right to the upper left is greater
// than the distance from the upper right to the lower right, then no rotation is necessary.
// Otherwise, rotate 90 deg

glm::vec3 target( eye + glm::vec3( 0.0f, 1.0f, 0.0f ) );
glm::vec3 up( glm::cross( glm::vec3( 1.0f, 0.0f, 0.0f ), target - eye ) );

camera.SetViewTransform( glm::lookAt( eye, target, up ) );
camera.SetViewOrigin( eye );
}

void lightSampler_t::SetOrigin( const glm::vec3& eye )
{
glm::vec3 target( eye.x, eye.y * 2.0f, eye.z );
glm::vec3 up( glm::cross( glm::vec3( 1.0f, 0.0f, 0.0f ), target - eye ) );

camera.SetViewTransform( glm::lookAt( eye, target, up ) );
camera.SetViewOrigin( eye );
}

//--------------------------------------------------------------

BSPRenderer::BSPRenderer( void )
: camera( nullptr ),
frustum( new Frustum() ),
mapDimsLength( 0 ),
transformBlockIndex( 0 ),
transformBlockObj( 0 ),
transformBlockSize( sizeof( glm::mat4 ) * 2 ),
map ( new Q3BspMap() ),
currLeaf( nullptr ),
vao( 0 ),
vbo( 0 ),
deltaTime( 0.0 ),
frameTime( 0.0f ),
curView( VIEW_MAIN )
: map ( new Q3BspMap() ),
camera( nullptr ),
frustum( new Frustum() ),
mapDimsLength( 0 ),
transformBlockIndex( 0 ),
transformBlockObj( 0 ),
transformBlockSize( sizeof( glm::mat4 ) * 2 ),

currLeaf( nullptr ),
vao( 0 ),
vbo( 0 ),
deltaTime( 0.0 ),
frameTime( 0.0f ),
curView( VIEW_MAIN )
{
viewParams_t view;
view.origin = glm::vec3( -131.291901f, -61.794476f, -163.203659f ); /// debug position which doesn't kill framerate

camera = new InputCamera( view, EuAng() );
camera->SetPerspective( 45.0f, 16.0f / 9.0f, 0.1f, 200000.0f );
}

BSPRenderer::~BSPRenderer( void )
@@ -88,6 +146,7 @@ void BSPRenderer::Prep( void )
GL_CHECK( glPolygonOffset( 5.0f, 1.0f ) );

GL_CHECK( glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ) );
GL_CHECK( glClearDepth( 1.0f ) );

GL_CHECK( glGenVertexArrays( 1, &vao ) );
GL_CHECK( glGenBuffers( 1, &vbo ) );
@@ -104,25 +163,20 @@ void BSPRenderer::Prep( void )

// Load main shader programs
{

std::vector< std::string > uniforms =
{
"fragTexSampler",
"fragLightmapSampler"
};

std::vector< std::string > attribs =
{
"position",
"color",
"tex0",
"lightmap"
"lightmap",
"tex0"
};

std::vector< std::string > sampleunifs( uniforms );
sampleunifs.push_back( "modelViewProjection" );
std::vector< std::string > uniforms =
{
"fragTexSampler",
"fragLightmapSampler"
};

MakeProg( "lightsample", "src/lightsample.vert", "src/main.frag", sampleunifs, attribs, false );
MakeProg( "main", "src/main.vert", "src/main.frag", uniforms, attribs, true );

uniforms.insert( uniforms.end(), {
@@ -147,59 +201,24 @@ void BSPRenderer::Load( const string& filepath, uint32_t mapLoadFlags )
GL_CHECK( glBindBuffer( GL_ARRAY_BUFFER, vbo ) );
GL_CHECK( glBufferData( GL_ARRAY_BUFFER, sizeof( bspVertex_t ) * map->data.numVertexes, map->data.vertexes, GL_STATIC_DRAW ) );

LoadVertexLayout( true );
// NOTE: this vertex layout may not persist when the model program is used; so be wary of that. "main"
// and "model" should both have the same attribute location values though
LoadVertexLayout( GLUTIL_LAYOUT_ALL & ~GLUTIL_LAYOUT_NORMAL, *( programs[ "main" ].get() ) );

const bspNode_t* root = &map->data.nodes[ 0 ];

// Base texture setup
mapDimsLength = ( int ) glm::length( glm::vec3( root->boxMax.x, root->boxMax.y, root->boxMax.z ) );
lodThreshold = mapDimsLength / 2;

// Setup light sampler transforms

GLint viewport[4];
GL_CHECK( glGetIntegerv( GL_VIEWPORT, viewport ) );

float w = ( float ) viewport[ 2 ];
float h = ( float ) viewport[ 3 ];

lightSampler.projection = /*camera->ViewData().clipTransform;*/ glm::ortho< float >( -w, w, -h, h, -10000.0f, 1000000.0f );

const bspModel_t* m = &map->data.models[ 0 ];

const glm::vec3& pos = ( glm::vec3( m->boxMax ) + glm::vec3( m->boxMin ) ) * 0.5f;

lightSampler.view = glm::lookAt( glm::vec3( pos.x, m->boxMin.y, pos.z ), glm::vec3( pos.x, m->boxMax.y, pos.z ), glm::vec3( 0.0f, 1.0f, 1.0f ) );
lightSampler.Elevate( map->data.models[ 0 ].boxMin, map->data.models[ 0 ].boxMax );
}

void BSPRenderer::Render( uint32_t renderFlags )
{
double startTime = glfwGetTime();

const glm::mat4* view = nullptr;
const glm::mat4* proj = nullptr;

switch ( curView )
{
case VIEW_MAIN:
view = &camera->ViewData().transform;
proj = &camera->ViewData().clipTransform;
break;
case VIEW_LIGHT_SAMPLE:
view = &lightSampler.view;
proj = &/*lightSampler.projection*/camera->ViewData().clipTransform;
break;
}

GL_CHECK( glBindBuffer( GL_UNIFORM_BUFFER, transformBlockObj ) );
GL_CHECK( glBufferSubData( GL_UNIFORM_BUFFER,
0, sizeof( glm::mat4 ), glm::value_ptr( *proj ) ) );
GL_CHECK( glBufferSubData( GL_UNIFORM_BUFFER,
sizeof( glm::mat4 ), sizeof( glm::mat4 ), glm::value_ptr( *view ) ) );

GL_CHECK( glBindBuffer( GL_UNIFORM_BUFFER, 0 ) );

drawPass_t pass( map, camera->ViewData() );
drawPass_t pass( map, CameraFromView()->ViewData() );

pass.leaf = map->FindClosestLeaf( pass.view.origin );
pass.renderFlags = renderFlags;
@@ -212,6 +231,8 @@ void BSPRenderer::Render( uint32_t renderFlags )
pass.isSolid = true;
DrawNode( 0, pass );

LoadTransforms( pass.view.transform, pass.view.clipTransform );

DrawFaceList( pass, pass.opaque );
DrawFaceList( pass, pass.transparent );

@@ -244,15 +265,16 @@ void BSPRenderer::Render( uint32_t renderFlags )
}
}
}

frameTime = glfwGetTime() - startTime;
}

void BSPRenderer::Update( float dt )
{
deltaTime = dt;
camera->Update();
frustum->Update( camera->ViewData() );
//CameraFromView()->Update();
camera->Update();
frustum->Update( CameraFromView()->ViewData() );
}

void BSPRenderer::DrawNode( int nodeIndex, drawPass_t& pass )
@@ -341,15 +363,16 @@ void BSPRenderer::BindTextureOrDummy( bool predicate, int index, int offset,

void BSPRenderer::DrawMapPass( drawPass_t& pass )
{

BindTextureOrDummy( map->glTextures[ pass.face->texture ].handle != 0,
pass.face->texture, 0, *( pass.program ), "fragTexSampler", map->glTextures );

BindTextureOrDummy( pass.face->lightmapIndex >= 0,
pass.face->lightmapIndex, 1, *( pass.program ), "fragLightmapSampler", map->glLightmaps );

pass.program->Bind();

DrawFaceVerts( pass, false );
DrawFaceVerts( pass );

GL_CHECK( glUseProgram( 0 ) );

@@ -363,6 +386,8 @@ void BSPRenderer::DrawMapPass( drawPass_t& pass )

GL_CHECK( glBindSampler( 0, 0 ) );
GL_CHECK( glBindSampler( 1, 0 ) );

DrawDebugInfo( pass );
}

void BSPRenderer::DrawEffectPass( drawPass_t& pass )
@@ -442,7 +467,7 @@ void BSPRenderer::DrawEffectPass( drawPass_t& pass )
stage.program->LoadInt( "sampler0", 0 );

stage.program->Bind();
DrawFaceVerts( pass, true );
DrawFaceVerts( pass );
stage.program->Release();

if ( Shade_IsIdentColor( stage ) )
@@ -465,38 +490,20 @@ void BSPRenderer::DrawDebugInfo( drawPass_t& pass )
{
ImPrep( pass.view.transform, pass.view.clipTransform );

uint8_t hasLightmap = FALSE;

if ( pass.shader )
{
const shaderInfo_t& shader = map->effectShaders.at( map->data.textures[ pass.face->texture ].name );
hasLightmap = shader.hasLightmap;
}

GL_CHECK( glPointSize( 10.0f ) );
glm::vec3 center( ( map->data.nodes[ 0 ].boxMax + map->data.nodes[ 0 ].boxMin ) / 2 );

// Draw lightmap origin
glBegin( GL_POINTS );
if ( hasLightmap )
glColor3f( 0.0f, 0.0f, 1.0f );
else
glColor3f( 0.0f, 1.0f, 0.0f );
glVertex3f( pass.face->lightmapOrigin.x, pass.face->lightmapOrigin.y, pass.face->lightmapOrigin.z );

glColor3f( 0.0f, 0.0f, 1.0f );
glVertex3iv( glm::value_ptr( map->data.nodes[ 0 ].boxMin ) );
glColor3f( 0.0f, 1.0f, 0.0f );
glVertex3iv( glm::value_ptr( map->data.nodes[ 0 ].boxMax ) );
glColor3f( 1.0f, 0.0f, 0.0f );
glVertex3fv( glm::value_ptr( center ) );
glColor3f( 1.0f, 1.0f, 0.0f );
glVertex3fv( glm::value_ptr( glm::vec3( center.x, 0.0f, center.z ) ) );
glEnd();

if ( pass.shader )
{
GL_CHECK( glPointSize( 5.0f ) );
glBegin( GL_POINTS );
glColor3f( 1.0f, 1.0f, 1.0f );
for ( uint32_t i = 0; i < map->glFaces[ pass.faceIndex ].indices.size(); ++i )
{
const glm::vec3& pos = map->data.vertexes[ map->glFaces[ pass.faceIndex ].indices[ i ] ].position;
glVertex3f( pos.x, pos.y, pos.z );
}
glEnd();
}


GL_CHECK( glLoadIdentity() );
}

@@ -508,13 +515,16 @@ void BSPRenderer::DrawFace( drawPass_t& pass )
MapAttribTexCoord( 2, offsetof( bspVertex_t, texCoords[ 0 ] ) );
MapAttribTexCoord( 3, offsetof( bspVertex_t, texCoords[ 1 ] ) );

if ( pass.shader )
{
DrawEffectPass( pass );
}
else
switch ( pass.type )
{
DrawMapPass( pass );
case PASS_EFFECT:
DrawEffectPass( pass );
break;

case PASS_MODEL:
case PASS_MAP:
DrawMapPass( pass );
break;
}

// Debug information
@@ -526,7 +536,7 @@ void BSPRenderer::DrawFace( drawPass_t& pass )
pass.facesVisited[ pass.faceIndex ] = 1;
}

void BSPRenderer::DrawFaceVerts( drawPass_t& pass, bool isEffectPass )
void BSPRenderer::DrawFaceVerts( drawPass_t& pass )
{
mapModel_t* m = &map->glFaces[ pass.faceIndex ];

@@ -559,12 +569,14 @@ void BSPRenderer::DrawFaceVerts( drawPass_t& pass, bool isEffectPass )
DeformVertexes( m, pass );
}

LoadBufferLayout( m->vbo, !isEffectPass );
uint32_t flags = GetPassLayoutFlags( pass.type );

LoadBufferLayout( m->vbo, flags, *( pass.program ) );

GL_CHECK( glMultiDrawElements( GL_TRIANGLE_STRIP,
&m->trisPerRow[ 0 ], GL_UNSIGNED_INT, ( const GLvoid** ) &m->rowIndices[ 0 ], m->trisPerRow.size() ) );

LoadBufferLayout( vbo, true );
LoadBufferLayout( vbo, flags, *( pass.program ) );
}
}

@@ -20,7 +20,14 @@ enum passType_t
{
PASS_EFFECT = 0,
PASS_MAP,
PASS_MODEL
PASS_MODEL,
PASS_LIGHT_SAMPLE
};

enum viewMode_t
{
VIEW_MAIN = 0,
VIEW_LIGHT_SAMPLE,
};

struct drawPass_t
@@ -51,23 +58,22 @@ struct drawPass_t
~drawPass_t( void );
};

enum viewMode_t
{
VIEW_MAIN = 0,
VIEW_LIGHT_SAMPLE,
struct lightSampler_t {
InputCamera camera;
GLuint fbo;
texture_t attachment;

lightSampler_t( void );
~lightSampler_t( void );

void Elevate( const glm::vec3& min, const glm::vec3& max );
void SetOrigin( const glm::vec3& eye );
};

class BSPRenderer
{
private:

struct {
glm::mat4 view, projection;
GLuint fbo;
texture_t attachment;
} lightSampler;

Q3BspMap* map;
const bspLeaf_t* currLeaf;

GLuint vao, vbo;
@@ -95,8 +101,12 @@ class BSPRenderer
void MakeProg( const std::string& name, const std::string& vertPath, const std::string& fragPath,
const std::vector< std::string >& uniforms, const std::vector< std::string >& attribs, bool bindTransformsUbo );

public:
void LoadTransforms( const glm::mat4& view, const glm::mat4& projection );

uint32_t GetPassLayoutFlags( passType_t type );

public:
Q3BspMap* map;
InputCamera* camera;
Frustum* frustum;

@@ -109,35 +119,94 @@ class BSPRenderer

viewMode_t curView;

lightSampler_t lightSampler;

BSPRenderer( void );
~BSPRenderer( void );

void Prep( void );
void Load( const std::string& filepath, uint32_t loadFlags );

void Render( uint32_t renderFlags );
void RenderMain( uint32_t renderFlags );

void DrawNode( int nodeIndex, drawPass_t& pass );
void DrawMapPass( drawPass_t& parms );
void DrawFace( drawPass_t& parms );
void DrawFaceVerts( drawPass_t& parms, bool isEffectPass );
void DrawFaceVerts( drawPass_t& parms );

bool CalcLightVol( const glm::vec3& position );

float CalcFPS( void ) const { return 1.0f / ( float )frameTime; }

void Update( float dt );


InputCamera* CameraFromView( void );
};

INLINE void BSPRenderer::DrawFaceList( drawPass_t& p, const std::vector< int >& list )
{
passType_t defaultPass = p.type;

for ( int face: list )
{
p.face = &map->data.faces[ face ];
p.faceIndex = face;
p.shader = map->GetShaderInfo( face );

if ( p.shader )
{
p.type = PASS_EFFECT;
}
else
{
p.type = defaultPass;
}

DrawFace( p );
}
}

INLINE void BSPRenderer::LoadTransforms( const glm::mat4& view, const glm::mat4& projection )
{
GL_CHECK( glBindBuffer( GL_UNIFORM_BUFFER, transformBlockObj ) );
GL_CHECK( glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof( glm::mat4 ), glm::value_ptr( projection ) ) );
GL_CHECK( glBufferSubData( GL_UNIFORM_BUFFER, sizeof( glm::mat4 ), sizeof( glm::mat4 ), glm::value_ptr( view ) ) );
GL_CHECK( glBindBuffer( GL_UNIFORM_BUFFER, 0 ) );
}

INLINE uint32_t BSPRenderer::GetPassLayoutFlags( passType_t type )
{
switch ( type )
{
case PASS_MAP:
return GLUTIL_LAYOUT_ALL & ~GLUTIL_LAYOUT_NORMAL;
break;
case PASS_EFFECT:
return GLUTIL_LAYOUT_POSITION | GLUTIL_LAYOUT_COLOR | GLUTIL_LAYOUT_TEX0;
break;
case PASS_MODEL:
return GLUTIL_LAYOUT_ALL;
break;
}

// Shouldn't happen...
return 0;
}

INLINE InputCamera* BSPRenderer::CameraFromView( void )
{
InputCamera* pCamera = nullptr;

switch ( curView )
{
case VIEW_MAIN:
pCamera = camera;
break;
case VIEW_LIGHT_SAMPLE:
pCamera = &lightSampler.camera;
break;
}

return pCamera;
}
@@ -20,8 +20,8 @@ Test::Test( int w, int h )
: width( w ), height( h ),
deltaTime( 0.0f ),
cursorVisible( true ), running( false ), useSRGBFramebuffer( true ),
camPtr( NULL ),
winPtr( NULL ),
camPtr( nullptr ),
winPtr( nullptr ),
mouseX( 0.0f ),
mouseY( 0.0f ),
lastMouseX( 0.0f ),
@@ -52,7 +52,7 @@ bool Test::Load( const char* winName )
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE );
glfwWindowHint( GLFW_SRGB_CAPABLE, GL_TRUE );

winPtr = glfwCreateWindow( width, height, winName, NULL, NULL );
winPtr = glfwCreateWindow( width, height, winName, nullptr, nullptr );

if ( !winPtr )
return false;
@@ -10,7 +10,7 @@ static const char* neDuel = "asset/quake/ne_duel/maps/ne_duel.bsp";
TRenderer::TRenderer( void )
: Test( 1366, 768 ),
currentTime( 0.0f ),
renderer( NULL ),
renderer( nullptr ),
mapFilepath( railgunArena ),
mapLoadFlags( Q3LOAD_ALL ),
mapRenderFlags( RENDER_BSP_EFFECT | RENDER_BSP_USE_TCMOD )
@@ -19,12 +19,13 @@ TRenderer::TRenderer( void )

TRenderer::~TRenderer( void )
{
camPtr = NULL;
camPtr = nullptr;
delete renderer;
}

void TRenderer::Run( void )
{
//camPtr = renderer->CameraFromView();
renderer->Update( deltaTime );
renderer->Render( mapRenderFlags );

@@ -44,16 +45,44 @@ void TRenderer::Load( void )
renderer->Prep();
renderer->Load( mapFilepath, mapLoadFlags );
camPtr = renderer->camera;

lightSamplerPos =
( renderer->map->data.models[ 0 ].boxMin + renderer->map->data.models[ 0 ].boxMax ) * 0.5f;
}

void TRenderer::OnKeyPress( int key, int scancode, int action, int mods )
{
Test::OnKeyPress( key, scancode, action, mods );

static const float ofsStep = 20.0f;

if ( action == GLFW_PRESS )
{
switch ( key )
{
/*
case GLFW_KEY_RIGHT:
lightSamplerPos.x += ofsStep;
renderer->lightSampler.SetOrigin( lightSamplerPos );
break;
case GLFW_KEY_UP:
lightSamplerPos.z -= ofsStep;
renderer->lightSampler.SetOrigin( lightSamplerPos );
break;
case GLFW_KEY_LEFT:
lightSamplerPos.x -= ofsStep;
renderer->lightSampler.SetOrigin( lightSamplerPos );
break;
case GLFW_KEY_DOWN:
lightSamplerPos.z += ofsStep;
renderer->lightSampler.SetOrigin( lightSamplerPos );
break;
*/


case GLFW_KEY_V:
if ( renderer->curView == VIEW_MAIN )
{
@@ -17,6 +17,8 @@ class TRenderer : public Test
uint32_t mapLoadFlags;
uint32_t mapRenderFlags;

glm::vec3 lightSamplerPos;

void Run( void );

public:
@@ -1,10 +1,12 @@
Build started 6/10/2015 1:33:26 AM.
Build started 6/11/2015 1:18:59 AM.
Project "C:\Dev\bspview\bspviewer\vs\bspview\bspview.vcxproj" on node 2 (Build target(s)).
InitializeBuildStatus:
Creating "Release\bspview.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.
ClCompile:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\CL.exe /c /I"C:\dev\lib\glutil/glew-msvc/include" /IC:\dev\lib\glutil/glm/ /IC:\dev\lib\glutil/glfw3/include /Zi /nologo /W3 /WX /Od /Oy- /D WIN32 /D _CRT_SECURE_NO_WARNINGS /D NDEBUG /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /RTC1 /MD /GS- /Gy- /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Release\\" /Fd"Release\vc120.pdb" /Gd /TP /analyze- /errorReport:prompt ..\..\src\renderer.cpp
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\CL.exe /c /I"C:\dev\lib\glutil/glew-msvc/include" /IC:\dev\lib\glutil/glm/ /IC:\dev\lib\glutil/glfw3/include /Zi /nologo /W3 /WX /Od /Oy- /D WIN32 /D _CRT_SECURE_NO_WARNINGS /D NDEBUG /D _WINDOWS /D _UNICODE /D UNICODE /Gm- /EHsc /RTC1 /MD /GS- /Gy- /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Release\\" /Fd"Release\vc120.pdb" /Gd /TP /analyze- /errorReport:prompt ..\..\src\renderer.cpp ..\..\src\tests\trenderer.cpp
renderer.cpp
trenderer.cpp
Generating Code...
Link:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"C:\Dev\bspview\bspviewer\vs\bspview\Release\bspview.exe" /INCREMENTAL:NO /NOLOGO /LIBPATH:"C:\dev\lib\glutil/glew-msvc/lib/Release/Win32/" /LIBPATH:"C:\dev\lib\glutil/glfw3/lib-vc2012/x86/" opengl32.lib glu32.lib glew32.lib glfw3dll.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"C:\Dev\bspview\bspviewer\vs\bspview\Release\bspview.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"C:\Dev\bspview\bspviewer\vs\bspview\Release\bspview.lib" /MACHINE:X86 /SAFESEH Release\aabb.obj
Release\deform.obj
@@ -32,4 +34,4 @@ Done Building Project "C:\Dev\bspview\bspviewer\vs\bspview\bspview.vcxproj" (Bui

Build succeeded.

Time Elapsed 00:00:01.28
Time Elapsed 00:00:02.11
BIN +0 Bytes (100%) vs/bspview/bspview.v12.suo
Binary file not shown.
@@ -117,7 +117,6 @@
<ClCompile Include="..\..\src\shader.cpp" />
<ClCompile Include="..\..\src\tests\test.cpp" />
<ClCompile Include="..\..\src\tests\trenderer.cpp" />
<None Include="..\..\src\lightsample.vert" />
<None Include="..\..\src\model.frag" />
<None Include="..\..\src\model.vert" />
</ItemGroup>