commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
173
include/engine/core/ace.cpp
Normal file
173
include/engine/core/ace.cpp
Normal 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)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
63
include/engine/core/ace_unit.cpp
Normal file
63
include/engine/core/ace_unit.cpp
Normal 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();
|
||||
}
|
||||
94
include/engine/core/cached_graphic_resource_factory.cpp
Normal file
94
include/engine/core/cached_graphic_resource_factory.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
30
include/engine/core/cached_mixer_resource_factory.cpp
Normal file
30
include/engine/core/cached_mixer_resource_factory.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
116
include/engine/core/cached_renderer_resource_factory.cpp
Normal file
116
include/engine/core/cached_renderer_resource_factory.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
224
include/engine/core/camera.cpp
Normal file
224
include/engine/core/camera.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
90
include/engine/core/camera_nml.cpp
Normal file
90
include/engine/core/camera_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
92
include/engine/core/clock.cpp
Normal file
92
include/engine/core/clock.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
143
include/engine/core/core_profiler.cpp
Normal file
143
include/engine/core/core_profiler.cpp
Normal 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
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
71
include/engine/core/embedded_resource_extractor.cpp
Normal file
71
include/engine/core/embedded_resource_extractor.cpp
Normal 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/");
|
||||
}
|
||||
26
include/engine/core/embedded_resource_handler_interface.cpp
Normal file
26
include/engine/core/embedded_resource_handler_interface.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
275
include/engine/core/emitter.cpp
Normal file
275
include/engine/core/emitter.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
154
include/engine/core/emitter_nml.cpp
Normal file
154
include/engine/core/emitter_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
449
include/engine/core/geometry.cpp
Normal file
449
include/engine/core/geometry.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
256
include/engine/core/geometry_bih.cpp
Normal file
256
include/engine/core/geometry_bih.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
1141
include/engine/core/geometry_kdtree.cpp
Normal file
1141
include/engine/core/geometry_kdtree.cpp
Normal file
File diff suppressed because it is too large
Load Diff
853
include/engine/core/geometry_nml.cpp
Normal file
853
include/engine/core/geometry_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
81
include/engine/core/geometry_normal.cpp
Normal file
81
include/engine/core/geometry_normal.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
589
include/engine/core/geometry_reducer.cpp
Normal file
589
include/engine/core/geometry_reducer.cpp
Normal 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;
|
||||
}
|
||||
51
include/engine/core/geometry_rgb.cpp
Normal file
51
include/engine/core/geometry_rgb.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
110
include/engine/core/geometry_tangent.cpp
Normal file
110
include/engine/core/geometry_tangent.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
238
include/engine/core/geometry_template.cpp
Normal file
238
include/engine/core/geometry_template.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
286
include/engine/core/geometry_to_triangle_list.cpp
Normal file
286
include/engine/core/geometry_to_triangle_list.cpp
Normal 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;
|
||||
}
|
||||
//-------------------------------------------------------------------------------
|
||||
964
include/engine/core/iso_surface.cpp
Normal file
964
include/engine/core/iso_surface.cpp
Normal 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;
|
||||
}
|
||||
|
||||
341
include/engine/core/item.cpp
Normal file
341
include/engine/core/item.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
156
include/engine/core/item_nml.cpp
Normal file
156
include/engine/core/item_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
227
include/engine/core/light.cpp
Normal file
227
include/engine/core/light.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
93
include/engine/core/light_nml.cpp
Normal file
93
include/engine/core/light_nml.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
93
include/engine/core/material.cpp
Normal file
93
include/engine/core/material.cpp
Normal 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();
|
||||
}
|
||||
54
include/engine/core/material_channel.cpp
Normal file
54
include/engine/core/material_channel.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
310
include/engine/core/material_nml.cpp
Normal file
310
include/engine/core/material_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
261
include/engine/core/material_to_shader_tree.cpp
Normal file
261
include/engine/core/material_to_shader_tree.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
213
include/engine/core/object.cpp
Normal file
213
include/engine/core/object.cpp
Normal 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) {}
|
||||
39
include/engine/core/object_nml.cpp
Normal file
39
include/engine/core/object_nml.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
211
include/engine/core/octree_renderable.cpp
Normal file
211
include/engine/core/octree_renderable.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
446
include/engine/core/path_kdtree.cpp
Normal file
446
include/engine/core/path_kdtree.cpp
Normal 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;
|
||||
}
|
||||
24
include/engine/core/physic_material.cpp
Normal file
24
include/engine/core/physic_material.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
62
include/engine/core/physic_material_nml.cpp
Normal file
62
include/engine/core/physic_material_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
193
include/engine/core/raster_font.cpp
Normal file
193
include/engine/core/raster_font.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
22
include/engine/core/render_data.cpp
Normal file
22
include/engine/core/render_data.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
102
include/engine/core/renderer.cpp
Normal file
102
include/engine/core/renderer.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
46
include/engine/core/renderer_nml.cpp
Normal file
46
include/engine/core/renderer_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
40
include/engine/core/renderer_profiler.cpp
Normal file
40
include/engine/core/renderer_profiler.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
158
include/engine/core/renderer_resource_factory.cpp
Normal file
158
include/engine/core/renderer_resource_factory.cpp
Normal 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"); }
|
||||
//------------------------------------------------------------------------------
|
||||
353
include/engine/core/renderer_toolbox.cpp
Normal file
353
include/engine/core/renderer_toolbox.cpp
Normal 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
|
||||
213
include/engine/core/resource_geometry_generator.cpp
Normal file
213
include/engine/core/resource_geometry_generator.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
171
include/engine/core/shader.cpp
Normal file
171
include/engine/core/shader.cpp
Normal 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;
|
||||
}
|
||||
446
include/engine/core/shader_block.cpp
Normal file
446
include/engine/core/shader_block.cpp
Normal 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; }
|
||||
175
include/engine/core/shader_input.cpp
Normal file
175
include/engine/core/shader_input.cpp
Normal 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;
|
||||
}
|
||||
165
include/engine/core/shader_isl_to_glsl.cpp
Normal file
165
include/engine/core/shader_isl_to_glsl.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
265
include/engine/core/shader_isl_to_hlsl.cpp
Normal file
265
include/engine/core/shader_isl_to_hlsl.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
272
include/engine/core/shader_nml.cpp
Normal file
272
include/engine/core/shader_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
69
include/engine/core/shader_tree.cpp
Normal file
69
include/engine/core/shader_tree.cpp
Normal 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(); }
|
||||
//------------------------------------------------------------------------------
|
||||
188
include/engine/core/shader_tree_compiler.cpp
Normal file
188
include/engine/core/shader_tree_compiler.cpp
Normal 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(); }
|
||||
//------------------------------------------------------------------------------
|
||||
882
include/engine/core/shader_tree_compiler_isl.cpp
Normal file
882
include/engine/core/shader_tree_compiler_isl.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
942
include/engine/core/shader_tree_compiler_tinyc.cpp
Normal file
942
include/engine/core/shader_tree_compiler_tinyc.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@ -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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
584
include/engine/core/shader_tree_nml.cpp
Normal file
584
include/engine/core/shader_tree_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
60
include/engine/core/shader_tree_to_shader.cpp
Normal file
60
include/engine/core/shader_tree_to_shader.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
45
include/engine/core/simple_list_renderable.cpp
Normal file
45
include/engine/core/simple_list_renderable.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
23
include/engine/core/skin.cpp
Normal file
23
include/engine/core/skin.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
18
include/engine/core/sound.cpp
Normal file
18
include/engine/core/sound.cpp
Normal 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);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
468
include/engine/core/terrain.cpp
Normal file
468
include/engine/core/terrain.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
194
include/engine/core/terrain_nml.cpp
Normal file
194
include/engine/core/terrain_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
166
include/engine/core/terrain_shader_generator.cpp
Normal file
166
include/engine/core/terrain_shader_generator.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
141
include/engine/core/texture_parm.cpp
Normal file
141
include/engine/core/texture_parm.cpp
Normal 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); }
|
||||
//------------------------------------------------------------------------------
|
||||
212
include/engine/core/triangle_list_optimizer.cpp
Normal file
212
include/engine/core/triangle_list_optimizer.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
58
include/engine/core/trigger.cpp
Normal file
58
include/engine/core/trigger.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user