Skip to content

Commit

Permalink
PrimitiveBatch3D
Browse files Browse the repository at this point in the history
  • Loading branch information
Daivuk committed Dec 29, 2023
1 parent dd22aa6 commit 769a823
Show file tree
Hide file tree
Showing 5 changed files with 352 additions and 1 deletion.
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ list(APPEND src_files
src/Point.cpp
src/Pool.cpp
src/PrimitiveBatch.cpp
src/PrimitiveBatch3D.cpp
src/Random.cpp
src/Ray.cpp
src/Renderer.cpp
Expand Down Expand Up @@ -251,7 +252,9 @@ list(APPEND src_files
src/zlib/zutil.c
)

add_library(libonut STATIC ${src_files})
file(GLOB inc_files ./include/onut/*.h)

add_library(libonut STATIC ${src_files} ${inc_files})

# Libraries
list(APPEND includes
Expand Down
74 changes: 74 additions & 0 deletions include/onut/PrimitiveBatch3D.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef PRIMITIVEBATCH3D_H_INCLUDED
#define PRIMITIVEBATCH3D_H_INCLUDED

// Onut
#include <onut/Maths.h>
#include <onut/PrimitiveMode.h>

// Forward declares
#include <onut/ForwardDeclaration.h>
OForwardDeclare(PrimitiveBatch3D);
OForwardDeclare(Shader);
OForwardDeclare(Texture);
OForwardDeclare(VertexBuffer);

namespace onut
{
class RenderStates;

class PrimitiveBatch3D
{
public:
static OPrimitiveBatch3DRef create();

PrimitiveBatch3D();
virtual ~PrimitiveBatch3D();

void begin(PrimitiveMode primitiveType, const OTextureRef& pTexture = nullptr, const Matrix& transform = Matrix::Identity);
void draw(const Vector3& position, const Color& color = Color::White, const Vector3& normal = Vector3::Up, const Vector2& texCoord = Vector2::Zero);

// Only for line lists
void drawPoint(const Vector3& position, float radius, const Color& color = Color::White);
void drawCube(const Vector3& position, float extends, const Color& color = Color::White);
void drawSphere(const Vector3& position, float radius, const Color& color = Color::White);
void drawArrow(const Vector3& start, const Vector3& end, float headSize, const Color& color = Color::White);

void end();

private:
struct SVertexP3T2C4
{
Vector3 position;
Vector3 normal;
Vector2 texCoord;
Color color;
};

static const int MAX_VERTEX_COUNT = 1200;
static const int SPHERE_SIDE_COUNT = 24;

void flush();

OVertexBufferRef m_pVertexBuffer;
SVertexP3T2C4* m_pMappedVertexBuffer = nullptr;

unsigned int m_vertexCount = 0;

bool m_isDrawing = false;

OTextureRef m_pTexWhite;
OTextureRef m_pTexture;
OShaderRef m_pVS;
OShaderRef m_pPS;

PrimitiveMode m_primitiveType;
RenderStates *m_pRenderStates = nullptr;

float* m_sinTable = nullptr;
float* m_cosTable = nullptr;
};
}

extern OPrimitiveBatch3DRef oPrimitiveBatch3D;

#endif
233 changes: 233 additions & 0 deletions src/PrimitiveBatch3D.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
// Onut
#include <onut/PrimitiveBatch3D.h>
#include <onut/Renderer.h>
#include <onut/Shader.h>
#include <onut/Texture.h>
#include <onut/VertexBuffer.h>

// Internal
#include "default_shaders.h"

// STL
#include <cassert>

OPrimitiveBatch3DRef oPrimitiveBatch3D;

namespace onut
{
OPrimitiveBatch3DRef PrimitiveBatch3D::create()
{
return OMake<PrimitiveBatch3D>();
}

PrimitiveBatch3D::PrimitiveBatch3D()
{
// Create a white texture for rendering "without" texture
unsigned char white[4] = {255, 255, 255, 255};
m_pTexWhite = OTexture::createFromData(white, {1, 1}, false);

// Vertex buffer.
m_pVertexBuffer = OVertexBuffer::createDynamic(sizeof(SVertexP3T2C4) * MAX_VERTEX_COUNT);

// Shaders
m_pVS = OShader::createFromSource(SHADER_SRC_PRIMITIVE_BATCH_3D_VS, OVertexShader);
m_pPS = OShader::createFromSource(SHADER_SRC_PRIMITIVE_BATCH_3D_PS, OPixelShader);

m_sinTable = new float[SPHERE_SIDE_COUNT + 1];
m_cosTable = new float[SPHERE_SIDE_COUNT + 1];
float inv_r_SPHERE_SIDE_COUNT = (1.0f / SPHERE_SIDE_COUNT) * O2PI;
for (int i = 0; i < SPHERE_SIDE_COUNT; ++i)
{
auto a = (float)i * inv_r_SPHERE_SIDE_COUNT;
m_sinTable[i] = std::sinf(a);
m_cosTable[i] = std::cosf(a);
}
m_sinTable[SPHERE_SIDE_COUNT] = m_sinTable[0];
m_cosTable[SPHERE_SIDE_COUNT] = m_cosTable[0];
}

PrimitiveBatch3D::~PrimitiveBatch3D()
{
delete[] m_sinTable;
delete[] m_cosTable;
}

void PrimitiveBatch3D::begin(PrimitiveMode primitiveType, const OTextureRef& pTexture, const Matrix& transform)
{
assert(!m_isDrawing); // Cannot call begin() twice without calling end()

if (!pTexture) m_pTexture = m_pTexWhite;
else m_pTexture = pTexture;

auto& rs = oRenderer->renderStates;

m_primitiveType = primitiveType;
rs.world = transform;
rs.vertexShader = m_pVS;
rs.pixelShader = m_pPS;
m_isDrawing = true;
m_pRenderStates = &oRenderer->renderStates;

m_pMappedVertexBuffer = reinterpret_cast<SVertexP3T2C4*>(m_pVertexBuffer->map());
}

void PrimitiveBatch3D::draw(const Vector3& position, const Color& color, const Vector3& normal, const Vector2& texCoord)
{
SVertexP3T2C4* pVerts = m_pMappedVertexBuffer + m_vertexCount;
pVerts->position = position;
pVerts->normal = normal;
pVerts->texCoord = texCoord;
pVerts->color = color;

++m_vertexCount;

if (m_vertexCount == MAX_VERTEX_COUNT)
{
if (m_primitiveType == OPrimitiveLineStrip)
{
auto lastVert = *pVerts;

flush();

auto pFirstVert = m_pMappedVertexBuffer;
*pFirstVert = lastVert;
++m_vertexCount;
}
else
{
flush();
}
}
}

void PrimitiveBatch3D::drawPoint(const Vector3& position, float radius, const Color& color)
{
if (m_primitiveType != OPrimitiveLineList) return;

draw(Vector3(position.x - radius, position.y, position.z), color);
draw(Vector3(position.x + radius, position.y, position.z), color);
draw(Vector3(position.x, position.y - radius, position.z), color);
draw(Vector3(position.x, position.y + radius, position.z), color);
draw(Vector3(position.x, position.y, position.z - radius), color);
draw(Vector3(position.x, position.y, position.z + radius), color);
}

void PrimitiveBatch3D::drawCube(const Vector3& position, float radius, const Color& color)
{
if (m_primitiveType != OPrimitiveLineList) return;

// X axis edges
draw(Vector3(position.x - radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z + radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z + radius), color);
draw(Vector3(position.x - radius, position.y - radius, position.z + radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z + radius), color);

// Y axis edges
draw(Vector3(position.x - radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z + radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z + radius), color);
draw(Vector3(position.x - radius, position.y - radius, position.z + radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z + radius), color);

// Z axis edges
draw(Vector3(position.x - radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x - radius, position.y - radius, position.z + radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x - radius, position.y + radius, position.z + radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y + radius, position.z + radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z - radius), color);
draw(Vector3(position.x + radius, position.y - radius, position.z + radius), color);
}

void PrimitiveBatch3D::drawSphere(const Vector3& position, float radius, const Color& color)
{
if (m_primitiveType != OPrimitiveLineList) return;

for (int i = 0; i < SPHERE_SIDE_COUNT; ++i)
{
draw(Vector3(position.x, position.y + m_cosTable[i] * radius, position.z + m_sinTable[i] * radius), color);
draw(Vector3(position.x, position.y + m_cosTable[i + 1] * radius, position.z + m_sinTable[i + 1] * radius), color);
draw(Vector3(position.x + m_cosTable[i] * radius, position.y, position.z + m_sinTable[i] * radius), color);
draw(Vector3(position.x + m_cosTable[i + 1] * radius, position.y, position.z + m_sinTable[i + 1] * radius), color);
draw(Vector3(position.x + m_cosTable[i] * radius, position.y + m_sinTable[i] * radius, position.z), color);
draw(Vector3(position.x + m_cosTable[i + 1] * radius, position.y + m_sinTable[i + 1] * radius, position.z), color);
}
}

void PrimitiveBatch3D::drawArrow(const Vector3& start, const Vector3& end, float headSize, const Color& color)
{
if (m_primitiveType != OPrimitiveLineList) return;

auto dir = end - start;
dir.Normalize();

auto headPos = end - dir * headSize;

draw(start, color);
draw(headPos, color);

Vector3 right;
if (dir.z >= 0.7f)
right = dir.Cross(Vector3::Right);
else
right = dir.Cross(Vector3::Up);

right.Normalize();
auto front = right.Cross(dir);

auto radius = headSize * 0.5f;
for (int i = 0; i < SPHERE_SIDE_COUNT; i += 2)
{
draw(headPos + right * m_sinTable[i] * radius + front * m_cosTable[i] * radius, color);
draw(headPos + right * m_sinTable[i + 2] * radius + front * m_cosTable[i + 2] * radius, color);
}

draw(headPos + right * m_sinTable[0] * radius + front * m_cosTable[0] * radius, color);
draw(end, color);
draw(headPos + right * m_sinTable[SPHERE_SIDE_COUNT / 4] * radius + front * m_cosTable[SPHERE_SIDE_COUNT / 4] * radius, color);
draw(end, color);
draw(headPos + right * m_sinTable[SPHERE_SIDE_COUNT / 2] * radius + front * m_cosTable[SPHERE_SIDE_COUNT / 2] * radius, color);
draw(end, color);
draw(headPos + right * m_sinTable[SPHERE_SIDE_COUNT * 3 / 4] * radius + front * m_cosTable[SPHERE_SIDE_COUNT * 3 / 4] * radius, color);
draw(end, color);
}

void PrimitiveBatch3D::end()
{
assert(m_isDrawing); // Should call begin() before calling end()

m_isDrawing = false;
if (m_vertexCount)
{
flush();
}
m_pVertexBuffer->unmap(sizeof(SVertexP3T2C4) * m_vertexCount);
}

void PrimitiveBatch3D::flush()
{
if (!m_vertexCount)
{
return; // Nothing to flush
}

m_pVertexBuffer->unmap(sizeof(SVertexP3T2C4) * m_vertexCount);

oRenderer->renderStates.textures[0] = m_pTexture;
oRenderer->renderStates.primitiveMode = m_primitiveType;
oRenderer->renderStates.vertexBuffer = m_pVertexBuffer;
oRenderer->draw(m_vertexCount);

m_pMappedVertexBuffer = reinterpret_cast<SVertexP3T2C4*>(m_pVertexBuffer->map());

m_vertexCount = 0;
}
}
38 changes: 38 additions & 0 deletions src/default_shaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,44 @@ static const char* SHADER_DEFERRED_OMNI_PS = ""
" oColor = float4(0.0, 0.0, 0.0, ao * tdiffuse.a);\n" \
"}\n"

static const char* SHADER_SRC_PRIMITIVE_BATCH_3D_VS = ""
" input float3 inPosition;\n"
" input float3 inNormal;\n"
" input float2 inUV;\n"
" input float4 inColor;\n"
"\n"
" output float3 outNormal;\n"
" output float2 outUV;\n"
" output float4 outColor;\n"
"\n"
" void main()\n"
" {\n"
" oPosition = mul(float4(inPosition, 1), oViewProjection);\n"
" outNormal = normalize(mul(oModel, float4(inNormal, 0.0)).xyz);\n"
" outUV = inUV;\n"
" outColor = inColor;\n"
" }\n"
"";

static const char* SHADER_SRC_PRIMITIVE_BATCH_3D_PS = ""
" input float3 inNormal;\n"
" input float2 inUV;\n"
" input float4 inColor;\n"
"\n"
" Texture0 diffuse_texture\n"
" {\n"
" filter = trilinear;\n"
" repeat = wrap;\n"
" }\n"
"\n"
" void main()\n"
" {\n"
" float4 diffuse = diffuse_texture(inUV);\n"
" oColor = saturate(diffuse * inColor);\n"
" }\n"
"";


static const char* SHADER_SSAO_LOW_PS = SSAO_PS(8);
static const char* SHADER_SSAO_MEDIUM_PS = SSAO_PS(16);
static const char* SHADER_SSAO_HIGH_PS = SSAO_PS(32);
3 changes: 3 additions & 0 deletions src/onut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <onut/onut.h>
#include <onut/ParticleSystemManager.h>
#include <onut/PrimitiveBatch.h>
#include <onut/PrimitiveBatch3D.h>
#include <onut/Random.h>
#include <onut/Renderer.h>
#include <onut/Settings.h>
Expand Down Expand Up @@ -141,6 +142,7 @@ namespace onut
// SpriteBatch
if (!oSpriteBatch) oSpriteBatch = SpriteBatch::create();
if (!oPrimitiveBatch) oPrimitiveBatch = PrimitiveBatch::create();
if (!oPrimitiveBatch3D) oPrimitiveBatch3D = PrimitiveBatch3D::create();

// Content
if (!oContentManager) oContentManager = ContentManager::create();
Expand Down Expand Up @@ -227,6 +229,7 @@ namespace onut
//oCloud = nullptr;
oContentManager = nullptr;
oPrimitiveBatch = nullptr;
oPrimitiveBatch3D = nullptr;
oSpriteBatch = nullptr;
oDeferred = nullptr;
oRenderer = nullptr;
Expand Down

0 comments on commit 769a823

Please sign in to comment.