commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions

173
include/engine/core/ace.cpp Normal file
View File

@ -0,0 +1,173 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/ace.h"
#include "ascii/parser.h"
#include "log/log.h"
using namespace GS::ACE;
//------------------------------------------------------------------------------
void Manager::UpdateACEUnit(Unit *u, float dt)
{
if (!u->pc)
u->is_done = true;
if (u->is_done)
return;
// Execute sequence until next exec opcode.
bool has_exec_left = false, looped = false;
List <Command> ::Item *cpc;
for (cpc = u->pc; cpc; cpc = cpc->Next())
{
Command *cmd = &cpc->Object();
if (cmd->code == AceCommandExec)
{
cpc = cpc->Next();
break;
}
if (cmd->duration_left > 0.00001)
{
float exec_dt = cmd->duration_left;
if (dt < cmd->duration_left)
{
exec_dt = dt;
has_exec_left = true;
}
u->ExecCommand(cmd, exec_dt);
cmd->duration_left -= exec_dt;
if (cmd->code == AceCommandNext)
looped = true;
}
}
// Sequence done.
if (looped)
{
// We need to reset the looping block commands duration.
for (List <Command> ::Item *lpc = u->loop_pc; lpc != cpc; lpc = lpc->Next())
lpc->Object().duration_left = lpc->Object().duration;
}
else
if (!has_exec_left)
u->pc = cpc;
}
//------------------------------------------------------------------------------
static bool DefineNameCompare(const Define *o, const GS::String &name) { return o->id == name; }
//------------------------------------------------------------------------------
int Manager::LoadACECommandList(const char *s, Unit *u) const
{
if (!s)
__ERR__(__LOG_E__ << "Cannot load a null command list.\n", -1);
u->ResetCommandList();
using namespace AsciiParser;
// Parse command list.
const char *e = s + String::strlen(s);
s = SkipSpace(s, e);
while (s < e)
{
Command &cc = u->list.Add(Command())->Object();
// Read in code.
String command(s, SkipEntry(s, e));
Define *d = ArrayListFindEx(define_list, DefineNameCompare, command);
if (!d)
__ERR__(__LOG_E__ << "Undefined ACE command '" << command << "'.\n", -1);
cc.code = d->code;
// Read in duration.
s = NextEntry(s, e);
if (s == e)
__ERR__(__LOG_E__ << "No duration for ACE command '" << command << "'.\n", -1);
cc.duration = String(s, SkipEntry(s, e)).Float();
if (cc.duration < 0.001f)
cc.duration = 0.001f; // Force minimum duration to 1ms.
cc.duration_left = cc.duration;
// Read up to 3 parameters.
s = NextEntry(s, e);
uint nparm = 0;
while (s < e)
{
if ((s[0] == '+') || (s[0] == ';'))
break;
if (nparm == 3)
__ERR__(__LOG_E__ << "ACE compiled with " << max_command_param << " command parameter(s) maximum.\n", -1);
if (s[0] != ',')
__ERR__(__LOG_E__ << "Expected ',' in ACE list declaration.\n", -1);
s = SkipSpace(s + 1, e);
if (s == e)
__ERR__(__LOG_E__ << "Expected ACE command parameter following ','.\n", -1);
String parm(s, SkipEntry(s, e, true));
cc.parm[nparm++] = parm.Float();
s = SkipSpace(SkipEntry(s, e, true), e);
}
if (s == e)
__ERR__(__LOG_E__ << "Mangled ACE command list.\n", -1);
if ((uint)d->nparm != nparm)
__ERR__(__LOG_E__ << "ACE command '" << command << "' takes " << d->nparm << " parameter(s), found " << nparm << ".\n", -1);
// Output exec command.
if (s[0] == ';')
u->list.Add(Command())->Object().code = AceCommandExec;
s = SkipSpace(s + 1, e); // Skip comma.
}
// Set PC to list root command.
u->is_done = false;
u->pc = u->list.GetRoot();
return u->list.GetCount();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Manager::DefineACECommand(const char *command, int code, int nparm, bool user_code)
{
if (user_code && (code < 0))
__ERR__(__LOG_E__ << "Negative command codes are reserved.\n", false)
Define *d = new Define;
if (!d)
__ERR__(__LOG_E__ << "Failed to allocate new container to define ACE command '" << command << "'.\n", false)
d->id = command;
d->code = code;
d->nparm = nparm;
define_list.Add(d);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Manager::Manager()
{
DefineACECommand("nop", AceCommandNop, 0, false);
DefineACECommand("loop", AceCommandLoop, 0, false);
DefineACECommand("next", AceCommandNext, 0, false);
}
Manager::~Manager()
{
ArrayListDeleteAllPtr(Define *, define_list)
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,63 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/ace.h"
#include "log/log.h"
using namespace GS::ACE;
//------------------------------------------------------------------------------
void Unit::ResetCommandList()
{
list.Clear();
loop_pc = NULL;
pc = NULL;
is_done = true;
}
void Unit::DumpCommandList()
{
for (uint n = 0; n < list.GetCount(); ++n)
{
Command &cmd = list.ObjectAt(n);
__LOG__ << "Command [" << cmd.code << "] : " << cmd.duration << "s, parm = {" << cmd.parm[0] << ", " << cmd.parm[1] << ", " << cmd.parm[2] << "}.\n";
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Unit::ExecCommand(Command *cmd, float dt)
{
if (!cmd || !dt)
return false;
switch (cmd->code)
{
case AceCommandNop:
break;
case AceCommandExec:
__LOG_W__ << "ACE unit is executing exec opcode (?!).\n";
break;
case AceCommandLoop:
cmd->SetDone();
loop_pc = pc;
break;
case AceCommandNext:
cmd->SetDone();
pc = loop_pc;
break;
}
return true;
}
//------------------------------------------------------------------------------
Unit::Unit()
{
ResetCommandList();
}

View File

@ -0,0 +1,94 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/cached_graphic_resource_factory.h"
#include "core/resource_geometry_generator.h"
#include "picture/pict_io.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
static bool DoLoadResource(const char *name, Geometry &g)
{
if (GeometryGenerator::IsGenerated(name))
return GeometryGenerator::Generate(name, g);
return NML::LoadFromFile(g, name);
}
static bool DoLoadResource(const char *name, Picture &p)
{ return PictureIO::Get().Load(p, name); }
template <class T> bool DoLoadResource(const char *name, T &t)
{ return NML::LoadFromFile(t, name); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template <class T> T *LoadResourceCommonSeq(const char *name, SharedList <T *> &list)
{
if (!name)
return NULL;
ListForeachPtr(T *, t, list)
if (t->name == name)
return t;
AutoPtr <T> t(new T);
if (t.IsNull())
return NULL;
t->name = name;
if (!DoLoadResource(name, *t))
return NULL;
list.Add(t);
return t.Detach();
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Picture *CachedResourceFactory::LoadPicture(const char *name)
{ return LoadResourceCommonSeq(name, pictures); }
Geometry *CachedResourceFactory::LoadGeometry(const char *name)
{ return LoadResourceCommonSeq(name, geometries); }
Material *CachedResourceFactory::LoadMaterial(const char *name)
{ return LoadResourceCommonSeq(name, materials); }
Shader *CachedResourceFactory::LoadShader(const char *name)
{ return LoadResourceCommonSeq(name, shaders); }
ParticleModel *CachedResourceFactory::LoadParticleModel(const char *name)
{ return LoadResourceCommonSeq(name, particle_models); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint CachedResourceFactory::GetCachedResourceCount()
{
uint count = 0;
count += geometries.GetCount();
count += materials.GetCount();
count += shaders.GetCount();
count += particle_models.GetCount();
count += pictures.GetCount();
return count;
}
uint CachedResourceFactory::PurgeCache()
{
uint purged = 0;
forever
{
uint pass_purged = 0;
purged += PurgeSharedList(geometries);
purged += PurgeSharedList(materials);
purged += PurgeSharedList(shaders);
purged += PurgeSharedList(particle_models);
purged += PurgeSharedList(pictures);
if (pass_purged == 0)
break;
purged += pass_purged;
}
return purged;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,30 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/cached_mixer_resource_factory.h"
#include "core/mixer.h"
using namespace GS::Audio;
//------------------------------------------------------------------------------
Sound *CachedResourceFactory::LoadSound(const char *name)
{
ListForeachPtr(Sound *, s, sounds)
if (s->name == name)
return s;
Sound *s = new Sound(mixer);
if (!s)
return NULL;
s->name = name;
s->mixer_data = mixer.LoadSound(name);
sounds.Add(s);
return s;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,116 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/cached_renderer_resource_factory.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Render;
//------------------------------------------------------------------------------
template <class T> static bool ResourceNameCompare(const T o, const String &name) { return String::Compare(o->name, name) == 0; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template <class T> T CheckCachedResourceCommonSeq(const char *uri, const SharedList <T> *cache)
{
if (!cache)
return NULL;
String name(uri);
name.FileCleanName();
return ListFindEx(*cache, ResourceNameCompare <T>, name);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *CachedRendererResourceFactory::LoadGeometry(const char *name, bool bypass_cache, Geometry *g)
{
if (!bypass_cache && !g)
if (Geometry *r = CheckCachedResourceCommonSeq <Geometry *> (name, &geometries))
return r;
Geometry *r = RendererResourceFactory::LoadGeometry(name, bypass_cache, g);
if (!bypass_cache && !g)
if (r)
geometries.Add(r);
return r;
}
Material *CachedRendererResourceFactory::LoadMaterial(const char *name, bool bypass_cache, Material *m)
{
if (!bypass_cache && !m)
if (Material *r = CheckCachedResourceCommonSeq <Material *> (name, &materials))
return r;
Material *r = RendererResourceFactory::LoadMaterial(name, bypass_cache, m);
if (!bypass_cache && !m)
if (r)
materials.Add(r);
return r;
}
Texture *CachedRendererResourceFactory::LoadTexture(const char *name, bool bypass_cache, Texture *t)
{
if (!bypass_cache && !t)
if (Texture *r = CheckCachedResourceCommonSeq <Texture *> (name, &textures))
return r;
Texture *r = RendererResourceFactory::LoadTexture(name, bypass_cache, t);
if (!bypass_cache && !t)
if (r)
textures.Add(r);
return r;
}
Shader *CachedRendererResourceFactory::LoadShader(const char *name, bool bypass_cache, Shader *s)
{
if (!bypass_cache && !s)
if (Shader *r = CheckCachedResourceCommonSeq <Shader *> (name, &shaders))
return r;
Shader *r = RendererResourceFactory::LoadShader(name, bypass_cache, s);
if (!bypass_cache && !s)
if (r)
shaders.Add(r);
return r;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CachedRendererResourceFactory::ListCachedResources()
{
ListForeachPtr(Geometry *, g, geometries)
__LOG_V__ << "- " << g->name << " (refcount=" << g->GetRefCount() << ")\n";
ListForeachPtr(Material *, m, materials)
__LOG_V__ << "- " << m->name << " (refcount=" << m->GetRefCount() << ")\n";
ListForeachPtr(Texture *, t, textures)
__LOG_V__ << "- " << t->name << " (refcount=" << t->GetRefCount() << ")\n";
ListForeachPtr(Shader *, s, shaders)
__LOG_V__ << "- " << s->name << " (refcount=" << s->GetRefCount() << ")\n";
}
uint CachedRendererResourceFactory::GetCachedResourceCount()
{
uint count = 0;
count += geometries.GetCount();
count += materials.GetCount();
count += textures.GetCount();
count += shaders.GetCount();
return count;
}
uint CachedRendererResourceFactory::PurgeCache()
{
uint purged = 0;
forever
{
uint pass_purged = 0;
pass_purged += PurgeSharedList(geometries);
pass_purged += PurgeSharedList(materials);
pass_purged += PurgeSharedList(textures);
pass_purged += PurgeSharedList(shaders);
if (pass_purged == 0)
break;
purged += pass_purged;
}
return purged;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,224 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/camera.h"
#include "core/light.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void Camera::AlignTo(const Light &l)
{
aspect_ratio = 1;
SnapshotTransformation(l.GetMatrix());
SetNearClippingPlane(l.GetNearClippingPlane());
SetFarClippingPlane(l.GetFarClippingPlane());
float fov = l.cone_angle + l.edge_angle;
SetZoomFactor(Math::Cos(fov) / Math::Sin(fov));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Camera::WorldToScreen(const fRect &v, const Vector4 &in, Vector4 &out, bool normalize)
{
Vector4 dp = in * GetInverseMatrix();
if (dp.z <= 0)
return false;
dp.x /= dp.z / zoom_factor;
dp.y /= dp.z / zoom_factor;
if (normalize)
{
if (aspect_ratio_ref_yaxis)
dp.x /= v.GetWidth() / v.GetHeight();
else dp.y /= v.GetWidth() / v.GetHeight();
}
out.Set((1 + dp.x) * 0.5f, (1 - dp.y) * 0.5f, 0);
return true;
}
Vector4 Camera::ScreenToWorld(const fRect &v, float x, float y, float z, float ar)
{
Vector4 sw((x - 0.5f) * 2.f, -(y - 0.5f) * 2.f, zoom_factor);
sw *= z / sw.z;
if (ar < 0)
{
if (aspect_ratio_ref_yaxis)
sw.x *= v.GetWidth() / v.GetHeight();
else sw.y *= v.GetWidth() / v.GetHeight();
}
else
sw.x *= ar;
return sw * GetMatrix();
}
Vector4 Camera::ComputeAspectRatioCorrection(const fRect &v, float global_ar) const
{
float k_ar = aspect_ratio;
if (k_ar <= 0.f) // Square AR.
k_ar = v.GetHeight() / v.GetWidth();
k_ar *= global_ar;
if (aspect_ratio_ref_yaxis)
return Vector4(k_ar, 1, 1);
return Vector4(1, 1.f / k_ar, 1);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Camera::ComputeProjectionMatrix(const fRect &v, Matrix4 &m) const
{
#if __PLATFORM_NINTENDO_WII__
const float za = z_far;
#else
const float za = z_near;
#endif
if (is_occulus_camera)
{
m = custom_projection;
/* // create scale and offset
float projXScale = 2.0f / (tan_left + tan_right);
float projXOffset = (tan_left - tan_right) * projXScale * 0.5f;
float projYScale = 2.0f / (tan_up + tan_down);
float projYOffset = (tan_up - tan_down) * projYScale * 0.5f;
//result.Scale = GS::Vector2(projXScale, projYScale);
//result.Offset = GS::Vector2(projXOffset, projYOffset);
// Hey - why is that Y.Offset negated?
// It's because a projection matrix transforms from world coords with Y=up,
// whereas this is from NDC which is Y=down.
m.Set
(
projXScale, 0, 0, 0,
0, projYScale, 0, 0,
0, 0, z_far / (z_far - z_near), 1,
projXOffset, -projYOffset, -(z_far * z_near) / (z_far - z_near), 0
);
/*
float idx = 1.0f / (tan_right - tan_left);
float idy = 1.0f / (tan_down - tan_up);
float idz = 1.0f / (z_far - z_near);
float sx = tan_right + tan_left;
float sy = tan_down + tan_up;
m.Set
(
2 * idx, 0, 0, 0,
0, 2 * idy, 0, 0,
0, 0, z_far / (z_far - z_near), 1,
sx*idx, -sy*idy, -(z_far * z_near) / (z_far - z_near), 0
);
*/
/*
float(*p)[4] = pmProj->m;
p[0][0] = 2 * idx; p[0][1] = 0; p[0][2] = sx*idx; p[0][3] = 0;
p[1][0] = 0; p[1][1] = 2 * idy; p[1][2] = sy*idy; p[1][3] = 0;
p[2][0] = 0; p[2][1] = 0; p[2][2] = -zFar*idz; p[2][3] = -zFar*zNear*idz;
p[3][0] = 0; p[3][1] = 0; p[3][2] = -1.0f; p[3][3] = 0;
*/
}
else
{
if (is_orthographic)
{
const float q = 1.f / (z_far - z_near);
m.Set
(
2.f / ortho_w, 0, 0, 0,
0, 2.f / ortho_h, 0, 0,
0, 0, q, 0,
0, 0, -q * za, 1
);
}
else
{
m.Set
(
zoom_factor, 0, 0, 0,
0, zoom_factor, 0, 0,
0, 0, z_far / (z_far - z_near), 1,
0, 0, -(z_far * z_near) / (z_far - z_near), 0
);
}
Vector4 ar = ComputeAspectRatioCorrection(v);
m.m[0][0] *= ar.x;
m.m[1][1] *= ar.y;
}
}
void Camera::ComputeFrustum(Frustum &f, const fRect &viewport, float zn, float zf) const
{
Vector4 k_ar = ComputeAspectRatioCorrection(viewport);
if (is_orthographic)
f.SetOrthographic(ortho_w, ortho_h, zn != -1 ? zn : z_near, zf != -1 ? zf : z_far, &GetMatrix(), k_ar.x, k_ar.y);
else f.SetPerspective(GetFov(), zn != -1 ? zn : z_near, zf != -1 ? zf : z_far, &GetMatrix(), k_ar.x, k_ar.y);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Camera::ComputeMatrix()
{
bool update_world = item_flags.IsSet(ItemFlagWorldMatrixDirty);
Item::ComputeMatrix();
// Remove scale from world matrix.
if (update_world)
{
Vector4 u = matrix.GetRow(0).Normalized();
matrix.m[0][0] = u.x; matrix.m[1][0] = u.y; matrix.m[2][0] = u.z;
Vector4 v = matrix.GetRow(1).Normalized();
matrix.m[0][1] = v.x; matrix.m[1][1] = v.y; matrix.m[2][1] = v.z;
Vector4 w = matrix.GetRow(2).Normalized();
matrix.m[0][2] = w.x; matrix.m[1][2] = w.y; matrix.m[2][2] = w.z;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
float Camera::GetFov() const
{ return Math::ATan(1.f / zoom_factor) * 2.f; }
void Camera::SetZoomFactor(float z)
{ zoom_factor = z; /*Types::Max(0.1f, z);*/ }
void Camera::SetFov(float fov)
{
fov = Types::Clamp(fov, Units::Deg(0.5f), Units::Deg(179.95f));
SetZoomFactor(1.f / Math::Tan(fov * 0.5f));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Camera::Camera()
{
using namespace Units;
SetZoomFactor(3.2f);
is_orthographic = false;
ortho_w = Mtr(1.f);
ortho_h = Mtr(1.f);
z_near = Cm(10.f);
z_far = Km(50.f);
aspect_ratio = -1.f;
aspect_ratio_ref_yaxis = true;
is_occulus_camera = false;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,90 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/camera.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::NML;
//------------------------------------------------------------------------------
bool Camera::FromMetaTag(Tag &tag)
{
if (tag.name != "Camera")
__ERR__(__LOG_E__ << "Could not parse light, incorrect root tag (" << tag.name << ").\n", false)
registry.DeleteKey("PostProcess:Dof;");
// Parse root tags.
NMLTagForeach(pt, tag)
{
if (pt->name == "Item")
Item::FromMetaTag(*pt);
else if (pt->name == "ZNear")
z_near = Types::Max(pt->GetReal(), 0.2f);
else if (pt->name == "ZFar")
z_far = pt->GetReal();
else if (pt->name == "ZoomFactor")
zoom_factor = pt->GetReal();
else if (pt->name == "Orthographic")
is_orthographic = true;
else if (pt->name == "OrthographicWidth")
ortho_w = pt->GetReal();
else if (pt->name == "OrthographicHeight")
ortho_h = pt->GetReal();
// Legacy support.
#if 1
else if (pt->name == "FStop")
registry.CreateKey("PostProcess:Dof:FStop", pt->GetReal());
else if (pt->name == "FocalDistance")
registry.CreateKey("PostProcess:Dof:FDist", pt->GetReal());
else if (pt->name == "ViewportOrigin");
else if (pt->name == "ViewportSize");
#endif
else if (pt->name == "AspectRatioRefYAxis")
aspect_ratio_ref_yaxis = pt->GetBool();
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Camera>.\n";
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Camera::AsMetaTag()
{
Tag *root = new Tag("Camera");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize camera. Failed to create root tag.\n", NULL)
// Store item.
root->AddChild(Item::AsMetaTag());
// Misc.
if (z_near != Units::Cm(10))
root->AddChild("ZNear", z_near);
if (z_far != Units::Km(100))
root->AddChild("ZFar", z_far);
if (zoom_factor != 3.2f)
root->AddChild("ZoomFactor", zoom_factor);
if (is_orthographic)
root->AddChild("Orthographic");
if (ortho_w != Units::Mtr(1.f))
root->AddChild("OrthographicWidth", ortho_w);
if (ortho_h != Units::Mtr(1.f))
root->AddChild("OrthographicHeight", ortho_h);
root->AddChild("AspectRatioRefYAxis", aspect_ratio_ref_yaxis);
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,92 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/clock.h"
#include "platform.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
float Clock::Getf() const
{ return (float)gtick / Platform::Get().GetClockFrequency(); }
float Clock::GetDeltaf() const
{ return (float)dt_clock / Platform::Get().GetClockFrequency(); }
void Clock::SetScalef(float k)
{ SetScale((int)(k * 1000.f)); }
float Clock::GetScalef() const
{ return (float)GetScale() / 1000.f; }
void Clock::SetFixedDeltaFramef(float dt)
{ fixed_delta = (dt >= 0.0) ? int(dt * Platform::Get().GetClockFrequency()) : -1; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Clock::Pause(bool _pause)
{ pause = _pause; }
void Clock::Reset()
{
_gtick = Platform::Get().GetClock(); // CU
dt_clock_filter.Reset();
}
void Clock::Update()
{
// Clock can run up to 49 days before looping.
if (pause)
{
_gtick = 0;
dt_clock = 0;
}
else
{
int tmp = Platform::Get().GetClock(); // CU
int raw_dt = tmp - _gtick; // CU
int dt = (raw_dt * clock_scale) / 1000; // CU
// Fixed delta clock.
if (fixed_delta > 0)
dt = (fixed_delta * clock_scale) / 1000; // CU
// Update tick.
if (_gtick != 0)
{
gtick += dt;
dt_clock = dt;
}
else
dt_clock = 0;
_gtick = tmp;
if (dt_clock < 0)
dt_clock = 0;
// Filter dt_clock.
dt_clock_filter.LogValue(dt_clock);
int filtered_dt_clock = dt_clock_filter.GetMedian();
dt_error += dt_clock - filtered_dt_clock;
int dt_error_correction = dt_error >> 2;
dt_error -= dt_error_correction;
dt_clock = filtered_dt_clock + dt_error_correction;
}
}
void Clock::EatDeltaClock()
{ _gtick = Platform::Get().GetClock(); }
Clock::Clock()
{
pause = false;
_gtick = 0;
gtick = 0;
dt_clock = 0;
dt_error = 0;
clock_scale = 1000;
fixed_delta = -1;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,143 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/core_profiler.h"
#include "core/raster_font.h"
#include "core/renderer.h"
using namespace GS;
#if __ENABLE_ALLOCATION_STAT__
static Time time_last;
#endif
//--------------------------------------------------------------------------
void Core::DrawAllocProfilerText(Render::Renderer &render, Render::RasterFont *font[2], float &x, float &y, float w, float h)
{
#if __ENABLE_ALLOCATION_STAT__
Time time = Platform::Get().GetTime();
Time time_elapsed = Types::Max(nTime(1), time - Platform::Get().GetStartTime());
// Update averages.
Time time_delta = time - time_last;
if (time_delta.toSec() > 1)
{
for (uint n = 0; n < nIAlloc::SystemCount; ++n)
{
nIAlloc::Stat &stat = nIAlloc::system_stat[n];
stat.alloc_avg = stat.alloc_count / time_delta.toSec();
stat.alloc_count = 0;
}
time_last = time;
}
//
nColor title_color(1.f, 0.9f, 0);
nRenderer::WriterConfig config(false);
render.Write(*font[1], "Allocation System\n\n", x, y, config, 1, &title_color);
float col, _col;
// Output legend.
#define MOVE_COL(EXP) { EXP; _col = col; }
MOVE_COL(col = x)
render.Write(*font[0], "System", _col, y, config);
MOVE_COL(col += 120)
render.Write(*font[0], "| Commit", _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], "| Commit Peak", _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], "| Alive", _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], "| Alive Peak", _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], "| Pressure (a/s)", _col, y, config);
y += 16 + 8;
// Output per system stats.
String current_group;
for (uint n = 0; n < nIAlloc::SystemCount; ++n)
{
// Output allocation group on change.
if (current_group != nIAlloc::system_desc[n].group)
{
// y += 4;
// MOVE_COL(col = x)
// render.Write(*font[0], nIAlloc::system_desc[n].group, _col, y, config, 1, &title_color);
// y += 16 + 8;
current_group = nIAlloc::system_desc[n].group;
}
// Output statistics.
nIAlloc::Stat &stat = nIAlloc::system_stat[n];
MOVE_COL(col = x)
render.Write(*font[0], nIAlloc::system_desc[n].name, _col, y, config);
MOVE_COL(col += 120)
render.Write(*font[0], String::Format("| %s", FormatNumber((float)stat.size, MemorySize).c_str()), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %s", FormatNumber((float)stat.size_peak, MemorySize).c_str()), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", stat.alive_count), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", stat.alive_count_peak), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", stat.alloc_avg), _col, y, config);
y += 16;
}
// Totals.
size_t total_size = 0,
total_size_peak = 0;
uint total_count = 0,
total_count_peak = 0,
total_pressure = 0;
for (uint n = 0; n < nIAlloc::SystemCount; ++n)
{
nIAlloc::Stat &stat = nIAlloc::system_stat[n];
total_size += stat.size;
total_size_peak += stat.size_peak;
total_count += stat.alive_count;
total_count_peak += stat.alive_count_peak;
total_pressure += stat.alloc_avg;
}
y += 8;
MOVE_COL(col = x)
render.Write(*font[0], "Total", _col, y, config);
MOVE_COL(col += 120)
render.Write(*font[0], String::Format("| %s", FormatNumber((float)total_size, MemorySize).c_str()), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %s", FormatNumber((float)total_size_peak, MemorySize).c_str()), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", total_count), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", total_count_peak), _col, y, config);
MOVE_COL(col += 90)
render.Write(*font[0], String::Format("| %d", total_pressure), _col, y, config);
#endif
}
//--------------------------------------------------------------------------

View File

@ -0,0 +1,71 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/embedded_resource_extractor.h"
#include "metafile/nml.h"
#include "filesystem/filesystem.h"
#include "filesystem/io_memory.h"
#include "platform.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
static bool FormatExtractionPath(String &out, const char *context, const char *suffix, bool to_ram)
{
__LOG_V__ << "Formatting extraction path for a resource embedded in '" << context << "'.\n";
if (!context)
__ERR__(__LOG_W__ << "Cannot extract embedded resource, context is empty.\n", false)
String extract_out = String(context).CutFileExtension();
if (to_ram)
{
extract_out = Platform::Get().io->StripRootPath(extract_out);
if (extract_out.IsAbsolutePath())
__ERR__(__LOG_W__ << "Extraction context represents an absolute path, cannot extract to ramdisk.\n", false)
else
{
if (!extract_out.StartsWith("@embedded"))
extract_out = String("@embedded/") + extract_out;
}
}
out = extract_out + suffix;
return true;
}
static bool SaveExtractedResource(const char *out, NML::Tag &t)
{
if (Platform::Get().io->Exists(out))
return true; // Do not export resource more than once.
__LOG_H__ << "Saving extracted resource to '" << out << "'.\n";
NML::File file;
file.AddRoot(&t);
bool r = NML::Parser::Save(out, file);
file.UnlinkRoot(&t); // Unlink root tag so that the meta file destructor does not free it.
return r;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool EmbeddedResourceExtractor::ExtractEmbeddedMaterial(String &out, NML::Tag &t, const char *context, int slot)
{ return FormatExtractionPath(out, context, String::Format("-material-%d.nmm", slot), extract_to_ram) && SaveExtractedResource(out, t); }
bool EmbeddedResourceExtractor::ExtractEmbeddedShaderTree(String &out, NML::Tag &t, const char *context)
{ return FormatExtractionPath(out, context, "-shader-tree.nsa", extract_to_ram) && SaveExtractedResource(out, t); }
//------------------------------------------------------------------------------
EmbeddedResourceExtractor::EmbeddedResourceExtractor(bool extract_to_ramdisk)
{
if ((extract_to_ram = extract_to_ramdisk) == true)
Platform::Get().io->Mount(new IO::Memory, "@embedded/");
}

View File

@ -0,0 +1,26 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/embedded_resource_handler_interface.h"
#include "memory/nauto_ptr.h"
using namespace GS::Core;
static GS::AutoPtr <IEmbeddedResourceHandler> embedded_resource_handler;
//------------------------------------------------------------------------------
IEmbeddedResourceHandler *IEmbeddedResourceHandler::Get()
{
if (embedded_resource_handler.IsNull())
embedded_resource_handler = new IEmbeddedResourceHandler;
return embedded_resource_handler.c_ptr();
}
void IEmbeddedResourceHandler::Set(IEmbeddedResourceHandler *h)
{
embedded_resource_handler = h;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,275 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/emitter.h"
#include "core/camera.h"
#include "core/resource_factories.h"
#include "core/graphic_resource_factory.h"
#include "core/render_resource_factory.h"
#include "timing/benchmark.h"
#include "rand/rand.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
ParticleModel::ParticleModel()
{
gravity.Set(0, 0, 0);
SetColor(Color(1, 1, 1, 1));
// size_curve.SetDefaultValue(1);
time_to_live.setSec(4.f);
damping = 1.f;
}
void ParticleModel::SetColor(const Color &color)
{
// red_curve.SetDefaultValue(color.x);
// green_curve.SetDefaultValue(color.y);
// blue_curve.SetDefaultValue(color.z);
// opacity_curve.SetDefaultValue(color.w);
}
void ParticleModel::AddColorPoint(const Time &t, const Color &color)
{
red_curve.Insert(CurvePoint(t, color.x));
green_curve.Insert(CurvePoint(t, color.y));
blue_curve.Insert(CurvePoint(t, color.z));
opacity_curve.Insert(CurvePoint(t, color.w));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void ParticleModel::RenderSetup(ResourceFactories *f)
{
if ((render_data = new RenderData) != NULL)
if (f && f->render)
render_data->material = f->render->LoadMaterial(material);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Emitter::ComputeMinMax(MinMax &minmax) const
{
minmax.mn = minmax.mx = GetMatrix().GetRow(3);
if (!GetParticleCount())
return;
for (uint n = 0; n < GetParticleCount(); ++n)
{
Particle *p = GetParticle(n);
minmax.Grow(MinMax(p->position - Vector4(p->size, p->size, p->size), p->position + Vector4(p->size, p->size, p->size)));
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Emitter::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Renderable::Context context, bool cull)
{
if (cull)
{
MinMax minmax;
ComputeMinMax(minmax);
if (view.frustum.ClassifyMinMax(minmax) == Frustum::Outside)
return 1;
}
is_seen = true;
const Matrix4 &vm = view.GetMatrix();
list.Push(new Render::Primitive(this, this, vm.GetRow(2).Dot(GetMatrix().GetRow(3) - vm.GetRow(3))));
return 1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Emitter::Sort(const Matrix4 &view)
{
if (!particle_pool || !is_seen)
return;
Vector4 view_front = view.GetRow(2).Normalized(),
view_pos = view.GetRow(3);
alive_count = 0;
for (uint n = 0; n < particle_pool.GetCount(); ++n)
if (particle_pool[n].IsAlive())
{
sort_array[alive_count].v = (particle_pool[n].position - view_pos).Dot(view_front);
sort_array[alive_count].o = n;
alive_count++;
}
GS::Sort <float, uint> ::QuickSort(alive_count, sort_array);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Emitter::Update(const Time &dt)
{
if (!particle_pool || !is_seen)
return;
// Spawn particles.
uint n = 0;
for (birth_time += dt * birth_rate * birth_rate_scale; birth_time.toSec() > 1; birth_time -= Time::fromSec(1))
{
// Seek next free particle.
for ( ; n < particle_pool.GetCount(); ++n)
if (particle_pool[n].time.toSec() < 0)
break;
// Emitter pool exhausted.
if (n == particle_pool.GetCount())
break;
// Spawn particle.
Particle &p = particle_pool[n];
p.time = birth_time / birth_rate;
p.angle = 0;
p.size = 0;
p.color.Set(0, 0, 0, 0);
ModelParticle(p, *this, time);
}
// Update running particles and drop dead ones.
if (render_data.IsValid())
if (ParticleModel *model = render_data->particle_model)
{
float damping = Math::Pow(model->damping, dt.toSec());
for (n = 0; n < particle_pool.GetCount(); ++n)
{
Particle &p = particle_pool[n];
if (!p.IsAlive())
continue;
// Kill particle.
p.time += dt;
if (p.time >= model->time_to_live)
p.time.setSec(-1);
else
{
float k_dt = dt.toSec();
p.position += p.velocity * k_dt;
p.velocity += render_data->particle_model->gravity * k_dt;
p.velocity *= damping;
model->size_curve.Evaluate(p.time, &p.size);
model->angle_curve.Evaluate(p.time, &p.angle);
model->red_curve.Evaluate(p.time, &p.color.x);
model->green_curve.Evaluate(p.time, &p.color.y);
model->blue_curve.Evaluate(p.time, &p.color.z);
model->opacity_curve.Evaluate(p.time, &p.color.w);
p.size *= p.size_scale;
p.color.w *= p.opacity_scale;
}
}
}
is_seen = false;
time += dt;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Emitter::RenderSetup(ResourceFactories *f)
{
if ((render_data = new RenderData) != NULL)
if (f && f->graphic)
if ((render_data->particle_model = f->graphic->LoadParticleModel(particle_model)) != NULL)
render_data->particle_model->RenderSetup(f);
}
bool Emitter::Setup()
{
alive_count = 0;
if (!particle_pool.Allocate(pool_size) || !sort_array.Allocate(pool_size))
__ERR__(__LOG_E__ << "Failed to allocate emitter particle pool (size " << pool_size << ").\n", false)
for (uint n = 0; n < pool_size; ++n)
particle_pool[n].time.setSec(-1);
time.setSec(0);
birth_time.setSec(0);
is_seen = true;
return true;
}
void Emitter::Free()
{
particle_pool.Free();
sort_array.Free();
alive_count = 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Emitter::SetSprayModel(float angle)
{
model = Model_Spray;
spray_angle = angle;
}
void Emitter::ModelParticle(Particle &p, const Item &i, const Time &/*emitter_time*/)
{
Vector4 ip = i.GetMatrix().GetRow(3);
switch (model)
{
default:
p.position = ip;
p.velocity.Set(0, 0, 0);
break;
case Model_Spray:
{
p.position = ip;
using namespace Random;
float a = (FRand(2.f) - 1.f) * spray_angle;
Vector4 d(Math::Sin(a), 0, Math::Cos(a));
Matrix3::RotationMatrixZAxis(FRand(Units::Deg(360.f))).Apply(&p.velocity, &d);
p.velocity = (p.velocity.Normalized() * FRRand(birth_speed_min, birth_speed_max)) * birth_speed_scale * Matrix3::FromMatrix4(i.GetMatrix());
}
break;
}
p.size_scale = birth_size_scale;
p.opacity_scale = birth_opacity_scale;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Emitter::Emitter()
{
is_seen = true;
birth_speed_min = 1;
birth_speed_max = 1.5;
pool_size = 500;
birth_rate = (float)pool_size / Units::Sec(5.f);
birth_rate_scale = 1;
birth_opacity_scale = 1;
birth_speed_scale = 1;
birth_size_scale = 1;
SetSprayModel(Units::Deg(45.f));
alive_count = 0;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,154 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/emitter.h"
#include "core/embedded_resource_handler_interface.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::NML;
//------------------------------------------------------------------------------
bool ParticleModel::FromMetaTag(Tag &tag)
{
if (tag.name != "ParticleModel")
__ERR__(__LOG_E__ << "Could not parse particle model, incorrect root tag (" << tag.name << ").\n", false)
NMLTagForeach(pt, tag)
{
if (pt->name == "Material")
IEmbeddedResourceHandler::Get()->ExtractEmbeddedMaterial(material, *pt, name, 0);
else if (pt->name == "MaterialRef")
material = pt->GetString();
else if (pt->name == "TTL")
time_to_live.setSec(pt->GetReal());
else if (pt->name == "Damping")
damping = pt->GetReal();
else if (pt->name == "Gravity")
gravity.FromMetaTag(*pt);
else if (pt->name == "AngleCurve" && pt->GetTag("Curve"))
angle_curve.FromMetaTag(*pt->GetTag("Curve"));
else if (pt->name == "SizeCurve" && pt->GetTag("Curve"))
size_curve.FromMetaTag(*pt->GetTag("Curve"));
else if (pt->name == "RedCurve" && pt->GetTag("Curve"))
red_curve.FromMetaTag(*pt->GetTag("Curve"));
else if (pt->name == "GreenCurve" && pt->GetTag("Curve"))
green_curve.FromMetaTag(*pt->GetTag("Curve"));
else if (pt->name == "BlueCurve" && pt->GetTag("Curve"))
blue_curve.FromMetaTag(*pt->GetTag("Curve"));
else if (pt->name == "OpacityCurve" && pt->GetTag("Curve"))
opacity_curve.FromMetaTag(*pt->GetTag("Curve"));
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <ParticleModel>.\n";
}
return true;
}
Tag *ParticleModel::AsMetaTag() const
{
Tag *root = new Tag("ParticleModel");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize particle model. Failed to create root tag.\n", NULL)
root->AddChild("MaterialRef", material.c_str());
root->AddChild("TTL", time_to_live.toSec());
root->AddChild("Damping", damping);
root->AddChild(gravity.AsMetaTag("Gravity"));
Tag *ct;
ct = root->AddChild("AngleCurve"); ct->AddChild(angle_curve.AsMetaTag());
ct = root->AddChild("SizeCurve"); ct->AddChild(size_curve.AsMetaTag());
ct = root->AddChild("RedCurve"); ct->AddChild(red_curve.AsMetaTag());
ct = root->AddChild("GreenCurve"); ct->AddChild(green_curve.AsMetaTag());
ct = root->AddChild("BlueCurve"); ct->AddChild(blue_curve.AsMetaTag());
ct = root->AddChild("OpacityCurve"); ct->AddChild(opacity_curve.AsMetaTag());
return root;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Emitter::FromMetaTag(Tag &tag)
{
if (tag.name != "Emitter")
__ERR__(__LOG_E__ << "Could not parse emitter, incorrect root tag (" << tag.name << ").\n", false)
birth_speed_min = birth_speed_max = 1;
pool_size = 100;
birth_rate = 1;
model = Model_Spray;
spray_angle = Units::Deg(45.f);
particle_model.Clear();
NMLTagForeach(pt, tag)
{
if (pt->name == "Item")
Item::FromMetaTag(*pt);
else if (pt->name == "SpeedMin")
birth_speed_min = pt->GetReal();
else if (pt->name == "SpeedMax")
birth_speed_max = pt->GetReal();
else if (pt->name == "PoolSize")
pool_size = pt->GetInteger();
else if (pt->name == "BirthRate")
birth_rate = pt->GetReal();
else if (pt->name == "Type")
{
String _type(pt->GetString());
if (_type == "Spray")
model = Model_Spray;
}
else if (pt->name == "SprayAngle")
spray_angle = pt->GetReal();
else if (pt->name == "ParticleModel")
particle_model = pt->GetString();
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Emitter>.\n";
}
return true;
}
Tag *Emitter::AsMetaTag() const
{
Tag *root = new Tag("Emitter");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize emitter. Failed to create root tag.\n", NULL)
// Store item.
root->AddChild(Item::AsMetaTag());
if (birth_speed_min != 1)
root->AddChild("SpeedMin", birth_speed_min);
if (birth_speed_max != 1)
root->AddChild("SpeedMax", birth_speed_max);
if (birth_rate != 1)
root->AddChild("BirthRate", birth_rate);
if (pool_size != 100)
root->AddChild("PoolSize", (int)pool_size);
// switch (emitter_type)
// {
// case Type_Spray: root->AddChild("Type", "Spray");
// }
root->AddChild("SprayAngle", spray_angle);
if (!particle_model.IsEmpty())
root->AddChild("ParticleModel", particle_model.c_str());
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,449 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
#include "math/matrix4.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
static const float HomogeneousDistance = Units::Mm(0.01f);
//------------------------------------------------------------------------------
bool Core::ComputeVertexArrayMinMax(const Array <Vector4> &vtx, MinMax &mm, const Matrix4 *mtx)
{
if (!vtx.GetCount())
return false;
Vector4 tvt = mtx ? vtx[0] * mtx[0] : vtx[0], mn = tvt, mx = tvt;
if (mtx)
for (uint n = 0; n < vtx.GetCount(); ++n)
{
tvt = vtx[n] * mtx[0];
if (tvt.x > mx.x) mx.x = tvt.x;
if (tvt.y > mx.y) mx.y = tvt.y;
if (tvt.z > mx.z) mx.z = tvt.z;
if (tvt.x < mn.x) mn.x = tvt.x;
if (tvt.y < mn.y) mn.y = tvt.y;
if (tvt.z < mn.z) mn.z = tvt.z;
}
else
for (uint n = 0; n < vtx.GetCount(); ++n)
{
tvt = vtx[n];
if (tvt.x > mx.x) mx.x = tvt.x;
if (tvt.y > mx.y) mx.y = tvt.y;
if (tvt.z > mx.z) mx.z = tvt.z;
if (tvt.x < mn.x) mn.x = tvt.x;
if (tvt.y < mn.y) mn.y = tvt.y;
if (tvt.z < mn.z) mn.z = tvt.z;
}
mm.mn = mn;
mm.mx = mx;
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Geometry::GetUVCount() const
{
uint c = 0;
for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n)
if (uv[n])
++c;
return c;
}
uint Geometry::GetBoneCount() const
{ return bone_name.GetCount(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Geometry::ComputeBoneBoundingVolumes(Array <MinMax> &bone_mm) const
{
uint bone_count = bone_bind_matrix.GetCount();
if (skin.IsNull() || !bone_count)
return false;
if (!bone_mm.Allocate(bone_count))
__ERR__(__LOG_E__ << "Failed to allocate bon minmax array.\n", false)
Array <bool> bone_mm_init(bone_count);
for (uint n = 0; n < bone_count; ++n)
bone_mm_init[n] = false;
for (uint v = 0; v < vtx.GetCount(); ++v)
for (int b = 0; b < __PV_BONE_LIMIT__; ++b)
if (skin[v].w[b] > 0.f)
{
int idx = skin[v].bone_index[b];
if (!bone_mm_init[idx])
{
bone_mm[idx].Set(vtx[v], vtx[v]);
bone_mm_init[idx] = true;
}
else
bone_mm[idx].Grow(vtx[v]);
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Geometry::ComputePolygonBindingCount() const
{
uint c = 0;
for (uint n = 0; n < pol.GetCount(); ++n)
c += pol[n].vtx_count;
return c;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
MinMax Geometry::ComputeMinMax(const Matrix4 *mtx) const
{
MinMax mm;
ComputeVertexArrayMinMax(vtx, mm, mtx);
return mm;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Geometry::AllocateVertex(uint count)
{ return vtx.Allocate(count); }
bool Geometry::AllocatePolygon(uint count)
{
binding.Free();
return pol.Allocate(count);
}
bool Geometry::AllocatePolygonBinding()
{
uint count = ComputePolygonBindingCount();
if (!binding.Allocate(count))
return false;
count = 0;
for (uint n = 0; n < pol.GetCount(); ++n)
{
pol[n].binding = &binding[count];
count += pol[n].vtx_count;
}
return true;
}
bool Geometry::AllocateBone(uint count)
{ return bone_name.Allocate(count) && bone_bind_matrix.Allocate(count); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ComputePolygonIndex(Array <uint> &i) const
{
if (i.Allocate(pol.GetCount()))
for (uint pc = 0, ci = 0; pc < pol.GetCount(); ++pc)
{
i[pc] = ci;
ci += pol[pc].vtx_count;
}
}
void Geometry::ComputeVertexToPolygon(Array <VertexToPolygon> &vtx_to_pol) const
{
if (!pol || !vtx)
return;
Array <uint> pol_per_vtx(vtx.GetCount());
if (!pol_per_vtx)
return;
Memory::Set(&pol_per_vtx[0], 0, pol_per_vtx.GetSize());
uint p, v;
for (p = 0; p < pol.GetCount(); ++p)
for (v = 0; v < pol[p].vtx_count; ++v)
pol_per_vtx[pol[p].binding[v]]++;
vtx_to_pol.Allocate(vtx.GetCount());
for (v = 0; v < vtx.GetCount(); ++v)
{
vtx_to_pol[v].pol_count = 0;
vtx_to_pol[v].pol_index.Allocate(pol_per_vtx[v]);
}
for (p = 0; p < pol.GetCount(); ++p)
for (v = 0; v < pol[p].vtx_count; ++v)
vtx_to_pol[pol[p].binding[v]].pol_index[vtx_to_pol[pol[p].binding[v]].pol_count++] = p;
}
void Geometry::ComputeVertexToVertex(Array <VertexToVertex> &vtx_to_vtx, const Array <VertexToPolygon> *vtx_to_pol) const
{
if (!pol || !vtx)
return;
// Allocate vertex to vertex buffer.
if (!vtx_to_vtx.Allocate(vtx.GetCount()))
__ERRRAW__(__LOG_E__ << "Could not allocate memory.\n")
// Allocate work area.
#define __VertexToVertexTempListSize 1024
PolygonVertex tmp_vtx_to_vtx[__VertexToVertexTempListSize];
// Compute vertex to polygon if not provided.
Array <VertexToPolygon> _vtx_to_pol;
if (!vtx_to_pol)
{
vtx_to_pol = &_vtx_to_pol;
ComputeVertexToPolygon(_vtx_to_pol);
}
for (int pass = 0; pass < 2; ++pass)
for (uint v = 0; v < vtx.GetCount(); ++v)
{
vtx_to_vtx[v].vtx_count = 0;
uint vtx_vtx_count = 0;
for (uint p = 0; p < (*vtx_to_pol)[v].pol_count; ++p)
{
uint pol_index = (*vtx_to_pol)[v].pol_index[p];
Polygon *poly = &pol[pol_index];
int ci;
for (ci = 0; ci < poly->vtx_count; ++ci)
if (poly->binding[ci] == v)
break;
for (int _c = (ci - 1); _c <= (ci + 1); _c += 2)
{
int vtx_index = _c;
if (vtx_index < 0)
vtx_index += poly->vtx_count;
if (vtx_index >= poly->vtx_count)
vtx_index -= poly->vtx_count;
// Invalidate already registered candidate.
bool insert = true;
for (uint nl = 0; nl < vtx_vtx_count; ++nl)
if ((tmp_vtx_to_vtx[nl].pol_index == pol_index) && (tmp_vtx_to_vtx[nl].vtx_index == (uint)vtx_index))
{
insert = false;
break;
}
if (insert)
{
tmp_vtx_to_vtx[vtx_vtx_count].pol_index = pol_index;
tmp_vtx_to_vtx[vtx_vtx_count].vtx_index = vtx_index;
if (vtx_vtx_count == __VertexToVertexTempListSize)
{
__LOG_E__ << "Temporary list exceeded, vertex to vertex LUT corrupted.\n";
vtx_vtx_count = __VertexToVertexTempListSize - 1;
}
if (pass == 1)
{
vtx_to_vtx[v].vtx[vtx_vtx_count].pol_index = pol_index;
vtx_to_vtx[v].vtx[vtx_vtx_count].vtx_index = vtx_index;
}
++vtx_vtx_count;
}
}
}
// Allocate vertex container for this vertex.
if (pass == 0)
vtx_to_vtx[v].vtx.Allocate(vtx_vtx_count);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::FlagHomogeneousVertex(Array <bool> &flag, const Array <uint> &pol_index, const Array <VertexToPolygon> &vtx_to_pol, int mat) const
{
if (!flag.Allocate(vtx.GetCount()))
__ERRRAW__(__LOG_E__ << "Could not allocate homogeneous vertex table.\n")
for (uint n = 0; n < vtx.GetCount(); ++n)
flag[n] = true;
#if 0
// Test for early exit in case no polygon uses this material.
for (uint n = 0; n < pol.GetCount(); n++)
if (pol[n].material == n)
break;
if (n == pol.GetCount())
return;
#endif
for (uint m = 0; m < vtx.GetCount(); ++m)
{
uint ngeo = vtx_to_pol[m].pol_count;
for (uint ac = 0; ac < ngeo; ++ac)
for (uint bc = 0; bc < ngeo; ++bc)
{
uint i_ac = vtx_to_pol[m].pol_index[ac],
i_bc = vtx_to_pol[m].pol_index[bc];
Polygon *apoly = &pol[i_ac], *bpoly = &pol[i_bc];
if (apoly == bpoly)
continue;
if (apoly->material == bpoly->material)
{
if ((mat == -1) || (apoly->material == (uint)mat))
{
uint _u, _v;
for (_u = 0; _u < apoly->vtx_count; ++_u)
if ( apoly->binding[_u] == m )
break;
for (_v = 0; _v < bpoly->vtx_count; ++_v)
if ( bpoly->binding[_v] == m )
break;
if (vtx_normal)
if (Vector4::Dist2(vtx_normal[pol_index[i_ac] + _u], vtx_normal[pol_index[i_bc] + _v]) > HomogeneousDistance)
flag[m] = false;
/*
if (vtx_tangent)
if (
(nVector::Dist2(vtx_tangent[pol_index[i_ac] + _u].B, vtx_tangent[pol_index[i_bc] + _v].B) > HomogeneousDistance) ||
(nVector::Dist2(vtx_tangent[pol_index[i_ac] + _u].T, vtx_tangent[pol_index[i_bc] + _v].T) > HomogeneousDistance)
)
vtx_homogeneous[m] = false;
*/
if (rgb)
if (Vector4::Dist2(rgb[pol_index[i_ac] + _u], rgb[pol_index[i_bc] + _v]) > HomogeneousDistance)
flag[m] = false;
for (uint cuv = 0; cuv < __UV_PER_GEOMETRY__; ++cuv)
if (uv[cuv])
if (Vector2::Dist2(uv[cuv][pol_index[i_ac] + _u], uv[cuv][pol_index[i_bc] + _v]) > HomogeneousDistance)
flag[m] = false;
}
}
else
flag[m] = false;
if (!flag[m])
goto nxth;
}
nxth:;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Geometry::MergeDuplicateMaterials()
{
if (material_table.GetCount() < 2)
return 0;
__LOG_H__ << "Merging materials in geometry '" << name << "'...\n";
// Build the drop table.
uint old_slot_count = material_table.GetCount();
Array <bool> drop(material_table.GetCount());
for (uint n = 0; n < material_table.GetCount(); ++n)
drop[n] = false;
Array <uint> material_remap(material_table.GetCount());
for (uint n = 0; n < material_table.GetCount(); ++n)
material_remap[n] = n;
// Flag materials to drop.
for (uint n = 0; n < material_table.GetCount(); ++n)
{
if (drop[n]) // Already dropped.
continue;
for (uint m = n + 1; m < material_table.GetCount(); ++m)
{
// Check by material name.
if (material_table[n].name != material_table[m].name)
goto skip_material_drop;
// Drop material.
drop[m] = true;
material_remap[m] = n;
skip_material_drop:;
}
}
// Create the new material array.
uint new_material_slot_count = 0;
for (uint n = 0; n < material_table.GetCount(); ++n)
if (!drop[n])
new_material_slot_count++;
Array <Geometry::MaterialSlot> new_material_slot(new_material_slot_count);
new_material_slot_count = 0;
for (uint n = 0; n < material_table.GetCount(); ++n)
if (!drop[n])
{
for (uint m = 0; m < material_table.GetCount(); ++m)
if (material_remap[m] == n)
material_remap[m] = new_material_slot_count;
new_material_slot[new_material_slot_count].name = material_table[n].name;
new_material_slot[new_material_slot_count].use_cache = material_table[n].use_cache;
++new_material_slot_count;
}
material_table.Transfer(new_material_slot);
// Remap polygon references.
for (uint n = 0; n < pol.GetCount(); ++n)
pol[n].material = (ushort)material_remap[pol[n].material];
uint merge_count = old_slot_count - material_table.GetCount();
__LOG__ << "Done, merged " << merge_count << " material slot(s).\n";
return merge_count;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::Free()
{
bone_name.Free();
skin.Free();
bone_bind_matrix.Free();
vtx.Free();
vtx_normal.Free();
vtx_tangent.Free();
pol_normal.Free();
pol_tangent.Free();
pol.Free();
binding.Free();
for (uint n = 0; n < __UV_PER_GEOMETRY__; n++)
uv[n].Free();
rgb.Free();
material_table.Free();
lod_proxy = NULL;
lod_distance = Units::Mtr(100.f);
shadow_proxy = NULL;
flag.Raise(FlagNullShadowProxy | FlagNullLodProxy, false);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry::Geometry()
{
lod_distance = Units::Mtr(100.f);
}
Geometry::~Geometry()
{
Free();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,256 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry_bih.h"
#include "core/graphic_resource_factory.h"
#include "metafile/nml_object.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool GeometryBIH::FastPolyTest(uint ip, Vector4 &s, Vector4 &d, float t_max)
{
Polygon &pol = geometry->pol[ip];
Vector4 &pn = geometry->pol_normal[ip];
float dnv = d.Dot(pn);
if (dnv >= 0.f)
return false; // backface
float t = (geometry->vtx[pol.binding[0]].Dot(pn) - s.Dot(pn)) / dnv;
if ((t < 0) || ((t_max > 0) && (t > t_max)))
return false; // Behind origin or beyond ray length.
// Make sure point is in polygon.
GeometryBIHAccel &ca = acc[ip];
// Note that the intersection point if offset toward the polygon origin.
float pu = s[ca.cu] + d[ca.cu] * t - geometry->vtx[pol.binding[0]][ca.cu];
float pv = s[ca.cv] + d[ca.cv] * t - geometry->vtx[pol.binding[0]][ca.cv];
const float ray_epsilon = -0.000001f;
float *k = ca.k;
for (int m = 1; m < (pol.vtx_count - 1); ++m)
{
float u = pv * k[0] + pu * k[1], v, w;
if (u < ray_epsilon)
goto next;
v = pu * k[2] + pv * k[3];
if (v < ray_epsilon)
goto next;
w = 1 - u - v;
if (w < ray_epsilon)
goto next;
return true;
next:;
k += 4;
}
return false;
}
void GeometryBIH::TraceLeaf(BIH::Node *leaf, float tmin, float tmax, BIH::Trace &, void *parm)
{
GeometryTrace *trace = (GeometryTrace *)parm;
uint *leaf_indice = (uint *)leaf->p;
Vector4 *vtx = geometry->vtx;
// Test each polygon in leaf.
for (uint n = 0; n < leaf->count; ++n)
{
uint idx = leaf_indice[n];
Vector4 &pn = geometry->pol_normal[idx];
Polygon &pol = geometry->pol[idx];
Material *material = material_table[pol.material].material;
trace->tri_test += pol.vtx_count - 2;
// Reject back facing polygons.
bool backface = false;
float dnv = trace->d.Dot(pn);
if (dnv >= 0.f)
{
if (material->renderword & Material::Render_DoubleSided)
backface = true;
else
continue;
}
float t = (vtx[pol.binding[0]].Dot(pn) - trace->s.Dot(pn)) / dnv;
// Reject intersections further away than the current best one.
if (trace->has_i && (t >= trace->i_t))
continue;
// Plane is outside ray boundaries.
if ((t < tmin) || (t > tmax))
continue;
// Make sure point is in polygon.
GeometryBIHAccel &ca = acc[idx];
// Note that the intersection point if offset toward the polygon origin.
float pu = trace->s[ca.cu] + trace->d[ca.cu] * t - vtx[pol.binding[0]][ca.cu],
pv = trace->s[ca.cv] + trace->d[ca.cv] * t - vtx[pol.binding[0]][ca.cv];
#define RAY_EPSILON -0.000001f
float *k = ca.k;
for (int m = 1; m < (pol.vtx_count - 1); ++m)
{
float u = pv * k[0] + pu * k[1], v, w;
if (u < RAY_EPSILON)
goto next;
v = pu * k[2] + pv * k[3];
if (v < RAY_EPSILON)
goto next;
w = 1 - u - v;
if (w < RAY_EPSILON)
goto next;
trace->has_i = true;
trace->i_t = t;
trace->ip = idx;
trace->it = m - 1;
trace->bi = pol_index[idx];
trace->u = u;
trace->v = v;
trace->w = w;
trace->g = geometry;
trace->m = material;
trace->st = material_table[pol.material].shader_tree;
trace->backface = backface;
break; // No need to look further.
next:;
k += 4;
}
}
}
void GeometryBIH::RaytraceGeometry(GeometryTrace &trace, const Vector4 &s, const Vector4 &d, float l)
{
trace.ip = -1;
trace.tri_test = 0;
trace.has_i = false;
trace.i_t = -1;
trace.s = s;
trace.d = d;
BIH::Trace bih_trace;
Raytrace(bih_trace, s, d, l, (void *)&trace);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool GeometryBIH::BuildFromGeometry(ResourceFactory &gf, Geometry *g)
{
Free();
// Build geometry LUTs.
geometry = g;
geometry->ComputePolygonIndex(pol_index);
// Load geometry resources.
material_table.Allocate(geometry->material_table.GetCount());
for (uint n = 0; n < material_table.GetCount(); ++n)
{
sMaterial m(gf.LoadMaterial(geometry->material_table[n].name));
if (m.IsNull())
return false;
if (!m->shader.IsEmpty())
{
sShaderTree tree(new ShaderTree);
if (NML::LoadFromFile(*tree, m->shader))
material_table[n].shader_tree = tree;
}
material_table[n].material = m;
}
// Build volume array to build tree.
Array <MinMax> varray(geometry->pol.GetCount());
if (!varray)
__ERR__(__LOG_E__ << "Failed to allocate volume objects.\n", false);
if (!acc.Allocate(geometry->pol.GetCount()))
__ERR__(__LOG_E__ << "Failed to allocate point in polygon acceleration array.\n", false);
geometry->ComputePolygonNormal();
for (uint n = 0; n < geometry->pol.GetCount(); ++n)
{
Polygon &pol = geometry->pol[n];
if (pol.vtx_count < 3)
continue;
Vector4 *vtx = geometry->vtx;
Vector4 u_edge = vtx[pol.binding[1]] - vtx[pol.binding[0]],
v_edge = vtx[pol.binding[2]] - vtx[pol.binding[0]];
geometry->pol_normal[n] = u_edge.Cross(v_edge).Normalized();
// Compute plane determinant.
acc[n].d = -vtx[pol.binding[0]].Dot(geometry->pol_normal[n]);
// Determine most significant axis.
Vector4 m = (vtx[pol.binding[1]] - vtx[pol.binding[0]]).Cross(vtx[pol.binding[2]] - vtx[pol.binding[0]]);
float x = Types::Abs(m.x), y = Types::Abs(m.y), z = Types::Abs(m.z);
uint axis = 2;
if ((x >= y) && (x >= z))
axis = 0;
else if ((y >= x) && (y >= z))
axis = 1;
char cu = (axis + 1) % 3,
cv = (axis + 2) % 3;
acc[n].cu = cu; acc[n].cv = cv;
// Compute point in triangle fixed coefficients.
if (acc[n].k.Allocate((pol.vtx_count - 2) * 4))
{
float *pk = acc[n].k.c_ptr();
for (int i = 1; i < (pol.vtx_count - 1); ++i)
{
Vector4 b = vtx[pol.binding[i + 1]] - vtx[pol.binding[0]],
c = vtx[pol.binding[i]] - vtx[pol.binding[0]];
float k = 1.f / (b[cu] * c[cv] - b[cv] * c[cu]);
*pk++ = b[cu] * k;
*pk++ = -b[cv] * k;
*pk++ = c[cv] * k;
*pk++ = -c[cu] * k;
}
// Build volume array.
varray[n].mn = varray[n].mx = geometry->vtx[pol.binding[0]];
for (uint m = 1; m < pol.vtx_count; ++m)
{
varray[n].mn.x = Types::Min(vtx[pol.binding[m]].x, varray[n].mn.x);
varray[n].mn.y = Types::Min(vtx[pol.binding[m]].y, varray[n].mn.y);
varray[n].mn.z = Types::Min(vtx[pol.binding[m]].z, varray[n].mn.z);
varray[n].mx.x = Types::Max(vtx[pol.binding[m]].x, varray[n].mx.x);
varray[n].mx.y = Types::Max(vtx[pol.binding[m]].y, varray[n].mx.y);
varray[n].mx.z = Types::Max(vtx[pol.binding[m]].z, varray[n].mx.z);
}
}
}
return Build(geometry->pol.GetCount(), &varray[0]);
}
void GeometryBIH::Free()
{
geometry = NULL;
material_table.Free();
acc.Free();
Tree::Free();
}
//------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,853 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
#include "core/embedded_resource_handler_interface.h"
#include "timing/benchmark.h"
#include "metafile/nml.h"
#include "math/matrix4.h"
#include "ascii/parser.h"
#include "memory/endian.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::AsciiParser;
//------------------------------------------------------------------------------
void Geometry::ParseVertex(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
vtx.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
float *fbff = (float *)vt->GetValue().GetBinaryBuffer();
if (vtx)
for (uint n = 0; n < vtx.GetCount(); ++n)
{
for (int m = 0; m < 3; ++m)
Endian::ToHost(&fbff[n * 3 + m], 4, Endian::Intel);
vtx[n].Set(fbff[n * 3 + 0], fbff[n * 3 + 1], fbff[n * 3 + 2]);
}
else __LOG_E__ << "Incomplete vertex chunk loading '" << name << "', expected vertex count integer tag.\n";
}
}
}
void Geometry::ParseAsciiVertex(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
vtx.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (vtx)
{
uint cvtx = 0;
NMLTagForeach(vx, *vt)
{
if (cvtx == vtx.GetCount())
{
__LOG_E__ << "Corrupter <AVertex> tag, more vertices than expected.\n";
break;
}
vtx[cvtx++].FromMetaTag(*vx);
}
}
else __LOG_E__ << "Incomplete vertex chunk loading '" << name << "', expected vertex count integer tag.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseSkin(const Tag *pt)
{
// Retrieve bone id list.
Tag *bonetag = pt->GetTag("Bones"),
*bindtag = pt->GetTag("Binds");
skin.Free();
bone_name.Free();
bone_bind_matrix.Free();
if (bonetag)
{
AllocateBone(bonetag->GetChildCount());
if (!bone_name)
__LOG_E__ << "Failed to allocate bone id list.\n";
else
{
int n = 0;
NMLTagForeach(b, *bonetag)
bone_name[n++] = b->GetString();
}
if (bindtag && (bindtag->GetChildCount() == bone_name.GetCount()))
{
int n = 0;
NMLTagForeach(m, *bindtag)
bone_bind_matrix[n++].FromMetaTag(*m);
}
}
// Retrieve skin weights.
Tag *weighttag = pt->GetTag("Weights");
if (bone_name.GetCount() && weighttag)
{
if (weighttag->GetChildCount() != vtx.GetCount())
__LOG_W__ << "Incoherent weight count (" << weighttag->GetChildCount() <<" for " << vtx.GetCount() << " vertice (is the skin being declared before the vertice?)).\n";
if (!skin.Allocate(weighttag->GetChildCount()))
__LOG_E__ << "Failed to allocate skin weights array.\n";
else
{
int n = 0;
NMLTagForeach(b, *weighttag)
{
const char *p = b->GetString(), *e = p + String::strlen(p);
skin[n].bone_index[0] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[1] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[2] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[3] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].w[0] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[1] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[2] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[3] = ((float)String::atoi(p)) / 255.f;
// Re-normalize weights.
float tw = 0.f;
for (int w = 0; w < 4; ++w)
tw += skin[n].w[w];
float k = 1.f / tw;
for (int w = 0; w < 4; ++w)
skin[n].w[w] *= k;
++n;
}
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParsePolygon(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol.Allocate(vt->GetInteger());
else if (vt->name == "BindingCount")
binding.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (pol && binding)
{
uint *pbuffer = (uint *)vt->GetValue().GetBinaryBuffer();
uint *pbinding = binding;
for (uint m = 0; m < pol.GetCount(); m++)
{
Endian::ToHost(pbuffer, 4, Endian::Intel);
pol[m].vtx_count = (ushort)*pbuffer++;
pol[m].binding = pbinding;
for (uint j = 0; j < pol[m].vtx_count; j++)
{
Endian::ToHost(pbuffer, 4, Endian::Intel);
*pbinding++ = *pbuffer++;
}
Endian::ToHost(pbuffer, 4, Endian::Intel);
pol[m].material = (ushort)*pbuffer++;
}
}
else __LOG_E__ << "Could not allocate polygon/binding memory.\n";
}
}
}
void Geometry::ParseAsciiPolygon(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol.Allocate(vt->GetInteger());
else if (vt->name == "BindingCount")
binding.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (binding && pol)
{
static String _PolyIndex("Index");
uint *pbinding = binding;
uint cpoly = 0;
NMLTagForeach(poly, *vt)
{
if (cpoly == pol.GetCount())
{
__LOG_E__ << "Corrupted <APolygon> tag, too many polygons.\n";
break;
}
Tag *count_tag = poly->GetTag("Count;"),
*material_tag = poly->GetTag("Material;");
pol[cpoly].vtx_count = 0;
pol[cpoly].binding = pbinding;
pol[cpoly].material = 0;
if (count_tag && material_tag)
{
pol[cpoly].vtx_count = (ushort)count_tag->GetInteger();
pol[cpoly].material = (ushort)material_tag->GetInteger();
NMLTagForeach(tag, *poly)
if (tag->name == _PolyIndex)
*pbinding++ = tag->GetInteger();
}
else __LOG_E__ << "Corrupt <Polygon> tag in <APolygon>.\n";
++cpoly;
}
}
else __LOG_E__ << "Could not allocate polygon/binding memory.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParsePolygonNormal(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol_normal.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (pol_normal)
{
char *pbuffer = (char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < pol.GetCount(); m++)
{
pol_normal[m].x = (float)(pbuffer[0]) / 127.f;
pol_normal[m].y = (float)(pbuffer[1]) / 127.f;
pol_normal[m].z = (float)(pbuffer[2]) / 127.f;
pol_normal[m].Normalize();
pbuffer += 3;
}
}
else __LOG_E__ << "Incomplete polygon normal chunk loading '" << name << "'.\n";
}
}
}
void Geometry::ParseVertexNormal(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <VNormal>.\n")
vtx_normal.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <VNormal>.\n")
if (vtx_normal)
{
signed char *pbuffer = (signed char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < vtx_normal.GetCount(); ++m)
{
vtx_normal[m].x = ((float)pbuffer[0]) / 127.f;
vtx_normal[m].y = ((float)pbuffer[1]) / 127.f;
vtx_normal[m].z = ((float)pbuffer[2]) / 127.f;
vtx_normal[m].Normalize();
pbuffer += 3;
}
}
else __LOG_E__ << "Incomplete vertex normal chunk loading '" << name << "'.\n";
}
void Geometry::ParseVertexTangent(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <VTangent>.\n")
vtx_tangent.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <VTangent>.\n")
// Allocate vertex normals.
if (vtx_tangent)
{
signed char *pbuffer = (signed char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < vtx_tangent.GetCount(); ++m)
{
Vector4 &T = vtx_tangent[m].T, &B = vtx_tangent[m].B;
T.x = ((float)pbuffer[0]) / 127.f;
T.y = ((float)pbuffer[1]) / 127.f;
T.z = ((float)pbuffer[2]) / 127.f;
T.Normalize();
B.x = ((float)pbuffer[3]) / 127.f;
B.y = ((float)pbuffer[4]) / 127.f;
B.z = ((float)pbuffer[5]) / 127.f;
B.Normalize();
pbuffer += 6;
}
}
else __LOG_E__ << "Incomplete vertex tangent chunk loading '" << name << "'.\n";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseAsciiRGB(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <ARGB>.\n")
rgb.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <ARGB>.\n")
if (rgb)
{
uint rgb_count = 0;
NMLTagForeach(rt, *vt)
{
if (rgb_count == rgb.GetCount())
{
__LOG_E__ << "Too many <Value> tags in RGB list of geometry '" << name << "'.\n";
break;
}
Tag *r_tag = rt->GetTypedTag("R;", Variant::VariantFloat),
*g_tag = rt->GetTypedTag("G;", Variant::VariantFloat),
*b_tag = rt->GetTypedTag("B;", Variant::VariantFloat),
*a_tag = rt->GetTypedTag("A;", Variant::VariantFloat);
rgb[rgb_count].x = r_tag ? r_tag->GetReal() : 0;
rgb[rgb_count].y = g_tag ? g_tag->GetReal() : 0;
rgb[rgb_count].z = b_tag ? b_tag->GetReal() : 0;
rgb[rgb_count].w = a_tag ? a_tag->GetReal() : 1;
++rgb_count;
}
if (rgb_count != rgb.GetCount())
__LOG_W__ << "Not enough <Value> tags in RGB list of geometry '" << name << "'.\n";
}
else __LOG_E__ << "Could not allocate RGB for geometry '" << name << "'.\n";
}
void Geometry::ParseRGB(const Tag *pt)
{
if (Tag *vt = pt->GetTag("Data"))
{
float *pbuffer = (float *)vt->GetValue().GetBinaryBuffer();
size_t size = vt->GetValue().GetBinarySize();
if (rgb.Allocate(binding.GetCount()))
{
uint components = (size == binding.GetCount() * 4) ? 4 : 3;
for (uint m = 0; m < rgb.GetCount(); m++)
{
for (uint n = 0; n < components; ++n)
Endian::ToHost(&pbuffer[n], 4, Endian::Intel);
rgb[m].Set(pbuffer[0], pbuffer[1], pbuffer[2]);
rgb[m].w = components == 4 ? pbuffer[3] : 1.f;
pbuffer += components;
}
}
else __LOG_E__ << "Could not allocate RGB channel for geometry '" << name << "'.\n";
}
else __LOG_E__ << "Expected <Data> tag under <RGB> tag.\n";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseUV(const Tag *pt)
{
uint current_uv = 0;
NMLTagForeach(vt, *pt)
{
if (vt->name != "Data")
continue;
if (current_uv == __UV_PER_GEOMETRY__)
{
__LOG_W__ << "Geometry '" << name << "' requires more UV channels than this build can handle.\n";
__LOG_W__ << "Please increase nUVMapCount and recompile to fully import this object.\n";
break;
}
float *pbuffer = (float *)vt->GetValue().GetBinaryBuffer();
if (uv[current_uv].Allocate(binding.GetCount()))
for (uint m = 0; m < binding.GetCount(); ++m)
{
for (int n = 0; n < 2; ++n)
Endian::ToHost(&pbuffer[n], 4, Endian::Intel);
uv[current_uv][m].x = pbuffer[0];
uv[current_uv][m].y = pbuffer[1];
pbuffer += 2;
}
else
__LOG_E__ << "could not allocate UV channel for geometry '" << name << "'.\n";
++current_uv;
}
}
void Geometry::ParseAsciiUV(const Tag *pt)
{
uint current_uv = 0;
NMLTagForeach(vt, *pt)
{
if (vt->name != "Data")
continue;
if (uv[current_uv].Allocate(binding.GetCount()))
{
uint uv_index = 0;
NMLTagForeach(uvt, *vt)
{
if (uv_index == binding.GetCount())
{
__LOG_E__ << "Too many <Value> tags in UV channel " << current_uv << " of geometry '" << name << "'.\n";
break;
}
Tag *u_tag = uvt->GetTypedTag("U;", Variant::VariantFloat),
*v_tag = uvt->GetTypedTag("V;", Variant::VariantFloat);
uv[current_uv][uv_index].x = u_tag ? u_tag->GetReal() : 0;
uv[current_uv][uv_index].y = v_tag ? v_tag->GetReal() : 0;
uv_index++;
}
}
else __LOG_E__ << "could not allocate UV channel for geometry '" << name << "'.\n";
if (++current_uv == __UV_PER_GEOMETRY__)
{
__LOG_W__ << "'" << name << "' requires more UV channels than this build can handle.\n";
__LOG_W__ << " Please increase nUVMapCount and recompile nEngine to fully import this object.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseMaterials(const Tag *pt)
{
// First pass, material count.
uint slot_count = 0;
NMLTagForeach(mt, *pt)
if ((mt->name == "Material") || (mt->name == "MaterialRef") || (mt->name == "MaterialRefEx"))
slot_count++;
// Allocate slots.
if (material_table.Allocate(slot_count))
{
slot_count = 0;
NMLTagForeach(mt, *pt)
{
String mref;
bool use_cache = true;
if (mt->name == "Material")
IEmbeddedResourceHandler::Get()->ExtractEmbeddedMaterial(mref, *mt, name, slot_count);
else if (mt->name == "MaterialRef")
mref = mt->GetString();
else if (mt->name == "MaterialRefEx")
{
if (Tag *t = mt->GetTypedTag("Name", Variant::VariantString))
mref = t->GetString();
if (Tag *t = mt->GetTypedTag("UseCache", Variant::VariantBool))
use_cache = t->GetBool();
}
material_table[slot_count].name = mref;
material_table[slot_count].use_cache = use_cache;
++slot_count;
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseMisc(const Tag &tag)
{
NMLTagForeach(pt, tag)
{
if (pt->name == "LodDistance")
lod_distance = pt->GetReal();
else if (pt->name == "LodNull")
flag.Raise(FlagNullLodProxy, pt->GetBool());
else if (pt->name == "ShadowNull")
flag.Raise(FlagNullShadowProxy, pt->GetBool());
else if (pt->name == "CopyLock")
copy_lock = pt->GetString();
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Geometry::FromMetaTag(const Tag &tag)
{
Benchmark bench(true);
// Build binary objects base name.
if (tag.name != "Geometry")
__ERR__(__LOG_E__ << "Could not parse material, incorrect root tag (" << tag.name << ")...\n", false)
Free();
// Parse root tags.
Tag *pt;
if ((pt = tag.GetTag("Materials")) != NULL)
ParseMaterials(pt);
if ((pt = tag.GetTag("Vertex")) != NULL)
ParseVertex(pt);
else
if ((pt = tag.GetTag("AVertex")) != NULL)
ParseAsciiVertex(pt);
if ((pt = tag.GetTag("Polygon")) != NULL)
ParsePolygon(pt);
else
if ((pt = tag.GetTag("APolygon")) != NULL)
ParseAsciiPolygon(pt);
if ((pt = tag.GetTag("PNormal")) != NULL)
ParsePolygonNormal(pt);
if ((pt = tag.GetTag("VNormal")) != NULL)
ParseVertexNormal(pt);
if ((pt = tag.GetTag("VTangent")) != NULL)
ParseVertexTangent(pt);
if ((pt = tag.GetTag("Skin")) != NULL)
ParseSkin(pt);
if ((pt = tag.GetTag("RGB")) != NULL)
ParseRGB(pt);
else
if ((pt = tag.GetTag("ARGB")) != NULL)
ParseAsciiRGB(pt);
if ((pt = tag.GetTag("UV")) != NULL)
ParseUV(pt);
else
if ((pt = tag.GetTag("AUV")) != NULL)
ParseAsciiUV(pt);
if ((pt = tag.GetTag("LodProxy")) != NULL)
lod_proxy = pt->GetString();
if ((pt = tag.GetTag("ShadowProxy")) != NULL)
shadow_proxy = pt->GetString();
ParseMisc(tag);
// Quick integrity check.
if (!vtx.GetCount())
__ERR__(__LOG_E__ << "No vertice in geometry '" << name << "'.\n", false)
if (!pol.GetCount())
__ERR__(__LOG_E__ << "No polygon in geometry '" << name << "'.\n", false)
if (vtx_tangent.IsNull())
ComputeVertexTangent();
bench.Stop();
__LOG__ << "Geometry::FromMetaTag(Tag &tag) done in " << bench.GetMs() << "ms. " << vtx.GetCount() << " vertice, " << pol.GetCount() << " polygon(s), " << material_table.GetCount() << " material(s).\n";
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Geometry::AsMetaTag() const
{
// Integrity check.
if (!vtx.GetCount() || !pol.GetCount() || !material_table.GetCount())
__ERR__(__LOG_E__ << "Cannot serialize '" << name << "', geometry is empty.\n", NULL)
Tag *root = new Tag("Geometry");
if (!root)
__ERR__(__LOG_E__ << "Could not create root tag to serialize geometry '" << name << "'.\n", NULL)
uint n;
// Vertice.
if (Tag *vertex = root->AddChild("Vertex"))
{
vertex->AddChild("Count", (int)vtx.GetCount());
if (float *vtx_rl = new float[vtx.GetCount() * 3])
{
for (n = 0; n < vtx.GetCount(); n++)
{
vtx_rl[n * 3 + 0] = vtx[n].x;
vtx_rl[n * 3 + 1] = vtx[n].y;
vtx_rl[n * 3 + 2] = vtx[n].z;
}
vertex->AddChild("Data", (uchar *)vtx_rl, vtx.GetCount() * 3 * sizeof(float));
_safe_delete_array(vtx_rl);
}
else
__LOG_E__ << "Failed to allocate raw vertice buffer.\n";
}
// Polygons.
if (Tag *polygon = root->AddChild("Polygon"))
{
polygon->AddChild("Count", (int)pol.GetCount());
polygon->AddChild("BindingCount", (int)binding.GetCount());
if (uint *pol_u4 = new uint[binding.GetCount() + pol.GetCount() * 2])
{
uint *ptr = pol_u4;
for (n = 0; n < pol.GetCount(); n++)
{
*ptr++ = pol[n].vtx_count;
for (uint m = 0; m < pol[n].vtx_count; m++)
*ptr++ = pol[n].binding[m];
*ptr++ = (uint)pol[n].material;
}
polygon->AddChild("Data", (uchar *)pol_u4, (binding.GetCount() + pol.GetCount() * 2) * sizeof(uint));
_safe_delete_array(pol_u4);
}
else
__LOG_E__ << "Failed to allocate raw polygon buffer.\n";
}
// Polygon normals.
if (pol_normal)
if (Tag *pnormal = root->AddChild("PNormal"))
{
pnormal->AddChild("Count", (int)pol.GetCount());
if (char *pnrm = new char[pol.GetCount() * 3])
{
char *ptr = pnrm;
for (n = 0; n < pol.GetCount(); n++)
{
*ptr++ = (char)(pol_normal[n].x * 127.f);
*ptr++ = (char)(pol_normal[n].y * 127.f);
*ptr++ = (char)(pol_normal[n].z * 127.f);
}
pnormal->AddChild("Data", (uchar *)pnrm, pol.GetCount() * 3);
_safe_delete_array(pnrm);
}
else
__LOG_E__ << "Failed to allocate raw normal buffer.\n";
}
// Vertex normals.
if (vtx_normal)
if (Tag *vnormal = root->AddChild("VNormal"))
{
vnormal->AddChild("Count", (int)binding.GetCount());
if (char *vnrm = new char[binding.GetCount() * 3])
{
char *ptr = vnrm;
for (n = 0; n < binding.GetCount(); n++)
{
*ptr++ = (char)(vtx_normal[n].x * 127.f);
*ptr++ = (char)(vtx_normal[n].y * 127.f);
*ptr++ = (char)(vtx_normal[n].z * 127.f);
}
vnormal->AddChild("Data", (uchar *)vnrm, binding.GetCount() * 3);
_safe_delete_array(vnrm);
}
else
__LOG_E__ << "Failed to allocate raw normal buffer.\n";
}
// Vertex tangent frames.
if (vtx_tangent)
if (Tag *vtangent = root->AddChild("VTangent"))
{
vtangent->AddChild("Count", (int)binding.GetCount());
if (char *vfrm = new char[binding.GetCount() * 6])
{
char *ptr = vfrm;
for (n = 0; n < binding.GetCount(); n++)
{
*ptr++ = (char)(vtx_tangent[n].T.x * 127.f);
*ptr++ = (char)(vtx_tangent[n].T.y * 127.f);
*ptr++ = (char)(vtx_tangent[n].T.z * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.x * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.y * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.z * 127.f);
}
vtangent->AddChild("Data", (uchar *)vfrm, binding.GetCount() * 6);
_safe_delete_array(vfrm);
}
else
__LOG_E__ << "Failed to allocate raw tangent frame buffer.\n";
}
// Output RGB.
if (rgb)
if (Tag *rgbtag = root->AddChild("RGB"))
{
// Test if we need to output alpha.
uint num_comp = 3;
for (uint m = 0; m < binding.GetCount(); ++m)
if (rgb[m].w < 1.f)
{
num_comp = 4;
break;
}
// Output buffer.
if (float *rgbbuf = new float[binding.GetCount() * num_comp])
{
float *prgb = rgbbuf;
for (uint m = 0; m < binding.GetCount(); ++m)
{
prgb[0] = rgb[m].x;
prgb[1] = rgb[m].y;
prgb[2] = rgb[m].z;
if (num_comp == 4)
prgb[3] = rgb[m].w;
prgb += num_comp;
}
rgbtag->AddChild("Data", (uchar *)rgbbuf, binding.GetCount() * num_comp * sizeof(float));
_safe_delete_array(rgbbuf);
}
}
// Output UVs.
if (GetUVCount())
if (Tag *uvtag = root->AddChild("UV"))
{
uvtag->AddChild("Count", (int)GetUVCount()); // LEGACY
if (float *uvbuf = new float[binding.GetCount() * 2])
{
for (n = 0; n < __UV_PER_GEOMETRY__; ++n)
if (uv[n])
{
for (uint m = 0; m < binding.GetCount(); m++)
{
uvbuf[m * 2 + 0] = uv[n][m].x;
uvbuf[m * 2 + 1] = uv[n][m].y;
}
uvtag->AddChild("Data", (uchar *)uvbuf, binding.GetCount() * 2 * sizeof(float));
}
_safe_delete_array(uvbuf);
}
else
__LOG_E__ << "Failed to allocate raw UVs buffer.\n";
}
// Output vertex weights.
if (bone_name.GetCount())
{
Tag *skintag = root->AddChild("Skin");
// Save bone id list.
if (Tag *bonetag = skintag->AddChild("Bones"))
for (uint n = 0; n < bone_name.GetCount(); ++n)
bonetag->AddChild("Id", bone_name[n]);
else
__LOG_E__ << "Failed to allocate bone id tag.\n";
// Save bone binding matrix.
if (Tag *bindtag = skintag->AddChild("Binds"))
for (uint n = 0; n < bone_name.GetCount(); ++n)
bindtag->AddChild(bone_bind_matrix[n].AsMetaTag("Matrix"));
else
__LOG_E__ << "Failed to allocate bone binding tag.\n";
// Save bone association/weights.
Tag *weighttag = skintag->AddChild("Weights");
for (uint n = 0; n < vtx.GetCount(); ++n)
weighttag->AddChild
(
"W", String::Format
( "%d,%d,%d,%d:%d,%d,%d,%d",
skin[n].bone_index[0], skin[n].bone_index[1], skin[n].bone_index[2], skin[n].bone_index[3],
(int)(skin[n].w[0] * 255.f), (int)(skin[n].w[1] * 255.f), (int)(skin[n].w[2] * 255.f), (int)(skin[n].w[3] * 255.f)).toUtf8()
);
}
// Proxies.
if (!lod_proxy.IsEmpty())
root->AddChild("LodProxy", lod_proxy.c_str());
if (lod_distance != Units::Mtr(100.f))
root->AddChild("LodDistance", lod_distance);
if (flag.IsSet(FlagNullLodProxy))
root->AddChild("LodNull", true);
if (!shadow_proxy.IsEmpty())
root->AddChild("ShadowProxy", shadow_proxy.c_str());
if (flag.IsSet(FlagNullShadowProxy))
root->AddChild("ShadowNull", true);
// Serialize materials.
if (Tag *mtag = root->AddChild("Materials"))
for (n = 0; n < material_table.GetCount(); n++)
if (Tag *extag = mtag->AddChild("MaterialRefEx"))
{
extag->AddChild("Name", material_table[n].name.c_str());
if (!material_table[n].use_cache)
extag->AddChild("UseCache", material_table[n].use_cache);
}
// Copyright lock.
if (!copy_lock.IsEmpty())
root->AddChild("CopyLock", copy_lock);
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,81 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool Geometry::ComputePolygonNormal(bool force)
{
if (!pol.GetCount() || !vtx.GetCount())
return false;
if (!force && (pol_normal.GetCount() == pol.GetCount()))
return true;
if (!pol_normal.Allocate(pol.GetCount()))
__ERR__(__LOG_E__ << "Geometry::ComputePolygonNormal() failed to allocate buffer.\n", false)
for (uint c = 0; c < pol.GetCount(); ++c)
if (pol[c].vtx_count > 2)
{
Vector4 va = vtx[pol[c].binding[2]] - vtx[pol[c].binding[0]],
vb = vtx[pol[c].binding[1]] - vtx[pol[c].binding[0]];
pol_normal[c] = vb.Cross(va).Normalized();
}
else
pol_normal[c].Set();
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Geometry::ComputeVertexNormal(Array <Vector4> &buffer, float msa)
{
if (!pol.GetCount() || !vtx.GetCount())
return false;
if (!ComputePolygonNormal())
return false;
Array <VertexToPolygon> vtx_to_pol;
ComputeVertexToPolygon(vtx_to_pol);
// Allocate full blown edge normal array.
__LOG__ << "Compute vertex normal for " << name << ".\n";
if (!binding.GetCount())
__ERR__(__LOG_E__ << "The total binding count is wrong. Check that the importer did properly update this flag.\n", false)
if (!vtx_normal.Allocate(binding.GetCount()))
__ERR__(__LOG_E__ << "Failed to allocate vertex normal buffer.\n", false)
for (uint cp = 0, ttp = 0; cp < pol.GetCount(); cp++)
for (uint cv = 0; cv < pol[cp].vtx_count; cv++)
{
uint gv = pol[cp].binding[cv];
Vector4 normal(0, 0, 0);
for (uint cg = 0; cg < vtx_to_pol[gv].pol_count; cg++)
if (pol_normal[cp].Dot(pol_normal[vtx_to_pol[gv].pol_index[cg]]) > msa) // MSA test.
normal += pol_normal[vtx_to_pol[gv].pol_index[cg]];
vtx_normal[ttp++] = normal.Normalized();
}
return true;
}
bool Geometry::ComputeVertexNormal(float msa, bool force)
{
if (!force && (vtx_normal.GetCount() == binding.GetCount()))
return true;
return ComputeVertexNormal(vtx_normal, msa);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,589 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry_reducer.h"
#include "core/geometry.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
void GeometryReducer::RemoveVertex (uint v)
{
vlist[v].active = false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
float GeometryReducer::ComputeEdgeCost(Geometry *sg, nLLEDGE *edg)
{
#define nMAXTRIPEREDGE 512 // FIXME
nLLTRI *sidetri[nMAXTRIPEREDGE];
nTENTRY *te;
uint nsidetri = 0, n;
te = tlist.lut[edg->a];
while (te)
{
if (te->tri->UseVertex(edg->b))
sidetri[nsidetri++] = te->tri;
te = te->n;
}
float curvature = 0.f;
te = tlist.lut[edg->a];
while (te)
{
float mincurv = 1.f;
for (n = 0; n < nsidetri; ++n)
{
float dot = te->tri->normal.Dot(sidetri[n]->normal);
dot = (1.f - dot) / 2.f;
if (dot < mincurv)
mincurv = dot;
}
if (mincurv > curvature)
curvature = mincurv;
te = te->n;
}
return curvature * Vector4::Dist(sg->vtx[edg->a], sg->vtx[edg->b]);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GeometryReducer::ComputeVertexCost(Geometry *sg, uint v)
{
nEENTRY *te = elist.lut[v];
vlist[v].cost = -1.f;
// cheapest collapse target for this vertex...
while (te)
{
float ecost = ComputeEdgeCost (sg, te->edge);
if ( (vlist[v].cost == -1.f) || (ecost < vlist[v].cost) )
{
vlist[v].tgtcollapse = te->edge->b;
vlist[v].cost = ecost;
}
te = te->n;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void nLLTRI::ReplaceVertex(uint f, uint t)
{
if ( a == f ) a = t;
else if ( b == f ) b = t;
else if ( c == f ) c = t;
}
char nLLTRI::UseVertex(uint i)
{
if ((a == i) || (b == i) || (c == i))
return true;
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
char GeometryReducer::IsBorder(uint v)
{
/*
If any of the edge going trough the vertex owns only one polygon then
the vertex is on a border...
`*/
for (nEENTRY *pedg = elist.lut[v]; pedg; pedg = pedg->n)
{
uint ecnt = 0;
for (nTENTRY *ptri = tlist.lut[v]; ptri; ptri = ptri->n)
if (ptri->tri->UseVertex (pedg->edge->b))
++ecnt;
if (ecnt < 2)
return true;
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *GeometryReducer::Reduce(Geometry *sg, float k)
{
if (!sg->pol.GetCount()) return NULL;
if (k <= 0.f) return NULL;
if (k >= 1.f) return NULL;
#ifdef DEBUG_COMPILATION
__LOG__ << "Geometry reducer invoked: " << k << "...\n";
#endif
// Allocate
Geometry *ng = new Geometry;
if (!ng)
return NULL;
// Triangulate geometry.
uint n, m;
nLLTRI *ctri;
elist.SetVertexCount (sg->vtx.GetCount());
tlist.SetGeo (sg);
for (n = 0; n < sg->pol.GetCount(); ++n)
{
const Polygon &p = sg->pol[n];
for (m = 1; m < (uint)(p.vtx_count - 1); ++m)
{
ctri = tlist.Add(p.binding[0], p.binding[m], p.binding[m+1]);
ctri->m = p.material;
tlist.ComputeNormal(ctri);
// insert edges
elist.Add(p.binding[0], p.binding[m]);
elist.Add(p.binding[m], p.binding[m+1]);
elist.Add(p.binding[m], p.binding[0]);
elist.Add(p.binding[m+1], p.binding[m]);
}
elist.Add(p.binding[0], p.binding[m]);
elist.Add(p.binding[m], p.binding[0]);
}
// create vertice list
vlist = new nLVERTEX[sg->vtx.GetCount()];
for ( n = 0; n < sg->vtx.GetCount(); n++ )
{
vlist[n].active = true;
vlist[n].locked = IsBorder (n);
vlist[n].tgtcollapse = n;
ComputeVertexCost (sg, n);
}
// collapse until we reach target...
uint _tgt = (uint)((float)tlist.ntri * k);
#ifdef DEBUG_COMPILATION
__LOG__ << "Collapsing from " << tlist.ntri << " to " << _tgt << "...\n";
float pcttri = (float)(tlist.ntri - _tgt) * 0.01f;
#endif
while ( tlist.ntri > _tgt )
{
// get the cheapest vertex to collapse
int vtx = -1;
float cst = 10000000.f;
for ( n = 0; n < sg->vtx.GetCount(); n++ )
{
if ( vlist[n].active && (!vlist[n].locked) && (vlist[n].cost < cst) )
{
vtx = n;
cst = vlist[n].cost;
}
}
/* // move vertex
if ( !vlist[vlist[vtx].tgtcollapse].locked )
{
VEC_INC (sg->vtx[vlist[vtx].tgtcollapse], sg->vtx[vtx]);
VEC_SCALEK (sg->vtx[vlist[vtx].tgtcollapse], 0.5f);
}
*/
// remap triangles
tlist.ReplaceVertex (vtx, vlist[vtx].tgtcollapse);
elist.RemapEdges (vtx, vlist[vtx].tgtcollapse);
// recompute cost for all modified vertice
ComputeVertexCost (sg, vlist[vtx].tgtcollapse);
nEENTRY *pedg = elist.lut[vlist[vtx].tgtcollapse];
while ( pedg )
{
ComputeVertexCost (sg, pedg->edge->b);
pedg = pedg->n;
}
#ifdef DEBUG_COMPILATION
if (!(tlist.ntri & 4095))
__LOG__ << (float)(100.f - ((float)(tlist.ntri - _tgt) / pcttri)) << "%%...\n";
#endif
// Invalidate vertex.
vlist[vtx].active = false;
}
_safe_delete_array(vlist);
#ifdef DEBUG_COMPILATION
__LOG__ << "Geometry reduction done.\n";
#endif
// Convert to mesh datas...
char *usevtx = new char[sg->vtx.GetCount()];
GS::Memory::Set(usevtx, 0, sg->vtx.GetCount());
ctri = tlist.root;
while ( ctri )
{
usevtx[ctri->a] = true;
usevtx[ctri->b] = true;
usevtx[ctri->c] = true;
ctri = ctri->n;
}
m = 0;
for ( n = 0; n < sg->vtx.GetCount(); n++ )
if ( usevtx[n] )
m++;
// Fill new geometry.
ng->pol.Allocate(tlist.ntri);
ng->binding.Allocate(ng->pol.GetCount() * 3);
ng->vtx.Allocate(m);
uint *rmpvtx = new uint[sg->vtx.GetCount()];
// Copy vertice.
m = 0;
for ( n = 0; n < sg->vtx.GetCount(); n++ )
if ( usevtx[n] )
{
rmpvtx[n] = m;
ng->vtx[m++] = sg->vtx[n];
}
_safe_delete_array(usevtx);
// Setup polygons.
m = 0;
ctri = tlist.root;
for ( n = 0; n < ng->pol.GetCount(); n++ )
{
ng->pol[n].vtx_count = 3;
ng->pol[n].binding = &ng->binding[m];
ng->binding[m++] = rmpvtx[ctri->a];
ng->binding[m++] = rmpvtx[ctri->b];
ng->binding[m++] = rmpvtx[ctri->c];
ng->pol[n].material = ctri->m;
ctri = ctri->n;
}
_safe_delete_array(rmpvtx);
// Copy material.
if (!ng->material_table.Allocate(sg->material_table.GetCount()))
return NULL;
for (n = 0; n < ng->material_table.GetCount(); n++)
ng->material_table[n] = sg->material_table[n];
// Setup geometry.
ng->ComputeVertexNormal();
return ng;
}
//------------------------------------------------------------------------------
//---------------------------------------------------
void nLTRILIST::ComputeNormal (nLLTRI *ctri)
//---------------------------------------------------
{
Vector4 va = sg->vtx[ctri->c] - sg->vtx[ctri->a];
Vector4 vb = sg->vtx[ctri->b] - sg->vtx[ctri->a];
ctri->normal = vb.Cross(va).Normalized();
}
//--------------------------------------------
void nLTRILIST::SetGeo (Geometry *g)
//--------------------------------------------
{
sg = g;
lut = new pnTENTRY[g->vtx.GetCount()];
for ( uint c = 0; c < g->vtx.GetCount(); c++ )
lut[c] = NULL;
}
//-----------------------------------------------------------
nLLTRI *nLTRILIST::Add (uint a, uint b, uint c)
//-----------------------------------------------------------
{
nLLTRI *tri = new nLLTRI;
tri->a = a;
tri->b = b;
tri->c = c;
tri->n = root;
tri->p = NULL;
if ( root )
root->p = tri;
root = tri;
// Register in vertex to poly.
AddTriToVertex(tri, a);
AddTriToVertex(tri, b);
AddTriToVertex(tri, c);
ntri++;
return tri;
}
//--------------------------------------------
void nLTRILIST::Remove(nLLTRI *t)
//--------------------------------------------
{
RemoveTriFromVertex(t, t->a);
RemoveTriFromVertex(t, t->b);
RemoveTriFromVertex(t, t->c);
if (t->p)
t->p->n = t->n;
else root = t->n;
if (t->n)
t->n->p = t->p;
delete t;
ntri--;
}
//--------------------------------------------------------------------
void nLTRILIST::RemoveTriFromVertex(nLLTRI *t, uint v)
//--------------------------------------------------------------------
{
nTENTRY *n = lut[v], *p = NULL;
while (n)
{
if (n->tri == t)
break;
p = n;
n = n->n;
}
if (!n)
return;
if (!p)
lut[v] = n->n;
else p->n = n->n;
_safe_delete(n);
}
//---------------------------------------------------------------
void nLTRILIST::AddTriToVertex (nLLTRI *t, uint v)
//---------------------------------------------------------------
{
nTENTRY *n = lut[v];
while ( n && (n->tri != t ))
n = n->n;
if ( n ) return;
n = new nTENTRY;
n->tri = t;
n->n = lut[v];
lut[v] = n;
}
//----------------------------------------------------------
void nLTRILIST::ReplaceVertex (uint a, uint b)
//----------------------------------------------------------
{
nTENTRY *s = lut[a], *n;
while ( s )
{
n = s->n;
if ( s->tri->UseVertex (b) )
Remove (s->tri);
else
{
s->tri->ReplaceVertex (a, b);
AddTriToVertex (s->tri, b);
ComputeNormal (s->tri);
RemoveTriFromVertex (s->tri, a);
}
s = n;
}
}
//---------------------------
nLTRILIST::nLTRILIST ()
//---------------------------
{
ntri = 0;
root = NULL;
}
//----------------------------
nLTRILIST::~nLTRILIST ()
//----------------------------
{
uint i;
for ( i = 0; i < sg->vtx.GetCount(); i++ )
{
nTENTRY *s = lut[i], *n;
while ( s )
{
n = s->n;
delete s;
s = n;
}
}
delete [] lut;
lut = NULL;
nLLTRI *s = root, *n;
while ( s )
{
n = s->n;
delete s;
s = n;
}
root = NULL;
ntri = 0;
}
//--------------------------------------------
void nEDGELIST::Add (uint a, uint b)
//--------------------------------------------
{
nEENTRY *pedg;
if ( a == b )
return;
pedg = lut[a];
while ( pedg )
{
if ( pedg->edge->b == b )
return;
pedg = pedg->n;
}
nLLEDGE *edg = new nLLEDGE;
edg->a = a;
edg->b = b;
edg->n = root;
edg->p = NULL;
if ( root )
root->p = edg;
root = edg;
// update lut
pedg = new nEENTRY;
pedg->edge = edg;
pedg->n = lut[a];
lut[a] = pedg;
nedg++;
}
//--------------------------------------------
void nEDGELIST::Remove (nLLEDGE *edg)
//--------------------------------------------
{
if ( !edg )
return;
if ( edg->n )
edg->n->p = edg->p;
if ( edg->p )
edg->p->n = edg->n;
else root = edg->n;
// update lut
nEENTRY *pedg = lut[edg->a], *ledg = NULL;
while ( pedg )
{
if ( pedg->edge == edg )
break;
ledg = pedg;
pedg = pedg->n;
}
if ( pedg )
{
if ( ledg )
ledg->n = pedg->n;
else lut[edg->a] = pedg->n;
delete pedg;
}
delete edg;
}
//-----------------------------------------------------
nLLEDGE *nEDGELIST::GetEdge (uint a, uint b)
//-----------------------------------------------------
{
nEENTRY *pedg = lut[a];
while ( pedg && (pedg->edge->b != b) )
pedg = pedg->n;
if ( !pedg )
return NULL;
return pedg->edge;
}
//---------------------------------------------------
void nEDGELIST::RemapEdges (uint a, uint b)
//---------------------------------------------------
{
nEENTRY *pedg = lut[a], *nedg;
// remap all edges and wipe invalid ones
while ( pedg )
{
uint ob = pedg->edge->b;
nedg = pedg->n;
Remove (GetEdge (pedg->edge->b, pedg->edge->a));
Remove (pedg->edge);
Add (b, ob);
Add (ob, b);
pedg = nedg;
}
}
//---------------------------------------------
void nEDGELIST::SetVertexCount (uint v)
//---------------------------------------------
{
lut = new pnEENTRY[v];
for ( uint n = 0; n < v; n++ )
lut[n] = NULL;
vtx_count = v;
}
//---------------------------
nEDGELIST::nEDGELIST ()
//---------------------------
{
lut = NULL;
root = NULL;
nedg = 0;
}
//----------------------------
nEDGELIST::~nEDGELIST ()
//----------------------------
{
uint n;
for (n = 0; n < vtx_count; n++)
{
nEENTRY *pedg = lut[n], *nedg;
while (pedg)
{
nedg = pedg->n;
delete pedg;
pedg = nedg;
}
}
_safe_delete_array(lut);
nLLEDGE *pedg = root, *nedg;
while (pedg)
{
nedg = pedg->n;
delete pedg;
pedg = nedg;
}
root = NULL;
}

View File

@ -0,0 +1,51 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void Geometry::SmoothRGB(uint pass_count, float max_smooth_angle)
{
if (!rgb)
return;
Array <uint> pol_index;
ComputePolygonIndex(pol_index);
Array <VertexToVertex> vtx_to_vtx;
ComputeVertexToVertex(vtx_to_vtx);
Array <Color> dst(binding.GetCount());
for (uint ns = 0; ns < pass_count; ++ns)
{
for (uint np = 0; np < pol.GetCount(); ++np)
for (uint nv = 0; nv < pol[np].vtx_count; ++nv)
{
uint imv = pol[np].binding[nv],
iv = pol_index[np] + nv;
dst[iv] = rgb[iv] * 4.f;
uint nrgb = 4;
for (uint nvv = 0; nvv < vtx_to_vtx[imv].vtx_count; nvv++)
if (pol[vtx_to_vtx[imv].vtx[nvv].pol_index].material == pol[np].material)
{
dst[iv] += rgb[pol_index[vtx_to_vtx[imv].vtx[nvv].pol_index] + vtx_to_vtx[imv].vtx[nvv].vtx_index];
nrgb++;
}
dst[iv] /= (float)nrgb;
}
Array <Color>::Swap(rgb, dst);
}
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,110 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
#include "log/log.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
bool Geometry::ComputePolygonTangent(uint uv_index, bool force)
{
if (!pol.GetCount() || !vtx.GetCount())
return false;
if (!force && (pol_tangent.GetCount() == pol.GetCount()))
return true;
if (!ComputePolygonNormal())
return false;
if ((uv_index >= __UV_PER_GEOMETRY__) || !uv[uv_index])
return false;
// Allocate polygon tangents.
if (!pol_tangent.Allocate(pol.GetCount()))
__ERR__(__LOG_W__ << "Geometry::ComputePolygonTangent() failed to allocate buffer!\n", false)
Array <uint> pol_index;
ComputePolygonIndex(pol_index);
for (uint c = 0; c < pol.GetCount(); c++)
if (pol[c].vtx_count > 2)
{
// Compute tangent frame for this polygon.
Vector4 side_0 = vtx[pol[c].binding[0]] - vtx[pol[c].binding[1]],
side_1 = vtx[pol[c].binding[2]] - vtx[pol[c].binding[1]];
float delta_U_0 = uv[uv_index][pol_index[c] + 0].x - uv[uv_index][pol_index[c] + 1].x,
delta_U_1 = uv[uv_index][pol_index[c] + 2].x - uv[uv_index][pol_index[c] + 1].x,
delta_V_0 = uv[uv_index][pol_index[c] + 0].y - uv[uv_index][pol_index[c] + 1].y,
delta_V_1 = uv[uv_index][pol_index[c] + 2].y - uv[uv_index][pol_index[c] + 1].y;
Vector4 T = (side_0 * delta_V_1 - side_1 * delta_V_0).Normalized().Reversed(),
B = (side_0 * delta_U_1 - side_1 * delta_U_0).Normalized();
if (T.Cross(B).Dot(pol_normal[c]) < 0)
{
T.Reverse();
B.Reverse();
}
pol_tangent[c].B = B;
pol_tangent[c].T = T;
}
return true;
}
bool Geometry::ComputeVertexTangent(bool rev_t, bool rev_b, bool force)
{
if (!pol.GetCount() || !vtx.GetCount())
return false;
if (!force && (vtx_tangent.GetCount() == binding.GetCount()))
return true;
if (!ComputeVertexNormal() || !ComputePolygonTangent())
return false;
Array <VertexToPolygon> vtx_to_pol;
ComputeVertexToPolygon(vtx_to_pol);
// Allocate full blown edge normal array.
if (vtx_tangent.Allocate(binding.GetCount()))
for (uint cp = 0, ttp = 0; cp < pol.GetCount(); ++cp)
for (uint cv = 0; cv < pol[cp].vtx_count; ++cv)
{
uint gv = pol[cp].binding[cv];
Vector4 T(0, 0, 0), B(0, 0, 0);
for (uint cg = 0; cg < vtx_to_pol[gv].pol_count; cg++)
{
Vector4 _T = pol_tangent[vtx_to_pol[gv].pol_index[cg]].T,
_B = pol_tangent[vtx_to_pol[gv].pol_index[cg]].B;
if (pol_tangent[cp].T.Dot(_T) < 0.f)
_T = _T.Reversed();
if (pol_tangent[cp].B.Dot(_B) < 0.f)
_B = _B.Reversed();
T += _T;
B += _B;
}
T -= vtx_normal[ttp] * vtx_normal[ttp].Dot(T);
T = T.Normalized();
B = vtx_normal[ttp].Cross(T);
vtx_tangent[ttp].T = rev_t ? T.Reversed() : T;
vtx_tangent[ttp].B = rev_b ? B.Reversed() : B;
++ttp;
}
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,238 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry_template.h"
#include "sort/sort.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void GeometryTemplate::ClearMaterials()
{ materials.Clear(); }
void GeometryTemplate::PushMaterial(const char *uri)
{ materials.Add(uri); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#define __AssertPolygon if (!polygon) __ERRRAW__(__LOG_E__ << "You must begin a polygon before pushing attributes.\n")
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void GeometryTemplate::BeginPolygon()
{ polygon = new Polygon; }
void GeometryTemplate::PushVertex(const Vector4 &v)
{ __AssertPolygon
polygon->vertex.Add(v); }
void GeometryTemplate::PushNormal(const Vector4 &n)
{ __AssertPolygon
polygon->normal.Add(n); }
void GeometryTemplate::PushColor(const Color &c)
{ __AssertPolygon
polygon->color.Add(c); }
void GeometryTemplate::PushUV(uint channel, const Vector2 &uv)
{ __AssertPolygon
polygon->uv[channel].Add(uv); }
void GeometryTemplate::EndPolygon(ushort material)
{
if (polygon)
{
polygon->material = material;
polygons.Add(polygon.Detach());
}
else
__LOG_E__ << "You must begin a polygon before ending it.\n";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Vector4 GeometryTemplate::GetVertex(const PolygonVertex &pv)
{ return polygons[pv.ipoly]->vertex[pv.ivertex]; }
Vector4 GeometryTemplate::GetNormal(const PolygonVertex &pv)
{ return polygons[pv.ipoly]->normal[pv.ivertex]; }
Vector2 GeometryTemplate::GetUV(uint channel, const PolygonVertex &pv)
{ return polygons[pv.ipoly]->uv[channel][pv.ivertex]; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *GeometryTemplate::Instantiate(const char *name)
{
if (!materials.GetCount())
__ERR__(__LOG_E__ << "Cannot instantiate a geometry with no material array.\n", NULL)
AutoPtr <Geometry> geo(new Geometry);
if (geo.IsNull())
__ERR__(__LOG_E__ << "Geometry allocation error.\n", NULL)
geo->name = name;
// Build vertex merge table.
uint vtx_per_poly_count = 0;
ListForeachPtr(Polygon *, p, polygons)
vtx_per_poly_count += p->vertex.GetCount();
typedef GS::Sort<float, uint> SortVPP;
Array <PolygonVertex> raw_v(vtx_per_poly_count);
Array <SortVPP::Entry> qs_e(vtx_per_poly_count);
vtx_per_poly_count = 0;
uint ipoly = 0;
Vector4 &support = polygons[0]->vertex[0];
ListForeachPtr(Polygon *, p, polygons)
{
for (uint ivertex = 0; ivertex < p->vertex.GetCount(); ++ivertex)
{
// Track this vertex.
raw_v[vtx_per_poly_count].ipoly = ipoly;
raw_v[vtx_per_poly_count].ivertex = ivertex;
// Quick-sort entry.
qs_e[vtx_per_poly_count].o = vtx_per_poly_count;
qs_e[vtx_per_poly_count].v = Vector4::Dist2(GetVertex(raw_v[vtx_per_poly_count]), support);
++vtx_per_poly_count;
}
++ipoly;
}
// Compute polygon start offsets.
Array <int> poly_offset(polygons.GetCount());
int poly_binding_start_offset = 0;
for (uint n = 0; n < polygons.GetCount(); ++n)
{
poly_offset[n] = poly_binding_start_offset;
poly_binding_start_offset += polygons[n]->vertex.GetCount();
}
// Count merged vertex.
SortVPP::QuickSort(vtx_per_poly_count, qs_e);
geo->binding.Allocate(vtx_per_poly_count);
uint packed_vtx_count = 0;
for (uint n = 0; n < vtx_per_poly_count; )
{
PolygonVertex &pv = raw_v[qs_e[n].o];
geo->binding[poly_offset[pv.ipoly] + pv.ivertex] = packed_vtx_count;
uint m = n + 1;
for (; m < vtx_per_poly_count; ++m)
{
if (Vector4::Dist2(GetVertex(raw_v[qs_e[n].o]), GetVertex(raw_v[qs_e[m].o])) > merge_threshold)
break;
PolygonVertex &pv = raw_v[qs_e[m].o];
geo->binding[poly_offset[pv.ipoly] + pv.ivertex] = packed_vtx_count;
}
++packed_vtx_count;
n = m;
}
// Pack vertices.
geo->vtx.Allocate(packed_vtx_count);
packed_vtx_count = 0;
for (uint n = 0; n < vtx_per_poly_count; )
{
uint m = n + 1;
for (; m < vtx_per_poly_count; ++m)
if (Vector4::Dist2(GetVertex(raw_v[qs_e[n].o]), GetVertex(raw_v[qs_e[m].o])) > merge_threshold)
break;
geo->vtx[packed_vtx_count++] = GetVertex(raw_v[qs_e[n].o]);
n = m;
}
// Build polygons.
geo->pol.Allocate(polygons.GetCount());
uint pol_count = 0, pol_bind = 0;
ListForeachPtr(Polygon *, p, polygons)
{
if (p->vertex.GetCount() > 65535)
__LOG_W__ << "Too many vertices in polygon " << pol_count << ".\n";
geo->pol[pol_count].vtx_count = (ushort)p->vertex.GetCount();
geo->pol[pol_count].binding = &geo->binding[pol_bind];
pol_bind += p->vertex.GetCount();
if (p->material > materials.GetCount())
{
p->material = 0;
__LOG_W__ << "Polygon " << pol_count << " is referencing a material outside of the material table.\n";
}
geo->pol[pol_count].material = p->material;
++pol_count;
}
// Output remaining attributes.
Polygon *poly = polygons[0];
bool has_normal = asbool(poly->normal.GetCount());
bool has_color = asbool(poly->color.GetCount());
bool has_uv[__UV_PER_GEOMETRY__];
for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n)
has_uv[n] = asbool(poly->uv[n].GetCount());
//--------------------------------------------------------------------------
#define __CreateAttribute(__Destination, __Attrib)\
{\
if (__Destination.Allocate(vtx_per_poly_count))\
{\
uint cpol = 0, cvpl = 0;\
ListForeachPtr(Polygon *, p, polygons)\
{\
if (p->vertex.GetCount() != __Attrib.GetCount())\
__LOG_W__ << "Incoherent normal count in polygon " << cpol << ".\n";\
else\
for (uint n = 0; n < p->vertex.GetCount(); ++n)\
__Destination[cvpl + n] = __Attrib[n];\
\
cvpl += p->vertex.GetCount();\
++cpol;\
}\
}\
else\
__LOG_E__ << "Failed to allocate attribute array while creating geometry '" << name << "'.\n";\
}
//--------------------------------------------------------------------------
if (has_normal)
__CreateAttribute(geo->vtx_normal, p->normal)
if (has_color)
__CreateAttribute(geo->rgb, p->color)
for (uint i_uv = 0; i_uv < __UV_PER_GEOMETRY__; ++i_uv)
if (has_uv[i_uv])
__CreateAttribute(geo->uv[i_uv], p->uv[i_uv])
if (!geo->material_table.Allocate(materials.GetCount()))
__ERR__(__LOG_E__ << "Failed to allocate material array when creating geometry '" << name << "'.\n", NULL)
uint slot_count = 0;
ListForeach(String, n, materials)
geo->material_table[slot_count++].name = n.Object();
return geo.Detach();
}
void GeometryTemplate::Clear()
{
polygon = NULL;
polygons.Clear();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
GeometryTemplate::GeometryTemplate()
{
merge_threshold = 0.0001f;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,286 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry_to_triangle_list.h"
#include "core/triangle_list.h"
#include "core/geometry.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
/*!
Converter max vertex per polygon.
*/
#define PolygonMaxVertexMap 128
/*
@short Define a larger step to skip polygons during the conversion.
For debug purpose only.
*/
#define TrilistStep 1
//-------------------------------------------------------------------------------
bool GeometryToTriangleList::Convert(const Geometry &g, AutoList <Trilist *> &trilist, uint mxtri, uint optimize_cache)
{
__LOG__ << "Building geometry triangle list...\n";
if (!g.pol.GetCount())
__ERR__(__LOG_E__ << "Invalid geometry (" << g.name << ").\n", false)
Array <uint> pol_index;
g.ComputePolygonIndex(pol_index);
Array <int> vmap(g.vtx.GetCount());
if (!vmap)
__ERR__(__LOG_E__ << "Could not allocate memory to remap vertice!\n", false)
bool warn_vertex_count_exceeded = false;
Array <VertexToPolygon> vtx_to_pol;
g.ComputeVertexToPolygon(vtx_to_pol);
// Triangle list are split by material.
Array <bool> flag;
for (uint n = 0; n < g.material_table.GetCount(); n++)
{
uint _p = 0, p;
// Flag homogeneous vertex for this material.
g.FlagHomogeneousVertex(flag, pol_index, vtx_to_pol, n);
while (_p < g.pol.GetCount())
{
ushort bone_map[256];
int bone_count = 0;
// Count how many vertex will go in this list.
uint tl_vtxc = 0, tl_tric = 0;
for (p = 0; p < g.vtx.GetCount(); p++)
vmap[p] = -1;
for (p = _p; p < g.pol.GetCount(); p += TrilistStep)
if ((g.pol[p].vtx_count > 2) && (g.pol[p].material == n))
{
// Check limit constraints.
if ((tl_tric + g.pol[p].vtx_count - 2) >= mxtri)
break;
if (bone_count >= (__PL_BONE_LIMIT__ - 4))
break;
// Valid polygon.
for (uint v = 0; v < g.pol[p].vtx_count; v++)
{
uint pol_crel = g.pol[p].binding[v];
// Keep track of the bone set for this list.
if (g.skin)
for (int n = 0; n < 4; ++n)
{
for (int b = 0; b < bone_count; ++b)
if (bone_map[b] == g.skin[pol_crel].bone_index[n])
goto bone_registered;
// Register bone.
if (bone_count < __PL_BONE_LIMIT__)
bone_map[bone_count++] = g.skin[pol_crel].bone_index[n];
else __LOG_E__ << "Bone array safeguard exceeded!\n";
bone_registered:;
}
if (flag[pol_crel])
{
if (vmap[pol_crel] == -1)
vmap[pol_crel] = tl_vtxc++;
}
else
tl_vtxc++;
}
tl_tric += g.pol[p].vtx_count - 2;
}
uint break_at = p;
/*
If we have a non-zero vertices triangle list, let's allocate it
and its buffers then fill it.
*/
if (tl_vtxc)
{
// Allocate trilist.
Trilist *ptrilist = new Trilist;
if (!ptrilist)
__ERR__(__LOG_E__ << "Couldn't allocate triangle list container objects.\n", false)
trilist.Add(ptrilist);
// Allocate trilist buffers.
ptrilist->vtx.Allocate(tl_vtxc);
ptrilist->idx.Allocate(tl_tric * 3);
if (g.skin)
ptrilist->skin.Allocate(tl_vtxc);
if (bone_count)
{
ptrilist->bone.Allocate(bone_count);
Memory::Copy(&ptrilist->bone[0], bone_map, sizeof(ushort) * bone_count);
}
if (g.vtx_normal)
ptrilist->nrm.Allocate(tl_vtxc);
if (g.vtx_tangent)
ptrilist->tangent.Allocate(tl_vtxc);
for (uint u = 0; u < __UV_PER_GEOMETRY__; u++) // Note: never remap geometry UV channels.
if (g.uv[u])
ptrilist->uv[u].Allocate(tl_vtxc);
if (g.rgb)
ptrilist->rgb.Allocate(tl_vtxc);
// Fill trilist.
ptrilist->mat = n;
for (p = 0; p < g.vtx.GetCount(); p++)
vmap[p] = -1;
uint c_vtx = 0, c_tri = 0;
for (p = _p; p < g.pol.GetCount(); p += TrilistStep)
{
if ((g.pol[p].vtx_count > 2) && (g.pol[p].material == n))
{
// Do not overrun.
if ((c_tri + g.pol[p].vtx_count - 2) >= mxtri)
break;
if (p == break_at)
break;
// STOP! Lists will break a few polygons before they are actually ended!
#if 0
if (ptrilist->vtx.GetCount() == tl_vtxc)
break;
#endif
// Append polygon.
uint cpol_vmap[PolygonMaxVertexMap], v;
for (v = 0; v < g.pol[p].vtx_count; v++)
{
uint pol_crel = g.pol[p].binding[v];
// Map or insert vertex.
bool do_insert_vtx = false;
if (flag[pol_crel])
{
if (vmap[pol_crel] == -1)
{
vmap[pol_crel] = c_vtx;
do_insert_vtx = true;
}
if (v < PolygonMaxVertexMap)
cpol_vmap[v] = vmap[pol_crel];
else
warn_vertex_count_exceeded = true;
}
else
{
if (v < PolygonMaxVertexMap)
{
cpol_vmap[v] = c_vtx;
do_insert_vtx = true;
}
else
warn_vertex_count_exceeded = true;
}
// Perform vertex insertion.
if (do_insert_vtx)
{
// Position dump.
ptrilist->vtx[c_vtx] = g.vtx[pol_crel];
// Normal dump.
if (ptrilist->nrm)
ptrilist->nrm[c_vtx] = g.vtx_normal[pol_index[p] + v];
// Tangent dump.
if (ptrilist->tangent)
ptrilist->tangent[c_vtx] = g.vtx_tangent[pol_index[p] + v];
// Skin dump.
if (ptrilist->skin)
for (int b = 0; b < 4; ++b)
{
// Resolve skin bone in local trilist bone map.
int n;
for (n = 0; n < bone_count; ++n)
if (bone_map[n] == g.skin[pol_crel].bone_index[b])
break;
// Failed to resolve, cancel this bone out.
if (n == bone_count)
{
ptrilist->skin[c_vtx].w[b] = 0;
ptrilist->skin[c_vtx].bone_index[b] = 0;
}
else
{
ptrilist->skin[c_vtx].w[b] = g.skin[pol_crel].w[b];
ptrilist->skin[c_vtx].bone_index[b] = (uchar)n;
}
}
// UV sets dump.
for (uint u = 0; u < __UV_PER_GEOMETRY__; u++)
if (ptrilist->uv[u] && g.uv[u])
ptrilist->uv[u][c_vtx] = g.uv[u][pol_index[p] + v];
// RGB color.
if (ptrilist->rgb)
ptrilist->rgb[c_vtx] = g.rgb[pol_index[p] + v];
// Insertion done.
++c_vtx;
}
}
// Remap and convert this polygon to triangle list index.
for (v = 1; v < uint(g.pol[p].vtx_count - 1); v++)
{
if (v == PolygonMaxVertexMap)
break;
uint itri = c_tri * 3;
ptrilist->idx[itri + 0] = cpol_vmap[0];
ptrilist->idx[itri + 1] = cpol_vmap[v];
ptrilist->idx[itri + 2] = cpol_vmap[v + 1];
++c_tri;
}
}
}
}
_p = p;
}
}
int ttri = 0, tbone = 0;
ListForeachPtr(Trilist *, ptl, trilist)
{
ttri += ptl->GetTriangleCount();
tbone += ptl->bone.GetCount();
}
if (warn_vertex_count_exceeded)
__LOG_E__ << "One or more polygon vertex count exceeded remapping capability (" << PolygonMaxVertexMap << ") in geometry '" << g.name << "'.\n";
__LOG__ << "Done, average: " << (float)ttri / trilist.GetCount() << " tri/list, " << (float)tbone / trilist.GetCount() << " bone/list.\n";
#if 0 // Grabs a few FPS at the cost of much longer load time.
if (optimize_cache > 0)
Trilist::Optimize(trilist, optimize_cache);
#endif
return true;
}
//-------------------------------------------------------------------------------

View File

@ -0,0 +1,964 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include <cstring>
#include "core/iso_surface.h"
#include "core/geometry.h"
#include "rand/rand.h"
using namespace GS;
using namespace GS::Core;
const int Isosurface::EdgeArray[256]={0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
const int Isosurface::TriTable[256][16]=
{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
/*static*/ uint Isosurface::m_MaxNbVertex = 3000;
/*static*/ Isosurface::TVertex* Isosurface::m_TempVertexBuffer = NULL; // Vertex buffer containing the geometry
/*static*/ int Isosurface::m_MaxIdx = 3000;
/*static*/ int* Isosurface::m_TempIdxBuffer = NULL; // index buffer containing the geometry
//***************************************************
void Isosurface::CalcNormalX(float &_x, float &_y, float &_z, Vector4 &_Normal)
{
float l_Xplus1 = _x+1;
float l_Yplus1 = _y+1;
float l_Zplus1 = _z+1;
float l_Xplus2 = _x+2;
float l_Xmoins1 = _x-1;
float l_Ymoins1 = _y-1;
float l_Zmoins1 = _z-1;
// so interpolation is on X, the composant x has a special treatment
_Normal.x = interpolateVal(m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus2,_y,_z)]- m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)]- m_Grid[GridIndex(l_Xmoins1,_y,_z)]);
_Normal.y = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(l_Xplus1,l_Yplus1,_z)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(_x,l_Ymoins1,_z)], m_Grid[GridIndex(l_Xplus1,l_Ymoins1,_z)]);
_Normal.z = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(l_Xplus1,_y,l_Zplus1)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zmoins1)], m_Grid[GridIndex(l_Xplus1,_y,l_Zmoins1)]);
}
//***************************************************
void Isosurface::CalcNormalY(float &_x, float &_y, float &_z, Vector4 &_Normal)
{
float l_Xplus1 = _x+1;
float l_Yplus1 = _y+1;
float l_Zplus1 = _z+1;
float l_Yplus2 = _y+2;
float l_Xmoins1 = _x-1;
float l_Ymoins1 = _y-1;
float l_Zmoins1 = _z-1;
// so interpolation is on Y, the composant Y has a special treatment
_Normal.y = interpolateVal(m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus2,_z)]- m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)]- m_Grid[GridIndex(_x,l_Ymoins1,_z)]);
_Normal.x = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(l_Xplus1,l_Yplus1,_z)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(l_Xmoins1,_y,_z)], m_Grid[GridIndex(l_Xmoins1,l_Yplus1,_z)]);
_Normal.z = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(_x,l_Yplus1,l_Zplus1)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(_x,_y,l_Zmoins1)], m_Grid[GridIndex(_x,l_Yplus1,l_Zmoins1)]);
}
//***************************************************
void Isosurface::CalcNormalZ(float &_x, float &_y, float &_z, Vector4 &_Normal)
{
float l_Xplus1 = _x+1;
float l_Yplus1 = _y+1;
float l_Zplus1 = _z+1;
float l_Zplus2 = _z+2;
float l_Xmoins1 = _x-1;
float l_Ymoins1 = _y-1;
float l_Zmoins1 = _z-1;
// so interpolation is on Z, the composant Z has a special treatment
_Normal.z = interpolateVal(m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus2)]- m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)]- m_Grid[GridIndex(_x,_y,l_Zmoins1)]);
_Normal.y = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(_x,l_Yplus1,_z)], m_Grid[GridIndex(_x,l_Yplus1,l_Zplus1)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(_x,l_Ymoins1,_z)], m_Grid[GridIndex(_x,l_Ymoins1,l_Zplus1)]);
_Normal.x = interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(l_Xplus1,_y,_z)], m_Grid[GridIndex(l_Xplus1,_y,l_Zplus1)]) -
interpolateVal(m_Grid[GridIndex(_x,_y,_z)], m_Grid[GridIndex(_x,_y,l_Zplus1)], m_Grid[GridIndex(l_Xmoins1,_y,_z)], m_Grid[GridIndex(l_Xmoins1,_y,l_Zplus1)]);
}
//***************************************************
// function permit to linear interpolate between vector
void Isosurface::interpolateVect(Vector4 &_Vect1, Vector4 &_Vect2, float &_Val1, float &_Val2, Vector4&_Vect)
{
// _Vect1 and _Vect2 are extremities (with _val1 and _val2)
// _Vect is the position to find
// if(fabsf(m_IsoValue - _Val1) < 0.00001)
// {
// // to don't have arround error
// _Vect = _Vect1;
// }
//
// if(fabsf(m_IsoValue - _Val2) < 0.00001)
// {
// // to don't have arround error
// _Vect = _Vect2;
// }
//
// if(fabsf(_Val1 - _Val2) < 0.00001)
// {
// // to don't have arround error
// _Vect = _Vect1;
// }
float l_Coef = (m_IsoValue - _Val1) / (_Val2 - _Val1);
_Vect.x = _Vect1.x + l_Coef * (_Vect2.x - _Vect1.x);
_Vect.y = _Vect1.y + l_Coef * (_Vect2.y - _Vect1.y);
_Vect.z = _Vect1.z + l_Coef * (_Vect2.z - _Vect1.z);
}
//***************************************************
// function permit to linear interpolate between val
float Isosurface::interpolateVal(float &_Val1, float &_Val2, float _Val_cible1, float _Val_cible2)
{
if(fabsf(m_IsoValue - _Val1) < 0.00001)
{
return _Val_cible1;
}
if(fabsf(m_IsoValue - _Val2) < 0.00001)
{
return _Val_cible2;
}
if(fabsf(_Val1 - _Val2) < 0.00001)
{
return _Val_cible1;
}
if(m_IsoValue - _Val1 != 0)
{
float l_Coef = (m_IsoValue - _Val1) / (_Val2 - _Val1);
return _Val_cible1 + l_Coef * (_Val_cible2 - _Val_cible1);
}
else
return _Val_cible1;
}
//***************************************************
// Set the value of the vertex
void Isosurface::EvalPos(float &_x, float &_y, float &_z, Vector4 &_CasePosition)
{
_CasePosition.x = (_x/* - m_NbGridCase.x*0.5f*/) * m_CaseSizeDivNbCase.x /*+m_Pos.x*/;
_CasePosition.y = (_y/* - m_NbGridCase.y*0.5f*/) * m_CaseSizeDivNbCase.y /*+m_Pos.y*/;
_CasePosition.z = (_z/* - m_NbGridCase.z*0.5f*/) * m_CaseSizeDivNbCase.z /*+m_Pos.z*/;
}
//***************************************************
// return the good float with the 3d parameter in the grid
int Isosurface::GridIndex(float &_x, float &_y, float &_z)const
{
return (int)(_x+_y*m_NbGridCase.x+_z*m_NbGridCase.x*m_NbGridCase.y);
}
//***************************************************
/// calcul the polygon for one case, and return the number of triangle for the polygon
int Isosurface::CalculPolygon(float &_x, float &_y, float &_z, STriangle* _TriangleList)
{
float l_GridValues[8]; // values for each vertex of the case
Vector4 l_GridPositions[8]; // case vertex position
// vertex List for the vertex in the final polygon
Vector4 l_ListVertex[12];
float l_Xplus1 = _x+1;
float l_Yplus1 = _y+1;
float l_Zplus1 = _z+1;
// calcul values of the vertex of the case
l_GridValues[0] = m_Grid[GridIndex(_x,_y,_z)];
l_GridValues[1] = m_Grid[GridIndex(l_Xplus1,_y,_z)];
l_GridValues[2] = m_Grid[GridIndex(l_Xplus1,_y,l_Zplus1)];
l_GridValues[3] = m_Grid[GridIndex(_x,_y,l_Zplus1)];
l_GridValues[4] = m_Grid[GridIndex(_x,l_Yplus1,_z)];
l_GridValues[5] = m_Grid[GridIndex(l_Xplus1,l_Yplus1,_z)];
l_GridValues[6] = m_Grid[GridIndex(l_Xplus1,l_Yplus1,l_Zplus1)];
l_GridValues[7] = m_Grid[GridIndex(_x,l_Yplus1,l_Zplus1)];
// Calcul vertex Position
EvalPos(_x, _y, _z, l_GridPositions[0]);
EvalPos(l_Xplus1, _y, _z, l_GridPositions[1]);
EvalPos(l_Xplus1, _y, l_Zplus1, l_GridPositions[2]);
EvalPos(_x, _y, l_Zplus1, l_GridPositions[3]);
EvalPos(_x, l_Yplus1, _z, l_GridPositions[4]);
EvalPos(l_Xplus1, l_Yplus1, _z, l_GridPositions[5]);
EvalPos(l_Xplus1, l_Yplus1, l_Zplus1, l_GridPositions[6]);
EvalPos(_x, l_Yplus1, l_Zplus1, l_GridPositions[7]);
// find the index in the edge Array to know wich side the surface intersect
int l_Index = 0;
if(l_GridValues[0] < m_IsoValue)
l_Index |= 1; // put the bit 0 at 1
if(l_GridValues[1] < m_IsoValue)
l_Index |= 2;
if(l_GridValues[2] < m_IsoValue)
l_Index |= 4;
if(l_GridValues[3] < m_IsoValue)
l_Index |= 8;
if(l_GridValues[4] < m_IsoValue)
l_Index |= 16;
if(l_GridValues[5] < m_IsoValue)
l_Index |= 32;
if(l_GridValues[6] < m_IsoValue)
l_Index |= 64;
if(l_GridValues[7] < m_IsoValue)
l_Index |= 128;
// Calcul vertex position where the surface intersect the case
if(EdgeArray[l_Index] == 0) // the case is out the surface
return 0;
if(EdgeArray[l_Index] & 1)
interpolateVect(l_GridPositions[0], l_GridPositions[1], l_GridValues[0], l_GridValues[1], l_ListVertex[0]);
if(EdgeArray[l_Index] & 2)
interpolateVect(l_GridPositions[1], l_GridPositions[2], l_GridValues[1], l_GridValues[2], l_ListVertex[1]);
if(EdgeArray[l_Index] & 4)
interpolateVect(l_GridPositions[2], l_GridPositions[3], l_GridValues[2], l_GridValues[3], l_ListVertex[2]);
if(EdgeArray[l_Index] & 8)
interpolateVect(l_GridPositions[3], l_GridPositions[0], l_GridValues[3], l_GridValues[0], l_ListVertex[3]);
if(EdgeArray[l_Index] & 16)
interpolateVect(l_GridPositions[4], l_GridPositions[5], l_GridValues[4], l_GridValues[5], l_ListVertex[4]);
if(EdgeArray[l_Index] & 32)
interpolateVect(l_GridPositions[5], l_GridPositions[6], l_GridValues[5], l_GridValues[6], l_ListVertex[5]);
if(EdgeArray[l_Index] & 64)
interpolateVect(l_GridPositions[6], l_GridPositions[7], l_GridValues[6], l_GridValues[7], l_ListVertex[6]);
if(EdgeArray[l_Index] & 128)
interpolateVect(l_GridPositions[7], l_GridPositions[4], l_GridValues[7], l_GridValues[4], l_ListVertex[7]);
if(EdgeArray[l_Index] & 256)
interpolateVect(l_GridPositions[0], l_GridPositions[4], l_GridValues[0], l_GridValues[4], l_ListVertex[8]);
if(EdgeArray[l_Index] & 512)
interpolateVect(l_GridPositions[1], l_GridPositions[5], l_GridValues[1], l_GridValues[5], l_ListVertex[9]);
if(EdgeArray[l_Index] & 1024)
interpolateVect(l_GridPositions[2], l_GridPositions[6], l_GridValues[2], l_GridValues[6], l_ListVertex[10]);
if(EdgeArray[l_Index] & 2048)
interpolateVect(l_GridPositions[3], l_GridPositions[7], l_GridValues[3], l_GridValues[7], l_ListVertex[11]);
// Calcul the triangles
int l_NbTriangles = 0;
for(int i=0; TriTable[l_Index][i]!=-1; i+=3)
{
_TriangleList[l_NbTriangles].m_Vertex[0] = l_ListVertex[TriTable[l_Index][i]];
_TriangleList[l_NbTriangles].m_Num[0] = TriTable[l_Index][i];
_TriangleList[l_NbTriangles].m_Vertex[1] = l_ListVertex[TriTable[l_Index][i+1]];
_TriangleList[l_NbTriangles].m_Num[1] = TriTable[l_Index][i+1];
_TriangleList[l_NbTriangles].m_Vertex[2] = l_ListVertex[TriTable[l_Index][i+2]];
_TriangleList[l_NbTriangles].m_Num[2] = TriTable[l_Index][i+2];
++l_NbTriangles;
}
return l_NbTriangles;
}
//***************************************************
// draw the triangle in the cellule x,y, z
void Isosurface::RenderCell(uint &vtx_count, float &_x, float &_y, float &_z)
{
// nVector l_U, l_V; // 2 vector permit to define 1 face
// float l_Color[3]; // color of the current vertex
Vector4 *l_Pos; // vertex pos
// Polygon triangle
STriangle l_TriangleList[12];
int l_NbFace= CalculPolygon(_x, _y, _z, l_TriangleList); // nombre de faces in the current polygone
for( int Face=0; Face< l_NbFace; ++Face)
{
m_Mutex.Lock();
// compute the normal vector
for(int i=0; i< 3; ++i)
{
// calcul of the normale for each vertex for each new triangle
// nVector l_Normal; // current Normale
l_Pos = &l_TriangleList[Face].m_Vertex[i];
/* if(_x>0 && _y>0 && _z>0)
{
float l_Xplus1 = _x+1;
float l_Yplus1 = _y+1;
float l_Zplus1 = _z+1;
switch(l_TriangleList[Face].m_Num[i])
{
case 0:
CalcNormalX(_x, _y, _z, l_Normal);
break;
case 1:
CalcNormalZ(l_Xplus1, _y, _z, l_Normal);
break;
case 2:
CalcNormalX(_x, _y, l_Zplus1, l_Normal);
break;
case 3:
CalcNormalZ(_x, _y, _z, l_Normal);
break;
case 4:
CalcNormalX(_x, l_Yplus1, _z, l_Normal);
break;
case 5:
CalcNormalZ(l_Xplus1, l_Yplus1, _z, l_Normal);
break;
case 6:
CalcNormalX(_x, l_Yplus1, l_Zplus1, l_Normal);
break;
case 7:
CalcNormalZ(_x, l_Yplus1, _z, l_Normal);
break;
case 8:
CalcNormalY(_x, _y, _z, l_Normal);
break;
case 9:
CalcNormalY(l_Xplus1, _y, _z, l_Normal);
break;
case 10:
CalcNormalY(l_Xplus1, _y, l_Zplus1, l_Normal);
break;
case 11:
CalcNormalY(_x, _y, l_Zplus1, l_Normal);
break;
}
}
*/
// if don't use the cube mapping
// if(texture == NULL)
{
// compute vertex color
/* l_Color[0] = (l_Pos->x/ m_GridSize.x +1) *0.5f;
l_Color[1] = (l_Pos->y/ m_GridSize.y +1) *0.5f;
l_Color[2] = (l_Pos->z/ m_GridSize.z +1) *0.5f;
glMaterialfv(GL_FRONT, GL_SPECULAR, l_Color);
glMaterialf(GL_FRONT, GL_SHININESS, 50.0f);
glMaterialfv(GL_FRONT, GL_AMBIENT, l_Color);
glMaterialfv(GL_FRONT, GL_DIFFUSE, l_Color);*/
}
// re- Normalise normal
// l_Normal = l_Normal.Normalize();
// glNormal3f(-l_Normal.x, -l_Normal.y, -l_Normal.z);
// glVertex3f(l_Pos->x, l_Pos->y, l_Pos->z);
if(vtx_count >= m_MaxNbVertex)
{ // not enough vertice increase the temp array
TVertex* l_NewTempVertexBuffer = new TVertex[m_MaxNbVertex+3000];
memcpy(l_NewTempVertexBuffer, m_TempVertexBuffer, sizeof(TVertex)*m_MaxNbVertex);
delete []m_TempVertexBuffer;
m_MaxNbVertex += 3000;
m_TempVertexBuffer = l_NewTempVertexBuffer;
}
if(m_CountIdxBuffer >= m_MaxIdx)
{ // not enough vertice increase the temp array
int* l_NewTempVertexBuffer = new int[m_MaxIdx+3000];
memcpy(l_NewTempVertexBuffer, m_TempIdxBuffer, sizeof(int)*m_MaxIdx);
delete []m_TempIdxBuffer;
m_MaxIdx += 3000;
m_TempIdxBuffer = l_NewTempVertexBuffer;
}
/*
m_TempVertexBuffer[vtx.GetCount()].nx = -l_Normal.x;
m_TempVertexBuffer[vtx.GetCount()].ny = -l_Normal.y;
m_TempVertexBuffer[vtx.GetCount()].nz = -l_Normal.z;
*/
// ugly stuff to find id
int l_IdFind = -1;
for(uint id = 0; id<vtx_count; ++id)
if( m_TempVertexBuffer[id].x == l_Pos->x
&& m_TempVertexBuffer[id].y == l_Pos->y
&& m_TempVertexBuffer[id].z == l_Pos->z)
{
l_IdFind = id;
break;
}
if(l_IdFind == -1)
{
m_TempVertexBuffer[vtx_count].x = l_Pos->x;
m_TempVertexBuffer[vtx_count].y = l_Pos->y;
m_TempVertexBuffer[vtx_count].z = l_Pos->z;
l_IdFind = vtx_count;
++vtx_count;
}
m_TempIdxBuffer[m_CountIdxBuffer++] = l_IdFind;
}
m_Mutex.Unlock();
}
}
//*********************************************
void ClipVector(Vector4 &_VectorIndexClip, Vector4 &_MaxIndex)
{
if(_VectorIndexClip.x < 0)
_VectorIndexClip.x = 0;
if(_VectorIndexClip.x >= _MaxIndex.x)
_VectorIndexClip.x = _MaxIndex.x-1;
if(_VectorIndexClip.y < 0)
_VectorIndexClip.y = 0;
if(_VectorIndexClip.y >= _MaxIndex.y)
_VectorIndexClip.y = _MaxIndex.y-1;
if(_VectorIndexClip.z < 0)
_VectorIndexClip.z = 0;
if(_VectorIndexClip.z >= _MaxIndex.z)
_VectorIndexClip.z = _MaxIndex.z-1;
}
//*********************************************
void Isosurface::ComputeMetaball(int nb_metaball, Vector4* pos_metaball, float* value_metaball)
{
Vector4 l_Vect; // vector between the ball center and the case of the grid
Vector4 l_Pos, l_PosMetaBall; // case center position
float l_Dist; // distance between ball center and the case
float l_TempRayon, l_TempRayon2, l_TempDistDivRayon; // rayon of the metaball and distance divide by the rayon
int l_Index, l_IndexMax = (int)(m_NbGridCase.x*m_NbGridCase.y*m_NbGridCase.z);
float x, y, z;
int i; // count paramater
Vector4 l_PosMetInGridDeb, l_PosMetInGridFin;
Vector4 l_TempSize(m_GridSize.x/(m_NbGridCase.x-2), m_GridSize.y/(m_NbGridCase.y-2), m_GridSize.z/(m_NbGridCase.z-2));
Vector4 l_TempSizeInverse((m_NbGridCase.x-2)/m_GridSize.x, (m_NbGridCase.y-2)/m_GridSize.y, (m_NbGridCase.z-2)/m_GridSize.z);
// clean all the grid
int l_NbCase = (int)(m_NbGridCase.x*m_NbGridCase.y*m_NbGridCase.z);
memset(m_Grid, 0, sizeof(float)*l_NbCase);
// memset(m_GridMetaBall->m_TabIndexValid, 0, sizeof(nVector)*m_NbGridCase.x*m_NbGridCase.y*m_NbGridCase.z);
int l_NbIndexValid = 0;
float l_MetaballIntensity = 1.0f;
for(i=0; i< nb_metaball; ++i)
{
l_PosMetaBall = pos_metaball[i];
l_TempRayon = value_metaball[i];
l_TempRayon2 = l_TempRayon*l_TempRayon;
if((l_PosMetaBall.x - l_TempRayon < m_Pos.x + m_GridSize.x && l_PosMetaBall.x + l_TempRayon > m_Pos.x)
&& (l_PosMetaBall.y - l_TempRayon < m_Pos.y + m_GridSize.y && l_PosMetaBall.y + l_TempRayon > m_Pos.y)
&& (l_PosMetaBall.z - l_TempRayon < m_Pos.z + m_GridSize.z && l_PosMetaBall.z + l_TempRayon > m_Pos.z))
{
l_PosMetInGridDeb.x = (((l_PosMetaBall.x - l_TempRayon)- m_Pos.x)*l_TempSizeInverse.x);
l_PosMetInGridDeb.y = (((l_PosMetaBall.y - l_TempRayon)- m_Pos.y)*l_TempSizeInverse.y);
l_PosMetInGridDeb.z = (((l_PosMetaBall.z - l_TempRayon)- m_Pos.z)*l_TempSizeInverse.z);
l_PosMetInGridFin.x = (((l_PosMetaBall.x + l_TempRayon)- m_Pos.x)*l_TempSizeInverse.x);
l_PosMetInGridFin.y = (((l_PosMetaBall.y + l_TempRayon)- m_Pos.y)*l_TempSizeInverse.y);
l_PosMetInGridFin.z = (((l_PosMetaBall.z + l_TempRayon)- m_Pos.z)*l_TempSizeInverse.z);
ClipVector(l_PosMetInGridDeb, m_NbGridCase);
ClipVector(l_PosMetInGridFin, m_NbGridCase);
// find only the voxel touch by the metaball
for(z=l_PosMetInGridDeb.z; z< l_PosMetInGridFin.z; ++z)
for(y=l_PosMetInGridDeb.y; y< l_PosMetInGridFin.y; ++y)
for(x=l_PosMetInGridDeb.x; x< l_PosMetInGridFin.x; ++x)
{
// calcul distance between the case and the center of the metal ball
l_Vect.x = (x*l_TempSize.x) + m_Pos.x - l_PosMetaBall.x;
l_Vect.y = (y*l_TempSize.y) + m_Pos.y - l_PosMetaBall.y;
l_Vect.z = (z*l_TempSize.z) + m_Pos.z - l_PosMetaBall.z;
l_Dist = l_Vect.Len2();
// take place for the metaball in the grid
if(l_Dist <= l_TempRayon2)
//if(l_Dist <= l_TempRayon2 && (y*l_TempSize.y) + m_Pos.y - l_PosMetaBall.y <= l_TempRayon2)
{
l_Index = (int)(x+ y*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y);
if(l_Index >=0 && l_Index <l_IndexMax)
{
l_TempDistDivRayon = 1 - l_Dist / l_TempRayon2;
m_Grid[l_Index] += l_MetaballIntensity * l_TempDistDivRayon* l_TempDistDivRayon;
}
}
}
}
}
// to go faster after, just stock the used voxel
// add the index valid , to don't look the other empty voxels
for(z=0; z< m_NbGridCase.z-1; ++z)
for(y=0; y< m_NbGridCase.y-1; ++y)
for(x=0; x< m_NbGridCase.x-1; ++x)
{
if(m_Grid[(int)(x+ y*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)((x+1)+ y*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)((x+1)+ (y+1)*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)((x+1)+ (y+1)*m_NbGridCase.x + (z+1)*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)((x+1)+ y*m_NbGridCase.x + (z+1)*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)(x+ (y+1)*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)(x+ (y+1)*m_NbGridCase.x + (z+1)*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f
|| m_Grid[(int)(x+ y*m_NbGridCase.x + (z+1)*m_NbGridCase.x*m_NbGridCase.y)] > 0.0f)
{
m_TabIndexValid[l_NbIndexValid].x = x;
m_TabIndexValid[l_NbIndexValid].y = y;
m_TabIndexValid[l_NbIndexValid].z = z;
++l_NbIndexValid;
}
}
m_NbIndexValid = l_NbIndexValid;
}
/// Triangularize the iso-surface
void Isosurface::Triangularize(Geometry* geometry, int nb_metaball, Vector4* pos_metaball, float* value_metaball)
{
// point[0].x += 0.1f;
// if(point[0].x > 25)
// point[0].x = 0;
// point[1].z -= 0.1f;
// point[2].y -= 0.1f;
// if(point[1].z < -5)
// point[1].z = 12;
// if(point[2].y < -15)
// point[2].y = 15;
ComputeMetaball(nb_metaball, pos_metaball, value_metaball);
m_CountIdxBuffer = 0;
uint vtx_count = 0;
#pragma omp parallel for
for(int i=0; i< m_NbIndexValid; ++i)
{
RenderCell(vtx_count, m_TabIndexValid[i].x, m_TabIndexValid[i].y, m_TabIndexValid[i].z);
}
if(vtx_count >0 && vtx_count <m_MaxNbVertex)
{
// initialize Cube vertex
// nombre de faces et de sommets
geometry->AllocateVertex(vtx_count);
geometry->AllocatePolygon(m_CountIdxBuffer/3);
// geometry->vtx_normal = new nVector[vtx.GetCount()];
// fill the table
#pragma omp parallel for
for(int i=0; i< static_cast<int> (vtx_count); ++i)
{
geometry->vtx[i] = Vector4(m_TempVertexBuffer[i].x, m_TempVertexBuffer[i].y, m_TempVertexBuffer[i].z);
// geometry->vtx_normal[i*3 + 2-n] = nVector(m_TempVertexBuffer[i*3 + n].nx, m_TempVertexBuffer[i*3 + n].ny, m_TempVertexBuffer[i*3 + n].nz);
}
#pragma omp parallel for
for(int i=0; i< static_cast<int> (geometry->pol.GetCount()); ++i)
{
geometry->pol[i].vtx_count = 3;
geometry->pol[i].material = 0;
}
geometry->AllocatePolygonBinding();
#pragma omp parallel for
for(int i=0; i< static_cast<int> (geometry->pol.GetCount()); ++i)
{
geometry->pol[i].vtx_count = 3;
for (int n = 0; n < 3; ++n)
geometry->pol[i].binding[2-n] = m_TempIdxBuffer[i * 3 + n];
geometry->pol[i].material = 0;
}
geometry->ComputeVertexNormal(true);
}
}
//********************************************************************
bool Isosurface::Init(const Vector4 &_pos, const Vector4 &size, const Vector4 &step)
{
m_Pos = _pos;
m_NbGridCase = step;
m_GridSize = size;
delete []m_Grid;
m_Grid = new float[int(ceil(m_NbGridCase.x)*ceil(m_NbGridCase.y)*ceil(m_NbGridCase.z))];
// clean all the grid
int l_NbCase = (int)(m_NbGridCase.x*m_NbGridCase.y*m_NbGridCase.z);
memset(m_Grid, 0, sizeof(float)*l_NbCase);
delete []m_TabIndexValid;
m_TabIndexValid = new Vector4[int(ceil(m_NbGridCase.x)*ceil(m_NbGridCase.y)*ceil(m_NbGridCase.z))];
m_NbIndexValid = 0;
for(float z=0; z< m_NbGridCase.z-1; ++z)
for(float y=0; y< m_NbGridCase.y-1; ++y)
for(float x=0; x< m_NbGridCase.x-1; ++x)
{
//if(m_Grid[x+ y*m_NbGridCase.x + z*m_NbGridCase.x*m_NbGridCase.y])
{
m_TabIndexValid[m_NbIndexValid].x = x;
m_TabIndexValid[m_NbIndexValid].y = y;
m_TabIndexValid[m_NbIndexValid].z = z;
++m_NbIndexValid;
}
}
m_CaseSizeDivNbCase = Vector4(m_GridSize.x/m_NbGridCase.x, m_GridSize.y/m_NbGridCase.y, m_GridSize.z/m_NbGridCase.z);
return true;
}
/// Get the iso-surface field size
void Isosurface::GetFieldSize(int &x, int &y, int &z)
{
x = (int)(m_GridSize.x);
y = (int)(m_GridSize.y);
z = (int)(m_GridSize.z);
}
/// Get the iso-surface field
void Isosurface::GetField(float *_Grid)
{
_Grid = m_Grid;
}
//-------------------------------------------------------
Isosurface::Isosurface()
{
m_Pos = Vector4(0,0,0);
m_Grid = NULL;
m_TabIndexValid = NULL;
m_IsoValue =0.99f;
m_CountIdxBuffer = 0;
m_TempIdxBuffer = new int[m_MaxIdx];
m_TempVertexBuffer = new TVertex[m_MaxNbVertex];
}
//-------------------------
Isosurface::~Isosurface()
{
delete []m_Grid;
delete []m_TempVertexBuffer;
}

View File

@ -0,0 +1,341 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/item.h"
#include "geometry/bounding_box.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
Matrix4 Item::GetMatrixNoPivot()
{
Matrix4 p = GetPivot();
SetPivot(Matrix4::IdentityMatrix());
Matrix4 m = GetMatrix();
SetPivot(p);
return m;
}
void Item::ComputeLocalMatrix()
{
if (!item_flags.IsSet(ItemFlagLocalMatrixDirty))
return;
if (!item_flags.IsSet(ItemFlagHasTarget) && item_flags.IsSet(ItemFlagRotationMatrixDirty))
{
rotation_matrix = Matrix3::FromEuler(rotation.x, rotation.y, rotation.z, rorder);
item_flags.Remove(ItemFlagRotationMatrixDirty);
}
local_matrix =
(
Matrix4::TranslationMatrix(position) *
Matrix4::FromMatrix3(rotation_matrix) *
Matrix4::ScaleMatrix(scale)
)
*
pivot_matrix;
item_flags.Remove(ItemFlagLocalMatrixDirty);
}
void Item::ComputeMatrix()
{
bool update_local = item_flags.IsSet(ItemFlagLocalMatrixDirty),
update_world = item_flags.IsSet(ItemFlagWorldMatrixDirty);
if (update_local)
ComputeLocalMatrix();
if (!parent)
{
if (update_world)
matrix = local_matrix;
}
else if (update_world)
{
matrix = parent->GetMatrix() * local_matrix;
if (item_flags.IsSet(ItemFlagInheritPositionOnly))
{
Matrix4 m(Matrix4::FromMatrix3(rotation_matrix));
m.SetRow(3, matrix.GetRow(3));
matrix = m;
}
}
/// Handle item target and scale.
if (update_local || update_world)
if (item_flags.IsSet(ItemFlagHasTarget))
{
matrix.Decompose(NULL, NULL, &rotation_matrix);
Matrix3 tgtm = Matrix3::FromOrthonormalBasis(target - matrix.GetRow(3));
matrix = matrix * Matrix4::FromMatrix3(rotation_matrix.Transposed() * tgtm);
rotation_matrix = tgtm;
}
item_flags.Remove(ItemFlagWorldMatrixDirty);
}
void Item::ComputeInverseMatrix()
{
if (item_flags.IsSet(ItemFlagInverseWorldMatrixDirty))
{
imatrix = GetMatrix().InversedFast();
item_flags.Remove(ItemFlagInverseWorldMatrixDirty);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Item::MarkWorldTransformationDirty()
{
item_flags.Set(ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty);
ListForeachPtr(Item *, i, children)
i->MarkWorldTransformationDirty();
}
void Item::MarkTransformationDirty(bool child_only)
{
if (!child_only)
item_flags.Set(ItemFlagLocalMatrixDirty | ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty);
ListForeachPtr(Item *, i, children)
i->MarkWorldTransformationDirty();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Item::SetPosition(const Vector4 &p)
{
position = p;
MarkTransformationDirty();
}
const Vector4 &Item::GetPosition() const
{ return position; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Item::SetRotation(const Vector4 &r)
{
rotation = r;
item_flags.Set(ItemFlagRotationMatrixDirty);
MarkTransformationDirty();
}
void Item::SetRotation(const Quaternion &q)
{
rotation_matrix = q.AsMatrix3();
item_flags.Remove(ItemFlagRotationMatrixDirty);
rotation = rotation_matrix.AsEuler(GetRotationOrder());
MarkTransformationDirty();
}
void Item::SetRotation(const Matrix3 &m)
{
rotation_matrix = m;
item_flags.Remove(ItemFlagRotationMatrixDirty);
rotation = rotation_matrix.AsEuler(GetRotationOrder());
MarkTransformationDirty();
}
const Vector4 &Item::GetRotation() const
{ return rotation; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Item::SetScale(const Vector4 &s)
{
scale = s;
MarkTransformationDirty();
}
const Vector4 &Item::GetScale() const
{ return scale; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Item::SetPivot(const Matrix4 &m)
{
pivot_matrix = m;
MarkTransformationDirty();
}
const Matrix4 &Item::GetPivot() const
{ return pivot_matrix; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
const Matrix4 &Item::GetPreviousMatrix() const
{ return prv_matrix; }
void Item::SetPreviousMatrix(const Matrix4 &mtx)
{ prv_matrix = mtx; }
const Matrix4 &Item::GetLocalMatrix()
{
ComputeMatrix();
return local_matrix;
}
const Matrix4 &Item::GetMatrix()
{
ComputeMatrix();
return matrix;
}
const Matrix4 &Item::GetInverseMatrix()
{
ComputeInverseMatrix();
return imatrix;
}
const Matrix3 &Item::GetRotationMatrix()
{
ComputeMatrix();
return rotation_matrix;
}
//------------------------------------------------------------------------------
//-------------------------------------------------------------------
void Item::OffsetWorldPosition(const Vector4 &offset)
//-------------------------------------------------------------------
{
if (parent)
position += (matrix.GetRow(3) + offset) * parent->imatrix - matrix.GetRow(3) * parent->imatrix;
else position += offset;
MarkTransformationDirty();
}
//------------------------------------------------
bool Item::IsLinkedTo(Item *item)
//------------------------------------------------
{
for (Item *c = this; c; )
{
if (c == item)
return true;
c = c->GetParent();
}
return false;
}
//------------------------------------------------------------------
void Item::ComputeLocalMinMax(MinMax &minmax) const
//------------------------------------------------------------------
{
Vector4 w_position = matrix.GetRow(3);
minmax.Set(w_position, w_position);
}
//------------------------------------------------------------------------------------------------
void Item::SnapshotTransformation(const Matrix4 &m, bool local, bool only_matrix)
//------------------------------------------------------------------------------------------------
{
local_matrix = (parent && !local) ? parent->GetInverseMatrix() * m : m;
item_flags.Remove(ItemFlagLocalMatrixDirty);
if (!only_matrix)
{
// Remove pivot before extracting transformation components.
(local_matrix * pivot_matrix.InversedFast()).Decompose(&position, &scale, &rotation_matrix);
rotation = rotation_matrix.AsEuler(rorder);
item_flags.Remove(ItemFlagRotationMatrixDirty);
}
MarkWorldTransformationDirty();
}
//--------------------------------------------
void Item::SetParent(Item *p)
//--------------------------------------------
{
if (p == this)
__ERRRAW__(__LOG_E__ << "Cannot parent item to itself.\n")
// Already linked.
if (p && p->children.Find(this)) // FIXME why not if (parent == i)???
return;
// Catch and correct deadlock.
for (Item *c = p; c; c = c->GetParent())
if (c->GetParent() && (c->GetParent() == this))
{
c->SetParent(GetParent()); // Extract 'this' from the parent chain.
__LOG_W__ << "Deadlock detected, link chain has been corrected.\n";
break;
}
// Remove from current parent children list.
if (parent)
parent->children.Remove(this);
// Set parent.
parent = p;
// Insert as a new parent child.
if (parent)
parent->children.Add(this);
MarkTransformationDirty();
}
//----------------------------------------------------
void Item::SetTarget(const Vector4 *p)
//----------------------------------------------------
{
if (p)
{
item_flags.Set(ItemFlagHasTarget);
target = *p;
}
else
item_flags.Remove(ItemFlagHasTarget);
MarkTransformationDirty();
}
//-----------------------------------------------------
void Item::SetMatrix(const Matrix4 &m)
//-----------------------------------------------------
{
SnapshotTransformation(m, false);
matrix = m;
imatrix = m.InversedFast();
item_flags.Remove(ItemFlagWorldMatrixDirty | ItemFlagInverseWorldMatrixDirty);
MarkTransformationDirty(true);
}
//--------------------------------------------------------------
void Item::SetRotationOrder(Math::rOrder order)
//--------------------------------------------------------------
{
rorder = order;
MarkTransformationDirty();
}
//------------------------------------------------------------------------------
Item::Item() : position(0, 0, 0), rotation(0, 0, 0), scale(1, 1, 1)
{
local_matrix = Matrix4::IdentityMatrix();
prv_matrix = Matrix4::IdentityMatrix();
matrix = Matrix4::IdentityMatrix();
imatrix = Matrix4::IdentityMatrix();
pivot_matrix = Matrix4::IdentityMatrix();
parent = NULL;
rorder = Math::rOrder_Default;
scale.Set(1,1,1,1);
mitem = NULL;
target.Set(0, 0, 1);
opacity = 1;
MarkTransformationDirty();
item_flags.Set(ItemFlagRotationMatrixDirty);
}
Item::~Item()
{
ListForeachPtr(Item *, child, children)
child->SetParent(NULL);
SetParent(NULL);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,156 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/item.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::NML;
//------------------------------------------------------------------------------
bool Item::FromMetaTag(Tag &tag)
{
if (tag.name != "Item")
__ERR__(__LOG_E__ << "Could not parse item, incorrect root tag (" << tag.name << ").\n", false)
item_flags = 0;
position.Set(0, 0, 0);
rotation.Set(0, 0, 0);
scale.Set(1, 1, 1);
opacity = 1;
pivot_matrix = Matrix4::IdentityMatrix();
rorder = Math::rOrder_Default;
registry.Clear();
// Parse root tags.
NMLTagForeach(pt, tag)
{
// Legacy support.
if (pt->name == "OffsetPosition")
{
Vector4 position;
position.FromMetaTag(*pt);
pivot_matrix.SetRow(3, position);
}
else if (pt->name == "OffsetMatrix")
pivot_matrix.FromMetaTag(*pt);
else if (pt->name == "Position")
position.FromMetaTag(*pt);
else if (pt->name == "Rotation")
rotation.FromMetaTag(*pt);
else if (pt->name == "Scale")
scale.FromMetaTag(*pt);
else if (pt->name == "Target")
target.FromMetaTag(*pt);
else if (pt->name == "TargetOffsetRotation")
;
else if (pt->name == "ItemFlag")
{
NMLTagForeach(ft, *pt)
{
if (ft->name == "HasTarget")
item_flags.Set(ItemFlagHasTarget);
if (ft->name == "Invisible")
item_flags.Set(ItemFlagInvisible);
if (ft->name == "LinkOnlyPosition")
item_flags.Set(ItemFlagInheritPositionOnly);
}
}
else if (pt->name == "RotationOrder")
{
String ro(pt->GetString());
if (ro == "ZYX") rorder = Math::rOrder_ZYX;
else if (ro == "YZX") rorder = Math::rOrder_YZX;
else if (ro == "ZXY") rorder = Math::rOrder_ZXY;
else if (ro == "XZY") rorder = Math::rOrder_XZY;
else if (ro == "YXZ") rorder = Math::rOrder_YXZ;
else if (ro == "XYZ") rorder = Math::rOrder_XYZ;
else if (ro == "XY") rorder = Math::rOrder_XY;
else __LOG_W__ << "Unknown rotation order '" << ro << "'.\n";
}
else if (
(pt->name == "OrientationQuaternion") ||
(pt->name == "OrientationMatrix")
)
;
else if (pt->name == "Registry")
{
NMLTagForeach(child, *pt)
registry.AddRoot(child->Clone());
}
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Item>.\n";
}
MarkTransformationDirty();
item_flags.Set(ItemFlagRotationMatrixDirty);
ComputeMatrix();
ComputeInverseMatrix();
return true;
}
Tag *Item::AsMetaTag() const
{
Tag *root = new Tag("Item");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize item. Failed to create root tag.\n", NULL)
Vector4 NULL_vec(0, 0, 0), NULL_scale(1, 1, 1);
// Save transformation.
if (pivot_matrix != Matrix4::IdentityMatrix())
root->AddChild(pivot_matrix.AsMetaTag("OffsetMatrix"));
if (position != NULL_vec)
root->AddChild(position.AsMetaTag("Position"));
if (rotation != NULL_vec)
root->AddChild(rotation.AsMetaTag("Rotation"));
if (scale != NULL_scale)
root->AddChild(scale.AsMetaTag("Scale"));
if (item_flags.Get() != 0)
if (Tag *ft = root->AddChild("ItemFlag"))
{
if (item_flags.IsSet(ItemFlagHasTarget))
ft->AddChild("HasTarget");
if (item_flags.IsSet(ItemFlagInvisible))
ft->AddChild("Invisible");
if (item_flags.IsSet(ItemFlagInheritPositionOnly))
ft->AddChild("LinkOnlyPosition");
}
root->AddChild(target.AsMetaTag("Target"));
switch (rorder)
{
case Math::rOrder_ZYX: root->AddChild("RotationOrder", "ZYX"); break;
case Math::rOrder_YZX: root->AddChild("RotationOrder", "YZX"); break;
case Math::rOrder_ZXY: root->AddChild("RotationOrder", "ZXY"); break;
case Math::rOrder_XZY: root->AddChild("RotationOrder", "XZY"); break;
case Math::rOrder_YXZ: root->AddChild("RotationOrder", "YXZ"); break;
case Math::rOrder_XYZ: root->AddChild("RotationOrder", "XYZ"); break;
case Math::rOrder_XY: root->AddChild("RotationOrder", "XY"); break;
default:
break;
}
// Registry.
Tag *tag_registry = root->AddChild("Registry");
NMLFileForeach(child, registry)
tag_registry->AddChild(child->Clone());
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,227 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/light.h"
#include "core/resource_factories.h"
#include "core/render_resource_factory.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void Light::ComputeProjectionMatrix(Matrix4 &m) const
{
switch (model)
{
case Model_Spot:
{
const float q = volume_range / (volume_range - z_near),
fov = (cone_angle + edge_angle),
zoom_factor = float(Math::Cos(fov) / Math::Sin(fov));
// Default aspect ration: PC(1:1).
m.Set
(
zoom_factor, 0, 0, 0,
0, zoom_factor, 0, 0,
0, 0, q, 1,
0, 0, -q * z_near, 0
);
}
break;
default:
m = Matrix4::IdentityMatrix();
break;
}
}
void Light::ComputeFrustrum(Frustum &f, float zn, float zf) const
{
if (model == Model_Spot)
f.SetPerspective((cone_angle + edge_angle) * 2, zn != -1 ? zn : z_near, zf != -1 ? zf : volume_range, &GetMatrix(), 1, 1);
}
void Light::ComputeMatrix()
{
bool update_world = item_flags.IsSet(ItemFlagWorldMatrixDirty);
Item::ComputeMatrix();
// Remove scale from world matrix.
if (update_world)
{
Vector4 u = matrix.GetRow(0).Normalized();
matrix.m[0][0] = u.x; matrix.m[1][0] = u.y; matrix.m[2][0] = u.z;
Vector4 v = matrix.GetRow(1).Normalized();
matrix.m[0][1] = v.x; matrix.m[1][1] = v.y; matrix.m[2][1] = v.z;
Vector4 w = matrix.GetRow(2).Normalized();
matrix.m[0][2] = w.x; matrix.m[1][2] = w.y; matrix.m[2][2] = w.z;
}
ComputeFrustrum(frustum);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Light::SampleColor(const Vector4 &location, const Vector4 &normal, Color &diff, Color &spec, Vector4 *view, float gloss)
{
float idiff, ispec;
if (!SampleEnergy(location, normal, &idiff, &ispec, view, gloss, true, false))
{
diff.Set();
spec.Set();
return false;
}
diff = diffuse_color * diffuse_intensity * idiff;
spec = specular_color * specular_intensity * ispec;
return true;
}
bool Light::SampleEnergy(const Vector4 &loc, const Vector4 &normal, float *diff, float *spec, Vector4 *view, float gloss, bool halfway, bool cooktorrance)
{
if (!diff && !spec)
return false;
Vector4 dt;
float a = 1;
switch (model)
{
case Model_Linear:
dt = GetMatrix().GetRow(2).Reversed().Normalized();
break;
default:
{
dt = GetMatrix().GetRow(3) - loc;
float dt_length = dt.Len();
dt /= dt_length;
// Compute light attenuation.
if (range)
{
float distance = dt_length / range;
switch (falloff)
{
/*
case Falloff_InvDist:
if (distance)
a = 1 / distance;
break;
case Falloff_InvDist2:
if (distance)
a = 1 / (distance * distance);
break;
*/
default:
case Falloff_Linear:
a = 1 - distance;
break;
}
if (a <= 0)
return false;
}
if (model == Model_Spot)
{
float c = Math::ACos(dt.Reversed().Dot(GetMatrix().GetRow(2).Normalized()));
if ((c < 0) || (c > (cone_angle + edge_angle)))
return false;
if (c > cone_angle)
a *= 1 - (c - cone_angle) / edge_angle;
}
}
break;
}
// Sample diffuse.
float e = normal.Dot(dt);
if (e < 0)
return false;
if (diff)
*diff = e * a * diffuse_intensity;
/*
Sample specular.
Use the halfway vector method if you'd like to avoid a vector reflection.
*/
if (spec)
{
*spec = 0;
if (view)
{
Vector4 local_view = view->Normalized();
float e = 0;
if (cooktorrance)
__LOG_W__ << "Cook-Torrance specular model not implemented.\n";
else
{
if (halfway)
e = (dt - local_view).Normalized().Dot(normal);
else e = local_view.Reflected(normal).Dot(dt);
e = (e > 0) ? Math::Pow(e, gloss * 96.f) : 0;
}
*spec = e * a * specular_intensity;
}
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Light::RenderSetup(ResourceFactories *f)
{
render_data = new RenderData;
if (f && f->render)
if (!projection_texture.IsEmpty())
render_data->projection_texture = f->render->LoadTexture(projection_texture);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Light::SetDefaults()
{
model = Light::Model_Point;
shadow = Light::Shadow_None;
range = Units::Mtr(0.f);
volume_range = Units::Mtr(500.f);
clip_distance = Units::Mtr(300.f);
cone_angle = Units::Deg(30.f);
edge_angle = Units::Deg(30.f);
shadow_cast_all = false;
shadow_bias = 0.01f;
shadow_distribution = 0.9f;
shadow_range = Units::Mtr(100.f);
shadow_color.Set(0, 0, 0);
volumetric = false;
volumetric_sample_step = 0.5f;
volumetric_range = 8.0f;
volumetric_thickness = 1.0f;
z_near = Units::Cm(2.f);
falloff = Falloff_Linear;
diffuse_color = Color::White;
diffuse_intensity = 1;
specular_color = Color::White;
specular_intensity = 0;
}
Light::Light()
{
SetDefaults();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,93 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/light.h"
#include "metafile/nml_object.h"
#include "reflection/c_refl.h"
#include "log/log.h"
using GS::Core::Light;
using GS::NML::Tag;
using namespace GS::Reflection;
//------------------------------------------------------------------------------
Enum::Dict Light::model_dict[] =
{
{ Model_None, "None" },
{ Model_Point, "Point" },
{ Model_Linear, "Parallel" },
{ Model_Spot, "Spot" }
};
Enum::Dict Light::shadow_dict[] =
{
{ Shadow_None, "None" },
{ Shadow_ProjectionMap, "PMap" },
{ Shadow_Map, "Map" }
};
Enum::Dict Light::falloff_dict[] =
{
{ Falloff_Linear, "Linear" },
{ Falloff_InvDist, "InvDist" },
{ Falloff_InvDist2, "InvDist2" }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Property Light::serializable[] =
{
{ Property::EnumProp, "Type", offsetof(Light, model), model_dict },
{ Property::EnumProp, "Falloff", offsetof(Light, falloff), falloff_dict },
{ Property::FloatProp, "Range", offsetof(Light, range), 0 },
{ Property::FloatProp, "VolumeRange", offsetof(Light, volume_range), 0 },
{ Property::FloatProp, "ClipDistance", offsetof(Light, clip_distance), 0 },
{ Property::StringProp, "ProjectionMap", offsetof(Light, projection_texture), 0 },
{ Property::FloatProp, "DiffuseIntensity", offsetof(Light, diffuse_intensity), 0 },
{ Property::FloatProp, "SpecularIntensity", offsetof(Light, specular_intensity), 0 },
{ Property::FloatProp, "ConeAngle", offsetof(Light, cone_angle), 0 },
{ Property::FloatProp, "EdgeAngle", offsetof(Light, edge_angle), 0 },
{ Property::FloatProp, "ZNear", offsetof(Light, z_near), 0 },
{ Property::EnumProp, "Shadow", offsetof(Light, shadow), shadow_dict },
{ Property::FloatProp, "ShadowBias", offsetof(Light, shadow_bias), 0 },
{ Property::FloatProp, "ShadowDistribution", offsetof(Light, shadow_distribution), 0 },
{ Property::FloatProp, "ShadowRange", offsetof(Light, shadow_range), 0 },
{ Property::BoolProp, "ShadowCastAll", offsetof(Light, shadow_cast_all), 0 },
{ Property::BoolProp, "Volumetric", offsetof(Light, volumetric), 0 },
{ Property::FloatProp, "VolumetricSampleStep", offsetof(Light, volumetric_sample_step), 0 },
{ Property::FloatProp, "VolumetricThick", offsetof(Light, volumetric_thickness), 0 },
{ Property::FloatProp, "VolumetricRange", offsetof(Light, volumetric_range), 0 },
{ Property::InvalidProp, 0, 0 }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Light::FromMetaTag(Tag &t)
{
SetDefaults();
if ((t.name != "Light") || !GenericObjectFromMetaTag(t, this, serializable))
return false;
if (Tag *c = t.GetTag("Item")) Item::FromMetaTag(*c);
if (Tag *c = t.GetTag("Diffuse")) diffuse_color.FromMetaTag(*c);
if (Tag *c = t.GetTag("Specular")) specular_color.FromMetaTag(*c);
if (Tag *c = t.GetTag("ShadowColor")) shadow_color.FromMetaTag(*c);
return true;
}
Tag *Light::AsMetaTag()
{
Tag *t = new Tag("Light");
t->AddChild(Item::AsMetaTag());
t->AddChild(diffuse_color.AsMetaTag("Diffuse"));
t->AddChild(specular_color.AsMetaTag("Specular"));
t->AddChild(shadow_color.AsMetaTag("ShadowColor"));
return GenericObjectToMetaTag(t, this, serializable);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,93 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/material.h"
#include "log/log.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
Material::TextureStage *Material::GetChannelStage(MaterialChannel channel) const
{
for (int n = 0; n < max_texture_stage; ++n)
if (texstage[n].channel == channel)
return &texstage[n];
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Material::TextureStage *Material::NewStage(MaterialChannel channel, const char *uri, UVMode uv_mode, uchar uv_index)
{
TextureStage *s = GetChannelStage(channel);
if (s)
return s;
// Find a free stage.
for (int n = 0; n < max_texture_stage; ++n)
if (texstage[n].channel == Channel_None)
{
s = &texstage[n];
break;
}
if (!s)
__ERR__(__LOG_W__ << "No more free texture stage, cannot create new stage.\n", NULL)
// Initialize stage.
s->channel = channel;
s->t = uri;
s->uv_mode = uv_mode;
s->uv_index = uv_index;
return s;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Material::Reset()
{
renderword = Render_None;
blendop = Blend_None;
diffuse.Set(1, 1, 1);
specular.Set(1, 1, 1);
self.Set(0, 0, 0);
ambient.Set(1, 1, 1);
glossiness = 0.4f;
opacity = 1;
reflection = 0;
irefraction = 1;
athreshold = 0.1f;
depth_bias = 0;
shader.Clear();
for (int n = 0; n < max_texture_stage; n++)
texstage[n].Reset();
texstage_count = 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Material::TextureStage::Reset()
{
channel = Channel_None;
op = Operator_Default;
t.Clear();
uv_mode = UV_UV;
uv_matrix = Matrix4::IdentityMatrix();
uv_index = 0;
}
//------------------------------------------------------------------------------
Material::Material()
{
texstage.Allocate(max_texture_stage);
Reset();
}

View File

@ -0,0 +1,54 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/material_channel.h"
#include "nstring/nstring.h"
//------------------------------------------------------------------------------
const char *GS::Core::MaterialChannelName(MaterialChannel channel)
{
switch (channel)
{
case Channel_Diffuse: return "Diffuse";
case Channel_Decal: return "Decal";
case Channel_Opacity: return "Opacity";
case Channel_Specular: return "Specular";
case Channel_Glossiness: return "Glossiness";
case Channel_Normal: return "Normal";
case Channel_Reflection: return "Reflection";
case Channel_SelfIllum: return "SelfIllum";
case Channel_Light: return "Light";
case Channel_BlendRGB: return "BlendRGB";
default:
break;
}
return "None";
}
GS::Core::MaterialChannel GS::Core::MaterialChannelFromName(const char *channel)
{
GS::String c(channel);
if (c == "Diffuse") return Channel_Diffuse;
else if (c == "Decal") return Channel_Decal;
else if (c == "Opacity") return Channel_Opacity;
else if (c == "Specular") return Channel_Specular;
else if (c == "Glossiness") return Channel_Glossiness;
else if (c == "Normal") return Channel_Normal;
else if (c == "Reflection") return Channel_Reflection;
else if (c == "SelfIllum") return Channel_SelfIllum;
else if (c == "BlendRGB") return Channel_BlendRGB;
else if (c == "Light") return Channel_Light;
#if 1
else if (c == "Detail") return Channel_Decal;
else if (c == "VertexColor") return Channel_Light;
else if (c == "Color") return Channel_Light;
#endif
return Channel_None;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,310 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/material.h"
#include "core/embedded_resource_handler_interface.h"
#include "metafile/nml.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::NML;
//------------------------------------------------------------------------------
bool Material::FromMetaTag(Tag &tag)
{
if (tag.name != "Material")
__ERR__(__LOG_E__ << "Could not parse material, incorrect root tag (" << tag.name << ").\n", false);
Reset();
/*
Implementation note.
These strings are declared here once for the whole function
to benefit from the hash value-based early exit that the String
comparison function provide.
*/
static String _diffuse("Diffuse"), _specular("Specular"), _self("Self"), _ambient("Ambient"),
_glossiness("Glossiness"), _reflection("Reflection"), _ior("IOR"), _ath("AlphaThreshold"),
_msa("MaxSmoothingAngle"), _opac("Opacity"), _rmask("RenderMask"), _blendop("BlendOp"), _shadermap("ShaderMap"),
_shd("Shader"), _stage("TextureStage"), _physic("PhysicMaterial"), _depthbias("DepthBias");
NMLTagForeach(pt, tag)
{
if (pt->name == _diffuse) diffuse.FromMetaTag(*pt);
else if (pt->name == _specular) specular.FromMetaTag(*pt);
else if (pt->name == _self) self.FromMetaTag(*pt);
else if (pt->name == _ambient) ambient.FromMetaTag(*pt);
else if (pt->name == _glossiness) glossiness = Types::Clamp(pt->GetReal(), 0.01f, 16.f);
else if (pt->name == _reflection) reflection = pt->GetReal();
else if (pt->name == _ior) irefraction = pt->GetReal();
else if (pt->name == _msa); // Legacy
else if (pt->name == _opac) opacity = pt->GetReal();
else if (pt->name == _ath) athreshold = pt->GetReal();
else if (pt->name == _depthbias) depth_bias = pt->GetReal();
else if (pt->name == _shd) shader = pt->GetString();
// Physic material.
else if (pt->name == _physic)
PhysicMaterial::FromMetaTag(*pt);
// Render word.
else if (pt->name == _rmask)
{
static String _shdless("Shadeless"), _smooth("Smoothing"), _add("Additive"), _dbs("DoubleSided"), _usefbuffer("UseFramebuffer"), _skn("Skinned"),
_wire("Wireframe"), _unlit("Unlit"), _vcolor("VertexColor"), _soft("SoftBody"), _sub("Subtractive"), _subs("Substractive"),
_vnrm("ForceVertexNormal"), _nrmtgt("NormalMapTangent"), _toon("Toon"), _alpha("Alpha"), _atest("AlphaTest"),
_parr("ParralaxDisp"), _nozw("NoZWrite"), _nozt("NoZTest"), _nofog("NoFog"), _fixdfunc("FixedFunction"), _asoftz("AlphaSoftZ"), _asmap("AlphaInShadow");
NMLTagForeach(mskt, *pt)
{
if (mskt->name == _unlit) renderword |= Render_Unlit;
else if (mskt->name == _smooth) renderword |= Render_Smooth;
else if (mskt->name == _nrmtgt) renderword |= Render_NormalTangent;
else if (mskt->name == _nofog) renderword |= Render_NoFog;
else if (mskt->name == _dbs) renderword |= Render_DoubleSided;
else if (mskt->name == _wire) renderword |= Render_Wire;
else if (mskt->name == _vcolor) renderword |= Render_VertexColor;
else if (mskt->name == _parr) renderword |= Render_ParralaxDisp;
else if (mskt->name == _toon) renderword |= Render_Toon;
else if (mskt->name == _nozw) renderword |= Render_NoZWrite;
else if (mskt->name == _nozt) renderword |= Render_NoZTest;
else if (mskt->name == _asoftz) renderword |= Render_AlphaSoftZ;
else if (mskt->name == _asmap) renderword |= Render_AlphaInShadow;
else if (mskt->name == _atest) renderword |= Render_AlphaTest;
else if (mskt->name == _usefbuffer) renderword |= Render_UseFramebuffer;
else if (mskt->name == _skn) renderword |= Render_Skinned;
#if 1 // Legacy
else if (mskt->name == _add) blendop = Blend_Add;
else if (mskt->name == _alpha) blendop = Blend_Alpha;
else if (mskt->name == _fixdfunc) blendop = Blend_Alpha;
else if (mskt->name == "Lit")
;
#endif
else __LOG_W__ << "Unknown tag '" << mskt->name << "' in material '" << name << "'.\n";
}
}
// Blend operator.
else if (pt->name == _blendop)
{
String op(pt->GetString());
if (op == "Add")
blendop = Blend_Add;
else if (op == "Alpha")
blendop = Blend_Alpha;
}
#if (__PLATFORM_NINTENDO_WII__ == 0)
// Shader map.
else if (pt->name == _shadermap)
IEmbeddedResourceHandler::Get()->ExtractEmbeddedShaderTree(shader, *pt, name);
#endif
// Texture stage.
else if (pt->name == _stage)
{
Tag *idx = pt->GetTag("Index");
if (idx && (idx->GetType() == Variant::VariantInteger))
{
int n = idx->GetInteger();
if ((n >= 0) && (n < 8))
{
TextureStage *lvl = &texstage[n];
static String _texture("Texture"), _iuv("UV");
static String _operator("Operator"), _uvsrc("UVSource");
// Reset level.
lvl->channel = Channel_None;
lvl->op = Operator_Default;
lvl->uv_index = 0;
// Fetch channel first.
Tag *tst = pt->GetTag("Channel");
lvl->channel = tst ? MaterialChannelFromName(tst->GetString()) : Channel_Diffuse;
// Pool remaining tags.
NMLTagForeach(tst, *pt)
{
if (tst->name == _texture)
lvl->t = tst->GetString();
else if (tst->name == _iuv)
lvl->uv_index = (uchar)tst->GetInteger();
else if (tst->name == _operator)
{
String op(tst->GetString());
if (op == "Multiply")
lvl->op = Operator_Multiply;
else if (op == "Add")
lvl->op = Operator_Add;
}
// Texture level UV source.
else if (tst->name == _uvsrc)
{
String fnv(tst->GetString());
if (fnv == "UVMap") lvl->uv_mode = UV_UV;
else if (fnv == "LSNormal") lvl->uv_mode = UV_LSN;
else if (fnv == "FrontMap") lvl->uv_mode = UV_FrontMap;
else if (fnv == "SphericalEnvironment") lvl->uv_mode = UV_SphericalEnvironment;
else __LOG_W__ << "Unknown UV source for texture stage " << n << " of material '" << name << "'.\n";
}
}
texstage_count++;
}
else __LOG_W__ << "Illegal texture stage index " << n << " in material '" << name << "'.\n";
}
else __LOG_W__ << "Illegal index tag type in material '" << name << "'.\n";
}
#if 1 // Legacy
else if (pt->name == "Id")
;
#endif
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Material>.\n";
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Material::AsMetaTag() const
{
Tag *material = new Tag("Material");
if (!material)
__ERR__(__LOG_E__ << "Could not serialize material '" << name << "'. Failed to create root tag.\n", NULL)
// Base properties.
if (diffuse != Color::White)
material->AddChild(diffuse.AsMetaTag("Diffuse", true));
if (specular != Color::White)
material->AddChild(specular.AsMetaTag("Specular"));
if (self != Color::Black)
material->AddChild(self.AsMetaTag("Self"));
if (ambient != Color::White)
material->AddChild(ambient.AsMetaTag("Ambient"));
if (glossiness != 0.4f)
material->AddChild("Glossiness", glossiness);
if (opacity != 1)
material->AddChild("Opacity", opacity);
if (reflection != 0)
material->AddChild("Reflection", reflection);
if (irefraction != 1)
material->AddChild("IOR", irefraction);
if (athreshold != 0.1)
material->AddChild("AlphaThreshold", athreshold);
if (depth_bias != 0)
material->AddChild("DepthBias", depth_bias);
// Physics.
material->AddChild(PhysicMaterial::AsMetaTag());
// Render word.
if (renderword != Render_None)
{
if (Tag *rword = material->AddChild("RenderMask"))
{
if (renderword & Render_Unlit) rword->AddChild("Unlit");
if (renderword & Render_Smooth) rword->AddChild("Smoothing");
if (renderword & Render_NormalTangent) rword->AddChild("NormalMapTangent");
if (renderword & Render_NoFog) rword->AddChild("NoFog");
if (renderword & Render_DoubleSided) rword->AddChild("DoubleSided");
if (renderword & Render_Wire) rword->AddChild("Wireframe");
if (renderword & Render_VertexColor) rword->AddChild("VertexColor");
if (renderword & Render_ParralaxDisp) rword->AddChild("ParralaxDisp");
if (renderword & Render_Toon) rword->AddChild("Toon");
if (renderword & Render_NoZWrite) rword->AddChild("NoZWrite");
if (renderword & Render_NoZTest) rword->AddChild("NoZTest");
if (renderword & Render_AlphaSoftZ) rword->AddChild("AlphaSoftZ");
if (renderword & Render_AlphaInShadow) rword->AddChild("AlphaInShadow");
if (renderword & Render_AlphaTest) rword->AddChild("AlphaTest");
if (renderword & Render_UseFramebuffer) rword->AddChild("UseFramebuffer");
if (renderword & Render_Skinned) rword->AddChild("Skinned");
}
else __LOG_W__ << "Could not serialize material '" << name << "' render word.\n";
}
// Blend operator.
if (blendop != Blend_None)
switch (blendop)
{
case Blend_Add: material->AddChild("BlendOp", "Add"); break;
case Blend_Alpha: material->AddChild("BlendOp", "Alpha"); break;
}
// Shader id.
if (!shader.IsEmpty())
material->AddChild("Shader", shader.c_str());
// Texture stages.
for (int n = 0; n < max_texture_stage; n++)
{
const TextureStage *lvl = &texstage[n];
if (!lvl->t.IsEmpty())
{
if (Tag *ts = new Tag("TextureStage"))
{
material->AddChild(ts);
ts->AddChild("Index", n);
ts->AddChild("Texture", lvl->t.c_str());
ts->AddChild("UV", lvl->uv_index);
if (lvl->op != Operator_Default)
switch (lvl->op)
{
case Operator_Add: ts->AddChild("Operator", "Add"); break;
case Operator_Multiply: ts->AddChild("Operator", "Multiply"); break;
}
if (lvl->channel != Channel_Diffuse)
{
if (const char *c = MaterialChannelName(lvl->channel))
ts->AddChild("Channel", c);
else
__LOG_W__ << "Bogus channel in texture stage " << n << " material '" << name << "'.\n";
}
if (lvl->uv_mode != UV_UV)
switch (lvl->uv_mode)
{
case UV_UV: ts->AddChild("UVSource", "UVMap"); break;
case UV_LSN: ts->AddChild("UVSource", "LSNormal"); break;
case UV_FrontMap: ts->AddChild("UVSource", "FrontMap"); break;
case UV_SphericalEnvironment: ts->AddChild("UVSource", "SphericalEnvironment"); break;
default:
__LOG_W__ << "Bogus channel in texture stage " << n << " material '" << name << "'.\n";
break;
}
}
else __LOG_W__ << "Could not serialize a texture stage in material '" << name << "'.\n";
}
}
return material;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,261 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/material_to_shader_tree.h"
#include "core/shader_block.h"
#include "core/shader_tree.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
ShaderBlock *MaterialToShaderTree::MaterialTextureStageToShaderBlock(const Material &m, const Material::TextureStage *ts, ShaderBlock *nb)
{
if (!ts)
__ERR__(__LOG_W__ << "Cannot convert material null texture stage.\n", NULL)
// Get texture stage index.
uint n = 0;
for (; n < Core::Material::max_texture_stage; ++n)
if (ts == &m.texstage[n])
break;
if (n == Material::max_texture_stage)
__ERR__(__LOG_W__ << "Texture stage does not belong to this material.\n", NULL)
//
MaterialTextureShaderBlock *texture_block = new MaterialTextureShaderBlock(n);
TextureSamplerShaderBlock *sampler_block = new TextureSamplerShaderBlock;
ShaderBlock *uv_block = NULL, *output_block = NULL;
switch (ts->uv_mode)
{
case Material::UV_UV:
uv_block = new GeometryUVShaderBlock(ts->uv_index);
break;
case Material::UV_FrontMap:
{
uv_block = new DivOperatorShaderBlock(new ScreenUVShaderBlock, new SwizzleShaderBlock(new ViewportShaderBlock, SwizzleShaderBlock::SwizzleZ, SwizzleShaderBlock::SwizzleW));
uv_block = new MulOperatorShaderBlock(new ConstantShaderBlock(1, -1), uv_block);
if ((ts->channel == Channel_Reflection) && nb)
{
ShaderBlock *offset_block = new MulOperatorShaderBlock(new SwizzleShaderBlock(nb, SwizzleShaderBlock::SwizzleX, SwizzleShaderBlock::SwizzleY), new ConstantShaderBlock(0.01f, 0.01f));
uv_block = new AddOperatorShaderBlock(uv_block, offset_block);
}
}
break;
case Material::UV_LSN:
{
ShaderBlock *tmp = new MulOperatorShaderBlock(new NormalViewMatrixShaderBlock, nb ? nb : new GeometryNormalShaderBlock);
tmp = new PackVectorToColorShaderBlock(tmp);
tmp = new SwizzleShaderBlock(tmp, SwizzleShaderBlock::SwizzleX, SwizzleShaderBlock::SwizzleY);
uv_block = tmp;
}
break;
case Material::UV_SphericalEnvironment:
{
// find the reflective vector
ConstantShaderBlock* negative_vector = new ConstantShaderBlock(-1.0f, -1.0f, -1.0f);
GeometryNormalShaderBlock* normal_stream = nb ? (GeometryNormalShaderBlock*)nb : new GeometryNormalShaderBlock;
NormalMatrixShaderBlock* normal_matrix = new NormalMatrixShaderBlock();
MulOperatorShaderBlock* mul_operator_normal = new MulOperatorShaderBlock(normal_matrix, normal_stream);
MulOperatorShaderBlock* mul_operator1 = new MulOperatorShaderBlock(negative_vector, mul_operator_normal);
// dot the negative normal and the view vector
ViewVectorShaderBlock* view_vector = new ViewVectorShaderBlock();
DotOperatorShaderBlock* dot_vector1 =new DotOperatorShaderBlock(mul_operator1, view_vector);
// take the abs of the dot
AbsShaderBlock* abs_operator2 = new AbsShaderBlock(dot_vector1);
// normal * 2 * abs(dot(-n, view))
ConstantShaderBlock* constant_vector2 = new ConstantShaderBlock(2.0f, 2.0f, 2.0f);
MulOperatorShaderBlock* mul_operator3 = new MulOperatorShaderBlock(mul_operator_normal, constant_vector2);
BuildShaderBlock* build_vector1 = new BuildShaderBlock(abs_operator2, BuildShaderBlock::BuildX, abs_operator2, BuildShaderBlock::BuildX, abs_operator2, BuildShaderBlock::BuildX);
MulOperatorShaderBlock* mul_operator4 = new MulOperatorShaderBlock(build_vector1, mul_operator3);
// view + (normal * 2 * abs(dot(-n, view)))
AddOperatorShaderBlock* add_vector1 = new AddOperatorShaderBlock(view_vector, mul_operator4);
NormalizeOperatorShaderBlock* normalize1 = new NormalizeOperatorShaderBlock(add_vector1);
//compute the euler angle from the vector , to transform into uv coordinate
// change the Y into {0,1}
BuildShaderBlock* build_vector2 = new BuildShaderBlock(normalize1, BuildShaderBlock::BuildY );
PackVectorToColorShaderBlock* pack_vector1 = new PackVectorToColorShaderBlock(build_vector2);
// change the XZ into {0, 1}
BuildShaderBlock* build_vector3 = new BuildShaderBlock(normalize1, BuildShaderBlock::BuildX, normalize1, BuildShaderBlock::BuildZ, NULL, BuildShaderBlock::BuildZero);
NormalizeOperatorShaderBlock* normalize2 = new NormalizeOperatorShaderBlock(build_vector3 );
// do the dot in x
ConstantShaderBlock* constant_vector5 = new ConstantShaderBlock(1.0f, 0.0f, 0.0f);
DotOperatorShaderBlock* dot_vector2 =new DotOperatorShaderBlock(constant_vector5, normalize2);
// set this dot from {-1, 1} to {0, 1}
PackVectorToColorShaderBlock* pack_vector2 = new PackVectorToColorShaderBlock(dot_vector2);
// do the dot in y
ConstantShaderBlock* constant_vector6 = new ConstantShaderBlock(0.0f, 1.0f, 0.0f);
DotOperatorShaderBlock* dot_vector3 =new DotOperatorShaderBlock(constant_vector6, normalize2);
// abs the dot and make it -1 or 1
AbsShaderBlock* abs_operator3 = new AbsShaderBlock(dot_vector3);
DivOperatorShaderBlock* div_vector3 = new DivOperatorShaderBlock(dot_vector3 , abs_operator3);
// multiply the 2 transform dot to obtain the good angle between {-1, 1}
MulOperatorShaderBlock* mul_operator6 = new MulOperatorShaderBlock(pack_vector2, div_vector3);
// transform result from {-1, 1} to {0, 1}
PackVectorToColorShaderBlock* pack_vector3 = new PackVectorToColorShaderBlock(mul_operator6);
// create the vector for the sampler 2D
BuildShaderBlock* build_vector4 = new BuildShaderBlock(pack_vector1, BuildShaderBlock::BuildX, pack_vector3, BuildShaderBlock::BuildX);
uv_block = build_vector4;
}
break;
}
sampler_block->input[0] = texture_block;
sampler_block->input[1] = uv_block;
output_block = sampler_block;
switch (ts->channel)
{
case Channel_Normal:
if (m.renderword & Material::Render_NormalTangent)
{
GeometryTangentFrameShaderBlock *tangent_frame_block = new GeometryTangentFrameShaderBlock;
SwizzleShaderBlock *swizzle_block = new SwizzleShaderBlock(sampler_block, SwizzleShaderBlock::SwizzleX, SwizzleShaderBlock::SwizzleY, SwizzleShaderBlock::SwizzleZ);
output_block = new MulOperatorShaderBlock(tangent_frame_block, new UnpackColorToVectorShaderBlock(swizzle_block));
}
else
output_block = new UnpackColorToVectorShaderBlock(new SwizzleShaderBlock(sampler_block, SwizzleShaderBlock::SwizzleX, SwizzleShaderBlock::SwizzleY, SwizzleShaderBlock::SwizzleZ));
break;
default: break;
}
return output_block;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool MaterialToShaderTree::Convert(const Material &m, ShaderTree &tree)
{
// Normal.
ShaderBlock *normal_block = NULL;
if (m.GetChannelStage(Channel_Normal))
normal_block = new NormalizeOperatorShaderBlock(MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Normal)));
else normal_block = new GeometryNormalShaderBlock;
// Diffuse.
ShaderBlock *diffuse_block = NULL;
if (m.GetChannelStage(Channel_Diffuse))
{
ShaderBlock *texa_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Diffuse), normal_block);
if (m.GetChannelStage(Channel_BlendRGB))
{
ShaderBlock *texb_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_BlendRGB), normal_block);
diffuse_block = new MixOperatorShaderBlock(texb_block, texa_block, new SwizzleShaderBlock(new GeometryVertexColorShaderBlock, SwizzleShaderBlock::SwizzleX));
}
else
diffuse_block = texa_block;
}
else diffuse_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialDiffuse);
// RGB stream (only if no blend rgb stage active).
GeometryVertexColorShaderBlock *vertex_color_block = NULL;
if (!m.GetChannelStage(Channel_BlendRGB))
if (m.renderword & Material::Render_VertexColor)
{
vertex_color_block = new GeometryVertexColorShaderBlock;
diffuse_block = new MulOperatorShaderBlock(diffuse_block, new BuildShaderBlock(vertex_color_block, BuildShaderBlock::BuildX, vertex_color_block, BuildShaderBlock::BuildY, vertex_color_block, BuildShaderBlock::BuildZ, 0, BuildShaderBlock::BuildOne));
}
// Light map & decal map.
if (m.GetChannelStage(Channel_Decal))
{
ShaderBlock *decal_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Decal), normal_block);
diffuse_block = new MixOperatorShaderBlock(decal_block, diffuse_block, new SwizzleShaderBlock(decal_block, SwizzleShaderBlock::SwizzleW));
}
if (m.GetChannelStage(Channel_Light))
diffuse_block = new MulOperatorShaderBlock(diffuse_block, MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Light), normal_block));
// Self.
ShaderBlock *constant_block = NULL;
if (m.GetChannelStage(Channel_SelfIllum))
constant_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_SelfIllum), normal_block);
else constant_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialSelf);
// Specular.
ShaderBlock *specular_block = NULL;
if (m.GetChannelStage(Channel_Specular))
specular_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Specular), normal_block);
else specular_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialSpecular);
// Reflection.
if (m.GetChannelStage(Channel_Reflection))
{
Material::TextureStage *reflection_stage = m.GetChannelStage(Channel_Reflection);
ShaderBlock *reflection_block = MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, reflection_stage, normal_block);
switch (reflection_stage->op)
{
case Material::Operator_Default:
case Material::Operator_Add:
constant_block = new AddOperatorShaderBlock(constant_block, reflection_block);
break;
case Material::Operator_Multiply:
diffuse_block = new MulOperatorShaderBlock(diffuse_block, reflection_block);
break;
}
}
// Glossiness.
ShaderBlock *glossiness_block = NULL;
if (m.GetChannelStage(Channel_Glossiness))
glossiness_block = new SwizzleShaderBlock(MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Glossiness), normal_block), SwizzleShaderBlock::SwizzleX);
else glossiness_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialGlossiness);
// Opacity.
ShaderBlock *opacity_block = NULL;
if (m.GetChannelStage(Channel_Opacity))
opacity_block = new SwizzleShaderBlock(MaterialToShaderTree::MaterialTextureStageToShaderBlock(m, m.GetChannelStage(Channel_Opacity), normal_block), SwizzleShaderBlock::SwizzleW);
else opacity_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialOpacity);
if (vertex_color_block)
opacity_block = new MulOperatorShaderBlock(opacity_block, new SwizzleShaderBlock(vertex_color_block, SwizzleShaderBlock::SwizzleW));
// Reflection (raytracer).
ShaderBlock *reflection_raytracer_block = NULL;
reflection_raytracer_block = new MaterialParamShaderBlock(MaterialParamShaderBlock::MaterialReflection);
// Assign to sinks.
tree.sink[ShaderTree::SinkDiffuse] = diffuse_block;
tree.sink[ShaderTree::SinkSpecular] = specular_block;
tree.sink[ShaderTree::SinkConstant] = constant_block;
tree.sink[ShaderTree::SinkNormal] = normal_block;
tree.sink[ShaderTree::SinkOpacity] = opacity_block;
tree.sink[ShaderTree::SinkGlossiness] = glossiness_block;
tree.sink[ShaderTree::SinkReflection] = reflection_raytracer_block;
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,213 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/object.h"
#include "core/camera.h"
#include "core/geometry.h"
#include "core/resource_factories.h"
#include "core/render_resource_factory.h"
#include "timing/benchmark.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
float Object::lod_bias = 0.f;
//------------------------------------------------------------------------------
void Object::RenderSetup(ResourceFactories *f)
{
render_data = new RenderData;
if (f && f->render)
{
render_data->geometry = f->render->LoadGeometry(geometry, !cache_geometry);
if (render_data->geometry.IsValid())
{
// Assert skin correctness.
uint bone_count = render_data->geometry->bone_bind_matrix.GetCount();
if (bone_count > 0)
{
if (skin.IsNull() || (skin->bones_mtx.GetCount() != bone_count))
{
AllocateSkin(render_data->geometry->bone_bind_matrix.GetCount());
// Initialize skin to the binding position.
for (uint n = 0; n < render_data->geometry->bone_bind_matrix.GetCount(); ++n)
skin->previous_bones_mtx[n] = skin->bones_mtx[n] = render_data->geometry->bone_bind_matrix[n];
}
}
else
FreeSkin();
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static float GetGeometrySortValue(const Matrix4 &vm, Render::Geometry *g, const Matrix4 &gm)
{ return vm.GetRow(2).Dot((g->hotspot * gm) - vm.GetRow(3)); }
void Object::ComputeRenderableMinMax(MinMax &mm)
{
ComputeLocalMinMax(mm);
OBB obb = OBB::FromMinMax(mm);
obb.Transform(GetMatrix());
obb.ComputeMinMax(mm);
}
uint Object::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Renderable::Context context, bool cull)
{
Render::Geometry *g = render_data.IsValid() ? render_data->geometry.c_ptr() : NULL;
if (!g)
return 1;
// Recursive LOD selection.
{
float d2 = Vector4::Dist2(default_view.GetMatrix().GetRow(3), GetMatrix().GetRow(3)) + lod_bias * lod_bias;
d2 /= GetScale().Len2(); // [EJ] scale affects lod selection
for ( ; g; g = g->lod_proxy)
{
// If closer than lod, stop there.
if (d2 < (g->lod_distance * g->lod_distance))
break;
// Null lod.
if (g->flag.IsSet(Geometry::FlagNullLodProxy))
return 1;
// No lod to follow, stop there.
if (g->lod_proxy.IsNull())
break;
}
}
// Check context proxy on the selected lod.
if (context == Renderable::Context_Shadow)
{
// Null proxy.
if (g->flag.IsSet(Geometry::FlagNullShadowProxy))
return 1;
if (g->shadow_proxy.IsValid())
g = g->shadow_proxy;
}
// Test geometry hidden flag.
if (g->flag.IsSet(Geometry::FlagHidden))
return 1;
// Culling.
if (cull)
{
MinMax minmax;
ComputeLocalMinMax(minmax);
if (view.frustum.ClassifyMinMax(minmax, &GetMatrix()) == Frustum::Outside)
return 1;
}
list.Push(new Render::Primitive(g, this, GetGeometrySortValue(view.GetMatrix(), g, GetMatrix())));
return 1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Object::GetBindMatrix(uint n, Matrix4 &m) const
{
if (render_data.IsNull() || render_data->geometry.IsNull())
return false;
if (n >= render_data->geometry->bone_bind_matrix.GetCount())
return false;
m = render_data->geometry->bone_bind_matrix[n];
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Object::ComputeLocalMinMax(MinMax &minmax) const
{
if (render_data.IsNull() || render_data->geometry.IsNull())
Item::ComputeLocalMinMax(minmax);
else
{
if (HasSkin())
{
// Compute skin minmax.
OBB obb;
for (uint n = 0; n < GetBoneCount(); ++n)
if (skin->ComputeBoneBoundingVolume(n, obb))
{
MinMax bmm;
obb.ComputeMinMax(bmm);
if (n)
minmax.Grow(bmm);
else minmax = bmm;
}
}
else
minmax = render_data->geometry->minmax;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Object::UpdateSkin()
{
if (render_data.IsValid() && render_data->geometry.IsValid())
for (uint n = 0; n < GetBoneCount(); ++n)
if (Item *bone = GetBone(n))
{
skin->previous_bones_mtx[n] = GetInverseMatrix() * (bone->GetPreviousMatrix() * render_data->geometry->bone_bind_matrix[n]);
skin->bones_mtx[n] = GetInverseMatrix() * (bone->GetMatrix() * render_data->geometry->bone_bind_matrix[n]);
}
else
{
skin->previous_bones_mtx[n] = Matrix4::IdentityMatrix();
skin->bones_mtx[n] = Matrix4::IdentityMatrix();
}
}
bool Object::BindBone(uint n, Item *bone)
{
if (skin.IsNull() || (n >= skin->bones.GetCount()))
return false;
skin->bones[n] = bone;
if (bone)
bone->item_flags.Set(ItemFlagBoneHint);
return true;
}
bool Object::AllocateSkin(uint bone_count)
{
skin = new Skin;
if (!skin->bones.Allocate(bone_count) || !skin->bones_mtx.Allocate(bone_count) || !skin->previous_bones_mtx.Allocate(bone_count) || !skin->bones_minmax.Allocate(bone_count))
{
FreeSkin();
__ERR__(__LOG_E__ << "Failed to allocate skinning structure.\n", false);
}
for (uint n = 0; n < bone_count; ++n)
{
skin->bones[n] = NULL;
skin->bones_mtx[n] = Matrix4::IdentityMatrix();
skin->previous_bones_mtx[n] = Matrix4::IdentityMatrix();
}
return true;
}
void Object::FreeSkin()
{
skin = NULL;
}
//------------------------------------------------------------------------------
Object::Object() : cache_geometry(true) {}

View File

@ -0,0 +1,39 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/object.h"
#include "reflection/c_refl.h"
#include "metafile/nml_object.h"
using GS::Core::Object;
using GS::Reflection::Property;
using namespace GS::NML;
//------------------------------------------------------------------------------
Property serializable[] =
{
{ Property::StringProp, "Geometry", offsetof(Object, geometry), 0 },
{ Property::BoolProp, "CacheGeometry", offsetof(Object, cache_geometry), 0 },
{ Property::InvalidProp, 0, 0, 0 }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Object::FromMetaTag(Tag &t)
{
if ((t.name != "Object") || !GenericObjectFromMetaTag(t, this, serializable))
return false;
if (Tag *c = t.GetTag("Item")) Item::FromMetaTag(*c);
return true;
}
Tag *Object::AsMetaTag() const
{
Tag *t = new Tag("Object");
t->AddChild(Item::AsMetaTag());
return GenericObjectToMetaTag(t, this, serializable);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,211 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/octree_renderable.h"
#include "core/camera.h"
#include "timing/benchmark.h"
#include "sort/sort.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
OctreeCullingSystem::Node *OctreeCullingSystem::InsertList(List <CachedNode *> &list)
{
AutoPtr <Node> node(new Node);
if (node.IsNull())
return NULL;
bool to_child = false;
if (list.GetCount() <= 4)
to_child = true;
else
{
// Build list AABB.
bool first = true;
MinMax mm;
ListForeachPtr(CachedNode *, cnode, list)
{
if (first)
mm = cnode->minmax;
else mm.Grow(cnode->minmax);
first = false;
}
// Select split axis.
Vector4 size = mm.mx - mm.mn;
uint axis = 2;
if ((size.x > size.y) && (size.x > size.z))
axis = 0;
else if ((size.y > size.x) && (size.y > size.z))
axis = 1;
List <CachedNode *> split_list[2];
// Check list for renderable occupying more than 50% of the split axis.
bool exclusion_split = false;
float size_threshold = size[axis] * 0.5f;
ListForeachPtr(CachedNode *, cnode, list)
if ((cnode->minmax.mx[axis] - cnode->minmax.mn[axis]) > size_threshold)
{
exclusion_split = true;
break;
}
if (exclusion_split)
ListForeachPtr(CachedNode *, cnode, list)
split_list[(cnode->minmax.mx[axis] - cnode->minmax.mn[axis]) > size_threshold ? 0 : 1].Add(cnode);
else
{
float split_coord = (mm.mn[axis] + mm.mx[axis]) * 0.5f;
ListForeachPtr(CachedNode *, cnode, list)
split_list[cnode->minmax.GetCenter()[axis] < split_coord ? 0 : 1].Add(cnode);
}
// Recurse split lists.
if (!split_list[0].GetCount() || !split_list[1].GetCount())
to_child = true;
else
{
node->child[0] = InsertList(split_list[0]);
node->child[1] = InsertList(split_list[1]);
node->minmax = node->child[0]->minmax;
node->minmax.Grow(node->child[1]->minmax);
}
}
if (to_child)
{
if (node->cached_node.Allocate(list.GetCount()))
{
bool first = true;
uint n = 0;
ListForeachPtr(CachedNode *, cnode, list)
{
node->cached_node[n++] = cnode;
if (first)
node->minmax = cnode->minmax;
else node->minmax.Grow(cnode->minmax);
first = false;
}
}
else
__ERR__(__LOG_E__ << "Failed to allocatel leaf container.\n", NULL)
}
return node.Detach();
}
bool OctreeCullingSystem::Update()
{
root = NULL;
if (renderable_list.GetCount())
{
if (!nodes.Allocate(renderable_list.GetCount()))
return false;
uint n = 0;
ArrayListForeachPtr(Renderable *, renderable, renderable_list)
{
nodes[n].renderable = renderable;
renderable->ComputeRenderableMinMax(nodes[n].minmax);
++n;
}
// Build root list.
List <CachedNode *> root_list;
for (uint n = 0; n < nodes.GetCount(); ++n)
root_list.Add(&nodes[n]);
// Perform insertion.
root = InsertList(root_list);
}
dirty = false;
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void OctreeCullingSystem::ComputeRenderableMinMax(MinMax &mm)
{
if (root)
mm = root->minmax;
}
void OctreeCullingSystem::GetNodeRenderablePrimitive(Node *node, const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context ctx)
{
// Grab leaf content.
if (uint count = node->cached_node.GetCount())
{
for (uint n = 0; n < count; ++n)
{
Renderable *renderable = node->cached_node[n]->renderable;
if (renderable->IsRenderable())
renderable->GetRenderablePrimitiveList(view, default_view, list, ctx, false);
}
}
else
{
// Gather branches.
GetNodeRenderablePrimitive(node->child[0], view, default_view, list, ctx);
GetNodeRenderablePrimitive(node->child[1], view, default_view, list, ctx);
}
}
void OctreeCullingSystem::CullNodeRenderablePrimitive(Node *node, const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context ctx)
{
if (node->cached_node.GetCount())
GetNodeRenderablePrimitive(node, view, default_view, list, ctx);
else
switch (view.frustum.ClassifyMinMax(node->minmax))
{
case Frustum::Outside:
break;
case Frustum::Clipped:
CullNodeRenderablePrimitive(node->child[0], view, default_view, list, ctx);
CullNodeRenderablePrimitive(node->child[1], view, default_view, list, ctx);
break;
case Frustum::Inside:
GetNodeRenderablePrimitive(node->child[0], view, default_view, list, ctx);
GetNodeRenderablePrimitive(node->child[1], view, default_view, list, ctx);
break;
}
}
uint OctreeCullingSystem::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context ctx, bool cull)
{
// Rebuild tree if octree is dirty.
if (dirty)
Update();
if (root)
{
if (cull)
CullNodeRenderablePrimitive(root, view, default_view, list, ctx);
else GetNodeRenderablePrimitive(root, view, default_view, list, ctx);
}
return renderable_list.GetCount();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void OctreeCullingSystem::AddRenderable(Renderable *r)
{
renderable_list.Add(r);
dirty = true;
}
void OctreeCullingSystem::DeleteRenderable(Renderable *r)
{
renderable_list.Remove(r);
dirty = true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,446 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include <cfloat>
#include <cstring>
#include "core/path_kdtree.h"
#include "core/geometry.h"
#include "log/log.h"
#include "core/renderer_toolbox.h"
using namespace GS;
using namespace GS::Core;
using GS::Render::Renderer;
PathKdtree::KDTreeNode::KDTreeNode():m_KDTREE_NODE_ID_SEGMENT(NULL){ memset(m_KDTREE_NODE_ID_ROPE, -1, sizeof(int)*6);};
#define KDTREE_MAX_DEPTH 20
#define KDTREE_MAX_POLY_PER_NODE 5
void PathKdtree::DrawKdtreeNode(Renderer &render, int _CurrentNode, Matrix4& m)
{
MinMax min_max;
min_max.mn.x = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_LEFT];
min_max.mn.y = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_BOTTOM];
min_max.mn.z = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_BACK];
min_max.mx.x = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_RIGHT];
min_max.mx.y = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_TOP];
min_max.mx.z = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB[KDTREE_SIDE_FRONT];
min_max.mn = min_max.mn*m;
min_max.mx = min_max.mx*m;
RendererToolbox::DrawAABB(render, min_max);
if(!m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF)
{
DrawKdtreeNode(render, m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT, m);
DrawKdtreeNode(render, m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT, m);
}
}
void PathKdtree::draw_scene_debug(Renderer &render, Matrix4& m)
{
DrawKdtreeNode(render, 0, m);
}
void PathKdtree::NearestQuadtreeTreeNode(Vector4 p, SharedArrayList<nMSegment*> &list_segment)
//------------------------------------------------------------------------------------------------------------------------
{
// go inside the quadtree
ArrayList<int> list_id_segment;
if(segment_list.GetCount() <= 0)
return;
int l_CurrentNode = 0;
while(!m_NodeTree[l_CurrentNode].m_KDTREE_NODE_IS_LEAF)
{
switch (m_NodeTree[l_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT)
{
case KDTREE_X_AXIS:
{
float l_X = p.x ;
if(l_X == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_X += 0.001f;
if(l_X > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
else
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
}
break;
case KDTREE_Y_AXIS:
{
float l_Y = p.y ;
if(l_Y == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_Y += 0.001f;
if(l_Y > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
else
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
}
break;
case KDTREE_Z_AXIS:
{
float l_Z = p.z;
if(l_Z == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_Z += 0.001f;
if(l_Z > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
else
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
}
break;
}
}
int* l_TempPntIdSegment = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_SEGMENT;
int l_CountSegment = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_COUNT_SEGMENT;
for(int i=0; i< l_CountSegment; ++i)
{
list_segment.Add(segment_list[*l_TempPntIdSegment]);
++l_TempPntIdSegment;
}
}
//-------------------------------------------------------------------
void PathKdtree::IncreaseSizeNodeKdtreeBuffer(int _IncreaseSize)
//-------------------------------------------------------------------
{
KDTreeNode* l_tempCopy = new KDTreeNode[m_SizeTree + _IncreaseSize];
memcpy(l_tempCopy, m_NodeTree, sizeof(KDTreeNode)*m_SizeTree);
for(int i=0; i<m_SizeTree; ++i)
{
if(m_NodeTree[i].m_KDTREE_NODE_ID_SEGMENT)
{
l_tempCopy[i].m_KDTREE_NODE_ID_SEGMENT = new int[m_NodeTree[i].m_KDTREE_NODE_COUNT_SEGMENT];
memcpy( l_tempCopy[i].m_KDTREE_NODE_ID_SEGMENT, m_NodeTree[i].m_KDTREE_NODE_ID_SEGMENT, sizeof(int)*m_NodeTree[i].m_KDTREE_NODE_COUNT_SEGMENT);
}
}
m_SizeTree += _IncreaseSize;
delete []m_NodeTree;
m_NodeTree = l_tempCopy;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
void PathKdtree::CreateNodeKdtree(int &_CurrentNode, int *_IdSegment, int _CountSegment, int _CurrentDepth, bool _ForceCreateLeaf )
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
{
// check if there is a minimum of place for 2 child
if(m_SizeTree < _CurrentNode + 3)
{
IncreaseSizeNodeKdtreeBuffer(1000);
}
// set the id of the node
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID = _CurrentNode;
//get the aabb
float * l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
// check if it's the moment to create the leaf
if(_ForceCreateLeaf || _CountSegment < KDTREE_MAX_POLY_PER_NODE || _CurrentDepth >= KDTREE_MAX_DEPTH
/*|| fabs(l_TempAABB[KDTREE_SIDE_LEFT] - l_TempAABB[KDTREE_SIDE_RIGHT]) < 0.1f
|| fabs(l_TempAABB[KDTREE_SIDE_BOTTOM] - l_TempAABB[KDTREE_SIDE_TOP]) < 0.1f
|| fabs(l_TempAABB[KDTREE_SIDE_BACK] - l_TempAABB[KDTREE_SIDE_FRONT]) < 0.1f*/)
{
// check if there is a minimum of place for all the poly
if(m_SizeTree < (_CurrentNode + _CountSegment))
{
IncreaseSizeNodeKdtreeBuffer(10000 + _CountSegment);
}
m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = true;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = -1;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = -1;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_COUNT_SEGMENT = _CountSegment;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_SEGMENT = new int[_CountSegment];
memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_SEGMENT, _IdSegment, sizeof(int)*_CountSegment);
// set the new id to set back
++_CurrentNode;
}
else
{
m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = false;
//find the correct split axe X or Z
float l_TempValueSplit = 0.0f;
int l_CountSegmentOnX = 0;
int l_CountSegmentOnZ = 0;
// get the middle of the aabb
float l_X_MiddleAABB = (l_TempAABB[KDTREE_X_AXIS*2] + l_TempAABB[KDTREE_X_AXIS*2+1])*0.5f;
float l_Z_MiddleAABB = (l_TempAABB[KDTREE_Z_AXIS*2] + l_TempAABB[KDTREE_Z_AXIS*2+1])*0.5f;
for(int i=0; i<_CountSegment; ++i)
{
if(segment_list[_IdSegment[i]]->bounding_box.GetCenter().x > l_X_MiddleAABB)
++l_CountSegmentOnX;
else
--l_CountSegmentOnX;
if(segment_list[_IdSegment[i]]->bounding_box.GetCenter().z > l_Z_MiddleAABB)
++l_CountSegmentOnZ;
else
--l_CountSegmentOnZ;
}
//set new axis
int l_NewAxis;
if(Types::Abs(l_CountSegmentOnX) < Types::Abs(l_CountSegmentOnZ))
l_NewAxis = KDTREE_X_AXIS;
else
l_NewAxis = KDTREE_Z_AXIS;
// problem , we need absolutly leaf with some path inside, bad split function, so patch it
if((l_NewAxis == KDTREE_X_AXIS && _CountSegment == Types::Abs(l_CountSegmentOnX)) || (l_NewAxis == KDTREE_Z_AXIS && _CountSegment == Types::Abs(l_CountSegmentOnZ)))
{
CreateNodeKdtree(_CurrentNode, _IdSegment, _CountSegment, _CurrentDepth, true );
return;
}
// axis check with the length and width
float diff_axis_aabb = (l_TempAABB[KDTREE_X_AXIS*2+1] - l_TempAABB[KDTREE_X_AXIS*2]) / (l_TempAABB[KDTREE_Z_AXIS*2+1] - l_TempAABB[KDTREE_Z_AXIS*2]);
if(diff_axis_aabb > 1.5)
l_NewAxis = KDTREE_X_AXIS;
if(diff_axis_aabb < 0.66)
l_NewAxis = KDTREE_Z_AXIS;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = l_NewAxis;
// get the middle of the aabb
float l_MiddleAABB = (l_TempAABB[l_NewAxis*2] + l_TempAABB[l_NewAxis*2+1])*0.5f;
l_TempValueSplit = l_MiddleAABB;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT = l_TempValueSplit;
// create the 2 childs
// create the 2 child list
int l_IdInBigArray;
// left node
{
int l_NewIdChildLeft = _CurrentNode + 1;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = l_NewIdChildLeft;
// set the new aabb
float * l_TempAABBLeftChild = m_NodeTree[l_NewIdChildLeft].m_KDTREE_NODE_AABB;
l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
memcpy(l_TempAABBLeftChild, l_TempAABB, sizeof(float)*6);
l_TempAABBLeftChild[l_NewAxis*2+1] = l_TempValueSplit;
int *l_IdLeftSegmentList = new int [_CountSegment];
int l_IdLeftCount = 0;
for(int i=0; i<_CountSegment; ++i)
{
bool l_Include = false;
switch(l_NewAxis)
{
case KDTREE_X_AXIS:
if(segment_list[_IdSegment[i]]->a.x <= l_TempValueSplit ||
segment_list[_IdSegment[i]]->b.x <= l_TempValueSplit)
l_Include = true;
break;
case KDTREE_Z_AXIS:
if(segment_list[_IdSegment[i]]->a.z <= l_TempValueSplit ||
segment_list[_IdSegment[i]]->b.z <= l_TempValueSplit)
l_Include = true;
break;
}
if(l_Include)
{
l_IdLeftSegmentList[l_IdLeftCount] = _IdSegment[i];
++l_IdLeftCount;
}
}
// copy the strict minimum, not good, because it's fragment memory, but it's just for the creation
{
int* l_tempCopy = new int[l_IdLeftCount];
memcpy(l_tempCopy, l_IdLeftSegmentList, sizeof(int)*l_IdLeftCount);
delete []l_IdLeftSegmentList;
l_IdLeftSegmentList = l_tempCopy;
}
CreateNodeKdtree(l_NewIdChildLeft, l_IdLeftSegmentList, l_IdLeftCount, _CurrentDepth+1);
l_IdInBigArray = l_NewIdChildLeft;
delete []l_IdLeftSegmentList;
}
// right node
{
if(m_SizeTree < l_IdInBigArray + 3)
IncreaseSizeNodeKdtreeBuffer(10000);
int l_NewIdChildRight = l_IdInBigArray;
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = l_NewIdChildRight;
// set the new aabb
float * l_TempAABBRightChild = m_NodeTree[l_NewIdChildRight].m_KDTREE_NODE_AABB;
l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
memcpy(l_TempAABBRightChild, l_TempAABB, sizeof(float)*6);
l_TempAABBRightChild[l_NewAxis*2] = l_TempValueSplit;
int *l_IdRightSegmentList = new int [_CountSegment];
int l_IdRightCount = 0;
for(int i=0; i<_CountSegment; ++i)
{
bool l_Include = false;
switch(l_NewAxis)
{
case KDTREE_X_AXIS:
if(segment_list[_IdSegment[i]]->a.x >= l_TempValueSplit ||
segment_list[_IdSegment[i]]->b.x >= l_TempValueSplit)
l_Include = true;
break;
case KDTREE_Z_AXIS:
if(segment_list[_IdSegment[i]]->a.z >= l_TempValueSplit ||
segment_list[_IdSegment[i]]->b.z >= l_TempValueSplit)
l_Include = true;
break;
}
if(l_Include)
{
l_IdRightSegmentList[l_IdRightCount] = _IdSegment[i];
++l_IdRightCount;
}
}
// copy the strict minimum, not good, because it's fragment memory, but it's just for the creation
{
int* l_tempCopy = new int[l_IdRightCount];
memcpy(l_tempCopy, l_IdRightSegmentList, sizeof(int)*l_IdRightCount);
delete []l_IdRightSegmentList;
l_IdRightSegmentList = l_tempCopy;
}
CreateNodeKdtree(l_NewIdChildRight, l_IdRightSegmentList, l_IdRightCount, _CurrentDepth+1);
//set the new id for the next node in the stack
_CurrentNode = l_NewIdChildRight;
delete []l_IdRightSegmentList;
}
}
}
//--------------------------------------------------------------------------------
void PathKdtree::BuildQuadtree()
//--------------------------------------------------------------------------------
{
if(segment_list.GetCount() <= 0)
return;
//very not powerful kdtree construction
m_SizeTree = segment_list.GetCount()*4;
m_NodeTree = new KDTreeNode[m_SizeTree];
int m_CurrentNode = 0;
m_NodeTree[m_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = KDTREE_X_AXIS;
// find the big bounding box
MinMax max_min_max = segment_list[0]->GetBoundingBox();
ArrayListForeachPtr(nMSegment*, segment, segment_list)
{
max_min_max.Grow(segment->GetBoundingBox());
}
max_min_max.mn.y -= 100.0f;
max_min_max.mx.y += 100.0f;
float * l_TempAABB = m_NodeTree[m_CurrentNode].m_KDTREE_NODE_AABB;
l_TempAABB[KDTREE_SIDE_LEFT] = max_min_max.mn.x;
l_TempAABB[KDTREE_SIDE_BOTTOM] = max_min_max.mn.y;
l_TempAABB[KDTREE_SIDE_BACK] = max_min_max.mn.z;
l_TempAABB[KDTREE_SIDE_RIGHT] = max_min_max.mx.x;
l_TempAABB[KDTREE_SIDE_TOP] = max_min_max.mx.y;
l_TempAABB[KDTREE_SIDE_FRONT] = max_min_max.mx.z;
// to build the kdtree: id of the poly
int* l_IdSegment = new int[segment_list.GetCount()];
for(uint i=0; i<segment_list.GetCount(); ++i)
l_IdSegment[i] = i;
CreateNodeKdtree(m_CurrentNode, l_IdSegment, segment_list.GetCount(), 0);
_safe_delete_array(l_IdSegment);
}
//-------------------------------------------------------------------
bool PathKdtree::AddSegment(nMSegment* segment)
//-------------------------------------------------------------------
{
segment_list.Add(segment);
return true;
}
//------------------------------------------------------------------------------------------
bool PathKdtree::AddSegment(SharedArrayList<nMSegment*> _segment_list)
//------------------------------------------------------------------------------------------
{
ArrayListForeachPtr(nMSegment*, segment, _segment_list)
segment_list.Add(segment);
return true;
}
//---------------------------------------------------
bool PathKdtree::InsideKdTree(const Vector4 &s)
//---------------------------------------------------
{
if(m_NodeTree[0].m_KDTREE_NODE_AABB[0] <= s.x && s.x <= m_NodeTree[0].m_KDTREE_NODE_AABB[1] &&
m_NodeTree[0].m_KDTREE_NODE_AABB[2] <= s.y && s.y <= m_NodeTree[0].m_KDTREE_NODE_AABB[3] &&
m_NodeTree[0].m_KDTREE_NODE_AABB[4] <= s.z && s.z <= m_NodeTree[0].m_KDTREE_NODE_AABB[5] )
return true;
else
return false;
}
//-----------------------------------------
void PathKdtree::Free()
//-----------------------------------------
{
_safe_delete_array(m_NodeTree);
m_count_bih = 0;
}
PathKdtree::PathKdtree()
{
m_NodeTree = NULL;
m_count_bih = 0;
}

View File

@ -0,0 +1,24 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------------*/
#include "core/physic_material.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
PhysicMaterial::PhysicMaterial()
{
mass = 1.f;
SetFriction();
restitution = 0.1f;
sb_damping = 0.99f;
sb_stiffness = 1;
sb_torsion = 1;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,62 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/physic_material.h"
#include "metafile/nml.h"
#include "log/log.h"
using namespace GS::Core;
using GS::NML::Tag;
//------------------------------------------------------------------------------
bool PhysicMaterial::FromMetaTag(Tag &tag)
{
if (tag.name != "PhysicMaterial")
__ERR__(__LOG_E__ << "Could not parse physic material, incorrect root tag (" << tag.name << ").\n", false);
static String _mss("Mass"), _damp("Damping"), _stiff("Stiffness"), _trs("Torsion"),
_sfr("StaticFriction"), _dfr("DynamicFriction"), _res("Restitution");
NMLTagForeach(pt, tag)
{
if (pt->name == _mss)
mass = pt->GetReal();
else if (pt->name == _sfr)
static_friction = pt->GetReal();
else if (pt->name == _dfr)
dynamic_friction = pt->GetReal();
else if (pt->name == _res)
restitution = pt->GetReal();
else if (pt->name == _damp)
sb_damping = pt->GetReal();
else if (pt->name == _stiff)
sb_stiffness = pt->GetReal();
else if (pt->name == _trs)
sb_torsion = pt->GetBool();
}
return true;
}
Tag *PhysicMaterial::AsMetaTag() const
{
Tag *m = new Tag("PhysicMaterial");
if (!m)
__ERR__(__LOG_E__ << "Could not serialize physic material. Failed to create root tag.\n", NULL);
if (mass != 1.f)
m->AddChild("Mass", mass);
m->AddChild("StaticFriction", static_friction);
m->AddChild("DynamicFriction", dynamic_friction);
m->AddChild("Restitution", restitution);
if (sb_damping != 0.99f)
m->AddChild("Damping", sb_damping);
if (sb_stiffness != 1)
m->AddChild("Stiffness", sb_stiffness);
if (sb_torsion != 1)
m->AddChild("Torsion", sb_torsion);
return m;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,193 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <stdio.h>
#include "core/raster_font.h"
#include "core/render_resource_factory.h"
#include "metafile/nml.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Render;
//------------------------------------------------------------------------------
float RasterFont::GetHeight(bool normalized) const
{
if (normalized)
return height;
return GetPage(0) ? height * GetPage(0)->GetWidth() : -1;
}
float RasterFont::GetBaseline(bool normalized) const
{
if (normalized)
return baseline;
return GetPage(0) ? baseline * GetPage(0)->GetWidth() : -1;
}
Vector2 RasterFont::ComputeLineRect(const char *s, bool normalized) const
{
Vector2 r(0, height);
for ( ; s[0] && s[0] != '\n'; ++s)
if (const Glyph *c = GetGlyphInfos(s[0]))
r.x += c->step;
if (!normalized)
{
if (GetPage(0))
{
r.x *= GetPage(0)->GetWidth();
r.y *= GetPage(0)->GetHeight();
}
else
r.Set(-1, -1);
}
return r;
}
Vector2 RasterFont::ComputeStringRect(const char *s, bool normalized) const
{
Vector2 r(0, 0);
forever
{
float w = 0; // Line width.
for ( ; s[0] && s[0] != '\n'; ++s)
if (const Glyph *c = GetGlyphInfos(s[0]))
w += c->step;
if (w > r.x) // Largest width.
r.x = w;
r.y += height; // Line height.
if (!s[0])
break;
++s; // Jump over the line feed.
}
if (!normalized)
{
if (GetPage(0))
{
r.x *= GetPage(0)->GetWidth();
r.y *= GetPage(0)->GetHeight();
}
else
r.Set(-1, -1);
}
return r;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Texture *RasterFont::GetPage(uint page) const
{ return (page < pages.GetCount()) ? pages.ObjectAt(page) : NULL; }
const RasterFont::Glyph *RasterFont::GetGlyphInfos(uchar index) const
{ return glyph[index].available ? &glyph[index] : NULL; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool RasterFont::Load(ResourceFactory &rf, const char *nml, const char *base)
{
Unload();
//-----------------------------------------------------------
#define RFL_ERROR(l) { (l); Unload(); return false; }
//-----------------------------------------------------------
using namespace GS::NML;
File file;
if (!Parser::Load(nml, file))
RFL_ERROR(__LOG_E__ << "Failed to load raster font description file '" << nml << "'.\n")
// Load font settings.
Tag *root = file.GetTag("Font:Common;");
if (!root)
RFL_ERROR(__LOG_E__ << "Missing base tag in font description ('" << nml << "').\n")
uint page_count = 1;
NMLTagForeach(tag, *root)
{
if (tag->name == "Height")
height = tag->GetReal();
else if (tag->name == "BaseLine")
baseline = tag->GetReal();
else if (tag->name == "PageCount")
page_count = tag->GetInteger();
else __LOG_W__ << "Unexpected tag in font description header ('" << tag->name << "').\n";
}
// Parse glyphs...
root = file.GetTag("Font;");
NMLTagForeach(tag, *root)
if (tag->name == "Char")
{
Tag *wrk = tag->GetTag("Id;");
if (!wrk || (wrk->GetType() != Variant::VariantInteger))
{
__LOG_W__ << "Glyph with no or invalid ID in font '" << nml << "', skipping.\n";
continue;
}
int glyphidx = wrk->GetInteger();
if (glyphidx > 255)
continue;
Glyph *pglyph = &glyph[glyphidx];
pglyph->page = 0;
pglyph->available = true;
NMLTagForeach(wrk, *tag)
{
if (wrk->name == "U")
pglyph->u = wrk->GetReal();
else if (wrk->name == "V")
pglyph->v = wrk->GetReal();
else if (wrk->name == "W")
pglyph->w = wrk->GetReal();
else if (wrk->name == "H")
pglyph->h = wrk->GetReal();
else if (wrk->name == "OffsetU")
pglyph->offx = wrk->GetReal();
else if (wrk->name == "OffsetV")
pglyph->offy = wrk->GetReal();
else if (wrk->name == "Step")
pglyph->step = wrk->GetReal();
else if (wrk->name == "Page")
{
if ((wrk->GetType() == Variant::VariantInteger) && ((uint)wrk->GetInteger() < page_count))
pglyph->page = wrk->GetInteger();
else
{
__LOG_W__ << "Invalid glyph page in font '" << nml << "' (Glyph #" << glyphidx << "), skipping.\n";
pglyph->available = false;
break;
}
}
}
}
// Sanity check...
if (!glyph[' '].available)
__LOG_W__ << "No space character in font '" << nml << "'.\n";
// Load font pages.
for (uint n = 0; n < page_count; n++)
if (Texture *t = rf.LoadTexture(String::Format("%s_%02d.tga", base, n)))
pages.Add(t);
name = nml;
return true;
}
void RasterFont::Unload()
{
pages.Clear();
for (uint n = 0; n < 256; n++)
glyph[n].Reset();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,22 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/render_data.h"
#include "picture/pict.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Render;
//------------------------------------------------------------------------------
bool Texture::Create(const Picture &p, Usage usage)
{
__LOG_V__ << "Creating texture '" << p.name << "'.\n";
name = p.name;
return Create((const char *)p.GetData(), p.GetWidth(), p.GetHeight(), FormatRGBA8, NoAA, usage);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,102 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/renderer.h"
#include "core/camera.h"
#include "core/raster_font.h"
#include "sort/sort.h"
#include "platform_config.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::Render;
//------------------------------------------------------------------------------
uint Renderer::BuildRenderablePrimitiveList(const Camera &view, const Camera &lod_view, GS::Stack <Primitive *> &list, Renderable::Context context) const
{
uint tested_primitive = 0;
list.Clear();
ListForeachPtr(Renderable *, renderable, renderable_list)
tested_primitive += renderable->GetRenderablePrimitiveList(view, lod_view, list, context, true);
return tested_primitive;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Camera *Renderer::GetCamera() const
{ return view_item; }
void Renderer::SetCamera(Camera *item)
{
view_item = item;
view_registry = item ? &item->registry : NULL;
}
void Renderer::ApplyCamera()
{
if (view_item)
{
SetViewMatrix(view_item->GetMatrix(), &view_item->GetInverseMatrix());
Matrix4 pm;
view_item->ComputeProjectionMatrix(GetViewport(), pm);
SetProjectionMatrix(pm);
view_item->ComputeFrustum(view_item->frustum, GetViewport());
frustum = view_item->frustum;
}
}
void Renderer::SetViewRegistry(GS::Registry *registry)
{ view_registry = registry; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
GS::tVector2 <uint> Renderer::GetOutputDimensions() const
{
if (output_texture)
return tVector2 <uint> (output_texture->GetWidth(), output_texture->GetHeight());
return dimensions;
}
float Renderer::GetOutputAspectRatio() const
{
if (output_texture)
return float(output_texture->GetHeight()) / float(output_texture->GetWidth());
return output_aspect_ratio > 0 ? output_aspect_ratio : (float)dimensions.y / (float)dimensions.x;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Renderer::PushRenderable(Renderable *renderable)
{ renderable_list.Add(renderable); }
void Renderer::DeleteRenderableList()
{ renderable_list.Clear(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Renderer::Renderer()
{
output_aspect_ratio = 0;
global_aspect_ratio = AR_Square;
default_window = NULL;
output_window = NULL;
environment_interface = NULL;
view_item = NULL;
view_registry = NULL;
dimensions.Set(1, 1);
ipd = 0.0f;
registry.RegisterMessageListener(this);
}
Renderer::~Renderer()
{
registry.UnregisterMessageListener(this);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,46 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/renderer.h"
using namespace GS::Render;
using GS::NML::Tag;
//------------------------------------------------------------------------------
bool Renderer::FromMetaTag(Tag &tag)
{
if (tag.name != GetName())
return false; // Incorrect tag.
registry.Clear();
NMLTagForeach(pt, tag)
{
if (pt->name == "Version")
;
else if (pt->name == "Registry")
{
NMLTagForeach(child, *pt)
registry.AddRoot(child->Clone());
}
}
return true;
}
Tag *Renderer::AsMetaTag()
{
Tag *root = new Tag(GetName());
root->AddChild("Version", GetVersion());
Tag *tag_registry = root->AddChild("Registry");
NMLFileForeach(child, registry)
tag_registry->AddChild(child->Clone());
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,40 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/renderer.h"
#include "core/core_profiler.h"
using namespace GS::Render;
//------------------------------------------------------------------------------
void Renderer::DrawProfilerText(RasterFont *font[2], float &x, float &y)
{
Color title_color(1.f, 0.9f, 0);
WriterConfig config(false);
// Renderer profiling.
Write(*font[1], "Profiler\n\n", x, y, config, 1, &title_color);
Write(*font[0], String::Format("Prepare light: slice = %0.02f ms, tasks = %0.02f ms (// x%0.01f)\n", stats.bench_prepare_light.slice_duration.toMs(), stats.bench_prepare_light.tasks_duration.toMs(), stats.bench_prepare_light.tasks_duration.toMs() / stats.bench_prepare_light.slice_duration.toMs()), x, y, config);
Write(*font[0], String::Format("Render queue: %0.02f ms\n", stats.bench_render.GetMs()), x, y, config, 1, &Core::GetColorCode <float> (stats.bench_render.GetMs(), 16, 32));
Write(*font[0], String::Format("Post-process: %0.02f ms\n", stats.bench_post_process.GetMs()), x, y, config, 1, &Core::GetColorCode <float> (stats.bench_post_process.GetMs(), 2, 3));
y += 8;
Write(*font[1], "Statistics\n\n", x, y, config, 1, &title_color);
Write(*font[0], String::Format("Queue pass = %d\n", stats.queue_pass), x, y, config);
Write(*font[0], String::Format("Light processed = %d\n", stats.light_processed), x, y, config);
y += 8;
Write(*font[0], String::Format("Renderable processed = %d (pass avg. = %d)\n", stats.renderable_processed, stats.queue_pass ? stats.renderable_processed / stats.queue_pass : 0), x, y, config);
Write(*font[0], String::Format("Renderable drawn = %d (pass avg. = %d)\n", stats.renderable_drawn, stats.queue_pass ? stats.renderable_drawn / stats.queue_pass : 0), x, y, config);
Write(*font[0], String::Format("Passed culling: %.02f%% (draw/submit ratio)\n", stats.renderable_processed ? stats.renderable_drawn * 100.f / stats.renderable_processed : 0), x, y, config);
y += 8;
Write(*font[0], String::Format("List drawn = %d (avg. tri/list = %s, efficiency = %.02f)\n", stats.list_drawn, Core::FormatNumber(stats.list_drawn ? (float)stats.triangle_drawn / (float)stats.list_drawn : 0).c_str(), stats.list_drawn ? 100.f / ((float)stats.list_drawn / stats.queue_pass) : 1), x, y, config, 1, &Core::GetColorCode <uint> (stats.list_drawn, 600, 1000));
Write(*font[0], String::Format("Triangle drawn = %s (pass avg. = %s)\n", Core::FormatNumber(stats.triangle_drawn).c_str(), Core::FormatNumber(stats.queue_pass ? (float)stats.triangle_drawn / (float)stats.queue_pass : 0).c_str()), x, y, config);
y += 16;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,158 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/renderer_resource_factory.h"
#include "core/renderer.h"
#include "core/geometry.h"
#include "core/shader.h"
#include "core/shader_tree.h"
#include "core/shader_tree_to_shader.h"
#include "core/resource_geometry_generator.h"
#include "picture/pict.h"
#include "picture/pict_io.h"
#include "metafile/nml_object.h"
#include "filesystem/filesystem.h"
using namespace GS;
using namespace GS::NML;
using namespace GS::Render;
//------------------------------------------------------------------------------
Geometry *RendererResourceFactory::NewGeometry() { return renderer.NewGeometry(); }
Material *RendererResourceFactory::NewMaterial() { return renderer.NewMaterial(); }
Texture *RendererResourceFactory::NewTexture() { return renderer.NewTexture(); }
Shader *RendererResourceFactory::NewShader() { return renderer.NewShader(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool DoLoadResource(ResourceFactory &rf, Geometry *r, const char *uri)
{
Core::Geometry g;
g.name = uri;
if (Core::GeometryGenerator::IsGenerated(uri))
{
if (!Core::GeometryGenerator::Generate(uri, g))
return false;
}
else
if (!LoadFromFile(g, uri))
return false;
return r->Create(rf, g);
}
static bool DoLoadResource(ResourceFactory &rf, Material *r, const char *uri)
{
Core::Material m;
m.name = uri;
if (!LoadFromFile(m, uri))
return false;
return r->Create(rf, m);
}
static bool DoLoadResource(ResourceFactory &rf, Shader *r, const char *uri)
{
Core::Shader s;
s.name = uri;
File file;
if (!Parser::Load(uri, file))
return false;
if (Tag *tag = file.GetTag("Shader"))
{
if (!s.FromMetaTag(*tag))
return false;
}
else
{
Core::ShaderTree shader_tree;
if (!shader_tree.FromMetaTag(*tag) || !Core::ConvertShaderTreeToShader(shader_tree, s))
return false;
}
return r->Create(rf, s);
}
static bool DoLoadResource(ResourceFactory &rf, Texture *r, const char *uri)
{
// Read optional texture parameters.
LoadFromFile(r->parm, TextureParm::GetParmFileName(uri), false);
// Read data.
if (!r->LoadCooked(uri))
{
Picture picture;
if (!PictureIO::Get().Load(picture, uri))
return false;
picture.Convert(PixelFormat::RGBA8);
r->parm.Apply(picture);
if (!r->Create(picture))
return false;
}
r->parm.Apply(*r);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static Data *GeometryFactory(ResourceFactory &rf) { return rf.NewGeometry(); }
static Data *MaterialFactory(ResourceFactory &rf) { return rf.NewMaterial(); }
static Data *TextureFactory(ResourceFactory &rf) { return rf.NewTexture(); }
static Data *ShaderFactory(ResourceFactory &rf) { return rf.NewShader(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template <class T> T *LoadResourceCommonSeq(const char *uri, ResourceFactory &rf, Data *(factory)(ResourceFactory &), T *r, const char *errored_uri)
{
if (!uri)
return NULL;
String name(uri);
name.FileCleanName();
// Load sequence.
if (rf.event_handler)
{
rf.event_handler->OpenLoad();
rf.event_handler->LoadProgress(String::Format("Loading resource '%s'...", name.c_str()));
}
T *res = r ? r : (T *)factory(rf);
if (!res)
return NULL;
if (!DoLoadResource(rf, res, name))
{
if (errored_uri && !DoLoadResource(rf, res, errored_uri))
if (!r) // note: do not erase res if it was externally provided (through r)!
_safe_delete(res);
}
if (res)
res->name = name;
if (rf.event_handler)
rf.event_handler->EndLoad();
return res;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *RendererResourceFactory::LoadGeometry(const char *uri, bool, Geometry *g)
{ return LoadResourceCommonSeq <Geometry> (uri, *this, GeometryFactory, g, NULL); }
Material *RendererResourceFactory::LoadMaterial(const char *uri, bool, Material *m)
{ return LoadResourceCommonSeq <Material> (uri, *this, MaterialFactory, m, "@core/builtin/material/missing.nmm"); }
Texture *RendererResourceFactory::LoadTexture(const char *uri, bool, Texture *t)
{ return LoadResourceCommonSeq <Texture> (uri, *this, TextureFactory, t, "@core/builtin/maps/missing_texture.png"); }
Shader *RendererResourceFactory::LoadShader(const char *uri, bool, Shader *s)
{ return LoadResourceCommonSeq <Shader> (uri, *this, ShaderFactory, s, "@core/builtin/shader/missing_shader.nsa"); }
//------------------------------------------------------------------------------

View File

@ -0,0 +1,353 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include "core/renderer_toolbox.h"
#include "core/core_profiler.h"
#include "core/item.h"
#include "core/raster_font.h"
#include "log/log.h"
#if __PLATFORM_NINTENDO_WII__
#include "system/wii_memory.h"
#include "wii_platform.h"
#endif
using namespace GS::Units;
using namespace GS::Math;
namespace GS {
namespace RendererToolbox {
//------------------------------------------------------------------------------
void Triangle3D(Renderer &render, const Vector4 vtx[3], const Color color[3], const Vector2 uv[3], const Render::Texture *t, Material::BlendOperator blendop, Material::RenderWord rword)
{ render.DrawTriangle(1, vtx, NULL, color, uv, t, blendop, rword); }
void Line3D(Renderer &render, const Vector4 &a, const Vector4 &b, const Color *c, Material::BlendOperator bo, Material::RenderWord rw)
{
Vector4 v[2] = { a, b };
Color u[2] = { c ? *c : Color(1, 1, 1), c ? *c : Color(1, 1, 1) };
render.DrawLine(1, v, u, bo, rw);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void DrawCircle(Renderer &render, const Vector4 &position, float radius, const Matrix3 *m, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Matrix3 m3 = m ? *m : Matrix3::IdentityMatrix();
for (float a = Deg(0.f); a < Deg(360.f); a += Deg(10.f))
Line3D(render, Vector4(Cos(a), Sin(a), 0) * m3 * radius + position, Vector4(Cos(a + Deg(10.f)), Sin(a + Deg(10.f)), 0) * m3 * radius + position, color, bo);
}
void DrawCylinder(Renderer &render, const Vector4 &position, float radius, float length, const Matrix3 *m, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Matrix3 m3 = m ? *m : Matrix3::IdentityMatrix();
DrawCircle(render, position + Vector4(0, 0, length * 0.5f) * m3, radius, &m3, color);
DrawCircle(render, position + Vector4(0, 0, length * -0.5f) * m3, radius, &m3, color);
Line3D(render, position + Vector4(radius, 0, length * 0.5f) * m3, position + Vector4(radius, 0, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(-radius, 0, length * 0.5f) * m3, position + Vector4(-radius, 0, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(0, radius, length * 0.5f) * m3, position + Vector4(0, radius, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(0, -radius, length * 0.5f) * m3, position + Vector4(0, -radius, length * -0.5f) * m3, color, bo);
}
void DrawCapsule(Renderer &render, const Vector4 &position, float radius, float length, const Matrix3 *m, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Matrix3 m3 = m ? *m : Matrix3::IdentityMatrix();
DrawSphere(render, position + Vector4(0, 0, length * 0.5f) * m3, radius, color);
DrawSphere(render, position - Vector4(0, 0, length * 0.5f) * m3, radius, color);
Line3D(render, position + Vector4(radius, 0, length * 0.5f) * m3, position + Vector4(radius, 0, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(-radius, 0, length * 0.5f) * m3, position + Vector4(-radius, 0, length * -0.5f) * m3, color, bo);
}
void DrawCone(Renderer &render, const Vector4 &position, float radius, float length, const Matrix3 *m, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Matrix3 m3 = m ? *m : Matrix3::IdentityMatrix();
DrawCircle(render, position + Vector4(0, 0, length * -0.5f) * m3, radius, &m3, color);
Line3D(render, position + Vector4(0, 0, length * 0.5f) * m3, position + Vector4(radius, 0, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(0, 0, length * 0.5f) * m3, position + Vector4(-radius, 0, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(0, 0, length * 0.5f) * m3, position + Vector4(0, radius, length * -0.5f) * m3, color, bo);
Line3D(render, position + Vector4(0, 0, length * 0.5f) * m3, position + Vector4(0, -radius, length * -0.5f) * m3, color, bo);
}
void DrawSphere(Renderer &render, const Vector4 &p, float r, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
#define SPHERE_NSEG 36
uint n;
float sn, cs;
Vector4 a[2], b[2], c[2];
float angle, dt;
Color _r(1, 1, 0), _g(1, 1, 0), _b(1, 1, 0);
angle = 0;
dt = Deg(360.f) / SPHERE_NSEG;
sn = Sin(angle) * r;
cs = Cos(angle) * r;
a[1].Set(p.x, p.y + cs, p.z + sn);
b[1].Set(p.x + sn, p.y + cs, p.z);
c[1].Set(p.x + cs, p.y, p.z + sn);
for (n = 0; n < SPHERE_NSEG; n++)
{
a[0] = a[1]; b[0] = b[1]; c[0] = c[1];
angle += dt;
sn = Sin(angle) * r;
cs = Cos(angle) * r;
a[1].Set(p.x, p.y + cs, p.z + sn);
b[1].Set(p.x + sn, p.y + cs, p.z);
c[1].Set(p.x + cs, p.y, p.z + sn);
Line3D(render, a[0], a[1], color ? color : &_r);
Line3D(render, b[0], b[1], color ? color : &_g);
Line3D(render, c[0], c[1], color ? color : &_b);
}
}
void DrawBall(Renderer &render, const Matrix4 &m, float r, Color *uc, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
#define BALL_NSEG 24
uint n;
float sn, cs;
Vector4 a[2], b[2], c[2];
float angle, dt;
angle = 0;
dt = Deg(360.f) / BALL_NSEG;
sn = Sin(angle) * r;
cs = Cos(angle) * r;
a[1].Set(0, cs, sn);
b[1].Set(sn, cs, 0);
c[1].Set(cs, 0, sn);
a[1] *= m;
b[1] *= m;
c[1] *= m;
Color color(1, 1, 1);
if (!uc)
uc = &color;
for (n = 0; n < BALL_NSEG; n++)
{
a[0] = a[1]; b[0] = b[1]; c[0] = c[1];
angle += dt;
sn = Sin(angle) * r;
cs = Cos(angle) * r;
a[1].Set(0, cs, sn);
b[1].Set(sn, cs, 0);
c[1].Set(cs, 0, sn);
a[1] *= m;
b[1] *= m;
c[1] *= m;
Line3D(render, a[0], a[1], uc, bo);
Line3D(render, b[0], b[1], uc, bo);
Line3D(render, c[0], c[1], uc, bo);
}
}
void DrawCross(Renderer &render, const Vector4 &c, float size, const Color *color, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
const Color dft(1, 1, 1), *cl;
if (color)
cl = color;
else cl = &dft;
Vector4 o(c);
Vector4 a[2];
a[0] = o; a[1] = o;
a[0].x -= size;
a[1].x += size;
Line3D(render, a[0], a[1], cl, bo);
a[0] = o; a[1] = o;
a[0].y -= size;
a[1].y += size;
Line3D(render, a[0], a[1], cl, bo);
a[0] = o; a[1] = o;
a[0].z -= size;
a[1].z += size;
Line3D(render, a[0], a[1], cl, bo);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void DrawAABB(Renderer &render, const MinMax &minmax, const Color *c, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
const Color color(0.5, 1.0, 0);
if (!c)
c = &color;
const Vector4 *min = &minmax.mn, *max = &minmax.mx;
Vector4 v[2];
v[0].Set(min->x, min->y, min->z); v[1].Set(max->x, min->y, min->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, min->y, min->z); v[1].Set(min->x, min->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(max->x, min->y, min->z); v[1].Set(max->x, min->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, min->y, max->z); v[1].Set(max->x, min->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, max->y, min->z); v[1].Set(max->x, max->y, min->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, max->y, min->z); v[1].Set(min->x, max->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(max->x, max->y, min->z); v[1].Set(max->x, max->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, max->y, max->z); v[1].Set(max->x, max->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, min->y, min->z); v[1].Set(min->x, max->y, min->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(max->x, min->y, min->z); v[1].Set(max->x, max->y, min->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(max->x, min->y, max->z); v[1].Set(max->x, max->y, max->z);
Line3D(render, v[0], v[1], c, bo);
v[0].Set(min->x, min->y, max->z); v[1].Set(min->x, max->y, max->z);
Line3D(render, v[0], v[1], c, bo);
}
void DrawOBB(Renderer &render, const OBB &obb, const Color *color, Material::BlendOperator bo)
{
Vector4 vtx[8], _vtx[8];
_vtx[0].Set(-0.5, 0.5, 0.5);
_vtx[1].Set( 0.5, 0.5, 0.5);
_vtx[2].Set( 0.5, -0.5, 0.5);
_vtx[3].Set(-0.5, -0.5, 0.5);
_vtx[4].Set(-0.5, 0.5, -0.5);
_vtx[5].Set( 0.5, 0.5, -0.5);
_vtx[6].Set( 0.5, -0.5, -0.5);
_vtx[7].Set(-0.5, -0.5, -0.5);
Matrix4 mtx = Matrix4::FromMatrix3(obb.bb_rotation * Matrix3::ScaleMatrix(obb.bb_scale));
mtx.SetRow(3, obb.bb_position);
mtx.Apply(vtx, _vtx, 8);
const Color _color(1, 0.5f, 0);
if (!color)
color = &_color;
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Line3D(render, vtx[0], vtx[1], color, bo);
Line3D(render, vtx[1], vtx[2], color, bo);
Line3D(render, vtx[2], vtx[3], color, bo);
Line3D(render, vtx[3], vtx[0], color, bo);
Line3D(render, vtx[4], vtx[5], color, bo);
Line3D(render, vtx[5], vtx[6], color, bo);
Line3D(render, vtx[6], vtx[7], color, bo);
Line3D(render, vtx[7], vtx[4], color, bo);
Line3D(render, vtx[0], vtx[4], color, bo);
Line3D(render, vtx[1], vtx[5], color, bo);
Line3D(render, vtx[2], vtx[6], color, bo);
Line3D(render, vtx[3], vtx[7], color, bo);
}
void DrawFilledOBB(Renderer &render, const OBB &obb, const Color *_color, Material::BlendOperator bo, Material::RenderWord rw)
{
Vector4 vtx[8], v[4];
vtx[0].Set(-0.5, 0.5, 0.5);
vtx[1].Set( 0.5, 0.5, 0.5);
vtx[2].Set( 0.5, -0.5, 0.5);
vtx[3].Set(-0.5, -0.5, 0.5);
vtx[4].Set(-0.5, 0.5, -0.5);
vtx[5].Set( 0.5, 0.5, -0.5);
vtx[6].Set( 0.5, -0.5, -0.5);
vtx[7].Set(-0.5, -0.5, -0.5);
Matrix4 mtx = Matrix4::FromMatrix3(obb.bb_rotation * Matrix3::ScaleMatrix(obb.bb_scale));
mtx.SetRow(3, obb.bb_position);
render.SetWorldMatrix(mtx);
Color color[3];
for (int n = 0; n < 3; ++n)
color[n] = _color ? *_color : Color(1, 0.5f, 0);
v[0] = vtx[0]; v[1] = vtx[1]; v[2] = vtx[2];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[0]; v[1] = vtx[2]; v[2] = vtx[3];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[4]; v[1] = vtx[5]; v[2] = vtx[1];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[4]; v[1] = vtx[1]; v[2] = vtx[0];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[7]; v[1] = vtx[6]; v[2] = vtx[5];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[7]; v[1] = vtx[5]; v[2] = vtx[4];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[3]; v[1] = vtx[2]; v[2] = vtx[6];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[3]; v[1] = vtx[6]; v[2] = vtx[7];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[2]; v[1] = vtx[1]; v[2] = vtx[5];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[2]; v[1] = vtx[5]; v[2] = vtx[6];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[0]; v[1] = vtx[3]; v[2] = vtx[7];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
v[0] = vtx[0]; v[1] = vtx[7]; v[2] = vtx[4];
Triangle3D(render, v, color, NULL, NULL, bo, rw);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void DrawCube(Renderer &render, const Vector4 &p, float size, const Color *color, Material::BlendOperator bo)
{
const Color _color(0, 0.5, 1.f);
if (!color)
color = &_color;
Vector4 dt(size, size, size);
Vector4 t = p - dt;
Vector4 t2 = p + dt;
MinMax mnmx(t, t2);
DrawAABB(render, mnmx, color, bo);
}
void DrawSquare(Renderer &render, const Vector4 &p, float size, Material::BlendOperator bo)
{
render.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
Vector4 a(p), b(p), c(p), d(p);
a.x -= size; a.y -= size;
b.x += size; b.y -= size;
c.x += size; c.y += size;
d.x -= size; d.y += size;
Color cs(1, 1, 1);
Line3D(render, a, b, &cs, bo);
Line3D(render, b, c, &cs, bo);
Line3D(render, c, d, &cs, bo);
Line3D(render, d, a, &cs, bo);
}
//------------------------------------------------------------------------------
} // RendererToolbox
} // GS

View File

@ -0,0 +1,213 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/resource_geometry_generator.h"
#include "core/geometry.h"
#include "core/material_to_shader_tree.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool GeometryGenerator::IsGenerated(const char *name)
{ return String(name).StartsWith("@sys/gen/"); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool GenerateSphere(const char *name, Geometry &g)
{
g.Free();
// Extract dimensions.
float r = 0.5f;
// Generate vertices.
const int s_count = 6, c_count = 16;
if (!g.AllocateVertex((s_count + 1) * c_count + 2))
return false;
Vector4 *v = g.vtx;
v->Set(0, r, 0);
v++;
for (int s = 0; s < (s_count + 1); ++s)
{
float t = float(s + 1) / (s_count + 2);
float a = t * Units::Deg(180.f);
float y = Math::Cos(a) * r;
float s_r = Math::Sin(a) * r;
for (int c = 0; c < c_count; ++c)
{
const float c_a = c * Units::Deg(360.f) / c_count;
v->Set(Math::Cos(c_a) * s_r, y, Math::Sin(c_a) * s_r);
v++;
}
}
v->Set(0, -r, 0);
// Build polygons.
if (!g.AllocatePolygon((s_count + 2) * c_count))
return false;
Polygon *p = g.pol;
for (int c = 0; c < c_count; ++c)
{
p->vtx_count = 3;
p->material = 0;
p++;
}
for (int s = 0; s < s_count; ++s)
for (int c = 0; c < c_count; ++c)
{
p->vtx_count = 4;
p->material = 0;
p++;
}
for (int c = 0; c < c_count; ++c)
{
p->vtx_count = 3;
p->material = 0;
p++;
}
if (!g.AllocatePolygonBinding())
return false;
p = g.pol;
for (int c = 0; c < c_count; ++c)
{
p->binding[0] = 0; p->binding[2] = c + 1; p->binding[1] = Types::Wrap(c + 2, 1, c_count);
p++;
}
for (int s = 0; s < s_count; ++s)
{
int i = 1 + c_count * s;
for (int c = 0; c < c_count; ++c)
{
p->binding[0] = i + c; p->binding[1] = Types::Wrap(i + c + 1, i, i + c_count - 1);
p->binding[3] = i + c + c_count; p->binding[2] = Types::Wrap(i + c + c_count + 1, i + c_count, i + c_count * 2 - 1);
p++;
}
}
int i = 1 + c_count * s_count;
for (int c = 0; c < c_count; ++c)
{
p->binding[0] = i + c; p->binding[1] = Types::Wrap(i + c + 1, i, i + c_count - 1);
p->binding[2] = i + c_count;
p++;
}
return true;
}
static bool GenerateCube(const char *name, Geometry &g)
{
g.Free();
// Extract dimensions.
Vector4 d(1, 1, 1);
d *= 0.5f;
// Generate vertices.
if (!g.AllocateVertex(8))
return false;
g.vtx[0].Set(-d.x, d.y, d.z);
g.vtx[1].Set( d.x, d.y, d.z);
g.vtx[2].Set( d.x, d.y, -d.z);
g.vtx[3].Set(-d.x, d.y, -d.z);
g.vtx[4].Set(-d.x, -d.y, d.z);
g.vtx[5].Set( d.x, -d.y, d.z);
g.vtx[6].Set( d.x, -d.y, -d.z);
g.vtx[7].Set(-d.x, -d.y, -d.z);
// Build polygons.
if (!g.AllocatePolygon(6))
return false;
for (uint n = 0; n < 6; ++n)
{
g.pol[n].vtx_count = 4;
g.pol[n].material = 0;
}
if (!g.AllocatePolygonBinding())
return false;
g.pol[0].binding[0] = 0; g.pol[0].binding[1] = 1; g.pol[0].binding[2] = 2; g.pol[0].binding[3] = 3;
g.pol[1].binding[0] = 3; g.pol[1].binding[1] = 2; g.pol[1].binding[2] = 6; g.pol[1].binding[3] = 7;
g.pol[2].binding[0] = 7; g.pol[2].binding[1] = 6; g.pol[2].binding[2] = 5; g.pol[2].binding[3] = 4;
g.pol[3].binding[0] = 4; g.pol[3].binding[1] = 5; g.pol[3].binding[2] = 1; g.pol[3].binding[3] = 0;
g.pol[4].binding[0] = 2; g.pol[4].binding[1] = 1; g.pol[4].binding[2] = 5; g.pol[4].binding[3] = 6;
g.pol[5].binding[0] = 0; g.pol[5].binding[1] = 3; g.pol[5].binding[2] = 7; g.pol[5].binding[3] = 4;
return true;
}
static bool GeneratePlane(const char *name, Geometry &g)
{
g.Free();
// Extract dimensions.
Vector4 d(1, 1, 1);
// Generate vertices.
if (!g.AllocateVertex(4))
return false;
g.vtx[0].Set(-d.x, 0, d.z);
g.vtx[1].Set( d.x, 0, d.z);
g.vtx[2].Set( d.x, 0, -d.z);
g.vtx[3].Set(-d.x, 0, -d.z);
// Build polygons.
if (!g.AllocatePolygon(1))
return false;
g.pol[0].vtx_count = 4;
g.pol[0].material = 0;
if (!g.AllocatePolygonBinding())
return false;
g.pol[0].binding[0] = 0; g.pol[0].binding[1] = 1; g.pol[0].binding[2] = 2; g.pol[0].binding[3] = 3;
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool GeometryGenerator::Generate(const char *name, Geometry &g)
{
String _name(name);
bool r = false;
if (_name.StartsWith("@sys/gen/plane"))
r = GeneratePlane(name, g);
else if (_name.StartsWith("@sys/gen/cube"))
r = GenerateCube(name, g);
else if (_name.StartsWith("@sys/gen/sphere"))
r = GenerateSphere(name, g);
if (r)
{
// Compute extra data.
g.ComputeVertexNormal(Units::Deg(45.f));
// Load materials.
if (g.material_table.Allocate(1))
g.material_table[0].name = "@core/builtin/material/default.nmm";
}
return r;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,171 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader.h"
#include "metafile/nml.h"
#include "filesystem/filesystem.h"
#include "platform.h"
using namespace GS;
using namespace GS::Core;
using namespace GS::NML;
//------------------------------------------------------------------------------
bool Shader::AddISLSection(const char *uri)
{
File isl_file;
if (!Parser::Load(uri, isl_file))
return false;
// Declare inputs.
ParseInputTag(isl_file.GetTag("Shader:Input;"));
ParseVaryingTag(isl_file.GetTag("Shader:Varying;"));
// Append vertex & fragment programs.
bool r = true;
if (Tag *t = isl_file.GetTypedTag("Shader:Vertex;", Variant::VariantString))
{
Array <char> data;
if ((r &= Platform::Get().io->FileLoad(t->GetString(), data)) != false)
vertex += String(data.c_ptr(), data.GetSize());
}
if (Tag *t = isl_file.GetTypedTag("Shader:Fragment;", Variant::VariantString))
{
Array <char> data;
if ((r &= Platform::Get().io->FileLoad(t->GetString(), data)) != false)
pixel += String(data.c_ptr(), data.GetSize());
}
return r;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Shader::Clone(Shader &clone) const
{
// TODO make something faster... please.
AutoPtr <Tag> tag(AsMetaTag());
clone.name = name;
return clone.FromMetaTag(*tag);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Shader::Define(const char *def, ShaderInput::Scope scope)
{
String directive = String::Format("#define %s\n", def);
if (scope & ShaderInput::Vertex)
vertex_decl = directive + vertex_decl;
if (scope & ShaderInput::Pixel)
pixel_decl = directive + pixel_decl;
}
ShaderVarying *Shader::DeclareVarying(const char *name, const char *type)
{
ShaderVarying *varying = new ShaderVarying;
if (!varying)
return NULL;
varying_list.Add(varying);
varying->name = name;
varying->type = type;
return varying;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ShaderInput *Shader::GetInput(ShaderInput::Semantic semantic) const
{
ListForeachPtr(ShaderInput *, input, input_list)
if (input->semantic == semantic)
return input;
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ShaderInput *Shader::DeclareInput(const char *name, ShaderInput::DataType data_type, ShaderInput::Semantic semantic, ShaderInput::Type parm_type, ShaderInput::Scope parm_scope, uint array_size)
{
// Catch duplicates.
ShaderInput *input = NULL;
switch (semantic)
{
case ShaderInput::Position:
case ShaderInput::Normal:
case ShaderInput::UV0:
case ShaderInput::UV1:
case ShaderInput::UV2:
case ShaderInput::Tangent:
case ShaderInput::Bitangent:
case ShaderInput::BoneIndex:
case ShaderInput::BoneWeight:
ListForeachPtr(ShaderInput *, p, input_list)
if (p->semantic == semantic)
{
input = p;
break;
}
break;
default:
ListForeachPtr(ShaderInput *, p, input_list)
if ((p->name == name) && (p->semantic == semantic))
{
input = p;
break;
}
break;
}
// Equivalent input found.
if (input)
{
input->scope |= parm_scope; // Merge scopes.
return input;
}
// Create a new input.
if ((input = new ShaderInput) == NULL)
return NULL;
input_list.Add(input);
input->name = name;
input->semantic = semantic;
input->type = parm_type;
input->data_type = data_type;
input->scope = parm_scope;
input->array_size = array_size;
input->parm_v.Set(0, 0, 0);
return input;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Shader::Clear()
{
input_list.Clear();
varying_list.Clear();
geometry_decl.Clear();
vertex_decl.Clear();
pixel_decl.Clear();
geometry.Clear();
vertex.Clear();
pixel.Clear();
}
//------------------------------------------------------------------------------
Shader::Shader(const char *n, const char *v, const char *f, const char *g)
{
name = n;
vertex = v;
pixel = f;
geometry = g;
}

View File

@ -0,0 +1,446 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_block.h"
#include "log/log.h"
using namespace GS::Core;
using GS::String;
// Tools.
ShaderBlockPin SwizzleShaderBlock::input_pin[] =
{ { "Input", "Source input to extract components from.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin SwizzleShaderBlock::output_pin =
{ "Swizzled", "Swizzled input.", ShaderInput::NoData };
ShaderBlockPin BuildShaderBlock::input_pin[] =
{ { "Input X", "Source component of the built vector.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input Y", "Source component of the built vector.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input Z", "Source component of the built vector.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input W", "Source component of the built vector.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin BuildShaderBlock::output_pin =
{ "Built", "Built vector.", ShaderInput::NoData };
ShaderBlockPin ClampShaderBlock::input_pin[] =
{ { "Input", "Source to clamp.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Min", "Minimum value.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Max", "Maximum value.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin ClampShaderBlock::output_pin =
{ "Clamped", "Clamped input.", ShaderInput::NoData };
ShaderBlockPin UnpackColorToVectorShaderBlock::input_pin[] =
{ { "Input", "Vector in the [0;1] range.", ShaderInput::Float | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin UnpackColorToVectorShaderBlock::output_pin =
{ "Unpacked [-1;1]", "Vector in the [-1;1] range.", ShaderInput::NoData };
ShaderBlockPin PackVectorToColorShaderBlock::input_pin[] =
{ { "Input", "Vector in the [-1;1] range.", ShaderInput::Float | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin PackVectorToColorShaderBlock::output_pin =
{ "Packed [0;1]", "Vector in the [0;1] range.", ShaderInput::NoData };
// Operator.
ShaderBlockPin MixOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input K", "Source input K.", ShaderInput::Float } };
ShaderBlockPin MixOperatorShaderBlock::output_pin =
{ "A*K+B*(1-K)", "Input A * Input K + Input B * (1.0 - Input K).", ShaderInput::NoData };
ShaderBlockPin AddOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin AddOperatorShaderBlock::output_pin =
{ "A+B", "Input A + Input B.", ShaderInput::NoData };
ShaderBlockPin SubOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin SubOperatorShaderBlock::output_pin =
{ "A-B", "Input A - Input B.", ShaderInput::NoData };
ShaderBlockPin MulOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 | ShaderInput::Matrix3 | ShaderInput::Matrix4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 | ShaderInput::Matrix3 | ShaderInput::Matrix4 } };
ShaderBlockPin MulOperatorShaderBlock::output_pin =
{ "A*B", "Input A * Input B.", ShaderInput::NoData };
ShaderBlockPin DivOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin DivOperatorShaderBlock::output_pin =
{ "A/B", "Input A / Input B.", ShaderInput::NoData };
ShaderBlockPin DotOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 },
{ "Input B", "Source input B.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin DotOperatorShaderBlock::output_pin =
{ "A.Dot(B)", "The cosinus of the angle between A and B.", ShaderInput::NoData };
ShaderBlockPin CrossOperatorShaderBlock::input_pin[] =
{ { "Input A", "Source input A.", ShaderInput::Vector3 },
{ "Input B", "Source input B.", ShaderInput::Vector3 } };
ShaderBlockPin CrossOperatorShaderBlock::output_pin =
{ "A.Cross(B)", "A vector perpendicular to both A and B.", ShaderInput::NoData };
ShaderBlockPin NormalizeOperatorShaderBlock::input_pin[] =
{ { "Input", "Source input.", ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin NormalizeOperatorShaderBlock::output_pin =
{ "Normalized", "Normalized input.", ShaderInput::NoData };
ShaderBlockPin CosinusShaderBlock::input_pin[] =
{ { "Input", "Input value in radian.", ShaderInput::Float } };
ShaderBlockPin CosinusShaderBlock::output_pin =
{ "Cosinus", "Cosinus of input.", ShaderInput::NoData };
ShaderBlockPin SinusShaderBlock::input_pin[] =
{ { "Input", "Input value in radian.", ShaderInput::Float } };
ShaderBlockPin SinusShaderBlock::output_pin =
{ "Sinus", "Sinus of input.", ShaderInput::NoData };
ShaderBlockPin PowShaderBlock::input_pin[] =
{ { "Value", "Input value.", ShaderInput::Float },
{ "Power", "Power to raise value to.", ShaderInput::Float } };
ShaderBlockPin PowShaderBlock::output_pin =
{ "Pow", "Value raised to power.", ShaderInput::NoData };
ShaderBlockPin AbsShaderBlock::input_pin[] =
{ { "Value", "Input value.", ShaderInput::Float | ShaderInput::Vector2 | ShaderInput::Vector3 | ShaderInput::Vector4 } };
ShaderBlockPin AbsShaderBlock::output_pin =
{ "Abs", "Absolute value of input.", ShaderInput::NoData };
// Texture
ShaderBlockPin TextureSamplerShaderBlock::input_pin[] =
{ { "Texture", "Texture input.", ShaderInput::Texture2D },
{ "UV Stream", "UV stream input.", ShaderInput::Vector2 | ShaderInput::Vector3 } };
ShaderBlockPin TextureSamplerShaderBlock::output_pin =
{ "Texel", "Texture sample.", ShaderInput::NoData };
// No input blocks.
ShaderBlockPin GeometryVertexShaderBlock::output_pin =
{ "Vertex", "Vertex stream.", ShaderInput::NoData };
ShaderBlockPin GeometrySkinningShaderBlock::output_pin =
{ "Skinned", "Skinned vector.", ShaderInput::NoData };
ShaderBlockPin GeometryNormalShaderBlock::output_pin =
{ "Normal", "Normal stream.", ShaderInput::NoData };
ShaderBlockPin GeometryUVShaderBlock::output_pin =
{ "UV", "UV stream.", ShaderInput::NoData };
ShaderBlockPin GeometryVertexColorShaderBlock::output_pin =
{ "Color", "Vertex color stream.", ShaderInput::NoData };
ShaderBlockPin GeometryTangentFrameShaderBlock::output_pin =
{ "Tangent", "Tangent frame.", ShaderInput::NoData };
ShaderBlockPin RenderBufferShaderBlock::output_pin =
{ "Buffer", "Texture object.", ShaderInput::NoData };
ShaderBlockPin TextureShaderBlock::output_pin =
{ "Texture", "Texture object.", ShaderInput::NoData };
ShaderBlockPin ConstantShaderBlock::output_pin =
{ "Constant", "Constant value.", ShaderInput::NoData };
ShaderBlockPin ColorShaderBlock::output_pin =
{ "Color", "RGBA Color.", ShaderInput::NoData };
ShaderBlockPin MaterialParamShaderBlock::output_pin =
{ "Parameter", "Material parameter.", ShaderInput::NoData };
ShaderBlockPin MaterialTextureShaderBlock::output_pin =
{ "Slot", "Texture slot.", ShaderInput::NoData };
ShaderBlockPin ClockShaderBlock::output_pin =
{ "Clock (s)", "System clock in second.", ShaderInput::NoData };
ShaderBlockPin ScreenUVShaderBlock::output_pin =
{ "Screen UV", "Screen position.", ShaderInput::NoData };
ShaderBlockPin ViewVectorShaderBlock::output_pin =
{ "World View", "View vector in world space.", ShaderInput::NoData };
ShaderBlockPin ViewportShaderBlock::output_pin =
{ "Viewport", "Viewport origin and dimension in 2d.", ShaderInput::NoData };
ShaderBlockPin NormalViewMatrixShaderBlock::output_pin =
{ "Normal View Matrix", "Normal view matrix.", ShaderInput::NoData };
ShaderBlockPin NormalMatrixShaderBlock::output_pin =
{ "Normal Matrix", "Normal matrix.", ShaderInput::NoData };
ShaderBlockPin ModelViewMatrixShaderBlock::output_pin =
{ "Model View Matrix", "Model view matrix.", ShaderInput::NoData };
ShaderBlockPin ModelMatrixShaderBlock::output_pin =
{ "Model Matrix", "Model matrix.", ShaderInput::NoData };
//------------------------------------------------------------------------------
String TextureShaderBlock::GetId() const
{ return String("Texture") + texture; }
String ConstantShaderBlock::GetId() const
{
switch (constant_type)
{
case ShaderInput::NoData:
return String("ConstNone");
case ShaderInput::Float:
return String("ConstFloat");
case ShaderInput::Vector2:
return String("ConstVec2");
case ShaderInput::Vector3:
return String("ConstVec3");
case ShaderInput::Vector4:
return String("ConstVec4");
}
__ERR__(__LOG_E__ << "Unknown constant.\n", String("ConstUnk"))
}
String MaterialParamShaderBlock::GetId() const
{ return String::Format("MatParm%d", param); }
String MaterialTextureShaderBlock::GetId() const
{ return String::Format("MatTexture%d", slot); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool ShaderBlock::IsEquivalent(const ShaderBlock *input_block) const
{
if (this == input_block)
return true;
if (type == input_block->type)
switch (type)
{
case ShaderBlock::TypeRenderBuffer:
{
RenderBufferShaderBlock *a = (RenderBufferShaderBlock *)this, *b = (RenderBufferShaderBlock *)input_block;
return a->buffer == b->buffer;
}
case ShaderBlock::TypeTextureSampler:
{
TextureSamplerShaderBlock *a = (TextureSamplerShaderBlock *)this, *b = (TextureSamplerShaderBlock *)input_block;
return (a->sampler_type == b->sampler_type) && a->input[0] && a->input[1] && b->input[0] && b->input[1] ? a->input[0]->IsEquivalent(b->input[0]) && a->input[1]->IsEquivalent(b->input[1]) : false;
}
case ShaderBlock::TypeTexture:
{
TextureShaderBlock *a = (TextureShaderBlock *)this, *b = (TextureShaderBlock *)input_block;
return a->texture == b->texture;
}
case ShaderBlock::TypeGeometryUV:
{
GeometryUVShaderBlock *a = (GeometryUVShaderBlock *)this, *b = (GeometryUVShaderBlock *)input_block;
return a->channel == b->channel;
}
case ShaderBlock::TypeMaterialParam:
{
MaterialParamShaderBlock *a = (MaterialParamShaderBlock *)this, *b = (MaterialParamShaderBlock *)input_block;
return a->param == b->param;
}
case ShaderBlock::TypeClock:
case ShaderBlock::TypeScreenUV:
case ShaderBlock::TypeViewVector:
case ShaderBlock::TypeViewport:
case ShaderBlock::TypeNormalViewMatrix:
case ShaderBlock::TypeNormalMatrix:
case ShaderBlock::TypeModelViewMatrix:
case ShaderBlock::TypeModelMatrix:
case ShaderBlock::TypeGeometryVertex:
case ShaderBlock::TypeGeometrySkinning:
case ShaderBlock::TypeGeometryNormal:
case ShaderBlock::TypeGeometryVertexColor:
case ShaderBlock::TypeGeometryTangentFrame:
return true;
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int UnpackColorToVectorShaderBlock::GetOutputType() const
{ return !input[0] ? ShaderInput::NoData : input[0]->GetOutputType(); }
int PackVectorToColorShaderBlock::GetOutputType() const
{ return !input[0] ? ShaderInput::NoData : input[0]->GetOutputType(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int MixOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || !input[2] || (input[0]->GetOutputType() != input[1]->GetOutputType()) || (input[2]->GetOutputType() != ShaderInput::Float)) ? ShaderInput::NoData : input[0]->GetOutputType(); }
int DotOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || (input[0]->GetOutputType() != input[1]->GetOutputType())) ? ShaderInput::NoData : ShaderInput::Float; }
int CrossOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || ((input[0]->GetOutputType() != input[1]->GetOutputType()) && (input[0]->GetOutputType() != ShaderInput::Vector3))) ? ShaderInput::NoData : ShaderInput::Vector3; }
int AddOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || (input[0]->GetOutputType() != input[1]->GetOutputType())) ? ShaderInput::NoData : input[0]->GetOutputType(); }
int SubOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || (input[0]->GetOutputType() != input[1]->GetOutputType())) ? ShaderInput::NoData : input[0]->GetOutputType(); }
int DivOperatorShaderBlock::GetOutputType() const
{ return (!input[0] || !input[1] || (input[0]->GetOutputType() != input[1]->GetOutputType())) ? ShaderInput::NoData : input[0]->GetOutputType(); }
int MulOperatorShaderBlock::GetOutputType() const
{
if (!input[0] || !input[1])
return ShaderInput::NoData;
int type_0 = input[0]->GetOutputType(),
type_1 = input[1]->GetOutputType();
if (type_0 > type_1)
{ int tmp = type_0; type_0 = type_1; type_1 = tmp; }
// Switch on largest type.
switch (type_1)
{
case ShaderInput::Matrix3:
return (type_0 != ShaderInput::Vector3) ? ShaderInput::NoData : ShaderInput::Vector3;
case ShaderInput::Matrix4:
return (type_0 != ShaderInput::Vector4) ? ShaderInput::NoData : ShaderInput::Vector4;
case ShaderInput::Float:
case ShaderInput::Vector2:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
return (type_0 != type_1) ? ShaderInput::NoData : type_0;
}
return ShaderInput::NoData;
}
int ClampShaderBlock::GetOutputType() const
{
if (!input[0] || !input[1] || !input[2])
return ShaderInput::NoData;
int type[3] =
{
input[0]->GetOutputType(),
input[1]->GetOutputType(),
input[2]->GetOutputType()
};
if (type[1] != type[2]) // min/max must match.
return ShaderInput::NoData;
if (type[0] != type[1])
return ShaderInput::NoData; // input and min/max types must match.
return type[0];
}
int NormalizeOperatorShaderBlock::GetOutputType() const
{ return !input[0] ? ShaderInput::NoData : input[0]->GetOutputType(); }
//------------------------------------------------------------------------------
//-----------------------------------------------------------
int SwizzleShaderBlock::GetOutputType() const
//-----------------------------------------------------------
{
if (!input[0] || (input[0]->GetOutputType() == ShaderInput::NoData))
return ShaderInput::NoData;
int output_count = 0;
for (int n = 0; n < 4; ++n)
if (swizzle[n] != SwizzleNone)
output_count++;
switch (output_count)
{
case 1: return ShaderInput::Float;
case 2: return ShaderInput::Vector2;
case 3: return ShaderInput::Vector3;
case 4: return ShaderInput::Vector4;
}
return ShaderInput::NoData;
}
//---------------------------------------------------------
int BuildShaderBlock::GetOutputType() const
//---------------------------------------------------------
{
int output_count = 0;
for (int n = 0; n < 4; ++n)
switch (build[n])
{
case BuildZero:
case BuildOne:
output_count++;
break;
default:
if (!input[n])
n = 4;
else
{
if (input[n]->GetOutputType() == ShaderInput::NoData)
return ShaderInput::NoData;
output_count++;
}
break;
}
switch (output_count)
{
case 1: return ShaderInput::Float;
case 2: return ShaderInput::Vector2;
case 3: return ShaderInput::Vector3;
case 4: return ShaderInput::Vector4;
}
return ShaderInput::NoData;
}
int CosinusShaderBlock::GetOutputType() const
{ return ShaderInput::Float; }
int SinusShaderBlock::GetOutputType() const
{ return ShaderInput::Float; }
int PowShaderBlock::GetOutputType() const
{ return ShaderInput::Float; }
int AbsShaderBlock::GetOutputType() const
{ return !input[0] ? ShaderInput::NoData : input[0]->GetOutputType(); }
int GeometryVertexShaderBlock::GetOutputType() const
{ return ShaderInput::Vector4; }
int GeometryUVShaderBlock::GetOutputType() const
{ return ShaderInput::Vector2; }
int GeometryNormalShaderBlock::GetOutputType() const
{ return ShaderInput::Vector3; }
int GeometrySkinningShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix4; }
int GeometryVertexColorShaderBlock::GetOutputType() const
{ return ShaderInput::Vector3; }
int GeometryTangentFrameShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix3; }
int RenderBufferShaderBlock::GetOutputType() const
{ return ShaderInput::Texture2D; }
int TextureShaderBlock::GetOutputType() const
{ return ShaderInput::Texture2D; }
int TextureSamplerShaderBlock::GetOutputType() const
{ return (input[0] && input[1]) ? ShaderInput::Vector4 : ShaderInput::NoData; }
int ConstantShaderBlock::GetOutputType() const
{ return constant_type; }
int ColorShaderBlock::GetOutputType() const
{ return ShaderInput::Vector4; }
int MaterialParamShaderBlock::GetOutputType() const
{
switch (param)
{
case MaterialGlossiness:
case MaterialOpacity:
case MaterialReflection:
return ShaderInput::Float;
}
return ShaderInput::Vector4;
}
int MaterialTextureShaderBlock::GetOutputType() const
{ return ShaderInput::Texture2D; }
int ScreenUVShaderBlock::GetOutputType() const
{ return ShaderInput::Vector2; }
int ViewVectorShaderBlock::GetOutputType() const
{ return ShaderInput::Vector3; }
int ViewportShaderBlock::GetOutputType() const
{ return ShaderInput::Vector4; }
int NormalViewMatrixShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix3; }
int NormalMatrixShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix3; }
int ModelViewMatrixShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix4; }
int ModelMatrixShaderBlock::GetOutputType() const
{ return ShaderInput::Matrix4; }
int ClockShaderBlock::GetOutputType() const
{ return ShaderInput::Float; }

View File

@ -0,0 +1,175 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_input.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
ShaderInput::SemanticDesc ShaderInput::semantic_desc[LastSemantic + 1] =
{
{ "Position", CategoryVertexStream, Vector3, MediumP },
{ "Normal", CategoryVertexStream, Vector3, LowP },
{ "UV0", CategoryVertexStream, Vector2, MediumP },
{ "UV1", CategoryVertexStream, Vector2, MediumP },
{ "UV2", CategoryVertexStream, Vector2, MediumP },
{ "VertexColor", CategoryVertexStream, Vector4, LowP },
{ "Tangent", CategoryVertexStream, Vector3, LowP },
{ "Bitangent", CategoryVertexStream, Vector3, LowP },
{ "BoneIndex", CategoryVertexStream, Vector4, LowP },
{ "BoneWeight", CategoryVertexStream, Vector4, LowP },
// Data uniform.
{ "Constant", CategoryConstant, Vector4, MediumP },
{ "Texture2D", CategoryTexture, DataTexture2D, NoP },
{ "Texture3D", CategoryTexture, DataTexture2D, NoP },
{ "TextureCube", CategoryTexture, DataTextureCube, NoP },
{ "Clock", CategoryRenderer, Float, MediumP },
{ "TimeOfDay", CategoryRenderer, Float, MediumP },
{ "ViewVector", CategoryRenderer, Vector3, MediumP },
{ "ViewPosition", CategoryRenderer, Vector4, MediumP },
{ "Viewport", CategoryRenderer, Vector4, MediumP },
{ "ZNear", CategoryRenderer, Float, MediumP },
{ "ZFar", CategoryRenderer, Float, MediumP },
{ "ZoomFactor", CategoryRenderer, Float, MediumP },
{ "FxScale", CategoryRenderer, Float, MediumP },
{ "InverseBufferSize", CategoryRenderer, Vector2, LowP },
{ "InverseViewportSize", CategoryRenderer, Vector2, LowP },
{ "DisplayBufferRatio", CategoryRenderer, Vector2, MediumP },
{ "ViewportRatio", CategoryRenderer, Vector2, MediumP },
{ "ViewDepthOffset", CategoryRenderer, Float, MediumP },
{ "AmbientColor", CategoryRenderer, Vector3, LowP },
{ "FogColor", CategoryRenderer, Vector3, LowP },
{ "FogNear", CategoryRenderer, Float, MediumP },
{ "FogFar", CategoryRenderer, Float, MediumP },
{ "FogInverseRange", CategoryRenderer, Float, LowP },
{ "DepthBuffer", CategoryRenderer, DataTexture2D, NoP },
{ "FrameBuffer", CategoryRenderer, DataTexture2D, NoP },
{ "GBuffer0", CategoryRenderer, DataTexture2D, NoP },
{ "GBuffer1", CategoryRenderer, DataTexture2D, NoP },
{ "GBuffer2", CategoryRenderer, DataTexture2D, NoP },
{ "GBuffer3", CategoryRenderer, DataTexture2D, NoP },
{ "NoiseMap", CategoryRenderer, DataTexture2D, NoP },
{ "NormalMatrix", CategoryTransform, Matrix3, LowP },
{ "NormalViewMatrix", CategoryTransform, Matrix3, HighP },
{ "ModelMatrix", CategoryTransform, Matrix4, HighP },
{ "ViewMatrix", CategoryTransform, Matrix4, HighP },
{ "ProjectionMatrix", CategoryTransform, Matrix4, HighP },
{ "ModelViewMatrix", CategoryTransform, Matrix4, HighP },
{ "ModelViewProjectionMatrix", CategoryTransform, Matrix4, HighP },
{ "InverseViewProjectionMatrix", CategoryTransform, Matrix4, HighP },
{ "InverseViewProjectionMatrixAtOrigin", CategoryTransform, Matrix4, HighP },
{ "PreviousModelViewMatrix", CategoryPreviousTransform, Matrix4, HighP },
{ "PreviousModelViewProjectionMatrix", CategoryPreviousTransform, Matrix4, HighP },
{ "MaterialOpacity", CategoryMaterialOpacity, Float, LowP },
{ "MaterialDiffuse", CategoryMaterial, Vector4, LowP },
{ "MaterialSpecular", CategoryMaterial, Vector4, LowP },
{ "MaterialSelf", CategoryMaterial, Vector4, LowP },
{ "MaterialAmbient", CategoryMaterial, Vector4, LowP },
{ "MaterialGlossiness", CategoryMaterial, Float, LowP },
{ "MaterialReflection", CategoryMaterial, Float, LowP },
{ "MaterialAlphaThreshold", CategoryMaterial, Float, LowP },
{ "MaterialDepthBias", CategoryMaterial, Float, LowP },
{ "MaterialTexture0", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture1", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture2", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture3", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture4", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture5", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture6", CategoryMaterial, DataTexture2D, NoP },
{ "MaterialTexture7", CategoryMaterial, DataTexture2D, NoP },
{ "LightRange", CategoryLight, Float, MediumP },
{ "LightSpotEdge", CategoryLight, Float, MediumP },
{ "LightSpotCone", CategoryLight, Float, MediumP },
{ "LightShadowBias", CategoryLight, Float, MediumP },
{ "LightDiffuseColor", CategoryLight, Vector3, LowP },
{ "LightSpecularColor", CategoryLight, Vector3, LowP },
{ "LightShadowColor", CategoryLight, Vector3, LowP },
{ "LightViewPosition", CategoryLight, Vector3, MediumP },
{ "LightViewDirection", CategoryLight, Vector3, LowP },
{ "LightShadowMatrix0", CategoryLight, Matrix4, MediumP },
{ "LightShadowMatrix1", CategoryLight, Matrix4, MediumP },
{ "LightShadowMatrix2", CategoryLight, Matrix4, MediumP },
{ "LightShadowMatrix3", CategoryLight, Matrix4, MediumP },
{ "LightShadowMatrix4", CategoryLight, Matrix4, MediumP },
{ "LightShadowMatrix5", CategoryLight, Matrix4, MediumP },
{ "InverseShadowMapSize", CategoryLight, Float, LowP },
{ "LightShadowMap0", CategoryLight, DataTextureShadow, NoP },
{ "LightShadowMap1", CategoryLight, DataTextureShadow, NoP },
{ "LightShadowMap2", CategoryLight, DataTextureShadow, NoP },
{ "LightShadowMap3", CategoryLight, DataTextureShadow, NoP },
{ "LightShadowMap4", CategoryLight, DataTextureShadow, NoP },
{ "LightShadowMap5", CategoryLight, DataTextureShadow, NoP },
{ "LightPSSMSliceDistance0", CategoryLight, Float, MediumP },
{ "LightPSSMSliceDistance1", CategoryLight, Float, MediumP },
{ "LightPSSMSliceDistance2", CategoryLight, Float, MediumP },
{ "LightPSSMSliceDistance3", CategoryLight, Float, MediumP },
{ "ViewToLightMatrix", CategoryLight, Matrix4, MediumP },
{ "LightProjectionMap", CategoryLight, DataTexture2D, NoP },
{ "BoneMatrix", CategorySkin, Matrix4, MediumP },
{ "PreviousBoneMatrix", CategorySkin, Matrix4, MediumP },
{ "SemanticLast", CategoryLast, NoData, NoP }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
const char *ShaderInput::GetCategoryName(Category category)
{
static const char *cat[CategoryLast] =
{
"VertexStream",
"Constant",
"Texture",
"Skin",
"Renderer",
"MaterialOpacity",
"Material",
"Transform",
"PreviousTransform",
"Light"
};
return cat[category];
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool ShaderInput::ConsumesTextureUnit() const
{
switch (data_type)
{
case DataTexture2D:
case DataTexture3D:
case DataTextureCube:
case DataTextureShadow:
return true;
default: break;
}
return false;
}
//------------------------------------------------------------------------------
ShaderInput::ShaderInput()
{
type = None;
scope = Vertex | Pixel;
semantic = LastSemantic;
array_size = 1;
parm_v.Set(0, 0, 0);
data_type = NoData;
}

View File

@ -0,0 +1,165 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_isl_to_glsl.h"
#include "core/shader.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool ISLtoGLSL::GetType(ShaderInput::DataType data_type, String &decl)
{
switch (data_type)
{
case ShaderInput::Float: decl = "float"; return true;
case ShaderInput::Vector2: decl = "vec2"; return true;
case ShaderInput::Vector3: decl = "vec3"; return true;
case ShaderInput::Vector4: decl = "vec4"; return true;
case ShaderInput::Matrix3: decl = "mat3"; return true;
case ShaderInput::Matrix4: decl = "mat4"; return true;
case ShaderInput::DataTexture2D: decl = "sampler2D"; return true;
case ShaderInput::DataTexture3D: decl = "sampler3D"; return true;
case ShaderInput::DataTextureCube: decl = "samplerCube"; return true;
case ShaderInput::DataTextureShadow: decl = "sampler2DShadow"; return true;
}
return false;
}
bool ISLtoGLSL::Translate(const Shader &shader, String &glsl_vertex, String &glsl_pixel, GLSLVariant variant)
{
glsl_vertex = shader.vertex;
glsl_pixel = shader.pixel;
String vertex_decl, pixel_decl, type_decl;
// Variant defaults.
switch (variant)
{
case EGL20:
{
vertex_decl += "#version 100\n\n"; // EGL 100 ~= GL 120
pixel_decl += "#version 100\n\n";
static String gles_precision("precision mediump float;\n");
vertex_decl += gles_precision;
pixel_decl += gles_precision;
}
break;
case OGL32:
vertex_decl += "#version 130\n\n";
pixel_decl += "#version 130\n\n";
break;
default:
// Allow implicit conversions.
// vertex_decl += "#version 120\n\n";
// pixel_decl += "#version 120\n\n";
break;
}
// Helper macros.
String mtx_mul = "#define n_mtx_mul(A, B) ((A)*(B))\n";
vertex_decl += mtx_mul;
pixel_decl += mtx_mul;
String mtx_conv = "mat3 _mat4_to_mat3(mat4 m) { return mat3(m[0].xyz, m[1].xyz, m[2].xyz); }\n";
vertex_decl += mtx_conv;
pixel_decl += mtx_conv;
String buildm3 = "\nmat3 _build_mat3(vec3 a, vec3 b, vec3 c) { return mat3(a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z); }\n";
vertex_decl += buildm3;
pixel_decl += buildm3;
// Convert symbols.
{
static const char *isl_symbol[] = { "%out.position%", NULL };
static const char *egl_symbol[] = { "gl_Position", NULL };
glsl_vertex.ReplaceAll(isl_symbol, egl_symbol, true);
}
{
static const char *isl_symbol[] = { "%in.fragcoord%", "%out.color%", "%out.color0%", "%out.color1%", "%out.color2%", "%out.color3%", "%out.depth%", NULL };
static const char *egl_symbol[] = { "gl_FragCoord", "gl_FragColor", "gl_FragData[0]", "gl_FragData[1]", "gl_FragData[2]", "gl_FragData[3]", "gl_FragDepth", NULL };
glsl_pixel.ReplaceAll(isl_symbol, egl_symbol, true);
}
//
{
static const char *outputs[] = { "%position%", "%normal%", "%diffuse%", "%specular%", "%glossiness%", "%constant%", "%opacity%", NULL };
static const char *out_vars[] = { "_o_vertex", "_o_normal", "_o_diffuse", "_o_specular", "_o_glossiness", "_o_constant", "_o_opacity", NULL };
glsl_vertex.ReplaceAll(outputs, out_vars, true);
glsl_pixel.ReplaceAll(outputs, out_vars, true);
}
// Create function declaration.
if (!glsl_vertex.Replace("%main%", "void main()"))
glsl_vertex = String("void main()\n{\n") + glsl_vertex + "}";
if (!glsl_pixel.Replace("%main%", "void main()"))
glsl_pixel = String("void main()\n{\n") + glsl_pixel + "}";
// Declare inputs.
ListForeachPtr(ShaderInput *, input, shader.input_list)
if (GetType(input->data_type, type_decl))
{
if (variant == EGL20)
{
static String lowp("lowp "), mediump("mediump "), highp("highp ");
switch (ShaderInput::semantic_desc[input->semantic].precision)
{
case ShaderInput::LowP: type_decl = lowp + type_decl; break;
case ShaderInput::MediumP: type_decl = mediump + type_decl; break;
case ShaderInput::HighP: type_decl = highp + type_decl; break;
}
}
String input_decl = input->array_size > 1 ? String::Format("%s[%d]", input->name.c_str(), input->array_size) : input->name,
local_decl;
switch (input->type)
{
case ShaderInput::Attribute:
local_decl = String::Format("attribute %s %s;\n", type_decl.c_str(), input_decl.c_str());
break;
case ShaderInput::Uniform:
local_decl = String::Format("uniform %s %s;\n", type_decl.c_str(), input_decl.c_str());
break;
}
if (input->scope & ShaderInput::Vertex)
vertex_decl += local_decl;
if (input->scope & ShaderInput::Pixel)
pixel_decl += local_decl;
}
else
__LOG_E__ << "Unsupported input '" << input->name << "' type (" << input->type << ").\n";
// Declare varyings.
ListForeachPtr(ShaderVarying *, varying, shader.varying_list)
{
String decl = String::Format("varying %s %s;\n", varying->type.c_str(), varying->name.c_str());
vertex_decl += decl;
pixel_decl += decl;
}
// Assemble final source.
glsl_vertex = vertex_decl + shader.vertex_decl + glsl_vertex;
glsl_pixel = pixel_decl + shader.pixel_decl + glsl_pixel;
//
if (variant == EGL20)
{
static const char *isl_symbol[] = { "sampler2DShadow", "shadow2D", NULL };
static const char *egl_symbol[] = { "sampler2D", "texture2D", NULL };
glsl_vertex.ReplaceAll(isl_symbol, egl_symbol, true);
glsl_pixel.ReplaceAll(isl_symbol, egl_symbol, true);
}
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,265 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------------*/
#include "core/shader_isl_to_hlsl.h"
#include "core/shader.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
String RewriteTextureSampling(const char *source, StringList &arg)
{
// ISL arg0: texture object variable.
// ISL arg1: UV variable.
return String::Format("%s_res.Sample(%s, %s)", arg[0].c_str(), arg[0].c_str(), arg[1].c_str());
}
String RewriteShadowSampling(const char *source, StringList &arg)
{
// ISL arg0: texture object variable.
// ISL arg1: UV variable.
return String::Format("%s_res.SampleCmpLevelZero(%s, (%s).xy, (%s).z * 2.0 - 1.0)", arg[0].c_str(), arg[0].c_str(), arg[1].c_str(), arg[1].c_str());
}
String RewritePCFCall(const char *source, StringList &arg)
{
// Make sure a call to ComputePCF is submitted and not the function definition (which already has 5 parameters by now).
if (arg[3].IndexOf(',') != -1)
return source;
return String::Format("ComputePCF(%s, %s, %s, %s_res, %s)", arg[0].c_str(), arg[1].c_str(), arg[2].c_str(), arg[2].c_str(), arg[3].c_str());
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String ISLtoHLSL::GetCategoryCBufferName(ShaderInput::Category c)
{
return String::Format("CBuffer%s", ShaderInput::GetCategoryName(c));
}
bool ISLtoHLSL::GetType(ShaderInput::DataType type, String &decl)
{
switch (type)
{
case ShaderInput::Float: decl = "float"; return true;
case ShaderInput::Vector2: decl = "vec2"; return true;
case ShaderInput::Vector3: decl = "vec3"; return true;
case ShaderInput::Vector4: decl = "vec4"; return true;
case ShaderInput::Matrix3: decl = "mat3"; return true;
case ShaderInput::Matrix4: decl = "mat4"; return true;
}
return false;
}
static void BuildInputLocalDecl(const ShaderInput * input, String &local_decl)
{
String type_decl;
switch (input->data_type)
{
case ShaderInput::DataTexture2D:
case ShaderInput::DataTextureCube:
local_decl = String::Format("SamplerState %s;\nTexture2D %s_res;\n", input->name.c_str(), input->name.c_str());
break;
case ShaderInput::DataTextureShadow:
local_decl = String::Format("SamplerComparisonState %s;\nTexture2D %s_res;\n", input->name.c_str(), input->name.c_str());
break;
default:
if (ISLtoHLSL::GetType(input->data_type, type_decl))
{
String input_decl = input->array_size > 1 ? String::Format("%s[%d]", input->name.c_str(), input->array_size) : input->name;
local_decl = String::Format("%s %s;\n", type_decl.c_str(), input_decl.c_str());
}
break;
}
}
static void DeclareInputs(const Shader &shader, String &vertex_decl, String &pixel_decl)
{
// Declare constants with one cbuffer per category.
String local_decl;
for (uint c = 0; c < ShaderInput::CategoryLast; ++c)
{
bool vertex_constant_scope_open = false,
pixel_constant_scope_open = false;
ListForeachPtr(ShaderInput *, input, shader.input_list)
{
if (input->type != ShaderInput::Uniform)
continue;
if (ShaderInput::semantic_desc[input->semantic].category != (ShaderInput::Category)c)
continue; // filter on category
BuildInputLocalDecl(input, local_decl);
if (input->scope & ShaderInput::Vertex)
{
if (!vertex_constant_scope_open && !input->ConsumesTextureUnit())
{
vertex_decl += String::Format("\ncbuffer CBuffer%s\n{\n", ShaderInput::GetCategoryName((ShaderInput::Category)c));
vertex_constant_scope_open = true;
}
vertex_decl += local_decl;
}
if (input->scope & ShaderInput::Pixel)
{
if (!pixel_constant_scope_open && !input->ConsumesTextureUnit())
{
pixel_decl += String::Format("\ncbuffer CBuffer%s\n{\n", ShaderInput::GetCategoryName((ShaderInput::Category)c));
pixel_constant_scope_open = true;
}
pixel_decl += local_decl;
}
}
// Close cbuffer scope.
if (vertex_constant_scope_open)
vertex_decl += "};\n";
if (pixel_constant_scope_open)
pixel_decl += "};\n";
}
}
bool ISLtoHLSL::Translate(const Shader &shader, String &hlsl_vertex, String &hlsl_pixel)
{
hlsl_vertex = shader.vertex;
hlsl_pixel = shader.pixel;
// Vertex/pixel structures.
String v_in_struct = "struct VertexInput\n{\n",
p_in_struct = "struct PixelInput\n{\n",
type_decl;
p_in_struct += " vec4 position : SV_Position;\n";
ListForeachPtr(ShaderInput *, input, shader.input_list)
if ((input->type == ShaderInput::Attribute) && GetType(input->data_type, type_decl))
{
String input_decl = input->array_size > 1 ? String::Format("%s[%d]", input->name.c_str(), input->array_size) : input->name;
String local_decl = String::Format(" %s %s : %s;\n", type_decl.c_str(), input_decl.c_str(), ShaderInput::semantic_desc[input->semantic].name);
if (input->scope & ShaderInput::Vertex)
v_in_struct += local_decl;
if (input->scope & ShaderInput::Pixel)
p_in_struct += local_decl;
hlsl_vertex.ReplaceAll(input->name, String::Format("IN.%s", input->name.c_str()), true);
}
int i_interpolator = 0;
ListForeachPtr(ShaderVarying *, varying, shader.varying_list)
{
p_in_struct += String::Format(" %s %s : Varying%d;\n", varying->type.c_str(), varying->name.c_str(), i_interpolator);
// Reserve enough registers for the varying type.
if (varying->type == "mat4")
i_interpolator += 4;
else if (varying->type == "mat3")
i_interpolator += 3;
else
i_interpolator++;
hlsl_vertex.ReplaceAll(varying->name, String::Format("OUT.%s", varying->name.c_str()), true);
hlsl_pixel.ReplaceAll(varying->name, String::Format("IN.%s", varying->name.c_str()), true);
}
v_in_struct += "};\n\n";
p_in_struct += "};\n\n";
// Pixel output.
String p_out_struct = "struct PixelOutput\n{\n";
if (hlsl_pixel.Contains("%out.color%")) p_out_struct += " vec4 color : SV_Target;\n";
if (hlsl_pixel.Contains("%out.color0%")) p_out_struct += " vec4 color0 : SV_Target1;\n";
if (hlsl_pixel.Contains("%out.color1%")) p_out_struct += " vec4 color1 : SV_Target2;\n";
if (hlsl_pixel.Contains("%out.color2%")) p_out_struct += " vec4 color2 : SV_Target3;\n";
if (hlsl_pixel.Contains("%out.color3%")) p_out_struct += " vec4 color3 : SV_Target4;\n";
if (hlsl_pixel.Contains("%out.depth%")) p_out_struct += " float depth : SV_Depth;\n";
p_out_struct += "};\n\n";
//
String vertex_decl, pixel_decl;
String header = String::Format("// GSFramework ISL to HLSL converter.\n// File: '%s'\n\n", shader.name.c_str());
vertex_decl += header;
pixel_decl += header;
vertex_decl += v_in_struct;
vertex_decl += p_in_struct;
pixel_decl += p_in_struct;
pixel_decl += p_out_struct;
// Translation helper.
vertex_decl += "\n#define mix lerp\n";
pixel_decl += "\n#define mix lerp\n";
vertex_decl += "\n#define n_mtx_mul mul\n";
pixel_decl += "\n#define n_mtx_mul mul\n";
String m4tom3 = "\nfloat3x3 _mat4_to_mat3(const float4x4 m) { return (float3x3)m; }\n";
vertex_decl += m4tom3;
pixel_decl += m4tom3;
String buildm3 = "\nfloat3x3 _build_mat3(const float3 a, const float3 b, const float3 c) { return float3x3(a.x, b.x, c.x, a.y, b.y, c.y, a.z, b.z, c.z); }\n";
vertex_decl += buildm3;
pixel_decl += buildm3;
// Declare uniforms.
DeclareInputs(shader, vertex_decl, pixel_decl);
// Create function declaration.
if (!hlsl_vertex.Replace("%main%", "void main(in VertexInput IN, out PixelInput OUT)"))
hlsl_vertex = String("void main(in VertexInput IN, out PixelInput OUT)\n{\n") + hlsl_vertex + "}";
if (!hlsl_pixel.Replace("%main%", "void main(in PixelInput IN, out PixelOutput OUT)"))
hlsl_pixel = String("void main(in PixelInput IN, out PixelOutput OUT)\n{\n") + hlsl_pixel + "}";
// Assemble final source.
hlsl_vertex = vertex_decl + shader.vertex_decl + hlsl_vertex;
hlsl_pixel = pixel_decl + shader.pixel_decl + hlsl_pixel;
// Convert shadow sampling.
hlsl_pixel.Replace("ComputePCF(vec3 fvp, mat4 pjm, sampler2DShadow tsampler, float k)", "ComputePCF(float3 fvp, float4x4 pjm, SamplerComparisonState tsampler, Texture2D tsampler_res, float k)", String::CaseSensitive);
hlsl_pixel = String::RewritePatternAll(hlsl_pixel, "ComputePCF(%,%,%,%)", RewritePCFCall);
// Convert texture sampling.
hlsl_vertex = String::RewritePatternAll(hlsl_vertex, "texture2D(%,%)", RewriteTextureSampling);
hlsl_pixel = String::RewritePatternAll(hlsl_pixel, "texture2D(%,%)", RewriteTextureSampling);
hlsl_vertex = String::RewritePatternAll(hlsl_vertex, "shadow2D(%,%)", RewriteShadowSampling);
hlsl_pixel = String::RewritePatternAll(hlsl_pixel, "shadow2D(%,%)", RewriteShadowSampling);
hlsl_vertex = String::RewritePatternAll(hlsl_vertex, "textureCube(%,%)", RewriteTextureSampling);
hlsl_pixel = String::RewritePatternAll(hlsl_pixel, "textureCube(%,%)", RewriteTextureSampling);
// Convert symbols.
{
static const char *isl_symbol[] = { "%out.position%", NULL };
static const char *hsl_symbol[] = { "OUT.position", NULL };
hlsl_vertex.ReplaceAll(isl_symbol, hsl_symbol, true);
}
{
static const char *isl_symbol[] = { "%in.fragcoord%", "%out.color%", "%out.color0%", "%out.color1%", "%out.color2%", "%out.color3%", "%out.depth%", NULL };
static const char *hsl_symbol[] = { "IN.position", "OUT.color", "OUT.color0", "OUT.color1", "OUT.color2", "OUT.color3", "OUT.depth", NULL };
hlsl_pixel.ReplaceAll(isl_symbol, hsl_symbol, true);
}
//
{
static const char *outputs[] = { "%position%", "%normal%", "%diffuse%", "%specular%", "%glossiness%", "%constant%", "%opacity%", NULL };
static const char *out_vars[] = { "_o_vertex", "_o_normal", "_o_diffuse", "_o_specular", "_o_glossiness", "_o_constant", "_o_opacity", NULL };
hlsl_vertex.ReplaceAll(outputs, out_vars, true);
hlsl_pixel.ReplaceAll(outputs, out_vars, true);
}
{
static const char *isl_symbol[] = { "vec2", "vec3", "vec4", "mat3", "mat4", "sampler2DShadow", NULL };
static const char *hsl_symbol[] = { "float2", "float3", "float4", "float3x3", "float4x4", "SamplerComparisonState", NULL };
hlsl_vertex.ReplaceAll(isl_symbol, hsl_symbol, true);
hlsl_pixel.ReplaceAll(isl_symbol, hsl_symbol, true);
}
// [EJ] PIX won't display sources correctly unless they use Windows eol markers.
hlsl_vertex.NormalizeEOL(String::EOLWindows);
hlsl_pixel.NormalizeEOL(String::EOLWindows);
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,272 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader.h"
#include "metafile/nml.h"
#include "filesystem/filesystem.h"
#include "platform.h"
#include "log/log.h"
using namespace GS::Core;
using GS::NML::Tag;
//------------------------------------------------------------------------------
void Shader::ParseVaryingTag(Tag *tag)
{
if (!tag || tag->name != "Varying")
return;
NMLTagForeach(it, *tag)
if (it->name == "Variable")
{
Tag *t_name = it->GetTypedTag("Name", Variant::VariantString),
*t_type = it->GetTypedTag("Type", Variant::VariantString);
if (t_name && t_type)
DeclareVarying(t_name->GetString(), t_type->GetString());
}
}
void Shader::ParseInputTag(Tag *tag)
{
if (!tag || tag->name != "Input")
return;
NMLTagForeach(it, *tag)
{
ShaderInput::Type type = ShaderInput::None;
uint scope = 0;
// Parse shader input.
if (it->name == "Attribute")
{
type = ShaderInput::Attribute;
scope = ShaderInput::Vertex;
}
else if (it->name == "Uniform")
{
type = ShaderInput::Uniform;
scope = ShaderInput::Pixel;
}
if (type != ShaderInput::None)
{
String input_name;
ShaderInput::DataType data_type = ShaderInput::NoData;
ShaderInput::Semantic semantic = ShaderInput::Constant;
if (Tag *t = it->GetTypedTag("Name", Variant::VariantString))
input_name = t->GetString();
if (Tag *t = it->GetTypedTag("Semantic", Variant::VariantString))
{
String cs(t->GetString());
#if 1 // Legacy semantic support (changed with 1.3.0).
if (cs == "Texture")
cs = "Texture2D";
else if (cs == "NativeTexture")
cs = "Texture2D";
else if (cs == "CubeTexture")
cs = "TextureCube";
else if (cs == "User")
cs = "Constant";
#endif
uint n = 0;
for (; n < ShaderInput::LastSemantic; ++n)
if (cs == ShaderInput::semantic_desc[n].name)
{
semantic = (ShaderInput::Semantic)n;
data_type = ShaderInput::semantic_desc[semantic].data_type;
break;
}
if (n == ShaderInput::LastSemantic)
__LOG_E__ << "Unknown shader input semantic '" << cs << "'.\n";
}
if (Tag *t = it->GetTag("Type"))
{
String type(t->GetString());
if (type == "float") data_type = ShaderInput::Float;
else if (type == "vec2") data_type = ShaderInput::Vector2;
else if (type == "vec3") data_type = ShaderInput::Vector3;
else if (type == "vec4") data_type = ShaderInput::Vector4;
else if (type == "mat3") data_type = ShaderInput::Matrix3;
else if (type == "mat4") data_type = ShaderInput::Matrix4;
else
__LOG_E__ << "Unknown type '" << type << "' for input '" << input_name << "'.\n";
}
if (Tag *t = it->GetTag("Scope"))
{
scope = 0;
if (t->GetTag("Vertex"))
scope |= ShaderInput::Vertex;
if (t->GetTag("Pixel") || t->GetTag("Fragment"))
scope |= ShaderInput::Pixel;
}
ShaderInput *input = NULL;
if (semantic != ShaderInput::LastSemantic)
input = DeclareInput(input_name, data_type, semantic, type, (ShaderInput::Scope)scope);
else
__LOG_W__ << "Unknown shader input semantic in shader '" << name << "'.\n";
if (input)
switch (input->semantic)
{
case ShaderInput::Texture2D:
case ShaderInput::TextureCube:
if (Tag *t = it->GetTypedTag("Texture", Variant::VariantString))
input->parm_t = t->GetString();
break;
case ShaderInput::Constant:
if (Tag *t = it->GetTag("Vector"))
input->parm_v.FromMetaTag(*t);
break;
}
}
}
}
bool Shader::FromMetaTag(Tag &tag)
{
if (tag.name != "Shader")
return false;
Clear();
NMLTagForeach(pt, tag)
{
if (pt->name == "Name")
name = pt->GetString();
else if (pt->name == "Varying")
ParseVaryingTag(pt);
else if (pt->name == "Input")
ParseInputTag(pt);
else if (pt->name == "VertexDeclaration")
vertex_decl = pt->GetString();
else if (pt->name == "PixelDeclaration")
pixel_decl = pt->GetString();
else if (pt->name == "GeometryDeclaration")
geometry_decl = pt->GetString();
else if (pt->name == "VertexSource")
vertex = pt->GetString();
else if ((pt->name == "PixelSource") || (pt->name == "FragmentSource"))
pixel = pt->GetString();
else if (pt->name == "GeometrySource")
geometry = pt->GetString();
else if (pt->name == "Vertex")
{
Array <char> buffer;
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
vertex.Set(buffer, &buffer[buffer.GetCount()]);
}
else if ((pt->name == "Pixel") || (pt->name == "Fragment"))
{
Array <char> buffer;
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
pixel.Set(buffer, &buffer[buffer.GetCount()]);
}
else if (pt->name == "Geometry")
{
Array <char> buffer;
if (Platform::Get().io->FileLoad(pt->GetString(), buffer))
geometry.Set(buffer, &buffer[buffer.GetCount()]);
}
else
__LOG_W__ << "Unknown tag '" << pt->name << "' in <Shader>.\n";
}
return true;
}
Tag *Shader::AsMetaTag() const
{
Tag *root = new Tag("Shader");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize shader. Failed to create root tag.\n", NULL)
if (input_list.GetCount())
if (Tag *it = root->AddChild("Input"))
ListForeachPtr(ShaderInput *, input, input_list)
{
Tag *t = NULL;
switch (input->type)
{
case ShaderInput::Attribute: t = new Tag("Attribute"); break;
case ShaderInput::Uniform: t = new Tag("Uniform"); break;
}
if (!t)
continue;
t->AddChild("Name", input->name);
t->AddChild("Semantic", ShaderInput::semantic_desc[input->semantic].name);
if (Tag *st = t->AddChild("Scope"))
{
if (input->scope & ShaderInput::Vertex)
st->AddChild("Vertex");
if (input->scope & ShaderInput::Pixel)
st->AddChild("Pixel");
if (input->scope & ShaderInput::Geometry)
st->AddChild("Geometry");
}
switch (input->semantic)
{
case ShaderInput::Constant:
switch (input->data_type)
{
case ShaderInput::Float: t->AddChild("Type", "float"); break;
case ShaderInput::Vector2: t->AddChild("Type", "vec2"); break;
case ShaderInput::Vector3: t->AddChild("Type", "vec3"); break;
case ShaderInput::Vector4: t->AddChild("Type", "vec4"); break;
case ShaderInput::Matrix3: t->AddChild("Type", "mat3"); break;
case ShaderInput::Matrix4: t->AddChild("Type", "mat4"); break;
}
t->AddChild(input->parm_v.AsMetaTag("Vector"));
break;
}
if (!input->parm_t.IsEmpty())
t->AddChild("Texture", input->parm_t.c_str());
it->AddChild(t);
}
if (varying_list.GetCount())
if (Tag *it = root->AddChild("Varying"))
ListForeachPtr(ShaderVarying *, varying, varying_list)
if (Tag *v = it->AddChild("Variable"))
{
v->AddChild("Name", varying->name);
v->AddChild("Type", varying->type);
}
if (!geometry_decl.IsEmpty())
root->AddChild("GeometryDeclaration", geometry_decl);
if (!vertex_decl.IsEmpty())
root->AddChild("VertexDeclaration", vertex_decl);
if (!pixel_decl.IsEmpty())
root->AddChild("PixelDeclaration", pixel_decl);
if (!geometry.IsEmpty())
root->AddChild("GeometrySource", geometry);
if (!vertex.IsEmpty())
root->AddChild("VertexSource", vertex);
if (!pixel.IsEmpty())
root->AddChild("PixelSource", pixel);
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,69 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree.h"
#include "core/shader_block.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
int ShaderTree::GetSinkCompatibility(ShaderSinkType sink) const
{
switch (sink)
{
case SinkNormal: return ShaderInput::Vector3;
case SinkDiffuse: return ShaderInput::Vector4;
case SinkModulate: return ShaderInput::Float;
case SinkSpecular: return ShaderInput::Vector4;
case SinkGlossiness: return ShaderInput::Float;
case SinkConstant: return ShaderInput::Vector4;
case SinkOpacity: return ShaderInput::Float;
case SinkReflection: return ShaderInput::Float;
}
return ShaderInput::NoData;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void ShaderTree::GatherBlockList(GS::List <ShaderBlock *> &block_list, ShaderBlock *root)
{
if (!root)
return;
// Gather all children.
for (uint n = 0; n < root->GetInputCount(); ++n)
GatherBlockList(block_list, root->GetInput(n));
// Add self.
if (!block_list.Find(root))
block_list.Append(root);
}
void ShaderTree::Free()
{
// Gather all blocks in tree.
List <ShaderBlock *> block_list;
for (int n = 0; n < SinkInvalid; ++n)
GatherBlockList(block_list, sink[n]);
// Disconnect all sinks.
for (int n = 0; n < SinkInvalid; ++n)
sink[n] = NULL;
// Delete all blocks.
ListDeleteAllPtr(ShaderBlock *, block_list)
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ShaderTree::ShaderTree()
{
for (int n = 0; n < SinkInvalid; ++n)
sink[n] = 0;
}
ShaderTree::~ShaderTree()
{ Free(); }
//------------------------------------------------------------------------------

View File

@ -0,0 +1,188 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree_compiler.h"
#include "core/geometry.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool ShaderTreeCompiler::GetNewVariable(String &variable, const char *prefix)
{
variable = String::Format("n_%s%d", prefix ? prefix : "n_var", variable_count++);
return true;
}
CShaderBlock *ShaderTreeCompiler::GetNewCompiledBlock(const ShaderBlock *block)
{
List <CShaderBlock *> ::Item *item = compiled_tree_block.Add(new CShaderBlock(block));
return item ? item->Object() : NULL;
}
//------------------------------------------------------------------------------
//-------------------------------------------------------------------
void ShaderTreeCompiler::AddPrefix(const char *prefix)
//-------------------------------------------------------------------
{
if (prefix)
id += prefix;
}
//-------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ShaderTreeCompiler::CompileTemporary(ShaderBlock *block, const char *prefix, ShaderInput::Scope scope)
//-------------------------------------------------------------------------------------------------------------------------
{
temporary_block_list.Add(block);
return CompileShaderBlock(block, prefix, scope);
}
//---------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ShaderTreeCompiler::CompileShaderBlock(const ShaderBlock *block, const char *prefix, ShaderInput::Scope scope)
//---------------------------------------------------------------------------------------------------------------------------------
{
if (!block)
return NULL;
// Id should describe the full tree structure.
AddPrefix(prefix);
id += block->GetId();
/*
Avoid compiling twice a block referenced multiple times.
Also geometry input blocks only need to be evaluated once.
*/
ListForeachPtr(CShaderBlock *, compiled_block, compiled_tree_block)
if (compiled_block->block->IsEquivalent(block))
return compiled_block;
// Compile as new block.
switch (block->type)
{
case ShaderBlock::TypeConstant:
return CompileConstantShaderBlock((const ConstantShaderBlock *)block, scope);
case ShaderBlock::TypeColor:
return CompileColorShaderBlock((const ColorShaderBlock *)block, scope);
case ShaderBlock::TypeMaterialParam:
return CompileMaterialParamShaderBlock((const MaterialParamShaderBlock *)block, scope);
case ShaderBlock::TypeMaterialTexture:
return CompileMaterialTextureShaderBlock((const MaterialTextureShaderBlock *)block, scope);
case ShaderBlock::TypeGeometryVertex:
return CompileGeometryVertexShaderBlock((const GeometryVertexShaderBlock *)block, scope);
case ShaderBlock::TypeGeometryNormal:
return CompileGeometryNormalShaderBlock((const GeometryNormalShaderBlock *)block, scope);
case ShaderBlock::TypeGeometrySkinning:
return CompileGeometrySkinningShaderBlock((const GeometrySkinningShaderBlock *)block, scope);
case ShaderBlock::TypeGeometryVertexColor:
return CompileGeometryVertexColorShaderBlock((const GeometryVertexColorShaderBlock *)block, scope);
case ShaderBlock::TypeGeometryTangentFrame:
return CompileGeometryTangentFrameShaderBlock((const GeometryTangentFrameShaderBlock *)block, scope);
case ShaderBlock::TypeGeometryUV:
return CompileGeometryUVShaderBlock((const GeometryUVShaderBlock *)block, scope);
case ShaderBlock::TypeRenderBuffer:
return CompileRenderBufferShaderBlock((const RenderBufferShaderBlock *)block, scope);
case ShaderBlock::TypeTexture:
return CompileTextureShaderBlock((const TextureShaderBlock *)block, scope);
case ShaderBlock::TypeTextureSampler:
return CompileTextureSamplerShaderBlock((const TextureSamplerShaderBlock *)block, scope);
case ShaderBlock::TypeMix:
return CompileMixShaderBlock((const MixOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeAdd:
return CompileAddShaderBlock((const AddOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeSub:
return CompileSubShaderBlock((const SubOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeMul:
return CompileMulShaderBlock((const MulOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeDiv:
return CompileDivShaderBlock((const DivOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeSwizzle:
return CompileSwizzleShaderBlock((const SwizzleShaderBlock *)block, scope);
case ShaderBlock::TypeBuild:
return CompileBuildShaderBlock((const BuildShaderBlock *)block, scope);
case ShaderBlock::TypeCos:
return CompileCosinusShaderBlock((const CosinusShaderBlock *)block, scope);
case ShaderBlock::TypeSin:
return CompileSinusShaderBlock((const SinusShaderBlock *)block, scope);
case ShaderBlock::TypePow:
return CompilePowShaderBlock((const PowShaderBlock *)block, scope);
case ShaderBlock::TypeAbs:
return CompileAbsShaderBlock((const AbsShaderBlock *)block, scope);
case ShaderBlock::TypeNormalize:
return CompileNormalizeBlock((const NormalizeOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeDot:
return CompileDotShaderBlock((const DotOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeCross:
return CompileCrossShaderBlock((const CrossOperatorShaderBlock *)block, scope);
case ShaderBlock::TypeClamp:
return CompileClampShaderBlock((const ClampShaderBlock *)block, scope);
case ShaderBlock::TypePackVectorToColor:
return CompilePackVectorToColor((const PackVectorToColorShaderBlock *)block, scope);
case ShaderBlock::TypeUnpackColorToVector:
return CompileUnpackColorToVector((const UnpackColorToVectorShaderBlock *)block, scope);
case ShaderBlock::TypeClock:
return CompileClockShaderBlock((const ClockShaderBlock *)block, scope);
case ShaderBlock::TypeScreenUV:
return CompileScreenUVShaderBlock((const ScreenUVShaderBlock *)block, scope);
case ShaderBlock::TypeViewVector:
return CompileViewVectorShaderBlock((const ViewVectorShaderBlock *)block, scope);
case ShaderBlock::TypeViewport:
return CompileViewportShaderBlock((const ViewportShaderBlock *)block, scope);
case ShaderBlock::TypeNormalViewMatrix:
return CompileNormalViewMatrixShaderBlock((const NormalViewMatrixShaderBlock *)block, scope);
case ShaderBlock::TypeNormalMatrix:
return CompileNormalMatrixShaderBlock((const NormalMatrixShaderBlock *)block, scope);
case ShaderBlock::TypeModelViewMatrix:
return CompileModelViewMatrixShaderBlock((const ModelViewMatrixShaderBlock *)block, scope);
case ShaderBlock::TypeModelMatrix:
return CompileModelMatrixShaderBlock((const ModelMatrixShaderBlock *)block, scope);
default:
__LOG_E__ << "Unsupported render block type (" << block->type << "), does not known how to compile.\n";
break;
}
return NULL;
}
//------------------------------------------------------------------------------
void ShaderTreeCompiler::Free()
{
id.Clear();
compiled_tree_block.Clear();
temporary_block_list.Clear();
vertex_declaration.Clear();
vertex_source.Clear();
pixel_declaration.Clear();
pixel_source.Clear();
texture_count = 0;
variable_count = 0;
shader = NULL;
}
void ShaderTreeCompiler::RestartCompiler(Shader *s)
{
Free();
shader = s;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ShaderTreeCompiler::ShaderTreeCompiler()
{
texture_count = 0;
variable_count = 0;
}
ShaderTreeCompiler::~ShaderTreeCompiler()
{ Free(); }
//------------------------------------------------------------------------------

View File

@ -0,0 +1,882 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree_compiler_isl.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
#define __MapCompilerGetNewCompiledBlock(__COMPILED_VAR__)\
CShaderBlock *__COMPILED_VAR__ = GetNewCompiledBlock(block);\
if (!__COMPILED_VAR__) return NULL;
#define __MapCompilerCompileInput(__COMPILED_VAR__, __INPUT_INDEX__)\
CShaderBlock *__COMPILED_VAR__ = CompileShaderBlock(block->GetInput(__INPUT_INDEX__));\
if (!__COMPILED_VAR__) return NULL;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool ISLShaderTreeCompiler::GetTypeDeclaration(ShaderInput::DataType data_type, String &declaration)
{
switch (data_type)
{
case ShaderInput::Float: declaration = "float"; return true;
case ShaderInput::Vector2: declaration = "vec2"; return true;
case ShaderInput::Vector3: declaration = "vec3"; return true;
case ShaderInput::Vector4: declaration = "vec4"; return true;
case ShaderInput::Matrix3: declaration = "mat3"; return true;
case ShaderInput::Matrix4: declaration = "mat4"; return true;
case ShaderInput::DataTexture2D: declaration = "sampler2D"; return true;
case ShaderInput::DataTextureShadow: declaration = "sampler2DShadow"; return true;
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileConstantShaderBlock(const ConstantShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "const");
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, block->constant_type, ShaderInput::Constant, ShaderInput::Uniform, scope))
parm->parm_v.Set(block->constant[0], block->constant[1], block->constant[2], block->constant[3]);
compiled_block->output = block->constant_type;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileColorShaderBlock(const ColorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "color");
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Constant, ShaderInput::Uniform, scope))
parm->parm_v = block->color;
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileClockShaderBlock(const ClockShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "clock");
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::Clock, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileViewVectorShaderBlock(const ViewVectorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "view_vector");
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector3, ShaderInput::ViewVector, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileViewportShaderBlock(const ViewportShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "viewport");
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Viewport, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileNormalViewMatrixShaderBlock(const NormalViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "normal_view_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalViewMatrix, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileNormalMatrixShaderBlock(const NormalMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "normal_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalMatrix, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileModelViewMatrixShaderBlock(const ModelViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "model_view_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelViewMatrix, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Matrix4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileModelMatrixShaderBlock(const ModelMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "model_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelMatrix, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Matrix4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileMaterialParamShaderBlock(const MaterialParamShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "mat_param");
switch (block->param)
{
case MaterialParamShaderBlock::MaterialDiffuse:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialDiffuse, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialSpecular:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSpecular, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialSelf:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSelf, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialAmbient:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialAmbient, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialGlossiness:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialGlossiness, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Float;
break;
case MaterialParamShaderBlock::MaterialOpacity:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialOpacity, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Float;
break;
case MaterialParamShaderBlock::MaterialReflection:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialReflection, ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::Float;
break;
}
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileMaterialTextureShaderBlock(const MaterialTextureShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "mat_tex");
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Semantic(ShaderInput::MaterialTexture0 + block->slot), ShaderInput::Uniform, scope);
compiled_block->output = ShaderInput::DataTexture2D;
return compiled_block;
}
//------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileGeometrySkinningShaderBlock(const GeometrySkinningShaderBlock *block, ShaderInput::Scope scope)
//----------------------------------------------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "skin_mtx");
shader->DeclareInput("bone_mtx", ShaderInput::Matrix4, ShaderInput::BoneMatrix, ShaderInput::Uniform, ShaderInput::Vertex, __PL_BONE_LIMIT__);
shader->DeclareInput("bone_idx", ShaderInput::Vector4, ShaderInput::BoneIndex, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareInput("bone_w", ShaderInput::Vector4, ShaderInput::BoneWeight, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying(compiled_block->variable, "mat4");
vertex_source += String::Format("%s = bone_mtx[int(bone_idx.x)] * bone_w.x + bone_mtx[int(bone_idx.y)] * bone_w.y + bone_mtx[int(bone_idx.z)] * bone_w.z + bone_mtx[int(bone_idx.w)] * bone_w.w;\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Matrix4;
return compiled_block;
}
//------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileGeometryTangentFrameShaderBlock(const GeometryTangentFrameShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
/*
Request the geometry normal.
Note: If an equivalent block already exists in the map it will be used
instead of the newly created one.
*/
ShaderBlock *normal_block = new GeometryNormalShaderBlock;
CShaderBlock *gl_normal_block = CompileShaderBlock(normal_block);
_safe_delete(normal_block);
// Compile the tangent frame generation code.
GetNewVariable(compiled_block->variable, "tangent_frame");
ShaderInput *a_tangent = shader->DeclareInput("a_tangent", ShaderInput::Vector3, ShaderInput::Tangent, ShaderInput::Attribute, ShaderInput::Vertex),
*a_bitangent = shader->DeclareInput("a_bitangent", ShaderInput::Vector3, ShaderInput::Bitangent, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying("_T", "vec3");
shader->DeclareVarying("_B", "vec3");
vertex_source += String::Format("_T = %s;\n _B = %s;\n", a_tangent->name.c_str(), a_bitangent->name.c_str());
pixel_source += String::Format("mat3 %s = _build_mat3(normalize(_T), normalize(_B), %s);\n", compiled_block->variable.c_str(), gl_normal_block->variable.c_str());
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileGeometryVertexShaderBlock(const GeometryVertexShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "vertex");
ShaderInput *pos_parm = shader->DeclareInput("a_position", ShaderInput::Vector3, ShaderInput::Position, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying(compiled_block->variable, "vec4");
vertex_source += String::Format("%s = vec4(%s, 1.0);\n", compiled_block->variable.c_str(), pos_parm->name.c_str());
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileGeometryNormalShaderBlock(const GeometryNormalShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
String varying;
GetNewVariable(varying, "varying_normal");
GetNewVariable(compiled_block->variable, "normal");
ShaderInput *nrm_parm = shader->DeclareInput("a_normal", ShaderInput::Vector3, ShaderInput::Normal, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying(varying, "vec3");
vertex_source += String::Format("%s = %s;\n", varying.c_str(), nrm_parm->name.c_str());
pixel_source += String::Format("vec3 %s = normalize(%s);\n", compiled_block->variable.c_str(), varying.c_str());
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileGeometryVertexColorShaderBlock(const GeometryVertexColorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "vertex_color");
ShaderInput *rgb_parm = shader->DeclareInput("a_rgb", ShaderInput::Vector4, ShaderInput::VertexColor, ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying(compiled_block->variable, "vec4");
vertex_source += String::Format("%s = %s;\n", compiled_block->variable.c_str(), rgb_parm->name.c_str());
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileGeometryUVShaderBlock(const GeometryUVShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "uv");
ShaderInput *uv_parm = shader->DeclareInput(String::Format("a_uv%d", block->channel), ShaderInput::Vector2, ShaderInput::Semantic(ShaderInput::UV0 + block->channel), ShaderInput::Attribute, ShaderInput::Vertex);
shader->DeclareVarying(compiled_block->variable, "vec2");
vertex_source += String::Format("%s = %s;\n", compiled_block->variable.c_str(), uv_parm->name.c_str());
compiled_block->output = ShaderInput::Vector2;
return compiled_block;
}
//------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileRenderBufferShaderBlock(const RenderBufferShaderBlock *block, ShaderInput::Scope scope)
//--------------------------------------------------------------------------------------------------------------------------------------------
{
/*
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "render_buffer");
fragment_declaration += String::Format("uniform sampler2D %s;\n", compiled_block->variable.c_str());
compiled_block->output = ShaderBlock::RenderPinTexture;
return compiled_block;
*/
return NULL;
}
//------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileTextureShaderBlock(const TextureShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "texture");
switch (block->texture_type)
{
default:
case TextureShaderBlock::Texture2D:
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTexture2D, ShaderInput::Texture2D, ShaderInput::Uniform, ShaderInput::Pixel))
parm->parm_t = block->texture;
compiled_block->output = ShaderInput::DataTexture2D;
break;
case TextureShaderBlock::Texture3D:
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTexture3D, ShaderInput::Texture3D, ShaderInput::Uniform, ShaderInput::Pixel))
parm->parm_t = block->texture;
compiled_block->output = ShaderInput::DataTexture3D;
break;
case TextureShaderBlock::TextureCube:
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTextureCube, ShaderInput::TextureCube, ShaderInput::Uniform, ShaderInput::Pixel))
parm->parm_t = block->texture;
compiled_block->output = ShaderInput::DataTextureCube;
break;
}
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileTextureSamplerShaderBlock(const TextureSamplerShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(texture_block, 0)
__MapCompilerCompileInput(uv_block, 1)
if (
!( ((texture_block->output == ShaderInput::DataTexture2D) && (uv_block->output == ShaderInput::Vector2)) ||
((texture_block->output == ShaderInput::DataTexture3D) && (uv_block->output == ShaderInput::Vector3)) ||
((texture_block->output == ShaderInput::DataTextureCube) && (uv_block->output == ShaderInput::Vector3)) )
)
__ERR__(__LOG_E__ << "Invalid input to the texture sampler block.\n", NULL)
GetNewVariable(compiled_block->variable, "texel");
switch (block->sampler_type)
{
default:
case TextureSamplerShaderBlock::Sampler2D:
pixel_source += String::Format("vec4 %s = texture2D(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
break;
case TextureSamplerShaderBlock::Sampler3D:
pixel_source += String::Format("vec4 %s = texture3D(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
break;
case TextureSamplerShaderBlock::SamplerCube:
pixel_source += String::Format("vec4 %s = textureCube(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
break;
}
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileMixShaderBlock(const MixOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
__MapCompilerCompileInput(mix_block, 2)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot mix blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot mix blocks, incorrect type (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "mix");
String type;
GetTypeDeclaration(left_block->output, type);
pixel_source += String::Format("%s %s = mix(%s, %s, %s);\n", type.c_str(), compiled_block->variable.c_str(), right_block->variable.c_str(), left_block->variable.c_str(), mix_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileAddShaderBlock(const AddOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot add blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot add blocks (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "add");
String type;
GetTypeDeclaration(left_block->output, type);
pixel_source += String::Format("%s %s = %s + %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileSubShaderBlock(const SubOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot subtract blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot subtract blocks (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "sub");
String type;
GetTypeDeclaration(left_block->output, type);
pixel_source += String::Format("%s %s = %s - %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileMulShaderBlock(const MulOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
// Check type compatibility.
ShaderInput::DataType left_type = left_block->output, right_type = right_block->output;
if (left_type > right_type)
{ ShaderInput::DataType tmp; tmp = left_type; left_type = right_type; right_type = tmp; }
if (
!(
(left_type == right_type) ||
((left_type == ShaderInput::Vector3) && (right_type == ShaderInput::Matrix3)) ||
((left_type == ShaderInput::Vector4) && (right_type == ShaderInput::Matrix4))
)
)
__ERR__(__LOG_E__ << "Cannot multiply blocks, output do not match.\n", NULL)
// Check type validity.
if (left_type == right_type)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot multiply textures.\n", NULL)
}
// Compile operator.
GetNewVariable(compiled_block->variable, "mul");
String type;
GetTypeDeclaration(left_type, type);
switch (right_type)
{
// n_mtx_mul
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
pixel_source += String::Format("%s %s = n_mtx_mul(%s, %s);\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
break;
default:
pixel_source += String::Format("%s %s = %s * %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
break;
}
compiled_block->output = left_type;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileDivShaderBlock(const DivOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot divide blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot divide blocks (" << left_block->output << ").\n", NULL)
}
GetNewVariable(compiled_block->variable, "div");
String type;
GetTypeDeclaration(left_block->output, type);
pixel_source += String::Format("%s %s = %s / %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileDotShaderBlock(const DotOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot compute dot operator, output do not match.\n", NULL)
GetNewVariable(compiled_block->variable, "dot");
pixel_source += String::Format("float %s = dot(%s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileCrossShaderBlock(const CrossOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if ((left_block->output != right_block->output) && (left_block->output != ShaderInput::Vector3))
__ERR__(__LOG_E__ << "Cannot only compute cross product on Vector3.\n", NULL)
GetNewVariable(compiled_block->variable, "cross");
pixel_source += String::Format("vec3 %s = cross(%s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileClampShaderBlock(const ClampShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
__MapCompilerCompileInput(min_block, 1)
__MapCompilerCompileInput(max_block, 2)
if ((min_block->output != max_block->output) && (value_block->output != min_block->output))
__ERR__(__LOG_E__ << ".\n", NULL)
GetNewVariable(compiled_block->variable, "clamp");
String type;
GetTypeDeclaration(value_block->output, type);
pixel_source += String::Format("%s %s = clamp(%s, %s, %s);\n", type.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), min_block->variable.c_str(), max_block->variable.c_str());
compiled_block->output = value_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileSwizzleShaderBlock(const SwizzleShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
// Set block output.
if ((compiled_block->output = (ShaderInput::DataType)block->GetOutputType()) == ShaderInput::NoData)
__ERR__(__LOG_E__ << "Invalid swizzle, no output.\n", NULL)
String output_type;
GetTypeDeclaration(compiled_block->output, output_type);
// Build fragment shader swizzle.
GetNewVariable(compiled_block->variable, "swizzle");
if (input_block->output == ShaderInput::Float)
pixel_source += String::Format("%s %s = %s(", output_type.c_str(), compiled_block->variable.c_str(), output_type.c_str());
else pixel_source += String::Format("%s %s = %s.", output_type.c_str(), compiled_block->variable.c_str(), input_block->variable.c_str());
switch (input_block->output)
{
case ShaderInput::Float:
for (int n = 0; (n < 4) && (block->swizzle[n] != SwizzleShaderBlock::SwizzleNone); ++n)
{
if (block->swizzle[n] != SwizzleShaderBlock::SwizzleX)
__ERR__(__LOG_E__ << "Impossible swizzle.\n", NULL)
pixel_source += ((n == 3) || (block->swizzle[n + 1] == SwizzleShaderBlock::SwizzleNone)) ?
String::Format("%s)", input_block->variable.c_str()) :
String::Format("%s,", input_block->variable.c_str());
}
break;
case ShaderInput::Vector2:
for (int n = 0; n < 4; ++n)
switch (block->swizzle[n])
{
case SwizzleShaderBlock::SwizzleX: pixel_source += "x"; break;
case SwizzleShaderBlock::SwizzleY: pixel_source += "y"; break;
case SwizzleShaderBlock::SwizzleNone: break;
default: __ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
}
break;
case ShaderInput::Vector3:
for (int n = 0; n < 4; ++n)
switch (block->swizzle[n])
{
case SwizzleShaderBlock::SwizzleX: pixel_source += "x"; break;
case SwizzleShaderBlock::SwizzleY: pixel_source += "y"; break;
case SwizzleShaderBlock::SwizzleZ: pixel_source += "z"; break;
case SwizzleShaderBlock::SwizzleNone: break;
default: __ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
}
break;
case ShaderInput::Vector4:
for (int n = 0; n < 4; ++n)
switch (block->swizzle[n])
{
case SwizzleShaderBlock::SwizzleX: pixel_source += "x"; break;
case SwizzleShaderBlock::SwizzleY: pixel_source += "y"; break;
case SwizzleShaderBlock::SwizzleZ: pixel_source += "z"; break;
case SwizzleShaderBlock::SwizzleW: pixel_source += "w"; break;
case SwizzleShaderBlock::SwizzleNone: break;
default: __ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
}
break;
}
pixel_source += ";\n";
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileBuildShaderBlock(const BuildShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
String component[4];
int count = 0;
for (int n = 0; n < 4; ++n)
{
switch (block->build[n])
{
case BuildShaderBlock::BuildZero:
component[count++] = "0.0";
break;
case BuildShaderBlock::BuildOne:
component[count++] = "1.0";
break;
case BuildShaderBlock::BuildX:
case BuildShaderBlock::BuildY:
case BuildShaderBlock::BuildZ:
case BuildShaderBlock::BuildW:
if (!block->input[n])
n = 4;
else
{
__MapCompilerCompileInput(input, n)
if (input->output == ShaderInput::Float)
component[count++] = input->variable.c_str();
else
switch (block->build[n])
{
case BuildShaderBlock::BuildX: component[count++] = String::Format("%s.x", input->variable.c_str()); break;
case BuildShaderBlock::BuildY: component[count++] = String::Format("%s.y", input->variable.c_str()); break;
case BuildShaderBlock::BuildZ: component[count++] = String::Format("%s.z", input->variable.c_str()); break;
case BuildShaderBlock::BuildW: component[count++] = String::Format("%s.w", input->variable.c_str()); break;
}
}
break;
}
}
if (!count)
compiled_block->output = ShaderInput::NoData;
else
{
GetNewVariable(compiled_block->variable, "built");
switch (count)
{
case 1:
pixel_source += String::Format("float %s = %s;\n", compiled_block->variable.c_str(), component[0].c_str());
compiled_block->output = ShaderInput::Float;
break;
case 2:
pixel_source += String::Format("vec2 %s = vec2(%s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str());
compiled_block->output = ShaderInput::Vector2;
break;
case 3:
pixel_source += String::Format("vec3 %s = vec3(%s, %s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str(), component[2].c_str());
compiled_block->output = ShaderInput::Vector3;
break;
case 4:
pixel_source += String::Format("vec4 %s = vec4(%s, %s, %s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str(), component[2].c_str(), component[3].c_str());
compiled_block->output = ShaderInput::Vector4;
break;
}
}
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompilePowShaderBlock(const PowShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
__MapCompilerCompileInput(power_block, 1)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
if (power_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible power type.\n", NULL)
GetNewVariable(compiled_block->variable, "pow");
pixel_source += String::Format("float %s = pow(%s, %s);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), power_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileAbsShaderBlock(const AbsShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
switch (value_block->output)
{
case ShaderInput::Float:
case ShaderInput::Vector2:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
break;
default:
__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
}
GetNewVariable(compiled_block->variable, "abs");
switch (value_block->output)
{
case ShaderInput::Float: pixel_source += String::Format("float %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector2: pixel_source += String::Format("vec2 %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector3: pixel_source += String::Format("vec3 %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector4: pixel_source += String::Format("vec4 %s = abs(%s.xyz, 1.0);\n", compiled_block->variable.c_str(), value_block->variable.c_str()); break;
}
compiled_block->output = value_block->output;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileCosinusShaderBlock(const CosinusShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)
GetNewVariable(compiled_block->variable, "cos");
pixel_source += String::Format("float %s = cos(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileSinusShaderBlock(const SinusShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)
GetNewVariable(compiled_block->variable, "sin");
pixel_source += String::Format("float %s = sin(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *ISLShaderTreeCompiler::CompileNormalizeBlock(const NormalizeOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "normalized");
String type;
GetTypeDeclaration(input_block->output, type);
pixel_source += String::Format("%s %s = normalize(%s);\n", type.c_str(), compiled_block->variable.c_str(), input_block->variable.c_str());
compiled_block->output = input_block->output;
return compiled_block;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileScreenUVShaderBlock(const ScreenUVShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "screen_uv");
pixel_source += String::Format("vec2 %s = gl_FragCoord.xy;\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Vector2;
return compiled_block;
}
//-------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompilePackVectorToColor(const PackVectorToColorShaderBlock *block, ShaderInput::Scope scope)
//-------------------------------------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "packed_vector");
switch (input_block->output)
{
case ShaderInput::Float:
pixel_source += String::Format("float %s = (%s + 1.0) * 0.5;\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
case ShaderInput::Vector3:
pixel_source += String::Format("vec3 %s = (%s + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
case ShaderInput::Vector4:
pixel_source += String::Format("vec4 %s = (%s + vec4(1.0, 1.0, 1.0, 0.0)) * vec3(0.5, 0.5, 0.5, 1.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
default:
__ERR__(__LOG_E__ << "Invalid input to pack to vector.\n", NULL)
}
compiled_block->output = input_block->output;
return compiled_block;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock *ISLShaderTreeCompiler::CompileUnpackColorToVector(const UnpackColorToVectorShaderBlock *block, ShaderInput::Scope scope)
//-----------------------------------------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "unpacked_vector");
switch (input_block->output)
{
case ShaderInput::Float:
pixel_source += String::Format("float %s = (%s - 0.5) * 2.0;\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
case ShaderInput::Vector3:
pixel_source += String::Format("vec3 %s = (%s - vec3(0.5, 0.5, 0.5)) * vec3(2.0, 2.0, 2.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
case ShaderInput::Vector4:
pixel_source += String::Format("vec4 %s = (%s - vec4(0.5, 0.5, 0.5, 0.0)) * vec4(2.0, 2.0, 2.0, 1.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
default:
__ERR__(__LOG_E__ << "Invalid input to unpack to vector.\n", NULL)
}
compiled_block->output = input_block->output;
return compiled_block;
}
//------------------------------------------------------------------------------
Shader *ISLShaderTreeCompiler::Finish()
{
__LOG__ << "Done compiling shader tree '" << id << "'.\n";
return shader;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,942 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree_compiler_tinyc.h"
#include "core/graphic_resource_factory.h"
#include "core/material.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
#define __MapCompilerGetNewCompiledBlock(__COMPILED_VAR__)\
CShaderBlock *__COMPILED_VAR__ = GetNewCompiledBlock(block);\
if (!__COMPILED_VAR__) return NULL;
#define __MapCompilerCompileInput(__COMPILED_VAR__, __INPUT_INDEX__)\
CShaderBlock *__COMPILED_VAR__ = CompileShaderBlock(block->GetInput(__INPUT_INDEX__));\
if (!__COMPILED_VAR__) return NULL;
//------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------
bool TinyCShaderTreeCompiler::GetTypeDeclaration(ShaderInput::DataType type, String &declaration)
//---------------------------------------------------------------------------------------------------------------------
{
switch (type)
{
case ShaderInput::Float: declaration = "struct nVector"; return true;
case ShaderInput::Vector2: declaration = "struct nVector"; return true;
case ShaderInput::Vector3: declaration = "struct nVector"; return true;
case ShaderInput::Vector4: declaration = "struct nVector"; return true;
case ShaderInput::Matrix3: declaration = "struct nMatrix3"; return true;
case ShaderInput::Matrix4: declaration = "struct nMatrix4"; return true;
case ShaderInput::DataTexture2D: declaration = "struct nTexture"; return true;
default:
break;
}
return false;
}
//------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileConstantShaderBlock(const ConstantShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "const");
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, block->constant_type, ShaderInput::Constant, ShaderInput::Uniform, ShaderInput::Pixel))
parm->parm_v.Set(block->constant[0], block->constant[1], block->constant[2], block->constant[3]);
compiled_block->output = block->constant_type;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileColorShaderBlock(const ColorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "color");
if (ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Constant, ShaderInput::Uniform, ShaderInput::Pixel))
parm->parm_v = block->color;
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileClockShaderBlock(const ClockShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "clock");
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::Clock, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileViewVectorShaderBlock(const ViewVectorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "view_vector");
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector3, ShaderInput::ViewVector, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileViewportShaderBlock(const ViewportShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "viewport");
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Viewport, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileNormalViewMatrixShaderBlock(const NormalViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "normal_view_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalViewMatrix, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileNormalMatrixShaderBlock(const NormalMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "normal_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalMatrix, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileModelViewMatrixShaderBlock(const ModelViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "model_view_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelViewMatrix, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Matrix4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileModelMatrixShaderBlock(const ModelMatrixShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "model_matrix");
shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelMatrix, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Matrix4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileMaterialParamShaderBlock(const MaterialParamShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "mat_param");
switch (block->param)
{
case MaterialParamShaderBlock::MaterialDiffuse:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialDiffuse, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialSpecular:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSpecular, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialSelf:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSelf, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialAmbient:
shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialAmbient, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Vector4;
break;
case MaterialParamShaderBlock::MaterialGlossiness:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialGlossiness, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Float;
break;
case MaterialParamShaderBlock::MaterialOpacity:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialOpacity, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Float;
break;
case MaterialParamShaderBlock::MaterialReflection:
shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialReflection, ShaderInput::Uniform, ShaderInput::Pixel);
compiled_block->output = ShaderInput::Float;
break;
}
return compiled_block;
}
//------------------------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileMaterialTextureShaderBlock(const MaterialTextureShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "texture");
pixel_declaration += String::Format("struct nTexture %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("%s.TexPnt = (void *)texture_slot_%d;\n", compiled_block->variable.c_str(), block->slot);
compiled_block->output = ShaderInput::DataTexture2D;
return compiled_block;
}
//------------------------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometrySkinningShaderBlock(const GeometrySkinningShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------------
{
//__MapCompilerGetNewCompiledBlock(compiled_block)
// GetNewVariable(compiled_block->variable, "skin_mtx");
//shader->DeclareInput("bone_mtx", ShaderBlock::RenderShaderInput::Matrix4, ShaderInput::BoneMatrix, ShaderInput::Uniform, ShaderInput::Vertex);
//shader->DeclareInput("bone_idx", ShaderBlock::RenderShaderInput::Vector4, ShaderInput::BoneIndex, ShaderInput::Attribute, ShaderInput::Vertex);
//shader->DeclareInput("bone_w", ShaderBlock::RenderShaderInput::Vector4, ShaderInput::BoneWeight, ShaderInput::Attribute, ShaderInput::Vertex);
//vertex_declaration += String::Format("varying mat4 %s;\n", compiled_block->variable.c_str());
//vertex_shader += String::Format("%s = (bone_mtx[int(bone_id.x)] * bone_w.x + bone_mtx[int(bone_id.y)] * bone_w.y + bone_mtx[int(bone_id.z)] * bone_w.z + bone_mtx[int(bone_id.w)] * bone_w.w) / (bone_w.x + bone_w.y + bone_w.z + bone_w.w);\n", compiled_block->variable.c_str());
//fragment_declaration += String::Format("varying mat4 %s;\n", compiled_block->variable.c_str());
//compiled_block->output = ShaderBlock::RenderShaderInput::Matrix4;
//return compiled_block;
return NULL;
}
//------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometryTangentFrameShaderBlock(const GeometryTangentFrameShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "tangentframe");
pixel_declaration += String::Format("struct nMatrix3 %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("TinyCGeometryTangentFrame(&%s, trace);\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Matrix3;
return compiled_block;
}
//------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometryVertexShaderBlock(const GeometryVertexShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "vertex");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("TinyCGeometryVertex(&%s, trace);\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometryNormalShaderBlock(const GeometryNormalShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "normal");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("TinyCGeometryNormal(&%s, trace);\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometryVertexColorShaderBlock(const GeometryVertexColorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "vertex_color");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("TinyCGeometryVertexColor(&%s, trace);\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileGeometryUVShaderBlock(const GeometryUVShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "uv");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("TinyCGeometryUV(&%s, trace, %d);\n", compiled_block->variable.c_str(), block->channel);
compiled_block->output = ShaderInput::Vector2;
return compiled_block;
}
//------------------------------------------------------------------------------
/*
vec3 vector_offset = (%s.xyz - vec3(0.5, 0.5, 0.0)) * vec3(2.0, 2.0, 1.0);\n\
{
// Object space normal map.
pixel_program += "vec3 normal = gl_NormalMatrix * normalize(texture2D(normal_texture, normal_uv).xzy - vec3(0.5, 0.5, 0.5));\n";
}
*/
//----------------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileRenderBufferShaderBlock(const RenderBufferShaderBlock *block, ShaderInput::Scope scope)
//----------------------------------------------------------------------------------------------------------------
{
/*
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "render_buffer");
fragment_declaration += String::Format("uniform sampler2D %s;\n", compiled_block->variable.c_str());
compiled_block->output = ShaderBlock::RenderPinTexture;
return compiled_block;
*/
return NULL;
}
//------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileTextureShaderBlock(const TextureShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "texture");
pixel_declaration += String::Format("struct nTexture %s;\n", compiled_block->variable.c_str());
if(((TextureShaderBlock *)block)->texture)
// fragment_shader += String::Format("%s.TexName = \"%s\";\n", compiled_block->variable.c_str(), ((nTextureShaderBlock *)block)->texture->name.CleanFilePath());
pixel_source += String::Format("%s.TexPnt = (void *)%d;\n", compiled_block->variable.c_str(), graphic_factory.LoadPicture(((TextureShaderBlock *)block)->texture.CleanFilePath()));
else
pixel_source += String::Format("%s.TexPnt = 0;\n", compiled_block->variable.c_str());
compiled_block->output = ShaderInput::DataTexture2D;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileTextureSamplerShaderBlock(const TextureSamplerShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(texture_block, 0)
__MapCompilerCompileInput(uv_block, 1)
if (
(texture_block->output != ShaderInput::DataTexture2D) ||
(uv_block->output != ShaderInput::Vector2)
)
__ERR__(__LOG_E__ << "Invalid input to the sampler2D block.\n", NULL)
GetNewVariable(compiled_block->variable, "texel");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format(" nTexture_LowLevelSampling(&%s, &%s, %s.TexPnt, %d, %d);\n", compiled_block->variable.c_str(), uv_block->variable.c_str(), texture_block->variable.c_str(), /* block->wrap[0]?1:0 */ 0, /* block->wrap[1]?1:0 */ 0);
compiled_block->output = ShaderInput::Vector4;
return compiled_block;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileMixShaderBlock(const MixOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
__MapCompilerCompileInput(mix_block, 2)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot mix blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot mix blocks, incorrect type (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "mix");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnMix(%s, %s, %s, %s.x);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str(), mix_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileAddShaderBlock(const AddOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot add blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot add blocks (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "add");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorAddVector(%s , %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileSubShaderBlock(const SubOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot subtract blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot subtract blocks (" << left_block->output << ").\n", NULL)
default:
break;
}
GetNewVariable(compiled_block->variable, "sub");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorMinusnVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileMulShaderBlock(const MulOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
// Check type compatibility.
ShaderInput::DataType
left_type = left_block->output,
right_type = right_block->output;
if (left_type > right_type)
{ ShaderInput::DataType tmp; tmp = left_type; left_type = right_type; right_type = tmp;
CShaderBlock* tmp_block; tmp_block = left_block; left_block = right_block; right_block = tmp_block;
}
if (
!(
(left_type == right_type) ||
((left_type == ShaderInput::Vector3) && (right_type == ShaderInput::Matrix3)) ||
((left_type == ShaderInput::Vector4) && (right_type == ShaderInput::Matrix4))
)
)
__ERR__(__LOG_E__ << "Cannot multiply blocks, output do not match.\n", NULL)
// Check type validity.
if (left_type == right_type)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot multiply textures.\n", NULL)
}
// Compile operator.
GetNewVariable(compiled_block->variable, "mul");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
if (left_type == right_type)
{
switch (left_type)
{
case ShaderInput::Float:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
pixel_source += String::Format("nReturnVectorMultiplyVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
break;
case ShaderInput::Matrix3:
pixel_source += String::Format("nReturnnMatrix3MultiplynMatrix3(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
break;
case ShaderInput::Matrix4:
pixel_source += String::Format("nReturnnMatrix4MultiplynMatrix4(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
break;
default:
pixel_source += String::Format("nReturnVector(%s,1, 1, 1);\n", compiled_block->variable.c_str());
}
}
else
{
if (left_type == ShaderInput::Float ||
left_type == ShaderInput::Vector3 ||
left_type == ShaderInput::Vector4)
{
if (right_type == ShaderInput::Matrix3)
pixel_source += String::Format("nReturnnVectorMultiplynMatrix3(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
else if (right_type == ShaderInput::Matrix4)
pixel_source += String::Format("nReturnnVectorMultiplynMatrix4(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
else
if (right_type == ShaderInput::Vector3 ||
left_type == ShaderInput::Vector4)
pixel_source += String::Format("nReturnVectorMultiplyFloat(&%s, &%s, &%s.x);\n", compiled_block->variable.c_str(), right_block->variable.c_str(), left_block->variable.c_str());
else
pixel_source += String::Format("nReturnVector(%s, 1, 1, 1);\n", compiled_block->variable.c_str());
}
else
pixel_source += String::Format("nReturnVector(%s, 1, 1, 1);\n", compiled_block->variable.c_str());
}
compiled_block->output = left_type;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileDivShaderBlock(const DivOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot divide blocks, output do not match.\n", NULL)
switch (left_block->output)
{
case ShaderInput::NoData:
__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
case ShaderInput::Matrix3:
case ShaderInput::Matrix4:
case ShaderInput::DataTexture2D:
__ERR__(__LOG_E__ << "Cannot divide blocks (" << left_block->output << ").\n", NULL)
}
GetNewVariable(compiled_block->variable, "div");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorDivnVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = left_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileDotShaderBlock(const DotOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if (left_block->output != right_block->output)
__ERR__(__LOG_E__ << "Cannot compute dot operator, output do not match.\n", NULL)
GetNewVariable(compiled_block->variable, "dot");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorDotnVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileCrossShaderBlock(const CrossOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(left_block, 0)
__MapCompilerCompileInput(right_block, 1)
if ((left_block->output != right_block->output) && (left_block->output != ShaderInput::Vector3))
__ERR__(__LOG_E__ << "Cannot only compute cross product on Vector3.\n", NULL)
GetNewVariable(compiled_block->variable, "cross");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorCrossnVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
compiled_block->output = ShaderInput::Vector3;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileClampShaderBlock(const ClampShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
__MapCompilerCompileInput(min_block, 1)
__MapCompilerCompileInput(max_block, 2)
if ((min_block->output != max_block->output) && (value_block->output != min_block->output))
__ERR__(__LOG_E__ << ".\n", NULL)
GetNewVariable(compiled_block->variable, "clamp");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorClampMinMax(%s, %s, %s, %s);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), min_block->variable.c_str(), max_block->variable.c_str());
compiled_block->output = value_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileSwizzleShaderBlock(const SwizzleShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
// Set block output.
if ((compiled_block->output = (ShaderInput::DataType)block->GetOutputType()) == ShaderInput::NoData)
__ERR__(__LOG_E__ << "Invalid swizzle, no output.\n", NULL)
String output_type;
GetTypeDeclaration(compiled_block->output, output_type);
// Build fragment shader swizzle.
GetNewVariable(compiled_block->variable, "swizzle");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format(" nReturnVector4(%s, ", compiled_block->variable.c_str());
for (int n = 0; n < 4; ++n)
{
if (block->swizzle[n] != SwizzleShaderBlock::SwizzleNone)
switch(block->swizzle[n] - SwizzleShaderBlock::SwizzleX)
{
case 0: //SwizzleX
pixel_source += String::Format("%s.x", input_block->variable.c_str());
break;
case 1: //SwizzleY
pixel_source += String::Format("%s.y", input_block->variable.c_str());
break;
case 2: //SwizzleZ
pixel_source += String::Format("%s.z", input_block->variable.c_str());
break;
case 3: //SwizzleW
pixel_source += String::Format("%s.w", input_block->variable.c_str());
break;
default: //SwizzleNone
pixel_source += String::Format("0");
}
else //SwizzleNone
pixel_source += String::Format("0");
// check to put the , or the )
if(n<3)
pixel_source += String::Format(",");
else
pixel_source += String::Format(");");
}
pixel_source += "\n";
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileBuildShaderBlock(const BuildShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
String component[4];
int count = 0;
for (int n = 0; n < 4; ++n)
{
switch (block->build[n])
{
case BuildShaderBlock::BuildZero:
component[count++] = "0.0";
break;
case BuildShaderBlock::BuildOne:
component[count++] = "1.0";
break;
case BuildShaderBlock::BuildX:
case BuildShaderBlock::BuildY:
case BuildShaderBlock::BuildZ:
case BuildShaderBlock::BuildW:
if (!block->input[n])
n = 4;
else
{
__MapCompilerCompileInput(input, n)
if (input->output == ShaderInput::Float)
component[count++] = String::Format("%s.x", input->variable.c_str());
else
switch (block->build[n])
{
case BuildShaderBlock::BuildX: component[count++] = String::Format("%s.x", input->variable.c_str()); break;
case BuildShaderBlock::BuildY: component[count++] = String::Format("%s.y", input->variable.c_str()); break;
case BuildShaderBlock::BuildZ: component[count++] = String::Format("%s.z", input->variable.c_str()); break;
case BuildShaderBlock::BuildW: component[count++] = String::Format("%s.w", input->variable.c_str()); break;
}
}
break;
}
}
if (!count)
compiled_block->output = ShaderInput::NoData;
else
{
GetNewVariable(compiled_block->variable, "built");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVector4(%s, ", compiled_block->variable.c_str());
switch (count)
{
case 1:
pixel_source += String::Format("%s, 0, 0, 1);\n", component[0].c_str());
compiled_block->output = ShaderInput::Float;
break;
case 2:
pixel_source += String::Format("%s, %s, 0, 1);\n", component[0].c_str(), component[1].c_str());
compiled_block->output = ShaderInput::Vector2;
break;
case 3:
pixel_source += String::Format("%s, %s, %s, 1);\n", component[0].c_str(), component[1].c_str(), component[2].c_str());
compiled_block->output = ShaderInput::Vector3;
break;
case 4:
pixel_source += String::Format("%s, %s, %s, %s);\n", component[0].c_str(), component[1].c_str(), component[2].c_str(), component[3].c_str());
compiled_block->output = ShaderInput::Vector4;
break;
}
}
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompilePowShaderBlock(const PowShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
__MapCompilerCompileInput(power_block, 1)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
if (power_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible power type.\n", NULL)
GetNewVariable(compiled_block->variable, "pow");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnPow(&%s.x, &%s.x, &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), power_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileAbsShaderBlock(const AbsShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
switch (value_block->output)
{
case ShaderInput::Float:
case ShaderInput::Vector2:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
break;
default:
__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
}
GetNewVariable(compiled_block->variable, "abs");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
switch (value_block->output)
{
case ShaderInput::Float: pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector2: pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector3: pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);nReturnFabs(&%s.z, &%s.z);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str()); break;
case ShaderInput::Vector4: pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);nReturnFabs(&%s.z, &%s.z);nReturnFabs(&%s.w, &%s.w);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str()); break;
}
compiled_block->output = value_block->output;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileCosinusShaderBlock(const CosinusShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)
GetNewVariable(compiled_block->variable, "cos");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnCosinus(&%s.x, &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileSinusShaderBlock(const SinusShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(value_block, 0)
if (value_block->output != ShaderInput::Float)
__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)
GetNewVariable(compiled_block->variable, "sin");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnSinus(&%s.x, &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
compiled_block->output = ShaderInput::Float;
return compiled_block;
}
CShaderBlock *TinyCShaderTreeCompiler::CompileNormalizeBlock(const NormalizeOperatorShaderBlock *block, ShaderInput::Scope scope)
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "normalized");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
pixel_source += String::Format("nReturnVectorNormalize(&%s, &%s);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
compiled_block->output = input_block->output;
return compiled_block;
}
//------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileScreenUVShaderBlock(const ScreenUVShaderBlock *block, ShaderInput::Scope scope)
//-------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
GetNewVariable(compiled_block->variable, "screen_uv");
pixel_declaration += String::Format("struct nVector %s; nReturnVector4(%s, 0.5f,, 0.5f, 0.5f, 1.0f);\n", compiled_block->variable.c_str(), compiled_block->variable.c_str());
compiled_block->output = ShaderInput::Vector2;
return compiled_block;
}
//--------------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompilePackVectorToColor(const PackVectorToColorShaderBlock *block, ShaderInput::Scope scope)
//--------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "packed_vector");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
switch (input_block->output)
{
case ShaderInput::Float:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
pixel_source += String::Format("TinyCPackVectorToColor(&%s, &%s);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
default:
__ERR__(__LOG_E__ << "Invalid input to pack to vector.\n", NULL)
}
compiled_block->output = input_block->output;
return compiled_block;
}
//------------------------------------------------------------------------------------------------------------------
CShaderBlock *TinyCShaderTreeCompiler::CompileUnpackColorToVector(const UnpackColorToVectorShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------
{
__MapCompilerGetNewCompiledBlock(compiled_block)
__MapCompilerCompileInput(input_block, 0)
GetNewVariable(compiled_block->variable, "unpacked_vector");
pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
switch (input_block->output)
{
case ShaderInput::Float:
case ShaderInput::Vector3:
case ShaderInput::Vector4:
pixel_source += String::Format("TinyCUnpackColorToVector(&%s, &%s);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
break;
default:
__ERR__(__LOG_E__ << "Invalid input to unpack to vector.\n", NULL)
}
compiled_block->output = input_block->output;
return compiled_block;
}
//----------------------------------------------------------------------------
void TinyCShaderTreeCompiler::SetShaderInputs( const Material &m)
{
// declaration of the input
ListForeachPtr(ShaderInput *, input, shader->input_list)
{
String type_declaration;
if (GetTypeDeclaration(input->data_type, type_declaration))
{
switch (input->type)
{
case ShaderInput::Attribute:
if (input->scope & ShaderInput::Vertex)
vertex_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
if (input->scope & ShaderInput::Pixel)
pixel_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
break;
case ShaderInput::Uniform:
if (input->scope & ShaderInput::Vertex)
vertex_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
if (input->scope & ShaderInput::Pixel)
pixel_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
break;
}
}
else
__LOG_E__ << "Unsupported input '" << input->name << "' type (" << input->type << ").\n";
}
// fill the base input
ListForeachPtr(ShaderInput *, input, shader->input_list)
{
switch (input->semantic)
{
case ShaderInput::NormalMatrix:
pixel_declaration += String::Format("TinyCNormalMatrix(&%s, trace);\n", input->name.c_str());
break;
case ShaderInput::NormalViewMatrix:
pixel_declaration += String::Format("TinyCNormalViewMatrix(&%s, trace);\n", input->name.c_str());
break;
case ShaderInput::ModelMatrix:
pixel_declaration += String::Format("TinyCModelMatrix(&%s, trace);\n", input->name.c_str());
break;
case ShaderInput::ModelViewMatrix:
pixel_declaration += String::Format("TinyCModelViewMatrix(&%s, trace);\n", input->name.c_str());
break;
case ShaderInput::ViewVector:
pixel_declaration += String::Format("TinyCViewVector(&%s, trace);\n", input->name.c_str());
break;
case ShaderInput::Clock:
pixel_declaration += String::Format("nReturnVector(%s, 0.0f, 0.0f, 0.0f);\n", input->name.c_str());
break;
/* case ShaderInput::ModelViewProjectionMatrix:
fragment_shader += String::Format("TinyCModelViewMatrix(&%s, trace);\n", input->name.c_str());
break;*/
case ShaderInput::Constant: pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), input->parm_v.x, input->parm_v.y, input->parm_v.z, input->parm_v.w); break;
case ShaderInput::MaterialDiffuse: pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.diffuse.x, m.diffuse.y, m.diffuse.z, m.diffuse.w); break;
case ShaderInput::MaterialSpecular: pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.specular.x, m.specular.y, m.specular.z, m.specular.w); break;
case ShaderInput::MaterialAmbient: pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(),m.ambient.x, m.ambient.y, m.ambient.z, m.ambient.w); break;
case ShaderInput::MaterialSelf: pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.self.x, m.self.y, m.self.z, m.self.w); break;
case ShaderInput::MaterialOpacity: pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), m.opacity); break;
case ShaderInput::MaterialGlossiness: pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), m.glossiness); break;
case ShaderInput::MaterialReflection: pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), 0.2f/*m.reflection*/); break;
}
}
}
//----------------------------------------------------------------------------
Shader *TinyCShaderTreeCompiler::Finish()
{
// Finish shader programs.
shader->pixel.Clear();
if (!pixel_declaration.IsEmpty())
shader->pixel += pixel_declaration;
if (!pixel_source.IsEmpty())
shader->pixel += String::Format("%s \n}\n", pixel_source.c_str());
else shader->pixel += "struct nVector TempValue;\n nReturnVector(TempValue, 1, 1, 1);\n return TempValue;\n }\n";
return shader;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,51 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree_convert_static_texture_block_to_dynamic.h"
#include "core/shader_block.h"
#include "core/shader_tree.h"
#include "core/material.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
static void RecurseAndConvertInputs(ShaderBlock *block, const Material &m)
{
for (uint n = 0; n < block->GetInputCount(); ++n)
if (ShaderBlock *input = block->GetInput(n))
{
if (input->type == ShaderBlock::TypeTexture)
{
// Seek a channel in the material using this texture.
TextureShaderBlock *t = (TextureShaderBlock *)input;
for (uint i = 0; i < Material::max_texture_stage; ++i)
if (m.texstage[n].t == t->texture)
{
// Got a match, replace static texture by a material texture reference to this slot.
if (MaterialTextureShaderBlock *new_block = new MaterialTextureShaderBlock(i))
{
new_block->pos = input->pos;
block->SetInput(n, new_block);
_safe_delete(input);
break;
}
}
// Texture block has no input, end here.
}
else
RecurseAndConvertInputs(input, m);
}
}
void GS::Core::ConvertStaticToDynamicTextureBlocks(ShaderTree &tree, const Material &m)
{
for (uint n = 0; n < ShaderTree::SinkInvalid; ++n)
if (tree.sink[n] != NULL)
RecurseAndConvertInputs(tree.sink[n], m);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,584 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree.h"
#include "core/shader_block.h"
#include "math/vector_nml.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
using NML::Tag;
/// Id of the NOOP shader block.
static String __ShaderBlockNoneTagId("None");
//------------------------------------------------------------------------------
Array <pShaderBlock> *ShaderBlock::BlockMapFromMetaTag(Tag &tag)
{
if (tag.name != "Map")
return NULL;
// Allocate block map.
Array <pShaderBlock> *block_map = new Array <pShaderBlock> (tag.GetChildCount());
if (!block_map)
__ERR__(__LOG_E__ << "Failed to allocate shader block map.\n", NULL)
for (uint n = 0; n < block_map->GetCount(); ++n)
(*block_map)[n] = NULL;
// Fill the block map.
uint block_count = 0;
NMLTagForeach(entry_tag, tag)
if (entry_tag->name == "Entry")
{
ShaderBlock *_block = NULL;
Tag *type_tag = entry_tag->GetTag("Type"),
*parm_tag = entry_tag->GetTag("Param");
//----------------------------------------------------
#define __InstanciateNewShaderBlock(__VAR__, __TYPE__)\
__TYPE__ *__VAR__ = new __TYPE__;\
_block = __VAR__;
#define __ValidateShaderBlockParam\
if (!parm_tag)\
break;
//----------------------------------------------------
if (type_tag)
{
int type;
String type_string(type_tag->GetString());
// Legacy block type support.
if ((type_string == "Sampler 2D") || (type_string == "Sampler Cube"))
type_string = "Texture Sampler";
if (type_string == "Normal Matrix")
type_string = "Normal View Matrix";
// Locate block.
for (type = ShaderBlock::TypeNone; type < ShaderBlock::TypeInvalid; ++type)
if (type_string == ShaderBlock::BlockTypeToString((BlockType)type))
break;
switch (type)
{
case TypeGeometryUV:
{
__InstanciateNewShaderBlock(block, GeometryUVShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Channel;", Variant::VariantInteger))
block->channel = tag->GetInteger();
}
break;
case TypeTextureSampler:
{
__InstanciateNewShaderBlock(block, TextureSamplerShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String sampler_type(tag->GetString());
if (sampler_type == "3D") block->sampler_type = TextureSamplerShaderBlock::Sampler3D;
else if (sampler_type == "Cube") block->sampler_type = TextureSamplerShaderBlock::SamplerCube;
else block->sampler_type = TextureSamplerShaderBlock::Sampler2D;
}
}
break;
case TypeRenderBuffer:
{
__InstanciateNewShaderBlock(block, RenderBufferShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Buffer;", Variant::VariantInteger))
block->buffer = (RenderBufferShaderBlock::RenderBuffer)tag->GetInteger();
}
break;
case TypeTexture:
{
__InstanciateNewShaderBlock(block, TextureShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Texture;", Variant::VariantString))
block->texture = tag->GetString();
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String texture_type(tag->GetString());
if (texture_type == "3D") block->texture_type = TextureShaderBlock::Texture3D;
else if (texture_type == "Cube") block->texture_type = TextureShaderBlock::TextureCube;
else block->texture_type = TextureShaderBlock::Texture2D;
}
}
break;
case TypeConstant:
{
__InstanciateNewShaderBlock(block, ConstantShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantInteger))
block->constant_type = (ShaderInput::DataType)tag->GetInteger();
Vector4 v(0, 0, 0);
if (Tag *tag = parm_tag->GetTag("Value;"))
v.FromMetaTag(*tag);
block->constant[0] = v.x;
block->constant[1] = v.y;
block->constant[2] = v.z;
block->constant[3] = v.w;
}
break;
case TypeColor:
{
__InstanciateNewShaderBlock(block, ColorShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTag("Color;"))
block->color.FromMetaTag(*tag);
}
break;
case TypeMaterialParam:
{
__InstanciateNewShaderBlock(block, MaterialParamShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Param;", Variant::VariantInteger))
block->param = (MaterialParamShaderBlock::MaterialParam)tag->GetInteger();
}
break;
case TypeMaterialTexture:
{
__InstanciateNewShaderBlock(block, MaterialTextureShaderBlock)
__ValidateShaderBlockParam
if (Tag *tag = parm_tag->GetTypedTag("Slot;", Variant::VariantInteger))
block->slot = tag->GetInteger();
if (Tag *tag = parm_tag->GetTypedTag("Type;", Variant::VariantString))
{
String texture_type(tag->GetString());
if (texture_type == "3D") block->texture_type = MaterialTextureShaderBlock::Texture3D;
else if (texture_type == "Cube") block->texture_type = MaterialTextureShaderBlock::TextureCube;
else block->texture_type = MaterialTextureShaderBlock::Texture2D;
}
}
break;
case TypeSwizzle:
{
__InstanciateNewShaderBlock(block, SwizzleShaderBlock)
__ValidateShaderBlockParam
const char *swizzle = "nnnn";
if (Tag *tag = parm_tag->GetTag("Swizzle;"))
swizzle = tag->GetString();
for (int n = 0; n < 4; ++n)
if (swizzle[n] == 'n') block->swizzle[n] = SwizzleShaderBlock::SwizzleNone;
else if (swizzle[n] == 'x') block->swizzle[n] = SwizzleShaderBlock::SwizzleX;
else if (swizzle[n] == 'y') block->swizzle[n] = SwizzleShaderBlock::SwizzleY;
else if (swizzle[n] == 'z') block->swizzle[n] = SwizzleShaderBlock::SwizzleZ;
else if (swizzle[n] == 'w') block->swizzle[n] = SwizzleShaderBlock::SwizzleW;
else
{
__LOG_E__ << "Unexpected end of swizzle mask.\n";
break;
}
}
break;
case TypeBuild:
{
__InstanciateNewShaderBlock(block, BuildShaderBlock)
__ValidateShaderBlockParam
const char *build = "0000";
if (Tag *tag = parm_tag->GetTag("Build;"))
build = tag->GetString();
for (int n = 0; n < 4; ++n)
if (build[n] == '0') block->build[n] = BuildShaderBlock::BuildZero;
else if (build[n] == '1') block->build[n] = BuildShaderBlock::BuildOne;
else if (build[n] == 'x') block->build[n] = BuildShaderBlock::BuildX;
else if (build[n] == 'y') block->build[n] = BuildShaderBlock::BuildY;
else if (build[n] == 'z') block->build[n] = BuildShaderBlock::BuildZ;
else if (build[n] == 'w') block->build[n] = BuildShaderBlock::BuildW;
else
{
__LOG_E__ << "Unexpected end of build mask.\n";
break;
}
}
break;
case TypeGeometryVertex: _block = new GeometryVertexShaderBlock; break;
case TypeGeometrySkinning: _block = new GeometrySkinningShaderBlock; break;
case TypeGeometryNormal: _block = new GeometryNormalShaderBlock; break;
case TypeGeometryVertexColor: _block = new GeometryVertexColorShaderBlock; break;
case TypeGeometryTangentFrame: _block = new GeometryTangentFrameShaderBlock; break;
case TypeScreenUV: _block = new ScreenUVShaderBlock; break;
case TypeViewVector: _block = new ViewVectorShaderBlock; break;
case TypeViewport: _block = new ViewportShaderBlock; break;
case TypeNormalViewMatrix: _block = new NormalViewMatrixShaderBlock; break;
case TypeNormalMatrix: _block = new NormalMatrixShaderBlock; break;
case TypeModelViewMatrix: _block = new ModelViewMatrixShaderBlock; break;
case TypeModelMatrix: _block = new ModelMatrixShaderBlock; break;
case TypeMix: _block = new MixOperatorShaderBlock; break;
case TypeAdd: _block = new AddOperatorShaderBlock; break;
case TypeMul: _block = new MulOperatorShaderBlock; break;
case TypeSub: _block = new SubOperatorShaderBlock; break;
case TypeDiv: _block = new DivOperatorShaderBlock; break;
case TypeDot: _block = new DotOperatorShaderBlock; break;
case TypeCross: _block = new CrossOperatorShaderBlock; break;
case TypeClamp: _block = new ClampShaderBlock; break;
case TypeNormalize: _block = new NormalizeOperatorShaderBlock; break;
case TypeSin: _block = new SinusShaderBlock; break;
case TypeCos: _block = new CosinusShaderBlock; break;
case TypePow: _block = new PowShaderBlock; break;
case TypeAbs: _block = new AbsShaderBlock; break;
case TypeClock: _block = new ClockShaderBlock; break;
case TypeUnpackColorToVector: _block = new UnpackColorToVectorShaderBlock; break;
case TypePackVectorToColor: _block = new PackVectorToColorShaderBlock; break;
default:
__LOG_E__ << "Invalid block type '" << type_string << "'.\n";
break;
}
}
if (_block)
if (Tag *pos_tag = entry_tag->GetTag("Pos"))
tVectorFromMetaTag(_block->pos, *pos_tag);
// Add block to the map.
if (block_map->GetCount() > block_count)
(*block_map)[block_count++] = _block;
else
__LOG_E__ << "Block map full, unexpected error.\n";
}
else __LOG_W__ << "Unexpected tag '" << entry_tag->name << "' in shader map.\n";
return block_map;
}
ShaderBlock *ShaderBlock::BranchFromMetaTag(Tag &tag, Array <pShaderBlock> *block_map)
{
// Load block.
Tag *index_tag = tag.GetTypedTag("Index;", Variant::VariantInteger);
if (!index_tag)
__ERR__(__LOG_E__ << "No block index found.\n", NULL)
// Load map if none provided.
bool drop_map = false;
if (!block_map)
{
Tag *map_tag = tag.GetTag("Map;");
if (!map_tag)
__ERR__(__LOG_E__ << "No map to build shader branch.\n", NULL)
if ((block_map = BlockMapFromMetaTag(*map_tag)) == NULL)
return NULL;
drop_map = true;
}
// Link block to its inputs.
ShaderBlock *block = (*block_map)[index_tag->GetUnsigned()];
if (block && block->GetInputCount())
if (Tag *inputs_tag = tag.GetTag("Input;"))
{
int input_count = 0;
NMLTagForeach(input_tag, *inputs_tag)
if (input_tag && (input_tag->name != __ShaderBlockNoneTagId))
block->SetInput(input_count++, ShaderBlock::BranchFromMetaTag(*input_tag, block_map));
}
if (drop_map)
_safe_delete(block_map);
return block;
}
bool ShaderTree::FromMetaTag(Tag &tag)
{
if (tag.name != "ShaderMap")
return false;
// Load import map.
Tag *map_tag = tag.GetTag("Map;");
Array <pShaderBlock> *block_map = map_tag ? ShaderBlock::BlockMapFromMetaTag(*map_tag) : NULL;
// Sink block position.
if (Tag *pos_tag = tag.GetTag("Pos"))
tVectorFromMetaTag(pos, *pos_tag);
// Read in sinks.
Tag *sink_tag;
if ((sink_tag = tag.GetTag("Vertex:Block;")) != NULL)
sink[SinkVertex] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Normal:Block;")) != NULL)
sink[SinkNormal] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Diffuse:Block;")) != NULL)
sink[SinkDiffuse] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Modulate:Block;")) != NULL)
sink[SinkModulate] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Specular:Block;")) != NULL)
sink[SinkSpecular] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Glossiness:Block;")) != NULL)
sink[SinkGlossiness] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Constant:Block;")) != NULL)
sink[SinkConstant] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Opacity:Block;")) != NULL)
sink[SinkOpacity] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
if ((sink_tag = tag.GetTag("Reflection:Block;")) != NULL)
sink[SinkReflection] = ShaderBlock::BranchFromMetaTag(*sink_tag, block_map);
_safe_delete(block_map);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *ShaderBlock::ParamAsMetaTag() const
{
Tag *parm = new Tag("Param");
switch (type)
{
case TypeGeometryUV:
{
GeometryUVShaderBlock *block = (GeometryUVShaderBlock *)this;
parm->AddChild("Channel", block->channel);
}
break;
case TypeTextureSampler:
{
TextureSamplerShaderBlock *block = (TextureSamplerShaderBlock *)this;
switch (block->sampler_type)
{
default:
case TextureSamplerShaderBlock::Sampler2D: parm->AddChild("Type", "2D"); break;
case TextureSamplerShaderBlock::Sampler3D: parm->AddChild("Type", "3D"); break;
case TextureSamplerShaderBlock::SamplerCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeRenderBuffer:
{
RenderBufferShaderBlock *block = (RenderBufferShaderBlock *)this;
parm->AddChild("Buffer", (int)block->buffer);
}
break;
case TypeTexture:
{
TextureShaderBlock *block = (TextureShaderBlock *)this;
if (!block->texture.IsEmpty())
parm->AddChild("Texture", block->texture.c_str());
switch (block->texture_type)
{
default:
case TextureShaderBlock::Texture2D: parm->AddChild("Type", "2D"); break;
case TextureShaderBlock::Texture3D: parm->AddChild("Type", "3D"); break;
case TextureShaderBlock::TextureCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeConstant:
{
ConstantShaderBlock *block = (ConstantShaderBlock *)this;
parm->AddChild("Type", (int)block->constant_type);
parm->AddChild(Vector4(block->constant[0], block->constant[1], block->constant[2], block->constant[3]).AsMetaTag("Value", true));
}
break;
case TypeColor:
{
ColorShaderBlock *block = (ColorShaderBlock *)this;
parm->AddChild(block->color.AsMetaTag("Color", true));
}
break;
case TypeMaterialParam:
{
MaterialParamShaderBlock *block = (MaterialParamShaderBlock *)this;
parm->AddChild("Param", block->param);
}
break;
case TypeMaterialTexture:
{
MaterialTextureShaderBlock *block = (MaterialTextureShaderBlock *)this;
parm->AddChild(new Tag("Slot", block->slot));
switch (block->texture_type)
{
default:
case MaterialTextureShaderBlock::Texture2D: parm->AddChild("Type", "2D"); break;
case MaterialTextureShaderBlock::Texture3D: parm->AddChild("Type", "3D"); break;
case MaterialTextureShaderBlock::TextureCube: parm->AddChild("Type", "Cube"); break;
}
}
break;
case TypeSwizzle:
{
SwizzleShaderBlock *block = (SwizzleShaderBlock *)this;
char swizzle[5];
for (int n = 0; n < 4; ++n)
switch (block->swizzle[n])
{
case SwizzleShaderBlock::SwizzleNone: swizzle[n] = 'n'; break;
case SwizzleShaderBlock::SwizzleX: swizzle[n] = 'x'; break;
case SwizzleShaderBlock::SwizzleY: swizzle[n] = 'y'; break;
case SwizzleShaderBlock::SwizzleZ: swizzle[n] = 'z'; break;
case SwizzleShaderBlock::SwizzleW: swizzle[n] = 'w'; break;
}
swizzle[4] = 0;
parm->AddChild("Swizzle", (const char *)swizzle);
}
break;
case TypeBuild:
{
BuildShaderBlock *block = (BuildShaderBlock *)this;
char build[5];
for (int n = 0; n < 4; ++n)
switch (block->build[n])
{
case BuildShaderBlock::BuildZero: build[n] = '0'; break;
case BuildShaderBlock::BuildOne: build[n] = '1'; break;
case BuildShaderBlock::BuildX: build[n] = 'x'; break;
case BuildShaderBlock::BuildY: build[n] = 'y'; break;
case BuildShaderBlock::BuildZ: build[n] = 'z'; break;
case BuildShaderBlock::BuildW: build[n] = 'w'; break;
}
build[4] = 0;
parm->AddChild("Build", (const char *)build);
}
break;
default:
break;
}
return parm;
}
void ShaderBlock::GatherChildren(List <ShaderBlock *> &children)
{
if (!children.Find(this))
children.Add(this);
for (uint n = 0; n < GetInputCount(); ++n)
if (GetInput(n))
GetInput(n)->GatherChildren(children);
}
Tag *ShaderBlock::BranchAsMetaTag(List <ShaderBlock *> &block_map)
{
// Locate block in map.
uint index = 0;
ListForeachPtr(ShaderBlock *, block, block_map)
{
if (block == this)
break;
index++;
}
if (index == block_map.GetCount())
return NULL;
// Export block and inputs.
Tag *block = new Tag("Block");
block->AddChild("Index", index);
if (GetInputCount())
{
Tag *input = block->AddChild("Input");
for (uint n = 0; n < GetInputCount(); ++n)
input->AddChild(GetInput(n) ? GetInput(n)->BranchAsMetaTag(block_map) : new Tag(__ShaderBlockNoneTagId.c_str()));
}
return block;
}
Tag *ShaderBlock::BlockMapAsMetaTag(const List <ShaderBlock *> &block_map)
{
Tag *map = new Tag("Map");
if (!map)
__ERR__(__LOG_E__ << "Failed to allocate root tag.\n", NULL);
ListForeachPtr(ShaderBlock *, block, block_map)
if (block)
if (Tag *entry = map->AddChild("Entry"))
{
entry->AddChild("Type", ShaderBlock::BlockTypeToString(block->type));
entry->AddChild(tVectorAsMetaTag(block->pos, "Pos"));
entry->AddChild(block->ParamAsMetaTag());
}
return map;
}
Tag *ShaderTree::AsMetaTag() const
{
Tag *map = new Tag("ShaderMap");
if (!map)
__ERR__(__LOG_E__ << "Could not serialize shader map. Failed to create root tag.\n", NULL);
// Sink block position.
map->AddChild(tVectorAsMetaTag(pos, "Pos"));
// Build block export map.
List <ShaderBlock *> block_map;
for (int n = 0; n < SinkInvalid; ++n)
if (sink[n])
sink[n]->GatherChildren(block_map);
// Serialize map.
map->AddChild(ShaderBlock::BlockMapAsMetaTag(block_map));
// Serialize all sinks.
#define __SerializeShaderMapSink(__SINK__, __LABEL__)\
if (__SINK__)\
{\
Tag *sinktag = map->AddChild(__LABEL__);\
sinktag->AddChild((__SINK__)->BranchAsMetaTag(block_map));\
}
// Serialize shader map.
__SerializeShaderMapSink(sink[SinkVertex], "Vertex")
__SerializeShaderMapSink(sink[SinkNormal], "Normal")
__SerializeShaderMapSink(sink[SinkDiffuse], "Diffuse")
__SerializeShaderMapSink(sink[SinkModulate], "Modulate")
__SerializeShaderMapSink(sink[SinkSpecular], "Specular")
__SerializeShaderMapSink(sink[SinkGlossiness], "Glossiness")
__SerializeShaderMapSink(sink[SinkConstant], "Constant")
__SerializeShaderMapSink(sink[SinkOpacity], "Opacity")
__SerializeShaderMapSink(sink[SinkReflection], "Reflection")
return map;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,60 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/shader_tree_to_shader.h"
#include "core/shader_tree_compiler_isl.h"
#include "core/shader_tree.h"
#include "core/shader.h"
#include "memory/nauto_ptr.h"
using namespace GS;
//------------------------------------------------------------------------------
bool Core::ConvertShaderTreeToShader(const Core::ShaderTree &tree, Core::Shader &shader)
{
ISLShaderTreeCompiler cp;
cp.RestartCompiler(&shader);
struct ShaderTreeOutput
{
const char *builtin;
ShaderTree::ShaderSinkType sink;
const char *default_value;
};
static ShaderTreeOutput vertex_sink[] =
{
{ "%position%", ShaderTree::SinkVertex, "vec4(a_position, 1.0)" },
{ NULL, ShaderTree::SinkInvalid }
};
for (uint n = 0; vertex_sink[n].builtin; ++n)
if (CShaderBlock *cblock = cp.CompileShaderBlock(tree.sink[vertex_sink[n].sink]))
shader.vertex += String::Format("%s = %s;\n", vertex_sink[n].builtin, cblock->variable.c_str());
static ShaderTreeOutput pixel_sink[] =
{
{ "%normal%", ShaderTree::SinkNormal, "vec3(0.0, 0.0, 0.0)" },
{ "%diffuse%", ShaderTree::SinkDiffuse, "vec4(0.75, 0.75, 0.75, 1.0)" },
{ "%specular%", ShaderTree::SinkSpecular, "vec4(0.5, 0.5, 0.5, 1.0)" },
{ "%glossiness%", ShaderTree::SinkGlossiness, "0.25" },
{ "%constant%", ShaderTree::SinkConstant, "vec4(0.0, 0.0, 0.0, 1.0)" },
{ "%opacity%", ShaderTree::SinkOpacity, "1.0" },
{ NULL, ShaderTree::SinkInvalid }
};
for (uint n = 0; pixel_sink[n].builtin; ++n)
if (CShaderBlock *cblock = cp.CompileShaderBlock(tree.sink[pixel_sink[n].sink]))
shader.pixel += String::Format("%s = %s;\n", pixel_sink[n].builtin, cblock->variable.c_str());
shader.name = cp.GetId();
shader.vertex = cp.GetVertexSource() + shader.vertex;
shader.pixel = cp.GetPixelSource() + shader.pixel;
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,45 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/simple_list_renderable.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void SimpleCullingSystem::AddRenderable(Renderable *r)
{ renderable_list.Add(r); }
void SimpleCullingSystem::DeleteRenderable(Renderable *r)
{ renderable_list.Remove(r); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void SimpleCullingSystem::ComputeRenderableMinMax(MinMax &mm)
{
if (!renderable_list.GetCount())
return;
renderable_list[0]->ComputeRenderableMinMax(mm);
MinMax l_mm;
for (uint n = 1; n < renderable_list.GetCount(); ++n)
{
renderable_list[n]->ComputeRenderableMinMax(l_mm);
mm.Grow(l_mm);
}
}
uint SimpleCullingSystem::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context ctx, bool cull)
{
uint tested_primitive = 0;
ArrayListForeachPtr(Renderable *, renderable, renderable_list)
if (renderable->IsRenderable())
tested_primitive += renderable->GetRenderablePrimitiveList(view, default_view, list, ctx, cull);
return tested_primitive;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,23 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------------*/
#include "core/skin.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
bool Skin::ComputeBoneBoundingVolume(uint n, OBB &obb) const
{
if (n >= bones.GetCount())
return false;
obb = OBB::FromMinMax(bones_minmax[n]);
obb.Transform(bones_mtx[n]);
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,18 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/sound.h"
#include "core/mixer.h"
using namespace GS::Audio;
//------------------------------------------------------------------------------
Sound::~Sound()
{
mixer.UnloadSound(mixer_data);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,468 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/camera.h"
#include "core/terrain.h"
#include "core/geometry.h"
#include "core/resource_factories.h"
#include "core/render_resource_factory.h"
#include "picture/pict.h"
#include "picture/pict_io.h"
#include "filesystem/filesystem.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void Terrain::RenderSetup(ResourceFactories *f)
{
if (LoadHeightmap(heightmap_path))
{
ComputeNormals();
BuildQuadtree();
}
ComputeNormals();
BuildQuadtree();
if (render_data = new RenderData)
if (f && f->render)
{
render_data->blendmap = f->render->LoadTexture(blendmap_path);
render_data->material = f->render->LoadMaterial(material);
for (uint n = 0; n < 4; ++n)
{
render_data->layer[n].diffuse = f->render->LoadTexture(layer[n].diffuse);
render_data->layer[n].specular = f->render->LoadTexture(layer[n].specular);
render_data->layer[n].normal = f->render->LoadTexture(layer[n].normal);
render_data->layer[n].self = f->render->LoadTexture(layer[n].self);
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Terrain::LocalToTexture(const Vector4 &p, float w, float h, float &u, float &v) const
{
float lx = p.x + width * 0.5f,
lz = p.z + depth * 0.5f;
u = (lx / width) * w;
v = (lz / depth) * h;
return asbool((u >= 0) && (u < w) && (v >= 0) && (v < h));
}
bool Terrain::LocalToHeightmap(const Vector4 &p, float &u, float &v) const
{
return LocalToTexture(p, (float)heightmap_w, (float)heightmap_h, u, v);
}
float Terrain::SampleHeight(float u, float v) const
{
// Fetch samples coordinates.
int s_u[4], s_v[4];
s_u[0] = Types::Clamp(int(u), 0, heightmap_w); s_v[0] = Types::Clamp(int(v), 0, heightmap_h);
s_u[1] = Types::Clamp(s_u[0] + 1, 0, heightmap_w); s_v[1] = Types::Clamp(s_v[0] + 0, 0, heightmap_h);
s_u[2] = Types::Clamp(s_u[0] + 0, 0, heightmap_w); s_v[2] = Types::Clamp(s_v[0] + 1, 0, heightmap_h);
s_u[3] = Types::Clamp(s_u[0] + 1, 0, heightmap_w); s_v[3] = Types::Clamp(s_v[0] + 1, 0, heightmap_h);
// Fetch samples.
float s[4];
for (int n = 0; n < 4; ++n)
s[n] = heightmap[s_v[n] * GetHeightmapPitch() + s_u[n]];
// Bilinear.
float k_u = u - int(u), k_v = v - (int)v;
return (s[0] * (1 - k_u) + s[1] * k_u) * (1 - k_v) + (s[2] * (1 - k_u) + s[3] * k_u) * k_v;
}
float Terrain::SampleHeight(const Vector4 &p) const
{
float u, v;
if (!LocalToHeightmap(p, u, v))
return 0;
return SampleHeight(u, v);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Terrain::ComputeRenderableMinMax(MinMax &mm)
{
if (root_node)
{
OBB obb(root_node->minmax);
obb.Transform(GetMatrix());
obb.ComputeMinMax(mm);
}
}
void Terrain::CullRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context context, Patch *node)
{
MinMax &minmax = node->minmax;
if (view.frustum.ClassifyMinMax(minmax, &GetMatrix()) == Frustum::Outside)
return;
// Check error for the current level.
Vector4 center = minmax.GetCenter() * GetMatrix();
float lod_d = (minmax.mx - minmax.mn).Len() * 1.5f,
/*v_d = nVector::Dist(center, view.GetMatrix().GetRow(3)),*/
d_d = Vector4::Dist(center, default_view.GetMatrix().GetRow(3));
float d = d_d;// Types::Min(v_d, d_d); // Ensure high-resolution close to the viewer and the light source.
if ((d > lod_d) || !node->children[0])
list.Push(new Render::Primitive(node, this, 0));
else
for (int n = 0; n < 4; ++n)
if (node->children[n])
CullRenderablePrimitiveList(view, default_view, list, context, node->children[n]);
}
uint Terrain::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Context context, bool nUnused(cull))
{
if (root_node)
CullRenderablePrimitiveList(view, default_view, list, context, root_node);
return node_count;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *Terrain::CreateNodeGeometry(const Patch *node)
{
Geometry *geometry = new Geometry;
int patch_w = node->w / node->decimation,
patch_h = node->h / node->decimation;
// Create vertices.
geometry->vtx.Allocate((patch_w + 1) * (patch_h + 1));
float step_w = width / heightmap_w, step_h = depth / heightmap_h;
Vector4 p(node->u * step_w * GetUnit(), 0, -node->v * step_h * GetUnit()),
*pv = geometry->vtx;
for (int _v = node->v; _v <= (node->v + node->h); _v += node->decimation)
{
float *ph = &heightmap[_v * heightmap_w + node->u];
for (int _u = node->u; _u <= (node->u + node->w); _u += node->decimation)
{
pv->Set(p.x, ph[0], p.z);
pv++;
ph += node->decimation;
p.x += step_w * node->decimation * GetUnit();
}
p.x = node->u * step_w * GetUnit();
p.z += step_h * node->decimation * GetUnit();
}
// Create polygons.
geometry->AllocatePolygon(patch_w * patch_h);
for (uint n = 0; n < geometry->pol.GetCount(); ++n)
{
geometry->pol[n].vtx_count = 4;
geometry->pol[n].material = 0;
}
geometry->AllocatePolygonBinding();
Polygon *polygon = geometry->pol;
for (int _v = 0; _v < patch_h; ++_v)
for (int _u = 0; _u < patch_w; ++_u)
{
polygon->vtx_count = 4;
polygon->material = 0;
polygon->binding[0] = _v * (patch_w + 1) + _u;
polygon->binding[1] = _v * (patch_w + 1) + _u + 1;
polygon->binding[2] = (_v + 1) * (patch_w + 1) + _u + 1;
polygon->binding[3] = (_v + 1) * (patch_w + 1) + _u;
polygon++;
}
geometry->ComputeVertexNormal();
return geometry;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Terrain::UpdatePatchMinMax(Patch *node) const
{
float *ph = &heightmap[node->v * GetHeightmapPitch() + node->u];
float min_height, max_height;
min_height = max_height = ph[0];
for (int _v = 0; _v < node->h; _v += node->decimation)
{
for (int _u = 0; _u < node->w; _u += node->decimation)
{
if (ph[_u] < min_height)
min_height = ph[_u];
if (ph[_u] > max_height)
max_height = ph[_u];
}
ph += GetHeightmapPitch() * node->decimation;
}
node->minmax.mn.Set(node->u * GetUnit() - width * 0.5f, min_height, (node->v + node->h) * GetUnit() - depth * 0.5f);
node->minmax.mx.Set((node->u + node->w) * GetUnit() - width * 0.5f, max_height, node->v * GetUnit() - depth * 0.5f);
}
Patch *Terrain::BuildTerrainStaticQuadtree(int u, int v, int w, int h, int decimation, int tree_depth)
{
if (!decimation || (tree_depth == 8))
return NULL;
if (!w || !h)
return NULL;
// Create a new node.
Patch *node = new Patch;
node->terrain = this;
node->u = u; node->v = v;
node->w = w; node->h = h;
node->decimation = decimation;
// Create node geometry (helper function, should normally be done on the fly by the renderer).
// CreateNodeGeometry(node);
// Update patch minmax.
UpdatePatchMinMax(node);
// Split to create children.
int hw = w / 2, hh = h / 2;
node->children[0] = BuildTerrainStaticQuadtree(node->u, node->v, hw, hh, decimation / 2, tree_depth + 1);
node->children[1] = BuildTerrainStaticQuadtree(node->u + hw, node->v, node->w - hw, hh, decimation / 2, tree_depth + 1);
node->children[2] = BuildTerrainStaticQuadtree(node->u, node->v + hh, hw, node->h - hh, decimation / 2, tree_depth + 1);
node->children[3] = BuildTerrainStaticQuadtree(node->u + hw, node->v + hh, node->w - hw, node->h - hh, decimation / 2, tree_depth + 1);
node_count++;
return node;
}
Patch *Terrain::BuildQuadtree()
{
node_count = 0;
return root_node = BuildTerrainStaticQuadtree(0, 0, heightmap_w, heightmap_h, heightmap_w / 64, 0);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Terrain::UpdateQuadtreePatch(Patch *patch, iRect &update_rect)
{
iRect patch_rect = patch->GetRect();
if (!patch_rect.Intersect(update_rect))
return;
UpdatePatchMinMax(patch);
for (int n = 0; n < 4; ++n)
if (patch->children[n])
UpdateQuadtreePatch(patch->children[n], update_rect);
}
void Terrain::UpdateQuadtree(int u, int v, int w, int h)
{
iRect update_rect(u, v, u + w, v + h);
UpdateQuadtreePatch(root_node, update_rect);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Terrain::ComputeNormals(int u, int v, int w, int h)
{
if (!attribmap)
return;
if (!u && !v && !w && !h)
{
w = heightmap_w;
h = heightmap_h;
}
u = Types::Clamp(u, 0, heightmap_w);
v = Types::Clamp(v, 0, heightmap_h);
if (u + w > heightmap_w) w = heightmap_w - u;
if (v + h > heightmap_h) h = heightmap_h - v;
float *ph = &heightmap[v * GetHeightmapPitch() + u];
Attrib *pv = &attribmap[v * GetHeightmapPitch() + u];
for (int _v = 0; _v < h; ++_v)
{
float *sh = ph;
Attrib *sv = pv;
for (int _u = 0; _u < w; ++_u)
{
Vector4 vu(unit, sh[1] - sh[0], 0),
vv(0, sh[GetHeightmapPitch()] - sh[0], unit),
n = vv.Normalized().Cross(vu.Normalized());
sv[0].nx = (char)(n.x * 127.f);
sv[0].ny = (char)(n.y * 127.f);
sv[0].nz = (char)(n.z * 127.f);
++sh;
++sv;
}
pv += GetHeightmapPitch();
ph += GetHeightmapPitch();
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Terrain::Allocate(uint w_res, uint h_res, float _unit)
{
Free();
// Global heightmap.
heightmap_w = w_res;
heightmap_h = h_res;
if (!attribmap.Allocate((heightmap_w + 1) * (heightmap_h + 1)) || !heightmap.Allocate((heightmap_w + 1) * (heightmap_h + 1)))
__ERR__(__LOG_E__ << "Failed to allocate terrain heightmap.\n", false)
Memory::Set(&attribmap[0], 0, (heightmap_w + 1) * (heightmap_h + 1) * sizeof(Attrib));
Memory::Set(&heightmap[0], 0, sizeof(float) * (heightmap_w + 1) * (heightmap_h + 1));
width = w_res * _unit;
depth = h_res * _unit;
unit = _unit;
return true;
}
void Terrain::Free()
{
width = 0;
depth = 0;
attribmap.Free();
heightmap.Free();
heightmap_w = 0;
heightmap_h = 0;
node_count = 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Terrain::Raytrace(const Vector4 &w_s, const Vector4 &w_d, TraceResult &trace, float len)
{
trace.has_hit = false;
// Move ray to terrain space.
Vector4 s = w_s * GetInverseMatrix(),
d = w_d * GetRotationMatrix().Transposed();
// Clip ray against the terrain bounding box.
float tmin, tmax;
if (!root_node->minmax.IntersectRay(s, d, tmin, tmax))
return false;
tmin -= 0.1f; tmax += 0.1f;
Vector4 e = s + d * tmax;
if (tmin > 0)
s += d * tmin;
// Walk along the ray, looking for an intersection point.
bool side = SampleHeight(s) < s.y;
Vector4 dt = e - s;
float max_dist = dt.Len();
dt /= max_dist;
dt *= 1.f; // minimum step size is 1 meters (so as not to spend too much time stepping)
float dt_len = dt.Len();
float dist = 0.f;
for (Vector4 p = s + dt; dist < max_dist; p += dt)
{
if ((SampleHeight(p) < p.y) != side)
{
#if 1
// [EJ] Extra precision at terrain crossing boundary.
s = p - dt;
for (int n = 0; n < 24; ++n)
{
Vector4 m = (s + p) * 0.5f;
if ((SampleHeight(m) < m.y) != side)
p = m;
else s = m;
}
#endif
// Final hit.
trace.has_hit = true;
trace.w_i = p * GetMatrix();
LocalToHeightmap(p, trace.uv.x, trace.uv.y);
return true;
}
dist += dt_len;
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Terrain::ApplyBlur(int pass_count)
{
if (heightmap)
for (int p = 0; p < pass_count; ++p)
{
int n = (heightmap_w + 1) + 1;
for (int v = 1; v < heightmap_h; ++v)
{
for (int u = 1; u < heightmap_w; ++u)
{
heightmap[n] = (heightmap[n] + heightmap[n - 1] + heightmap[n - (heightmap_w + 1)] + heightmap[n + 1] + heightmap[n + (heightmap_w + 1)]) / 5.f;
++n;
}
n += 2;
}
}
}
bool Terrain::FromPicture(const char *path, int blur_pass_count)
{
// Initial values.
Picture pic;
PictureIO::Get().Load(pic, path);
int n = 0;
for (int v = 0; v < (heightmap_h + 1); ++v)
for (int u = 0; u < (heightmap_w + 1); ++u)
heightmap[n++] = pic.SampleColor((float)u / heightmap_w, (float)v / heightmap_h).x * 16.f;
ApplyBlur(blur_pass_count);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Terrain::Attrib *Terrain::GetAttributesMapAt(int u, int v) const
{ return &attribmap[(heightmap_w + 1) * v + u]; }
Vector4 Terrain::GetNormalAt(int u, int v) const
{
Attrib *n = GetAttributesMapAt(u, v);
return Vector4((float)n->nx / 127.f, (float)n->ny / 127.f, (float)n->nz / 127.f);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Terrain::Terrain()
{
width = 0;
depth = 0;
heightmap_w = 0;
heightmap_h = 0;
node_count = 0;
for (uint n = 1; n < 4; ++n)
layer[n].enabled = false;
}
Terrain::~Terrain()
{
Free();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,194 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/terrain.h"
#include "core/engine.h"
#include "core/embedded_resource_handler_interface.h"
#include "picture/pict_io.h"
#include "filesystem/filesystem.h"
#include "platform.h"
#include "log/log.h"
using namespace GS::Core;
using GS::NML::Tag;
//------------------------------------------------------------------------------
bool Terrain::LoadHeightmap(const char *uri)
{
if (Platform::Get().io->FileSize(uri) != (size_t)(4 * heightmap_w * heightmap_h))
__ERR__(__LOG_W__ << "Corrupt heightmap data in " << uri << ", incorrect data size.\n", false)
AutoPtr <IO::Handle> h(Platform::Get().io->Open(uri));
if (h.IsNull())
return false;
float *ph = heightmap;
for (int v = 0; v < heightmap_h; ++v)
{
h->Read(ph, heightmap_w * 4);
ph += heightmap_w;
ph[0] = ph[-1];
ph++;
}
for (int u = 0; u < heightmap_w; ++u)
{
ph[0] = ph[-(heightmap_w + 1)];
ph++;
}
return true;
}
bool Terrain::SaveHeightmap(const char *uri)
{
AutoPtr <IO::Handle> h(Platform::Get().io->Open(uri, IO::ModeWrite));
if (h.IsNull())
return false;
float *ph = heightmap;
for (int v = 0; v < heightmap_h; ++v)
{
h->Write(ph, heightmap_w * 4);
ph += heightmap_w + 1;
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Terrain::FromMetaTag(Tag &tag)
{
if (tag.name != "Terrain")
__ERR__(__LOG_E__ << "Could not parse terrain, incorrect root tag (" << tag.name << ").\n", false)
NMLTagForeach(pt, tag)
{
if (pt->name == "Item")
Item::FromMetaTag(*pt);
else if (pt->name == "Width")
width = pt->GetReal();
else if (pt->name == "Height")
depth = pt->GetReal();
else if (pt->name == "Material") // Legacy path, embedded material.
IEmbeddedResourceHandler::Get()->ExtractEmbeddedMaterial(material, *pt, "terrain", 0);
else if (pt->name == "MaterialName")
material = pt->GetString();
else if (pt->name == "Layers")
{
NMLTagForeach(layer_tag, *pt)
if (layer_tag->name == "Layer")
{
Tag *index_tag = layer_tag->GetTag("Index");
Layer &l = layer[index_tag ? index_tag->GetInteger() : 0];
if (layer_tag->GetTag("Enabled;"))
l.enabled = true;
if (Tag *map = layer_tag->GetTag("Diffuse;"))
l.diffuse = map->GetString();
if (Tag *map = layer_tag->GetTag("Normal;"))
l.normal = map->GetString();
if (Tag *map = layer_tag->GetTag("Specular;"))
l.specular = map->GetString();
if (Tag *map = layer_tag->GetTag("Self;"))
l.self = map->GetString();
if (Tag *map = layer_tag->GetTag("UVAngle;"))
l.angle = map->GetReal();
if (Tag *map = layer_tag->GetTag("UVTiling;"))
l.tiling = map->GetReal();
}
}
else if (pt->name == "Shader")
shader_path = pt->GetString();
else if (pt->name == "Blendmap")
blendmap_path = pt->GetString();
else if (pt->name == "Heightmap")
{
Tag *w_tag = pt->GetTypedTag("Width;", Variant::VariantInteger),
*h_tag = pt->GetTypedTag("Height;", Variant::VariantInteger),
*d_tag = pt->GetTypedTag("Data;", Variant::VariantString),
*r_tag = pt->GetTypedTag("Resolution;", Variant::VariantFloat);
if (w_tag && h_tag && d_tag && r_tag)
if (Allocate(w_tag->GetInteger(), h_tag->GetInteger(), r_tag->GetReal()))
heightmap_path = d_tag->GetString();
}
else
__LOG_W__ << "Unknown tag '" << pt->name << "' in <Terrain>.\n";
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Terrain::LayerAsMetaTag(int index)
{
Layer &l = layer[index];
Tag *layer_tag = new Tag("Layer");
if (!layer_tag)
__ERR__(__LOG_E__ << "Failed to serialize terrain layer " << index << ".\n", NULL)
layer_tag->AddChild("Index", index);
if (l.enabled)
layer_tag->AddChild(new Tag("Enabled"));
if (!l.diffuse.IsEmpty())
layer_tag->AddChild("Diffuse", l.diffuse.toUtf8());
if (!l.normal.IsEmpty())
layer_tag->AddChild("Normal", l.normal.toUtf8());
if (!l.specular.IsEmpty())
layer_tag->AddChild("Specular", l.specular.toUtf8());
if (!l.self.IsEmpty())
layer_tag->AddChild("Self", l.self.toUtf8());
layer_tag->AddChild("UVAngle", l.angle);
layer_tag->AddChild("UVTiling", l.tiling);
return layer_tag;
}
Tag *Terrain::AsMetaTag()
{
Tag *root = new Tag("Terrain");
if (!root)
__ERR__(__LOG_E__ << "Could not serialize terrain. Failed to create root tag.\n", NULL)
// Store item.
root->AddChild(Item::AsMetaTag());
// Store terrain.
root->AddChild("Width", width);
root->AddChild("Height", depth);
if (!material.IsEmpty())
root->AddChild("MaterialName", material.c_str());
// Store layers.
if (Tag *layers_tag = root->AddChild("Layers"))
for (int n = 0; n < 4; ++n)
layers_tag->AddChild(LayerAsMetaTag(n));
root->AddChild("Blendmap", blendmap_path.c_str());
root->AddChild("Shader", shader_path.c_str());
// Store heightmap.
if (Tag *height_tag = root->AddChild("Heightmap"))
{
height_tag->AddChild("Width", heightmap_w);
height_tag->AddChild("Height", heightmap_h);
height_tag->AddChild("Resolution", unit);
// Note: The terrain heightmap is saved by the editor.
height_tag->AddChild("Data", heightmap_path.c_str());
}
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,166 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/terrain_shader_generator.h"
#include "core/shader.h"
using namespace GS::Core;
//------------------------------------------------------------------------------
static void DeclareStaticTexture(Shader &shader, const char *var, const char *name)
{
if (name)
if (ShaderInput *input = shader.DeclareInput(var, ShaderInput::DataTexture2D, ShaderInput::Texture2D, ShaderInput::Uniform, ShaderInput::Pixel))
input->parm_t = name;
}
bool TerrainShaderGenerator::GenerateShader(Shader &shader, const char *t_blend, const Terrain::Layer layers[4])
{
shader.Clear();
// Get the number of layers.
uint layer_count = 0;
for (uint n = 0; n < 4; ++n)
if (layers[n].enabled)
++layer_count;
if (layer_count == 0)
return false;
// Declare default inputs.
shader.DeclareInput("a_position", ShaderInput::Vector3, ShaderInput::Position, ShaderInput::Attribute, ShaderInput::Vertex);
shader.DeclareInput("a_normal", ShaderInput::Vector3, ShaderInput::Normal, ShaderInput::Attribute, ShaderInput::Vertex);
shader.DeclareInput("a_uv", ShaderInput::Vector2, ShaderInput::UV0, ShaderInput::Attribute, ShaderInput::Vertex);
shader.DeclareVarying("v_normal", "vec3");
shader.vertex << "v_normal = a_normal;\n";
// If using more than one layer, declare the blend map.
if (layer_count > 1)
{
DeclareStaticTexture(shader, "t_blend", t_blend);
shader.DeclareVarying("v_uv", "vec2");
shader.vertex << "v_uv = a_uv;\n";
shader.pixel << "vec4 blend = texture2D(t_blend, v_uv);\n";
}
// Declare texture inputs.
bool use_tangent = false;
for (uint n = 0; n < 4; ++n)
{
if (!layers[n].enabled)
continue;
if (!layers[n].normal.IsEmpty())
{
DeclareStaticTexture(shader, String::Format("t_norm_%d", n), layers[n].normal);
use_tangent = true;
}
DeclareStaticTexture(shader, String::Format("t_diff_%d", n), layers[n].diffuse);
DeclareStaticTexture(shader, String::Format("t_spec_%d", n), layers[n].specular);
DeclareStaticTexture(shader, String::Format("t_self_%d", n), layers[n].self);
}
// Build tangent matrix.
if (use_tangent)
{
shader.DeclareVarying("v_tangent", "vec3");
shader.DeclareVarying("v_bitangent", "vec3");
// Compute tangent & bitangent.
shader.vertex <<
"\
v_tangent = normalize(cross(a_normal, vec3(0, 0, 1)));\n\
v_bitangent = normalize(cross(v_tangent, a_normal));\n\
";
// Build tangent frame.
shader.pixel << "mat3 tangent_frame = _build_mat3(v_tangent, v_bitangent, v_normal);\n";
}
// Declare layers.
for (uint n = 0; n < 4; ++n)
if (layers[n].enabled)
{
// Vertex
ShaderVarying *uv_varying = shader.DeclareVarying(String("v_uv_layer_") << n, "vec2");
shader.vertex << String::Format("%s = a_uv * %.2f;\n", uv_varying->name.c_str(), layers[n].tiling);
// Pixel
if (layers[n].normal.IsEmpty())
shader.pixel << String::Format("vec3 norm_%d = v_normal;\n", n);
else
{
shader.pixel << String::Format("vec3 normal_map_%d = texture2D(t_norm_%d, %s).xyz;\n", n, n, uv_varying->name.c_str());
shader.pixel << String::Format("normal_map_%d = normalize(vec3(normal_map_%d.xy * 2.0 - 1.0, normal_map_%d.z));\n", n, n, n);
shader.pixel << String::Format("vec3 norm_%d = n_mtx_mul(tangent_frame, normal_map_%d);\n", n, n);
}
if (layers[n].diffuse.IsEmpty())
shader.pixel << String::Format("vec4 diff_%d = vec4(1.0, 1.0, 1.0, 1.0);\n", n);
else shader.pixel << String::Format("vec4 diff_%d = texture2D(t_diff_%d, %s);\n", n, n, uv_varying->name.c_str());
if (layers[n].specular.IsEmpty())
shader.pixel << String::Format("vec4 spec_%d = vec4(1.0, 1.0, 1.0, 1.0);\n", n);
else shader.pixel << String::Format("vec4 spec_%d = texture2D(t_spec_%d, %s);\n", n, n, uv_varying->name.c_str());
if (layers[n].self.IsEmpty())
shader.pixel << String::Format("vec4 self_%d = vec4(0.0, 0.0, 0.0, 1.0);\n", n);
else shader.pixel << String::Format("vec4 self_%d = texture2D(t_self_%d, %s);\n", n, n, uv_varying->name.c_str());
}
// Build the layer mixing code.
if (layer_count == 1)
{
uint n = 0;
for ( ; n < 4; ++n)
if (layers[n].enabled)
break;
shader.pixel << "%normal% = " << String::Format("norm_%d", n) << ";\n";
shader.pixel << "%diffuse% = " << String::Format("diff_%d", n) << ";\n";
shader.pixel << "%specular% = " << String::Format("diff_%d", n) << ";\n";
shader.pixel << "%constant% = " << String::Format("self_%d", n) << ";\n";
}
else
{
static const char *layer_comp[4] = { "x", "y", "z", "w" };
String norm, diff, spec, self;
bool first_assign = true;
for (uint n = 0; n < 4; ++n)
{
if (!layers[n].enabled)
continue;
if (first_assign)
{
norm << "%normal% = " << String::Format("norm_%d * blend.%s", n, layer_comp[n]);
diff << "%diffuse% = " << String::Format("diff_%d * blend.%s", n, layer_comp[n]);
spec << "%specular% = " << String::Format("spec_%d * blend.%s", n, layer_comp[n]);
self << "%constant% = " << String::Format("self_%d * blend.%s", n, layer_comp[n]);
first_assign = false;
}
else
{
norm << String::Format(" + norm_%d * blend.%s", n, layer_comp[n]);
diff << String::Format(" + diff_%d * blend.%s", n, layer_comp[n]);
spec << String::Format(" + spec_%d * blend.%s", n, layer_comp[n]);
self << String::Format(" + self_%d * blend.%s", n, layer_comp[n]);
}
}
shader.pixel << norm << ";\n";
shader.pixel << diff << ";\n";
shader.pixel << spec << ";\n";
shader.pixel << self << ";\n";
}
return true;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,141 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/texture_parm.h"
#include "core/render_data.h"
#include "picture/pict.h"
#include "metafile/nml.h"
#include "metafile/nml_object.h"
#include "reflection/c_refl.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Render;
using namespace GS::Reflection;
//------------------------------------------------------------------------------
const char *TextureParm::GetSwizzleFlags(Swizzle swizzle)
{
static char RGBA[4] = { 0, 1, 2, 3 };
static char BGRA[4] = { 2, 1, 0, 3 };
static char ARGB[4] = { 3, 0, 1, 2 };
static char ABGR[4] = { 3, 2, 1, 0 };
static char XYZ[4] = { 0, 1, 2, 3 };
static char XZY[4] = { 0, 2, 1, 3 };
static char YXZ[4] = { 1, 0, 2, 3 };
static char YZX[4] = { 1, 2, 0, 3 };
static char ZXY[4] = { 2, 0, 1, 3 };
static char ZYX[4] = { 2, 1, 0, 3 };
switch (swizzle)
{
default:
break;
case SwizzleRGBA: return RGBA;
case SwizzleBGRA: return BGRA;
case SwizzleARGB: return ARGB;
case SwizzleABGR: return ABGR;
case SwizzleXYZ: return XYZ;
case SwizzleXZY: return XZY;
case SwizzleYXZ: return YXZ;
case SwizzleYZX: return YZX;
case SwizzleZXY: return ZXY;
case SwizzleZYX: return ZYX;
}
return RGBA;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void TextureParm::Apply(Picture &p) const
{
const char *f = GetSwizzleFlags(swizzle);
p.Swizzle(f[0], f[1], f[2], f[3]);
p.Negative(invert[0], invert[1], invert[2], invert[3]);
p.Flip(flip[0], flip[1]);
}
void TextureParm::Apply(Texture &t) const
{
t.SetFiltering(filtering);
t.SetAnisotropy(anisotropy);
t.SetWrapping(wrap_u, wrap_v);
// Note: LOD bias is done per texture stage.
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Enum::Dict TextureParm::filtering_dict[] =
{
{ TextureParm::FilterDefault, "Default" },
{ TextureParm::FilterNearest, "Nearest" },
{ TextureParm::FilterBilinear, "Bilinear" },
{ TextureParm::FilterTrilinear, "Trilinear" },
{ 0, 0 }
};
Enum::Dict TextureParm::anisotropic_dict[] =
{
{ TextureParm::AnisotropyDefault, "Default" },
{ TextureParm::AnisotropyNone, "None" },
{ TextureParm::Anisotropy2x, "2x" },
{ TextureParm::Anisotropy4x, "4x" },
{ TextureParm::Anisotropy8x, "8x" },
{ TextureParm::Anisotropy16x, "16x" },
{ 0, 0 }
};
Enum::Dict TextureParm::wrap_dict[] =
{
{ TextureParm::WrapDefault, "Default" },
{ TextureParm::WrapRepeat, "Repeat" },
{ TextureParm::WrapClamp, "Clamp" },
{ 0, 0 }
};
Enum::Dict TextureParm::swizzle_dict[] =
{
{ TextureParm::SwizzleRGBA, "RGBA" },
{ TextureParm::SwizzleBGRA, "BGRA" },
{ TextureParm::SwizzleARGB, "ARGB" },
{ TextureParm::SwizzleABGR, "ABGR" },
{ TextureParm::SwizzleXYZ, "XYZ" },
{ TextureParm::SwizzleXZY, "XZY" },
{ TextureParm::SwizzleYXZ, "YXZ" },
{ TextureParm::SwizzleYZX, "YZX" },
{ TextureParm::SwizzleZXY, "ZXY" },
{ TextureParm::SwizzleZYX, "ZYX" },
{ 0, 0 }
};
Property TextureParm::serializable[] =
{
{ Property::EnumProp, "WrapU", offsetof(TextureParm, wrap_u), wrap_dict },
{ Property::EnumProp, "WrapV", offsetof(TextureParm, wrap_v), wrap_dict },
{ Property::EnumProp, "Filtering", offsetof(TextureParm, filtering), filtering_dict },
{ Property::EnumProp, "Anisotropy", offsetof(TextureParm, anisotropy), anisotropic_dict },
{ Property::EnumProp, "Swizzle", offsetof(TextureParm, swizzle), swizzle_dict },
{ Property::BoolProp, "InvertR", offsetof(TextureParm, invert[0]), NULL },
{ Property::BoolProp, "InvertG", offsetof(TextureParm, invert[1]), NULL },
{ Property::BoolProp, "InvertB", offsetof(TextureParm, invert[2]), NULL },
{ Property::BoolProp, "InvertA", offsetof(TextureParm, invert[3]), NULL },
{ Property::BoolProp, "FlipU", offsetof(TextureParm, flip[0]), NULL },
{ Property::BoolProp, "FlipV", offsetof(TextureParm, flip[1]), NULL },
{ Property::FloatProp, "LODBias", offsetof(TextureParm, lod_bias), NULL },
{ Property::InvalidProp, 0, 0 }
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
String TextureParm::GetParmFileName(const char *uri)
{ return String::Format("%s.parm", uri); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool TextureParm::FromMetaTag(NML::Tag &t)
{ return t.name == "TextureParm" ? GenericObjectFromMetaTag(t, this, serializable) : false; }
NML::Tag *TextureParm::AsMetaTag() const
{ return NML::GenericObjectToMetaTag(new NML::Tag("TextureParm"), this, serializable); }
//------------------------------------------------------------------------------

View File

@ -0,0 +1,212 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
------------------------------------------------------------------------
Original implementation of the following publication:
Linear-Speed Vertex Cache Optimization
Tom Forsyth, RAD Game Tools: tom.forsyth@eelpi.gotdns.org
----------------------------------------------------------------------------- */
#include <cmath>
#include "core/triangle_list.h"
#include "container/nlist.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
struct VertexScore
{
uint triangle_to_draw;
float score;
int position; ///< Position in cache.
};
struct TriangleData
{
bool processed;
};
#define MaxSizeVertexCache 32
#define FindVertexScore_CacheDecayPower 1.5f
#define FindVertexScore_LastTriScore 0.75f
#define FindVertexScore_ValenceBoostScale 2.0f
#define FindVertexScore_ValenceBoostPower 0.5f
//------------------------------------------------------------------------------
static void ComputeVertexScore(VertexScore *vertex)
{
// Unneeded vertex.
if (!vertex->triangle_to_draw)
{
vertex->score = -1;
return;
}
float score = 0;
if (vertex->position < 0)
; // Not in cache, no score.
else
{
/*
This vertex was used in the last triangle,
so it has a fixed score, whichever of the three
it's in. Otherwise, you can get very different
answers depending on whether you add the triangle
1,2,3 or 3,1,2 - which is silly.
*/
if (vertex->position < 3)
score = FindVertexScore_LastTriScore;
else score = std::pow(1.f - (vertex->position - 3) / (MaxSizeVertexCache - 3), FindVertexScore_CacheDecayPower);
}
/*
Bonus points for having a low number of triangles still to
use the vertex, so we get rid of lone vertice quickly.
*/
float boost = std::pow((float)vertex->triangle_to_draw, -FindVertexScore_ValenceBoostPower);
vertex->score = score + FindVertexScore_ValenceBoostScale * boost;
}
static float ComputeTriangleScore(uint n, uint *idx, const VertexScore *vertex)
{ return vertex[idx[n * 3]].score + vertex[idx[n * 3 + 1]].score + vertex[idx[n * 3 + 2]].score; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void CacheVertex(uint idx, VertexScore *vertex, Array <int> &LRUCache)
{
// Seek for vertex in cache.
int m;
for (m = 0; m < MaxSizeVertexCache; ++m)
if (LRUCache[m] == (int)idx)
break;
// Handle corner case where a vertice is pushed out of cache.
if (m == MaxSizeVertexCache)
{
m--;
if (LRUCache[m] != -1)
{
vertex[LRUCache[m]].position = -1;
ComputeVertexScore(&vertex[LRUCache[m]]);
}
}
// Shift cache, insert vertex to top.
for (int t = (m - 1); t >= 0; --t)
if (LRUCache[t] != -1)
{
vertex[LRUCache[t]].position++;
LRUCache[t + 1] = LRUCache[t];
}
LRUCache[0] = idx;
vertex[idx].position = 0;
}
void Trilist::Optimize(const List <Trilist *> &list, int /*cache_size*/)
{
__LOG__ << "Optimizing triangle list...\n";
uint total_vtx_count = 0, total_tri_count = 0, n;
ListForeachPtr(Trilist *, t, list)
{
if (t->vtx.GetCount() > total_vtx_count)
total_vtx_count = t->vtx.GetCount();
if (t->GetTriangleCount() > total_tri_count)
total_tri_count = t->GetTriangleCount();
}
Array <VertexScore> vertex(total_vtx_count);
Array <TriangleData> triangle(total_tri_count);
if (!vertex || !triangle)
__ERRRAW__(__LOG_E__ << "Failed to allocate vertex optimization array.\n");
// Process each list.
Array <int> LRUCache(MaxSizeVertexCache);
Array <uint> ordered_idx;
ListForeachPtr(Trilist *, t, list)
{
// Reset scores.
for (n = 0; n < total_vtx_count; ++n)
{
vertex[n].triangle_to_draw = 0;
vertex[n].score = 0;
}
for (n = 0; n < total_tri_count; ++n)
triangle[n].processed = false;
for (n = 0; n < MaxSizeVertexCache; ++n)
LRUCache[n] = -1;
// Compute triangle count per vertex index.
for (n = 0; n < t->GetTriangleCount(); ++n)
for (uint m = 0; m < 3; ++m)
vertex[t->idx[n * 3 + m]].triangle_to_draw++;
// Start optimization cycles.
if (!ordered_idx.Allocate(t->idx.GetCount()))
{
__LOG_W__ << "Failed to allocate triangle list ordered index list, skipping.\n";
continue;
}
for (uint processed_tri_count = 0; processed_tri_count < t->GetTriangleCount(); ++processed_tri_count)
{
int best_score_triangle_index = -1, m;
float best_score_triangle = -1;
/// Pick up best triangle.
for (n = 0; n < t->GetTriangleCount(); ++n)
{
if (triangle[n].processed)
continue;
float score = ComputeTriangleScore(n, t->idx, vertex);
if (score > best_score_triangle)
{
best_score_triangle_index = n;
best_score_triangle = score;
}
}
// Failsafe match.
if (best_score_triangle_index == -1)
{
for (n = 0; n < t->GetTriangleCount(); ++n)
if (!triangle[n].processed)
break;
best_score_triangle_index = n;
}
// Add best triangle to the new list.
for (m = 0; m < 3; ++m)
{
uint idx = t->idx[best_score_triangle_index * 3 + m];
ordered_idx[processed_tri_count * 3 + m] = idx;
CacheVertex(idx, vertex, LRUCache);
vertex[idx].triangle_to_draw--;
}
// Update cached vertices score.
for (m = 0; m < MaxSizeVertexCache; ++m)
if (LRUCache[m] != -1)
ComputeVertexScore(&vertex[LRUCache[m]]);
triangle[best_score_triangle_index].processed = true;
}
// Commit optimized index list.
t->idx.Transfer(ordered_idx);
}
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,58 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/trigger.h"
using namespace GS;
using namespace GS::Core;
//------------------------------------------------------------------------------
void Trigger::DropItem(Item *item) {
ListForeachPtr(ItemInTrigger *, ti, items_in_trigger)
if (ti->item == item) {
items_in_trigger.Remove(ti);
delete ti;
}
}
void Trigger::MarkItem(Item *item)
{
ListForeachPtr(ItemInTrigger *, ti, items_in_trigger)
if (ti->item == item)
{
ti->inside = true;
return;
}
items_in_trigger.Add(new ItemInTrigger(item));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Trigger::ReadyItemList()
{
ListForeachPtr(ItemInTrigger *, ti, items_in_trigger)
ti->inside = false;
}
void Trigger::PurgeItemList()
{
ListForeachPtr(ItemInTrigger *, ti, items_in_trigger)
if (!ti->inside)
DropItem(ti->item);
}
//------------------------------------------------------------------------------
bool Trigger::IsInside(const Vector4 &p)
{
Vector4 local = p * GetInverseMatrix();
return (local.x > -0.5) && (local.x < 0.5) && (local.y > -0.5) && (local.y < 0.5) && (local.z > -0.5) && (local.z < 0.5);
}
Trigger::~Trigger()
{
ListForeachPtr(ItemInTrigger *, ti, items_in_trigger)
delete ti;
}