Files
Webcam/include/engine/gpu/gpu_renderer.cpp

463 lines
13 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "gpu/gpu_renderer.h"
#include "core/renderer_environment_interface.h"
#include "core/renderer_resource_factory.h"
#include "core/camera.h"
using namespace GS;
using namespace GS::GPU;
using Render::TextureParm;
//------------------------------------------------------------------------------
void Renderer::SetViewMatrix(const Matrix4 &m, const Matrix4 *inverse)
{
m_view = m;
m_iview = inverse ? *inverse : m.InversedFast();
}
void Renderer::SetProjectionMatrix(const Matrix4 &m)
{ m_projection = m; }
void Renderer::SetWorldMatrix(const Matrix4 &m, const Matrix4 *inverse)
{
m_world = m;
m_iworld = inverse ? *inverse : m.InversedFast();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int Renderer::GetAnisotropySampleCount(TextureParm::Anisotropy aniso) const
{
uint sample = 1;
switch (aniso)
{
default:
sample = registry.GetInteger("Texture:Filtering:Sample", 4);
break;
case TextureParm::AnisotropyNone: sample = 1; break;
case TextureParm::Anisotropy2x: sample = 2; break;
case TextureParm::Anisotropy4x: sample = 4; break;
case TextureParm::Anisotropy8x: sample = 8; break;
case TextureParm::Anisotropy16x: sample = 16; break;
}
if (sample > gpu_config.max_anisotropy)
sample = gpu_config.max_anisotropy;
return sample;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::SetDisplayList(DisplayList *dlist)
{
SetIndexSource(dlist ? dlist->idx.c_ptr() : NULL);
SetVertexSource(dlist ? dlist->vtx.c_ptr() : NULL, dlist ? dlist->stride : 0);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::SetMaterial(const GPU::Material &m, const DrawContext::Context &ctx, bool force_alpha)
{
bool fog_enabled = (environment_interface != NULL) && environment_interface->IsFogEnabled();
if (m.renderword & Core::Material::Render_DoubleSided)
EnableCulling(false);
if (m.renderword & Core::Material::Render_AlphaTest)
if (gpu_config.enable_aa)
EnableAlphaToCoverage(true);
uint blendop = m.blendop;
if ((blendop == Core::Material::Blend_None) && force_alpha)
blendop = Core::Material::Blend_Alpha;
switch (ctx.render)
{
case DrawContext::Deferred:
case DrawContext::Opaque:
break;
case DrawContext::Alpha:
switch (ctx.draw)
{
case DrawContext::Base:
switch (blendop)
{
case Core::Material::Blend_Add:
if (fog_enabled)
SetBlendFunc(BlendSrcAlpha, BlendOne);
else
SetBlendFunc(BlendOne, BlendOne);
break;
case Core::Material::Blend_Alpha:
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
break;
}
break;
case DrawContext::Light:
switch (blendop)
{
case Core::Material::Blend_Add:
if (fog_enabled)
SetBlendFunc(BlendSrcAlpha, BlendOne);
else
SetBlendFunc(BlendOne, BlendOne);
break;
case Core::Material::Blend_Alpha:
SetBlendFunc(BlendSrcAlpha, BlendOne);
break;
}
break;
}
}
}
void Renderer::UnsetMaterial(const GPU::Material &m, const DrawContext::Context &ctx)
{
if (m.renderword & Core::Material::Render_DoubleSided)
EnableCulling(true);
if (m.renderword & Core::Material::Render_AlphaTest)
if (gpu_config.enable_aa)
EnableAlphaToCoverage(false);
switch (ctx.render)
{
case DrawContext::Deferred:
case DrawContext::Opaque:
break;
case DrawContext::Alpha:
switch (ctx.draw)
{
case DrawContext::Base:
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
break;
case DrawContext::Light:
SetBlendFunc(BlendSrcAlpha, BlendOne);
break;
}
break;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::DrawSetState(Core::Material::BlendOperator bo, Core::Material::RenderWord f)
{
switch (bo)
{
default:
case Core::Material::Blend_None:
break;
case Core::Material::Blend_Alpha:
EnableBlending(true);
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
break;
case Core::Material::Blend_Add:
EnableBlending(true);
SetBlendFunc(BlendSrcAlpha, BlendOne);
break;
}
EnableDepthWrite(!asbool(f & Core::Material::Render_NoZWrite));
EnableDepthTest(!asbool(f & Core::Material::Render_NoZTest));
EnableCulling(!asbool(f & Core::Material::Render_DoubleSided));
}
void Renderer::DrawRestoreState(Core::Material::BlendOperator bo, Core::Material::RenderWord f)
{
EnableCulling(true);
EnableDepthTest(true);
EnableDepthWrite(true);
if (bo != Core::Material::Blend_None)
{
EnableBlending(false);
SetBlendFunc(BlendSrcAlpha, BlendOneMinusSrcAlpha);
}
}
void Renderer::DrawLine(uint count, const Vector4 *v, const Color *c, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p)
{
DrawSetState(bo, f);
// Dispatch inputs to the correct program.
Shader *p = (Shader *)r_p;
if (p == NULL)
{
p = c ? single_color_program : simple_program;
if (!p)
return;
}
SetShaderProgram(p);
ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position),
*color_parm = p->GetInput(Core::ShaderInput::VertexColor);
SetIndexSource(NULL); // FIXME broken on the DirectX back-end
SetVertexSource(NULL, 0); // FIXME broken on the DirectX back-end
if (vtx_parm)
p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)v);
if (color_parm && c)
p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)c);
p->SetRendererInputs(*this);
p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld);
DrawElements(Types::PrimitiveLine, 2 * count);
if (vtx_parm)
p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL);
if (color_parm)
p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL);
DrawRestoreState(bo, f);
}
void Renderer::DrawTriangle(uint count, const Vector4 *v, const ushort *idx, const Color *c, const Vector2 *uv, const Render::Texture *t, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p)
{
DrawSetState(bo, f);
// Dispatch inputs to the correct program.
Shader *p = (Shader *)r_p;
if (p == NULL)
{
if (c)
p = t ? single_texture_color_program : single_color_program;
else
if (t)
p = single_texture_program;
if (!p)
return;
}
SetShaderProgram(p);
// If no indice were provided, assume a linear attribute array.
Array <ushort> indice;
if (!idx)
if (indice.Allocate(count * 3))
{
idx = indice;
for (uint n = 0; n < count * 3; ++n)
indice[n] = ushort(n);
}
// Set program inputs.
ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position),
*uv_parm = p->GetInput(Core::ShaderInput::UV0),
*color_parm = p->GetInput(Core::ShaderInput::VertexColor),
*texture_parm = p->GetInput(Core::ShaderInput::Texture2D);
if (gpu_config.can_stream_vertex_from_memory)
{
SetIndexSource(NULL);
SetVertexSource(NULL, 0);
if (vtx_parm)
p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)v);
if (uv_parm && uv)
p->Set(*uv_parm->location, 2, Types::ValueFloat, false, sizeof(Vector2), (const void *)uv);
if (color_parm && c)
p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)c);
}
else
{
DirectVertexLayout layout;
BuildDirectVertexLayout(count * 3, idx, v, c, uv, layout, direct_idx_vbo, direct_vtx_vbo);
SetIndexSource(direct_idx_vbo);
SetVertexSource(direct_vtx_vbo, layout.stride);
if (vtx_parm)
p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, layout.stride, (const void *)layout.vtx_offset);
if (uv_parm && uv)
p->Set(*uv_parm->location, 2, Types::ValueFloat, false, layout.stride, (const void *)layout.uv_offset);
if (color_parm && c)
p->Set(*color_parm->location, 4, Types::ValueUByte, true, layout.stride, (const void *)layout.color_offset);
}
if (texture_parm && t)
p->Set(*texture_parm->location, *t, texture_parm->index);
p->SetRendererInputs(*this);
p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld);
p->CommitInputs();
DrawElements(Types::PrimitiveTriangle, count * 3, Types::ValueUShort, gpu_config.can_stream_vertex_from_memory ? idx : 0);
if (vtx_parm)
p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL);
if (uv_parm)
p->Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL);
if (color_parm)
p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL);
DrawRestoreState(bo, f);
stats.triangle_drawn += count;
}
void Renderer::DrawSprite(uint count, const Vector4 *v, const Color *c, const float *s, const Render::Texture *t, float g_size, Core::Material::BlendOperator bo, Core::Material::RenderWord f, Render::Shader *r_p)
{
Array <Vector4> sprite_p;
Array <Color> sprite_c;
Array <Vector2> sprite_uv;
Array <ushort> sprite_idx;
Shader *p = (Shader *)r_p;
if (p == NULL)
p = simple_program;
// Setup display list.
if (!sprite_p.Allocate(count * 4) || !sprite_idx.Allocate(count * 3 * 2))
return;
Vector4 *p_v = sprite_p.c_ptr();
ushort *idx = sprite_idx.c_ptr();
Vector4 left = m_view.GetRow(0),
up = m_view.GetRow(1);
if (s)
for (uint n = 0; n < count; ++n)
{
register float k = g_size * s[n];
Vector4 uml = (up - left) * k;
Vector4 lpu = (left + up) * k;
Vector4 lmu = (left - up) * k;
*p_v++ = v[n] + uml;
*p_v++ = v[n] + lpu;
*p_v++ = v[n] + lmu;
*p_v++ = v[n] - lpu;
}
else
for (uint n = 0; n < count; ++n)
{
Vector4 uml = (up - left) * g_size;
Vector4 lpu = (left + up) * g_size;
Vector4 lmu = (left - up) * g_size;
*p_v++ = v[n] + uml;
*p_v++ = v[n] + lpu;
*p_v++ = v[n] + lmu;
*p_v++ = v[n] - lpu;
}
for (ushort n = 0; n < count; ++n)
{
ushort s = (ushort)(n << 2);
*idx++ = s; *idx++ = s + 1; *idx++ = s + 2;
*idx++ = s; *idx++ = s + 2; *idx++ = s + 3;
}
if (c) // Color.
{
if (!sprite_c.Allocate(count * 4))
return;
Color *p_c = sprite_c.c_ptr();
for (uint n = 0; n < count; ++n)
{
const Color &cl = c[n];
for (uint i = 0; i < 4; ++i)
*p_c++ = cl;
}
p = single_color_program;
}
if (t) // Texture.
{
if (!sprite_uv.Allocate(count * 4))
return;
Vector2 *p_uv = sprite_uv.c_ptr();
for (uint n = 0; n < count; ++n)
{
p_uv[0].Set(0, 0); p_uv[1].Set(1, 0);
p_uv[2].Set(1, 1); p_uv[3].Set(0, 1);
p_uv += 4;
}
p = c ? single_texture_color_program : single_texture_program;
}
// Compute aspect ratio.
Matrix4 m_ar;
if (view_item)
m_ar = Matrix4::ScaleMatrix(view_item->ComputeAspectRatioCorrection(viewport));
else m_ar = Matrix4::ScaleMatrix(Vector4(viewport.GetHeight() / viewport.GetWidth(), 1, 0, 1));
// Set program inputs.
DrawSetState(bo, f);
SetShaderProgram(p);
ShaderInput *vtx_parm = p->GetInput(Core::ShaderInput::Position),
*uv_parm = p->GetInput(Core::ShaderInput::UV0),
*color_parm = p->GetInput(Core::ShaderInput::VertexColor),
*texture_parm = p->GetInput(Core::ShaderInput::Texture2D);
if (vtx_parm)
p->Set(*vtx_parm->location, 3, Types::ValueFloat, false, sizeof(Vector4), (const void *)sprite_p.c_ptr());
if (uv_parm && t)
p->Set(*uv_parm->location, 2, Types::ValueFloat, false, sizeof(Vector2), (const void *)sprite_uv.c_ptr());
if (color_parm && c)
p->Set(*color_parm->location, 4, Types::ValueFloat, false, sizeof(Color), (const void *)sprite_c.c_ptr());
if (texture_parm && t)
p->Set(*texture_parm->location, *t, texture_parm->index);
p->SetRendererInputs(*this);
p->SetTransformInputs(m_projection, m_view, m_iview, &m_world, &m_iworld);
p->CommitInputs();
DrawElements(Types::PrimitiveTriangle, sprite_idx.GetCount(), Types::ValueUShort, sprite_idx.c_ptr());
if (vtx_parm)
p->Set(*vtx_parm->location, 0, Types::ValueLast, false, 0, NULL);
if (uv_parm)
p->Set(*uv_parm->location, 0, Types::ValueLast, false, 0, NULL);
if (color_parm)
p->Set(*color_parm->location, 0, Types::ValueLast, false, 0, NULL);
DrawRestoreState(bo, f);
stats.triangle_drawn += count * 2;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Renderer::Renderer() : terrain_patch_vtx(Alloc::RendererTerrain), terrain_patch_cache(Alloc::RendererTerrain)
{
core_resource_factory = new Render::RendererResourceFactory(*this);
pending_shadow_map_refresh = false;
pending_core_shader_refresh = false;
render_technique = TechniqueForward;
m_view = Matrix4::IdentityMatrix();
m_iview = Matrix4::IdentityMatrix();
m_world = Matrix4::IdentityMatrix();
m_iworld = Matrix4::IdentityMatrix();
m_projection = Matrix4::IdentityMatrix();
pcf_radius = 1.75f;
frame_clock = 0.f;
clipping.Set(-1, -1, -1, -1);
output_fbo = NULL;
}
//------------------------------------------------------------------------------