Commit ce1e5732 authored by chili's avatar chili
Browse files

using dynamic vtx layout for suzanne asstest

parent 2b41752b
......@@ -13,46 +13,16 @@
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include "Vertex.h"
namespace dx = DirectX;
GDIPlusManager gdipm;
void f()
{
VertexBuffer vb( std::move(
VertexLayout{}
.Append<VertexLayout::Position3D>()
.Append<VertexLayout::Normal>()
.Append<VertexLayout::Texture2D>()
) );
vb.EmplaceBack(
dx::XMFLOAT3{1.0f,1.0f,5.0f},
dx::XMFLOAT3{ 2.0f,1.0f,4.0f },
dx::XMFLOAT2{ 6.0f,9.0f }
);
vb.EmplaceBack(
dx::XMFLOAT3{ 6.0f,9.0f,6.0f },
dx::XMFLOAT3{ 9.0f,6.0f,9.0f },
dx::XMFLOAT2{ 4.2f,0.0f }
);
auto pos = vb[0].Attr<VertexLayout::Position3D>();
auto nor = vb[0].Attr<VertexLayout::Normal>();
auto tex = vb[1].Attr<VertexLayout::Texture2D>();
vb.Back().Attr<VertexLayout::Position3D>().z = 420.0f;
pos = vb.Back().Attr<VertexLayout::Position3D>();
const auto& cvb = vb;
pos = cvb[1].Attr<VertexLayout::Position3D>();
}
App::App()
:
wnd( 800,600,"The Donkey Fart Box" ),
light( wnd.Gfx() )
{
f();
class Factory
{
public:
......
......@@ -4,6 +4,7 @@
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include "Vertex.h"
AssTest::AssTest( Graphics& gfx,std::mt19937& rng,
std::uniform_real_distribution<float>& adist,
......@@ -19,11 +20,12 @@ AssTest::AssTest( Graphics& gfx,std::mt19937& rng,
if( !IsStaticInitialized() )
{
struct Vertex
{
dx::XMFLOAT3 pos;
dx::XMFLOAT3 n;
};
using hw3dexp::VertexLayout;
hw3dexp::VertexBuffer vbuf( std::move(
VertexLayout{}
.Append<VertexLayout::Position3D>()
.Append<VertexLayout::Normal>()
));
Assimp::Importer imp;
const auto pModel = imp.ReadFile( "models\\suzanne.obj",
......@@ -32,14 +34,12 @@ AssTest::AssTest( Graphics& gfx,std::mt19937& rng,
);
const auto pMesh = pModel->mMeshes[0];
std::vector<Vertex> vertices;
vertices.reserve( pMesh->mNumVertices );
for( unsigned int i = 0; i < pMesh->mNumVertices; i++ )
{
vertices.push_back( {
{ pMesh->mVertices[i].x * scale,pMesh->mVertices[i].y * scale,pMesh->mVertices[i].z * scale },
vbuf.EmplaceBack(
dx::XMFLOAT3{ pMesh->mVertices[i].x * scale,pMesh->mVertices[i].y * scale,pMesh->mVertices[i].z * scale },
*reinterpret_cast<dx::XMFLOAT3*>(&pMesh->mNormals[i])
} );
);
}
std::vector<unsigned short> indices;
......@@ -53,7 +53,7 @@ AssTest::AssTest( Graphics& gfx,std::mt19937& rng,
indices.push_back( face.mIndices[2] );
}
AddStaticBind( std::make_unique<VertexBuffer>( gfx,vertices ) );
AddStaticBind( std::make_unique<VertexBuffer>( gfx,vbuf ) );
AddStaticIndexBuffer( std::make_unique<IndexBuffer>( gfx,indices ) );
......
......@@ -3,291 +3,298 @@
#include <DirectXMath.h>
#include <type_traits>
struct BGRAColor
namespace hw3dexp
{
unsigned char a;
unsigned char r;
unsigned char g;
unsigned char b;
};
class VertexLayout
{
public:
enum ElementType
struct BGRAColor
{
Position2D,
Position3D,
Texture2D,
Normal,
Float3Color,
Float4Color,
BGRAColor,
unsigned char a;
unsigned char r;
unsigned char g;
unsigned char b;
};
class Element
class VertexLayout
{
public:
Element( ElementType type,size_t offset )
:
type( type ),
offset( offset )
{}
size_t GetOffsetAfter() const noexcept(!IS_DEBUG)
enum ElementType
{
Position2D,
Position3D,
Texture2D,
Normal,
Float3Color,
Float4Color,
BGRAColor,
};
class Element
{
public:
Element( ElementType type,size_t offset )
:
type( type ),
offset( offset )
{}
size_t GetOffsetAfter() const noexcept(!IS_DEBUG)
{
return offset + Size();
}
size_t GetOffset() const
{
return offset;
}
size_t Size() const noexcept(!IS_DEBUG)
{
return SizeOf( type );
}
static constexpr size_t SizeOf( ElementType type ) noexcept(!IS_DEBUG)
{
using namespace DirectX;
switch( type )
{
case Position2D:
return sizeof( XMFLOAT2 );
case Position3D:
return sizeof( XMFLOAT3 );
case Texture2D:
return sizeof( XMFLOAT2 );
case Normal:
return sizeof( XMFLOAT3 );
case Float3Color:
return sizeof( XMFLOAT3 );
case Float4Color:
return sizeof( XMFLOAT3 );
case BGRAColor:
return sizeof( hw3dexp::BGRAColor );
}
assert( "Invalid element type" && false );
return 0u;
}
ElementType GetType() const noexcept
{
return type;
}
private:
ElementType type;
size_t offset;
};
public:
template<ElementType Type>
const Element& Resolve() const noexcept(!IS_DEBUG)
{
return offset + Size();
for( auto& e : elements )
{
if( e.GetType() == Type )
{
return e;
}
}
assert( "Could not resolve element type" && false );
return elements.front();
}
const Element& ResolveByIndex( size_t i ) const noexcept(!IS_DEBUG)
{
return elements[i];
}
size_t GetOffset() const
template<ElementType Type>
VertexLayout& Append() noexcept(!IS_DEBUG)
{
return offset;
elements.emplace_back( Type,Size() );
return *this;
}
size_t Size() const noexcept(!IS_DEBUG)
{
return SizeOf( type );
return elements.empty() ? 0u : elements.back().GetOffsetAfter();
}
size_t GetElementCount() const noexcept
{
return elements.size();
}
private:
std::vector<Element> elements;
};
class Vertex
{
friend class VertexBuffer;
public:
template<VertexLayout::ElementType Type>
auto& Attr() noexcept(!IS_DEBUG)
{
using namespace DirectX;
const auto& element = layout.Resolve<Type>();
auto pAttribute = pData + element.GetOffset();
if constexpr( Type == VertexLayout::Position2D )
{
return *reinterpret_cast<XMFLOAT2*>(pAttribute);
}
else if constexpr( Type == VertexLayout::Position3D )
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
}
else if constexpr( Type == VertexLayout::Texture2D )
{
return *reinterpret_cast<XMFLOAT2*>(pAttribute);
}
else if constexpr( Type == VertexLayout::Normal )
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
}
else if constexpr( Type == VertexLayout::Float3Color )
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
}
else if constexpr( Type == VertexLayout::Float4Color )
{
return *reinterpret_cast<XMFLOAT4*>(pAttribute);
}
else if constexpr( Type == VertexLayout::BGRAColor )
{
return *reinterpret_cast<BGRAColor*>(pAttribute);
}
else
{
assert( "Bad element type" && false );
return *reinterpret_cast<char*>(pAttribute);
}
}
static constexpr size_t SizeOf( ElementType type ) noexcept(!IS_DEBUG)
template<typename T>
void SetAttributeByIndex( size_t i,T&& val ) noexcept(!IS_DEBUG)
{
using namespace DirectX;
switch( type )
const auto& element = layout.ResolveByIndex( i );
auto pAttribute = pData + element.GetOffset();
switch( element.GetType() )
{
case Position2D:
return sizeof( XMFLOAT2 );
case Position3D:
return sizeof( XMFLOAT3 );
case Texture2D:
return sizeof( XMFLOAT2 );
case Normal:
return sizeof( XMFLOAT3 );
case Float3Color:
return sizeof( XMFLOAT3 );
case Float4Color:
return sizeof( XMFLOAT3 );
case BGRAColor:
return sizeof( ::BGRAColor );
case VertexLayout::Position2D:
SetAttribute<XMFLOAT2>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Position3D:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Texture2D:
SetAttribute<XMFLOAT2>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Normal:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Float3Color:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Float4Color:
SetAttribute<XMFLOAT4>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::BGRAColor:
SetAttribute<BGRAColor>( pAttribute,std::forward<T>( val ) );
break;
default:
assert( "Bad element type" && false );
}
assert( "Invalid element type" && false );
return 0u;
}
ElementType GetType() const noexcept
protected:
Vertex( char* pData,const VertexLayout& layout ) noexcept(!IS_DEBUG)
:
pData( pData ),
layout( layout )
{
return type;
assert( pData != nullptr );
}
private:
ElementType type;
size_t offset;
};
public:
template<ElementType Type>
const Element& Resolve() const noexcept(!IS_DEBUG)
{
for( auto& e : elements )
template<typename First,typename ...Rest>
// enables parameter pack setting of multiple parameters by element index
void SetAttributeByIndex( size_t i,First&& first,Rest&&... rest ) noexcept(!IS_DEBUG)
{
SetAttributeByIndex( i,std::forward<First>( first ) );
SetAttributeByIndex( i + 1,std::forward<Rest>( rest )... );
}
// helper to reduce code duplication in SetAttributeByIndex
template<typename Dest,typename Src>
void SetAttribute( char* pAttribute,Src&& val ) noexcept(!IS_DEBUG)
{
if( e.GetType() == Type )
if constexpr( std::is_assignable<Dest,Src>::value )
{
return e;
*reinterpret_cast<Dest*>(pAttribute) = val;
}
else
{
assert( "Parameter attribute type mismatch" && false );
}
}
assert( "Could not resolve element type" && false );
return elements.front();
}
const Element& ResolveByIndex( size_t i ) const noexcept(!IS_DEBUG)
{
return elements[i];
}
template<ElementType Type>
VertexLayout& Append() noexcept(!IS_DEBUG)
{
elements.emplace_back( Type,Size() );
return *this;
}
size_t Size() const noexcept(!IS_DEBUG)
{
return elements.empty() ? 0u : elements.back().GetOffsetAfter();
}
size_t GetElementCount() const noexcept
{
return elements.size();
}
private:
std::vector<Element> elements;
};
private:
char* pData = nullptr;
const VertexLayout& layout;
};
class Vertex
{
friend class VertexBuffer;
public:
template<VertexLayout::ElementType Type>
auto& Attr() noexcept(!IS_DEBUG)
class ConstVertex
{
using namespace DirectX;
const auto& element = layout.Resolve<Type>();
auto pAttribute = pData + element.GetOffset();
if constexpr( Type == VertexLayout::Position2D )
public:
ConstVertex( const Vertex& v ) noexcept(!IS_DEBUG)
:
vertex( v )
{}
template<VertexLayout::ElementType Type>
const auto& Attr() const noexcept(!IS_DEBUG)
{
return *reinterpret_cast<XMFLOAT2*>(pAttribute);
return const_cast<Vertex&>(vertex).Attr<Type>();
}
else if constexpr( Type == VertexLayout::Position3D )
private:
Vertex vertex;
};
class VertexBuffer
{
public:
VertexBuffer( VertexLayout layout ) noexcept(!IS_DEBUG)
:
layout( std::move( layout ) )
{}
const char* GetData() const noexcept(!IS_DEBUG)
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
return buffer.data();
}
else if constexpr( Type == VertexLayout::Texture2D )
const VertexLayout& GetLayout() const noexcept
{
return *reinterpret_cast<XMFLOAT2*>(pAttribute);
return layout;
}
else if constexpr( Type == VertexLayout::Normal )
size_t Size() const noexcept(!IS_DEBUG)
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
return buffer.size() / layout.Size();
}
else if constexpr( Type == VertexLayout::Float3Color )
template<typename ...Params>
void EmplaceBack( Params&&... params ) noexcept(!IS_DEBUG)
{
return *reinterpret_cast<XMFLOAT3*>(pAttribute);
assert( sizeof...(params) == layout.GetElementCount() && "Param count doesn't match number of vertex elements" );
buffer.resize( buffer.size() + layout.Size() );
Back().SetAttributeByIndex( 0u,std::forward<Params>( params )... );
}
else if constexpr( Type == VertexLayout::Float4Color )
Vertex Back() noexcept(!IS_DEBUG)
{
return *reinterpret_cast<XMFLOAT4*>(pAttribute);
assert( buffer.size() != 0u );
return Vertex{ buffer.data() + buffer.size() - layout.Size(),layout };
}
else if constexpr( Type == VertexLayout::BGRAColor )
Vertex Front() noexcept(!IS_DEBUG)
{
return *reinterpret_cast<BGRAColor*>(pAttribute);
assert( buffer.size() != 0u );
return Vertex{ buffer.data(),layout };
}
else
Vertex operator[]( size_t i ) noexcept(!IS_DEBUG)
{
assert( "Bad element type" && false );
return *reinterpret_cast<char*>(pAttribute);
assert( i < Size() );
return Vertex{ buffer.data() + layout.Size() * i,layout };
}
}
template<typename T>
void SetAttributeByIndex( size_t i,T&& val ) noexcept(!IS_DEBUG)
{
using namespace DirectX;
const auto& element = layout.ResolveByIndex( i );
auto pAttribute = pData + element.GetOffset();
switch( element.GetType() )
ConstVertex Back() const noexcept(!IS_DEBUG)
{
case VertexLayout::Position2D:
SetAttribute<XMFLOAT2>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Position3D:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Texture2D:
SetAttribute<XMFLOAT2>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Normal:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Float3Color:
SetAttribute<XMFLOAT3>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::Float4Color:
SetAttribute<XMFLOAT4>( pAttribute,std::forward<T>( val ) );
break;
case VertexLayout::BGRAColor:
SetAttribute<BGRAColor>( pAttribute,std::forward<T>( val ) );
break;
default:
assert( "Bad element type" && false );
}
}
protected:
Vertex( char* pData,const VertexLayout& layout ) noexcept(!IS_DEBUG)
:
pData( pData ),
layout( layout )
{
assert( pData != nullptr );
}
private:
template<typename First,typename ...Rest>
// enables parameter pack setting of multiple parameters by element index
void SetAttributeByIndex( size_t i,First&& first,Rest&&... rest ) noexcept(!IS_DEBUG)
{
SetAttributeByIndex( i,std::forward<First>( first ) );
SetAttributeByIndex( i + 1,std::forward<Rest>( rest )... );
}
// helper to reduce code duplication in SetAttributeByIndex
template<typename Dest,typename Src>
void SetAttribute( char* pAttribute,Src&& val ) noexcept(!IS_DEBUG)
{
if constexpr( std::is_assignable<Dest,Src>::value )
return const_cast<VertexBuffer*>(this)->Back();
}
ConstVertex Front() const noexcept(!IS_DEBUG)
{
*reinterpret_cast<Dest*>(pAttribute) = val;
return const_cast<VertexBuffer*>(this)->Front();
}
else
ConstVertex operator[]( size_t i ) const noexcept(!IS_DEBUG)
{
assert( "Parameter attribute type mismatch" && false );
return const_cast<VertexBuffer&>(*this)[i];
}
}
private:
char* pData = nullptr;
const VertexLayout& layout;
};
class ConstVertex
{
public:
ConstVertex( const Vertex& v ) noexcept(!IS_DEBUG)
:
vertex( v )
{}
template<VertexLayout::ElementType Type>
const auto& Attr() const noexcept(!IS_DEBUG)
{
return const_cast<Vertex&>(vertex).Attr<Type>();
}
private:
Vertex vertex;
};
class VertexBuffer
{
public:
VertexBuffer( VertexLayout layout ) noexcept(!IS_DEBUG)
:
layout( std::move( layout ) )
{}
const VertexLayout& GetLayout() const noexcept
{
return layout;
}
size_t Size() const noexcept(!IS_DEBUG)
{
return buffer.size() / layout.Size();
}
template<typename ...Params>
void EmplaceBack( Params&&... params ) noexcept(!IS_DEBUG)
{
assert( sizeof...(params) == layout.GetElementCount() && "Param count doesn't match number of vertex elements" );
buffer.resize( buffer.size() + layout.Size() );
Back().SetAttributeByIndex( 0u,std::forward<Params>( params )... );
}
Vertex Back() noexcept(!IS_DEBUG)
{
assert( buffer.size() != 0u );
return Vertex{ buffer.data() + buffer.size() - layout.Size(),layout };
}
Vertex Front() noexcept(!IS_DEBUG)
{
assert( buffer.size() != 0u );
return Vertex{ buffer.data(),layout };
}
Vertex operator[]( size_t i ) noexcept(!IS_DEBUG)
{
assert( i < Size() );
return Vertex{ buffer.data() + layout.Size() * i,layout };
}
ConstVertex Back() const noexcept(!IS_DEBUG)
{
return const_cast<VertexBuffer*>(this)->Back();
}
ConstVertex Front() const noexcept(!IS_DEBUG)
{
return const_cast<VertexBuffer*>(this)->Front();
}
ConstVertex operator[]( size_t i ) const noexcept(!IS_DEBUG)
{
return const_cast<VertexBuffer&>(*this)[i];
}
private:
std::vector<char> buffer;
VertexLayout layout;
};
\ No newline at end of file
private:
std::vector<char> buffer;
VertexLayout layout;
};
}
\ No newline at end of file
#pragma once
#include "Bindable.h"
#include "GraphicsThrowMacros.h"
#include "Vertex.h"
class VertexBuffer : public Bindable
{
......@@ -23,6 +24,23 @@ public:
sd.pSysMem = vertices.data();
GFX_THROW_INFO( GetDevice( gfx )->CreateBuffer( &bd,&sd,&pVertexBuffer ) );
}
VertexBuffer( Graphics& gfx,const hw3dexp::VertexBuffer& vbuf )
:
stride( (UINT)vbuf.GetLayout().Size() )
{
INFOMAN( gfx );
D3D11_BUFFER_DESC bd = {};
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.Usage = D3D11_USAGE_DEFAULT;
bd.CPUAccessFlags = 0u;
bd.MiscFlags = 0u;
bd.ByteWidth = UINT( vbuf.Size() );
bd.StructureByteStride = stride;
D3D11_SUBRESOURCE_DATA sd = {};
sd.pSysMem = vbuf.GetData();
GFX_THROW_INFO( GetDevice( gfx )->CreateBuffer( &bd,&sd,&pVertexBuffer ) );
}
void Bind( Graphics& gfx ) noexcept override;
protected:
UINT stride;
......
......@@ -182,8 +182,8 @@
<ClInclude Include="Texture.h" />
<ClInclude Include="Topology.h" />
<ClInclude Include="TransformCbuf.h" />
<ClInclude Include="Vertex.h" />
<ClInclude Include="VertexBuffer.h" />
<ClInclude Include="VertexLayout.h" />
<ClInclude Include="VertexShader.h" />
<ClInclude Include="Window.h" />
<ClInclude Include="WindowsMessageMap.h" />
......
......@@ -326,7 +326,7 @@
<ClInclude Include="AssTest.h">
<Filter>Header Files\Drawable</Filter>
</ClInclude>
<ClInclude Include="VertexLayout.h">
<ClInclude Include="Vertex.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment